您的位置:首页 > 移动开发 > Android开发

Android OTA 升级(五):updater .

2013-07-27 10:27 375 查看
一、简介

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

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

二、入口函数main

bootable/recovery/updater/updater.c

// 这里定义脚本的位置,注释说明本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

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

 
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原语允许我们去执行自定义程序,这应该足够满足我们的个性化需求了
                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  Android OTA