Android OTA 升级(五):updater

一、简介

      前面分析的OTA升级的各部分代码都是在搭一个舞台,而主角现在终于登场,它就是updater。Google的代码架构设计非常好,各部分尽量松耦合。前面介绍升级脚本时,可知有两种类型的脚本,amend & edify(Amend脚本<update-script>在Android 1.5中已经被废除,只保留了Edify脚本<updater-script>). 他们各自对应一个updater. 这里,我们主要关注新的edify的updater.

       Updater可以作为学习解释器/编译器的同学一个很好的实例,但是我们只关心产品化相关的内容,所以并不去深究lex/yacc相关的东西。

二、入口函数main

bootable/recovery/updater/updater.c

  1. // 这里定义脚本的位置,注释说明本updater支持edify格式的脚本。   
  2. // Where in the package we expect to find the edify script to execute.   
  3. // (Note it's "updateR-script", not the older "update-script".)   
  4. #define SCRIPT_NAME "META-INF/com/google/android/updater-script"   
  5.   
  6. int main(int argc, char** argv) {  
  7.     // Various things log information to stdout or stderr more or less   
  8.     // at random.  The log file makes more sense if buffering is   
  9.     // turned off so things appear in the right order.   
  10.     setbuf(stdout, NULL);  
  11.     setbuf(stderr, NULL);  
  12.   
  13.     if (argc != 4) {  
  14.         fprintf(stderr, "unexpected number of arguments (%d)\n", argc);  
  15.         return 1;  
  16.     }  
  17.     // 获取 version 参数。   
  18.     char* version = argv[1];  
  19.     if ((version[0] != '1' && version[0] != '2' && version[0] != '3') ||  
  20.         version[1] != '\0') {  
  21.         // We support version 1, 2, or 3.   
  22.         fprintf(stderr, "wrong updater binary API; expected 1, 2, or 3; "  
  23.                         "got %s\n",  
  24.                 argv[1]);  
  25.         return 2;  
  26.     }  
  27.   
  28.     // 获取命令管道(用于图形显示等,见前篇)   
  29.     // Set up the pipe for sending commands back to the parent process.   
  30.     int fd = atoi(argv[2]);  
  31.     FILE* cmd_pipe = fdopen(fd, "wb");  
  32.     setlinebuf(cmd_pipe);  
  33.   
  34.     // Extract the script from the package.   
  35.   
  36.     char* package_data = argv[3];  
  37.     ZipArchive za;  
  38.     int err;  
  39.     err = mzOpenZipArchive(package_data, &za);  
  40.     if (err != 0) {  
  41.         fprintf(stderr, "failed to open package %s: %s\n",  
  42.                 package_data, strerror(err));  
  43.         return 3;  
  44.     }  
  45.   
  46.    // 读入脚本 META-INF/com/google/android/updater-script   
  47.     const ZipEntry* script_entry = mzFindZipEntry(&za, SCRIPT_NAME);  
  48.     if (script_entry == NULL) {  
  49.         fprintf(stderr, "failed to find %s in %s\n", SCRIPT_NAME, package_data);  
  50.         return 4;  
  51.     }  
  52.   
  53.     char* script = malloc(script_entry->uncompLen+1);  
  54.     if (!mzReadZipEntry(&za, script_entry, script, script_entry->uncompLen)) {  
  55.         fprintf(stderr, "failed to read script from package\n");  
  56.         return 5;  
  57.     }  
  58.     script[script_entry->uncompLen] = '\0';  
  59.   
  60.     // Configure edify's functions.   
  61.     // 注册语句处理函数   
  62.     RegisterBuiltins();  
  63.     RegisterInstallFunctions();  
  64.     RegisterDeviceExtensions();  
  65.     FinishRegistration();  
  66.   
  67.     // Parse the script.   
  68.     // 调用yy* 库函数解析脚本。   
  69.     Expr* root;  
  70.     int error_count = 0;  
  71.     yy_scan_string(script);  
  72.     int error = yyparse(&root, &error_count);  
  73.     if (error != 0 || error_count > 0) {  
  74.         fprintf(stderr, "%d parse errors\n", error_count);  
  75.         return 6;  
  76.     }  
  77.   
  78.     // Evaluate the parsed script.   
  79.     UpdaterInfo updater_info;  
  80.     updater_info.cmd_pipe = cmd_pipe;  
  81.     updater_info.package_zip = &za;  
  82.     updater_info.version = atoi(version);  
  83.   
  84.     State state;  
  85.     state.cookie = &updater_info;  
  86.     state.script = script;  
  87.     state.errmsg = NULL;  
  88.   
  89.     // 解释执行脚本。 核心函数是 Evaluate。它会调用其他callback函数,而这些callback函数   
  90.     // 又会调用Evaluate去解析不同的脚本片段。从而实现一个简单的解释器   
  91.     char* result = Evaluate(&state, root);  
  92.     if (result == NULL) {  
  93.         if (state.errmsg == NULL) {  
  94.             fprintf(stderr, "script aborted (no error message)\n");  
  95.             fprintf(cmd_pipe, "ui_print script aborted (no error message)\n");  
  96.         } else {  
  97.             fprintf(stderr, "script aborted: %s\n", state.errmsg);  
  98.             char* line = strtok(state.errmsg, "\n");  
  99.             while (line) {  
  100.                 fprintf(cmd_pipe, "ui_print %s\n", line);  
  101.                 line = strtok(NULL, "\n");  
  102.             }  
  103.             fprintf(cmd_pipe, "ui_print\n");  
  104.         }  
  105.         free(state.errmsg);  
  106.         return 7;  
  107.     } else {  
  108.         fprintf(stderr, "script result was [%s]\n", result);  
  109.         free(result);  
  110.     }  
  111.   
  112.     if (updater_info.package_zip) {  
  113.         mzCloseZipArchive(updater_info.package_zip);  
  114.     }  
  115.     free(script);  
  116.   
  117.     return 0;  
  118. }  
