Android OTA系统升级---原理二

本文详细介绍了Android系统如何通过/cache/recovery/command进行OTA包升级,包括RecoverySystem类中的bootCommand函数如何工作,以及Android系统烧写过程中的三种模式:bootloader、recovery和mainsystem之间的通信机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在一文中已经说明,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。
        bootloader主要用来屏蔽硬件的差异,类似于PC中的BIOS,它的功能相对比较简单,内部提供了一些命令,比如:可以将nand flash分区加载到内存、运行内存中的程序、操作SD卡等。Android中的booloader是uboot,位于源码的uboot目录下。
        main system就是正常运行的Android操作系统,而recovery则是一个mini的Android系统,顾名思义,就是用来进行系统



三种模式

        烧写的过程中,需要在三种模式下互相切换。确切的说,应该是三个操作环境:bootloader、recovery和main system。
        bootloader主要用来屏蔽硬件的差异,类似于PC中的BIOS,它的功能相对比较简单,内部提供了一些命令,比如:可以将nand flash分区加载到内存、运行内存中的程序、操作SD卡等。Android中的booloader是uboot,位于源码的uboot目录下。
        main system就是正常运行的Android操作系统,而recovery则是一个mini的Android系统,顾名思义,就是用来进行系统恢复相关的操作的,它的运行规则和main system一样,只是,它在启动时只加载recovery服务,此服务用于烧写Android系统。
        三者之间的关系如下图所示:

bootloader

        板子启动时,在Putty控制台中按回车,可以进入uboot,输入help可以查看其可用的命令。uboot的命令是可以自定义的,需要在uboot源码中进行设置。uboot下可以使用fastboot命令,进入fastboot模式下,可以使用PC与之连接(此时,使用fastboot协议通信),进行Android系统的烧写工作。
        在uboot中,你可以更新uboot在内的所有系统模块。

recovery

        recovery系统包含了内核和类似于根文件系统两部分,启动时仍采用init进程和init.rc配置脚本,不同的是init.rc脚本比较简单,system目录中只存放了一些必备的工具。
        recovery系统下,你能更新除uboot之外的所有Android系统模块。
        recovery模式下,只有一个recovery服务,该服务对应于recovery进程,源码位置:bootable\recovery。

main system

        main system是正常运行的Android系统。

通信
        Android板子每个时刻只可以处于bootloader、recovery、main system其中的一个模式中,烧写过程中,三个模式之间需要通信,比如:main system通知recovery烧写那个升级包。大致有三种方式可以用来通信:BCB、寄存器和cache分区。

BCB

        BCB (bootloader control block)可以用于main system传递数据给bootloader和recovery模式。BCB的内容存在于nand flash的一个独立的分区,可以在nand flash分区表中看到,分区的名称为misc。
        通过BCB,main system可以通知bootloader启动到recovery模式下,同时也可以传递命令给recovery,比如烧写哪个文件。
        recovery在烧写的过程中,会设置BCB,以确保烧写成功前,一直会开机启动到recovery模式下,这样可以防止烧写过程中断电的情况。

寄存器

        main system模式下,运行如下命令会重启,并进入recovery模式:(也可调用android_reboot函数)
[plain]  view plain  copy
  1. reboot recovery  

        reboot命令实际上是系统调用,最终会调用到内核的kernel_restart函数,该函数最终会设置某个寄存器的位置,然后执行重启操作。
重启后,bootloader会检测到该寄存器的值,并根据其值,启动到recovery模式下。

cache分区

        recovery和main system模式下,都会将nand flash的cache分区挂载到cache目录从而实现这两种模式下的通信。比如:main system模式下,下载升级包update.zip,并将其路径设置到文件/cache/recovery/command中,然后重启到recovery模式下,recovery进程会读取到文件/cache/recovery/command中的值,并执行系统升级工作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值