在一文中已经说明,android系统进行OTA包升级是通过/cache/recovery/command,与系统通信,接收升级命令指令,详细可以查看源码: bootable/recovery/recovery.c.
//bootable/recovery/recovery.c的入口函数 main:
int
main(int argc, char **argv) {
time_t start = time(NULL);
......
load_volume_table();
ensure_path_mounted(LAST_LOG_FILE);
rotate_last_logs(10);
get_args(&argc, &argv);
int previous_runs = 0;
const char *send_intent = NULL;
const char *update_package = NULL;
int wipe_data = 0, wipe_cache = 0, show_text = 0;
int clr_format_bit = 0;
bool just_exit = false;
int arg;
//接收命令,如命令是f,则是wipe_data,若是u, 就是系统升级
while ((arg = getopt_long(argc, argv, "", OPTIONS, NULL)) != -1) {
switch (arg) {
case 'p': previous_runs = atoi(optarg); break;
case 's': send_intent = optarg; break;
case 'u': update_package = optarg; break;
case 'f': wipe_data = wipe_cache = clr_format_bit = 1; break;
case 'w': wipe_data = wipe_cache = 1; break;
case 'c': wipe_cache = 1; break;
case 't': show_text = 1; break;
case 'x': just_exit = true; break;
case 'l': locale = optarg; break;
case '?':
LOGE("Invalid command argument\n");
continue;
}
}
//这里绘制的应该就是我们通常通过Power键+音量-键看到的界面了
Device* device = make_device();
ui = device->GetUI();
gCurrentUI = ui;
ui->Init();
ui->SetLocale(locale);
ui->SetBackground(RecoveryUI::NONE);
if (show_text) ui->ShowText(true);
struct selinux_opt seopts[] = {
{ SELABEL_OPT_PATH, "/file_contexts" }
};
......
}
指令映射关系OPTIONS数组:
static const struct option OPTIONS[] = {
{ "send_intent", required_argument, NULL, 's' },
{ "update_package", required_argument, NULL, 'u' },
{ "wipe_data", no_argument, NULL, 'w' },
{ "wipe_cache", no_argument, NULL, 'c' },
{ "show_text", no_argument, NULL, 't' },
{ "just_exit", no_argument, NULL, 'x' },
{ "first_format", no_argument, NULL, 'f' },
{ "locale", required_argument, NULL, 'l' },
{ NULL, 0, NULL, 0 },
};
static const char *CACHE_LOG_DIR = "/cache/recovery";
//命令驱动文件。
static const char *COMMAND_FILE = "/cache/recovery/command";
有兴趣可以继续深入研究。
再来看看RecoverySystem类中的private static void bootCommand(Context context, String... args)函数。
private static void bootCommand(Context context, String... args) throws IOException {
RECOVERY_DIR.mkdirs(); // In case we need it
COMMAND_FILE.delete(); // In case it's not writable
LOG_FILE.delete();
FileWriter command = new FileWriter(COMMAND_FILE); //COMMAND_FILE="/cache/recovery/command";
try {
// 这是bootCommand调用
// final String filenameArg = "--update_package=" + filename;
//final String localeArg = "--locale=" + Locale.getDefault().toString();
// bootCommand(context, filenameArg, localeArg);
//将升级包的路径文件名和本地语言区域写入到"/cache/recovery/command";
for (String arg : args) {
if (!TextUtils.isEmpty(arg)) {
command.write(arg);
command.write("\n");
}
}
} finally {
command.close();
}
//重启进入Recovery模式
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
pm.reboot(PowerManager.REBOOT_RECOVERY);
....
}
所以可以看出RecoverySystem将升级包路径文件名传递给 /cache/recovery/command, 重启后进入Recovery模式,进行升级包安装。
android的工作模式: http://blog.csdn.net/chenyufei1013/article/details/12705719
三种模式
三种模式
bootloader
recovery
main system
BCB
寄存器
reboot命令实际上是系统调用,最终会调用到内核的kernel_restart函数,该函数最终会设置某个寄存器的位置,然后执行重启操作。