// 这里定义脚本的位置,注释说明本updater支持edify格式的脚本。
// Where in the package we expect to find the edify script to execute.
// (Note it's "updateR-script", not the older "update-script".)
#define SCRIPT_NAME "META-INF/com/google/android/updater-script"

int main(int argc, char** argv) {
    // Various things log information to stdout or stderr more or less
    // at random.  The log file makes more sense if buffering is
    // turned off so things appear in the right order.
    setbuf(stdout, NULL);
    setbuf(stderr, NULL);

    if (argc != 4) {
        fprintf(stderr, "unexpected number of arguments (%d)\n", argc);
        return 1;
    }
    // 获取 version 参数。
    char* version = argv[1];
    if ((version[0] != '1' && version[0] != '2' && version[0] != '3') ||
        version[1] != '\0') {
        // We support version 1, 2, or 3.
        fprintf(stderr, "wrong updater binary API; expected 1, 2, or 3; "
                        "got %s\n",
                argv[1]);
        return 2;
    }

    // 获取命令管道(用于图形显示等,见前篇)
    // Set up the pipe for sending commands back to the parent process.
    int fd = atoi(argv[2]);
    FILE* cmd_pipe = fdopen(fd, "wb");
    setlinebuf(cmd_pipe);

    // Extract the script from the package.

    char* package_data = argv[3];
    ZipArchive za;
    int err;
    err = mzOpenZipArchive(package_data, &za);
    if (err != 0) {
        fprintf(stderr, "failed to open package %s: %s\n",
                package_data, strerror(err));
        return 3;
    }

   // 读入脚本 META-INF/com/google/android/updater-script
    const ZipEntry* script_entry = mzFindZipEntry(&za, SCRIPT_NAME);
    if (script_entry == NULL) {
        fprintf(stderr, "failed to find %s in %s\n", SCRIPT_NAME, package_data);
        return 4;
    }

    char* script = malloc(script_entry->uncompLen+1);
    if (!mzReadZipEntry(&za, script_entry, script, script_entry->uncompLen)) {
        fprintf(stderr, "failed to read script from package\n");
        return 5;
    }
    script[script_entry->uncompLen] = '\0';

    // Configure edify's functions.
    // 注册语句处理函数
    RegisterBuiltins();
    RegisterInstallFunctions();
    RegisterDeviceExtensions();
    FinishRegistration();

    // Parse the script.
    // 调用yy* 库函数解析脚本。
    Expr* root;
    int error_count = 0;
    yy_scan_string(script);
    int error = yyparse(&root, &error_count);
    if (error != 0 || error_count > 0) {
        fprintf(stderr, "%d parse errors\n", error_count);
        return 6;
    }

    // Evaluate the parsed script.
    UpdaterInfo updater_info;
    updater_info.cmd_pipe = cmd_pipe;
    updater_info.package_zip = &za;
    updater_info.version = atoi(version);

    State state;
    state.cookie = &updater_info;
    state.script = script;
    state.errmsg = NULL;

    // 解释执行脚本。 核心函数是 Evaluate。它会调用其他callback函数,而这些callback函数
    // 又会调用Evaluate去解析不同的脚本片段。从而实现一个简单的解释器
    char* result = Evaluate(&state, root);
    if (result == NULL) {
        if (state.errmsg == NULL) {
            fprintf(stderr, "script aborted (no error message)\n");
            fprintf(cmd_pipe, "ui_print script aborted (no error message)\n");
        } else {
            fprintf(stderr, "script aborted: %s\n", state.errmsg);
            char* line = strtok(state.errmsg, "\n");
            while (line) {
                fprintf(cmd_pipe, "ui_print %s\n", line);
                line = strtok(NULL, "\n");
            }
            fprintf(cmd_pipe, "ui_print\n");
        }
        free(state.errmsg);
        return 7;
    } else {
        fprintf(stderr, "script result was [%s]\n", result);
        free(result);
    }

    if (updater_info.package_zip) {
        mzCloseZipArchive(updater_info.package_zip);
    }
    free(script);

    return 0;
}

