Android基于ClockworkMod Recovery(CWM)的系统升级
Android 系统自带了升级的接库RecoverySystem.installPackage,但是通过installPackage进入ClockworkMod Recovery(CWM)后,包的签名验证是打开的,导致升级错误。但是在实践中发现,如果通过自己手动按键进入CWM Recovery模式后,签名验证默认是关闭的,而自己通过APK升级进入后验证是打开的,这个就说明签名验证是可以通过外部参数调整的。由于CWM本身是不开源的,无法看到具体的实现细节,只能通过反编译,RomManager的日志和猜。
CWM提供了一个配套的RomManager.apk进行升级,那我们就从RomManager.apk下手。
通过分析RomManager.apk的日志,发现RomManager.apk在运行的时候会通过一个 rommanager.sh 的脚本,来进行相关的reboot 并进入recovery模式。
1 2 3 4 5 6 7 | border@kvbian:~ s$ cat rommanager.sh mkdir -p /cache/recovery ; cat /data/data/com.koushikdutta.rommanager/files/extendedcommand > /cache/recovery/extendedcommand ; rm /cache/recovery/command ; mkdir -p /sdcard/clockworkmod ; echo 1 > /sdcard/clockworkmod/.recoverycheckpoint ; reboot recovery ; border@kvbian:~ s$ cat extendedcommand ui_print("ROM Manager Version 5.0.0.5"); ui_print("2012年4月18日"); ui_print("Preparing to install ROM..."); assert(install_zip("/sdcard/update/kvbian-rom-signed-20120417-2112.zip")); |
从上面的rommanager.sh 脚本可以看出:
CWM如果要取消签名验证进行升级,不能使用Android默认的
/cache/recovery/command 文件进行相关的命令。
而是使用 /cache/recovery/extendedcommand 执行相关的升级命令。
同时要在 /sdcard/clockworkmod/.recoverycheckpoint 文件做相关的标记。
相关的升级代码:
权限:
1 2 | <uses-permission android:name="android.permission.ACCESS_CACHE_FILESYSTEM" /> <uses-permission android:name="android.permission.REBOOT" /> |
Java 代码(完成的程序参考: 升级程序RomUpdate下载):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 | package com.kvbian.romupdate; import java.io.File; import java.io.FileOutputStream; import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; import android.app.Activity; import android.content.Context; import android.os.Bundle; import android.os.PowerManager; import android.os.StrictMode; import android.util.Log; import android.widget.TextView; /** * @author Jiang Bian * mail: borderj@gmail.com * blog: http://wifihack.net * */ public class RomUpdateActivity extends Activity { /** Called when the activity is first created. */ /* * Android 3.0 * 测试机器: GT-P7300/GT-P7310 * 本程序之在 ClockworkMod_Recovery_v5.5.0.4 版本测试过,其他版本没有测试。 * ClockworkMod Recovery(CWM) 如果要取消签名验证进行升级,不能使用Android默认的 * /cache/recovery/command 文件进行相关的命令。 * 而是使用 /cache/recovery/extendedcommand 执行相关的升级命令。 * * 同时要在 /sdcard/clockworkmod/.recoverycheckpoint 文件做相关的标记。 * * 本文参考: * 1. frameworks/base/core/java/android/os/RecoverySystem.java * 2. bootable/recovery/recovery.c * 3. RomManager.apk */ private static final String TAG = "RomUpdateActivity"; private static final String ROM_DOWNLOAD_URL = "http://192.168.1.66/update.zip"; private static final String ROMPATH = "/sdcard/update.zip"; private static int buffer_size = 1024 * 10; /** Used to communicate with recovery. See bootable/recovery/recovery.c. */ private static File RECOVERY_DIR = new File("/cache/recovery"); private static File CLOCK_WORK_MOD_DIR = new File("/sdcard/clockworkmod"); private static File CLOCK_WORK_MOD_CHECKPOINT_FILE = new File(CLOCK_WORK_MOD_DIR, ".recoverycheckpoint"); private static File COMMAND_FILE = new File(RECOVERY_DIR, "command"); // // /cache/recovery/extendedcommand private static File EXTENDED_FILE = new File(RECOVERY_DIR, "extendedcommand"); private static File LOG_FILE = new File(RECOVERY_DIR, "log"); /** * Reboot into the recovery system with the supplied argument. * @throws IOException if something goes wrong. * From: frameworks/base/core/java/android/os/RecoverySystem.java border@kvbian:~ s$ cat rommanager.sh mkdir -p /cache/recovery ; cat /data/data/com.koushikdutta.rommanager/files/extendedcommand > /cache/recovery/extendedcommand ; rm /cache/recovery/command ; mkdir -p /sdcard/clockworkmod ; echo 1 > /sdcard/clockworkmod/.recoverycheckpoint ; reboot recovery ; border@kvbian:~ s$ cat extendedcommand ui_print("ROM Manager Version 5.0.0.5"); ui_print("2012年4月18日"); ui_print("Preparing to install ROM..."); assert(install_zip("/sdcard/update/kvbian-rom-signed-20120417-2112.zip")); */ private void bootCommand(Context context) throws IOException { RECOVERY_DIR.mkdirs(); // In case we need it CLOCK_WORK_MOD_DIR.mkdirs(); EXTENDED_FILE.delete(); COMMAND_FILE.delete(); // In case it's not writable CLOCK_WORK_MOD_CHECKPOINT_FILE.delete(); LOG_FILE.delete(); Log.v(TAG, "write ClockWorkMod Checkpoint File: " + CLOCK_WORK_MOD_CHECKPOINT_FILE.getAbsolutePath()); FileWriter checkpoint = new FileWriter(CLOCK_WORK_MOD_CHECKPOINT_FILE); try { checkpoint.write("1"); checkpoint.write("\n"); } finally { checkpoint.close(); } Log.v(TAG, "write Extended Command File: " + EXTENDED_FILE.getAbsolutePath()); Log.v(TAG, "write Extended Command File args: " + ROMPATH); FileWriter command = new FileWriter(EXTENDED_FILE); try { command.write("ui_print(\"ZPad ROM Manager Version:\"); "); command.write("\n"); command.write("ui_print(\"2012.4.18\");"); command.write("\n"); command.write("ui_print(\"Preparing to install ROM...\");"); command.write("\n"); //assert(install_zip("/sdcard/update/kvbian-rom-signed-20120417-2112.zip")); command.write("assert(install_zip(\"" + ROMPATH + "\"));"); command.write("\n"); } finally { command.close(); } /** * boot-recovery * recovery */ // Having written the command file, go ahead and reboot PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE); //pm.reboot("recovery"); pm.reboot("recovery"); } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder() .detectDiskReads().detectDiskWrites().detectNetwork() // or // .detectAll() // for // all // detectable // problems .penaltyLog().build()); StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder() .detectLeakedSqlLiteObjects().detectLeakedClosableObjects() .penaltyLog().penaltyDeath().build()); // getRomFromNet(ROM_DOWNLOAD_URL); romUpdate(this); TextView tv = new TextView(this); tv.setText("RomUpdate Version: 1.1 - 2012.4.18"); setContentView(tv); } public void romUpdate(Context context) { try { bootCommand(context); } catch (IOException e) { Log.v(TAG, e.getMessage()); e.printStackTrace(); } } public void getRomFromNet(String romURL) { try { // set the download URL, a url that points to a file on the internet // this is the file to be downloaded Log.v(TAG, " ------------- url: " + romURL + " ------------- "); URL url = new URL(romURL); // create the new connection HttpURLConnection urlConnection = (HttpURLConnection) url .openConnection(); File file = new File(ROMPATH); // this will be used in reading the data from the internet InputStream inputStream = urlConnection.getInputStream(); // this is the total size of the file int totalSize = urlConnection.getContentLength(); // variable to store total downloaded bytes int downloadedSize = 0; // create a buffer... byte[] buffer = new byte[1024]; int bufferLength = 0; // used to store a temporary size of the Log.v(TAG, "Download From [" + romURL + "], Save File To: " + ROMPATH + "]"); FileOutputStream fileOutput = new FileOutputStream(file); while ((bufferLength = inputStream.read(buffer)) > 0) { fileOutput.write(buffer, 0, bufferLength); downloadedSize += bufferLength; } // close the output stream when done fileOutput.close(); Log.v(TAG, " Save File To: [" + ROMPATH + "]"); } catch (MalformedURLException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } } |
测试机器: GT-P7300/GT-P7310
测试环境: Android 3.0
在 ClockworkMod_Recovery_v5.5.0.4 版本测试过,其他版本没有测试。
本文参考:
1. frameworks/base/core/java/android/os/RecoverySystem.java
2. bootable/recovery/recovery.c
3. RomManager.apk
4. 升级程序RomUpdate下载
![[Google]]( http://wifihack.net/blog/wp-content/plugins/easy-adsense-lite/google-light.gif)
Recent Comments