还没开始,就结束了。代码非常简单,因为细节隐藏在那些callback函数里。我们看一下。
三、callback函数

1)  RegisterBuiltins

  1. void RegisterBuiltins() {  
  2.     RegisterFunction("ifelse", IfElseFn);  
  3.     RegisterFunction("abort", AbortFn);  
  4.     RegisterFunction("assert", AssertFn);  
  5.     RegisterFunction("concat", ConcatFn);  
  6.     RegisterFunction("is_substring", SubstringFn);  
  7.     RegisterFunction("stdout", StdoutFn);  
  8.     RegisterFunction("sleep", SleepFn);  
  9.   
  10.     RegisterFunction("less_than_int", LessThanIntFn);  
  11.     RegisterFunction("greater_than_int", GreaterThanIntFn);  
  12. }  
void RegisterBuiltins() {
    RegisterFunction("ifelse", IfElseFn);
    RegisterFunction("abort", AbortFn);
    RegisterFunction("assert", AssertFn);
    RegisterFunction("concat", ConcatFn);
    RegisterFunction("is_substring", SubstringFn);
    RegisterFunction("stdout", StdoutFn);
    RegisterFunction("sleep", SleepFn);

    RegisterFunction("less_than_int", LessThanIntFn);
    RegisterFunction("greater_than_int", GreaterThanIntFn);
}

这些语句控制执行流程。
2) RegisterInstallFunctions

  1. void RegisterInstallFunctions() {  
  2.     RegisterFunction("mount", MountFn);  
  3.     RegisterFunction("is_mounted", IsMountedFn);  
  4.     RegisterFunction("unmount", UnmountFn);  
  5.     RegisterFunction("format", FormatFn);  
  6.     RegisterFunction("show_progress", ShowProgressFn);  
  7.     RegisterFunction("set_progress", SetProgressFn);  
  8.     RegisterFunction("delete", DeleteFn);  
  9.     RegisterFunction("delete_recursive", DeleteFn);  
  10.     RegisterFunction("package_extract_dir", PackageExtractDirFn);  
  11.     RegisterFunction("package_extract_file", PackageExtractFileFn);  
  12.     RegisterFunction("retouch_binaries", RetouchBinariesFn);  
  13.     RegisterFunction("undo_retouch_binaries", UndoRetouchBinariesFn);  
  14.     RegisterFunction("symlink", SymlinkFn);  
  15.     RegisterFunction("set_perm", SetPermFn);  
  16.     RegisterFunction("set_perm_recursive", SetPermFn);  
  17.   
  18.     RegisterFunction("getprop", GetPropFn);  
  19.     RegisterFunction("file_getprop", FileGetPropFn);  
  20.     RegisterFunction("write_raw_image", WriteRawImageFn);  
  21.     RegisterFunction("write_raw_parameter_image", WriteRawParameterImageFn);  
  22.     RegisterFunction("clear_misc_command", ClearMiscCommandFn);  
  23.   
  24.     RegisterFunction("apply_patch", ApplyPatchFn);  
  25.     RegisterFunction("apply_patch_check", ApplyPatchCheckFn);  
  26.     RegisterFunction("apply_patch_space", ApplyPatchSpaceFn);  
  27.   
  28.     RegisterFunction("read_file", ReadFileFn);  
  29.     RegisterFunction("sha1_check", Sha1CheckFn);  
  30.   
  31.     RegisterFunction("wipe_cache", WipeCacheFn);  
  32.   
  33.     RegisterFunction("ui_print", UIPrintFn);  
  34.   
  35.     RegisterFunction("run_program", RunProgramFn);  
  36. }  
void RegisterInstallFunctions() {
    RegisterFunction("mount", MountFn);
    RegisterFunction("is_mounted", IsMountedFn);
    RegisterFunction("unmount", UnmountFn);
    RegisterFunction("format", FormatFn);
    RegisterFunction("show_progress", ShowProgressFn);
    RegisterFunction("set_progress", SetProgressFn);
    RegisterFunction("delete", DeleteFn);
    RegisterFunction("delete_recursive", DeleteFn);
    RegisterFunction("package_extract_dir", PackageExtractDirFn);
    RegisterFunction("package_extract_file", PackageExtractFileFn);
    RegisterFunction("retouch_binaries", RetouchBinariesFn);
    RegisterFunction("undo_retouch_binaries", UndoRetouchBinariesFn);
    RegisterFunction("symlink", SymlinkFn);
    RegisterFunction("set_perm", SetPermFn);
    RegisterFunction("set_perm_recursive", SetPermFn);

    RegisterFunction("getprop", GetPropFn);
    RegisterFunction("file_getprop", FileGetPropFn);
    RegisterFunction("write_raw_image", WriteRawImageFn);
    RegisterFunction("write_raw_parameter_image", WriteRawParameterImageFn);
    RegisterFunction("clear_misc_command", ClearMiscCommandFn);

    RegisterFunction("apply_patch", ApplyPatchFn);
    RegisterFunction("apply_patch_check", ApplyPatchCheckFn);
    RegisterFunction("apply_patch_space", ApplyPatchSpaceFn);

    RegisterFunction("read_file", ReadFileFn);
    RegisterFunction("sha1_check", Sha1CheckFn);

    RegisterFunction("wipe_cache", WipeCacheFn);

    RegisterFunction("ui_print", UIPrintFn);

    RegisterFunction("run_program", RunProgramFn);
}

    这些语句执行各种功能。基本上,我们只需要知道用法就可以了。值得注意的是,run_program原语允许我们去执行自定义程序,这应该足够满足我们的个性化需求了。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值