Principle and process analysis of Android OTA upgrade (8) - - the execution process of update_binary

Keywords: Android Apache Makefile Google

Principle and Process Analysis of Android OTA Upgrade (VIII) - Execution Process of Upgrade Program update_binary

1. Analysis of the execution process of update_binary

   The program binary executed by the child process in the previous article is actually update-binary in the package. As we mentioned above, Recovery services do this part by copying the update-binary in the package to / tmp/update_binary in the memory file system before executing it. The source code of update_binary program is located in gingerbread0919/bootable/recovery/updater/updater.c. The source code is as follows:
     * Copyright (C) 2009 The Android Open Source Project 
     * Licensed under the Apache License, Version 2.0 (the "License"); 
     * you may not use this file except in compliance with the License. 
     * You may obtain a copy of the License at 
     * Unless required by applicable law or agreed to in writing, software 
     * distributed under the License is distributed on an "AS IS" BASIS, 
     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
     * See the License for the specific language governing permissions and 
     * limitations under the License. 

    #include <stdio.h>  
    #include <unistd.h>  
    #include <stdlib.h>  

    #include "edify/expr.h"  
    #include "updater.h"  
    #include "install.h"  
    #include "minzip/Zip.h"  

    // Generated by the makefile, this function defines the  
    // RegisterDeviceExtensions() function, which calls all the  
    // registration functions for device-specific extensions.  
    #include ""  

    // 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;  

        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",  
            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");  

        // 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;  

        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.  


        // Parse the script.  

        Expr* root;  
        int error_count = 0;  
        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;  

        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");  
            return 7;  
        } else {  
            fprintf(stderr, "script result was [%s]\n", result);  

        if (updater_info.package_zip) {  

        return 0;  

Through the above source code to analyze the execution process of this program:

    Function parameters and version checking: The current updater binary API supports version numbers of 1, 2, 3.

    (2) Get the pipeline and open it: Write commands to the pipeline during the execution of the program to inform its parent process to update the UI display according to the command.

    (3) Read the updater-script script: Read the updater-script script from the package into a dynamic memory for later execution.

    (4) Configure edify's functions: the statement processing function in the registration script, that is, the function to identify the commands in the script. There are mainly the following categories

               RegisterBuiltins(): Statements that control processes in a registry program, such as ifelse, assert, abort, stdout, etc.

                        Register Install Functions (): Functions required for installation during actual installation, such as mount, format, set_progress, set_perm, and so on.

               RegisterDevice Extensions (): Additional items related to devices are not implemented in the source code.

               FinishRegistration(): End registration.

    Parsethe script: Call yy* library function to parse the script and store the parsed content in an Expr type Python class. The main functions are yy_scan_string() and yyparse().

    Execution script: The core function is Evaluate (), which calls other callback functions, and these callback functions will call Evaluate to parse different script fragments, thus realizing a simple script interpreter.

    Error message prompt: Finally, according to the return value of Evaluate (), give some printing information.

        This execution process is very simple, and the main function is Evaluate. It is responsible for the final execution of parsed script commands. The command in the installation process is updater-script.

        The next section will introduce the syntax of the updater-script script and the execution process of the script in the specific upgrade.

Document reference:

1. Android OTA Upgrade Principle and Process Analysis (8) - Upgrade Program update_binary Execution Process

Posted by brax23 on Tue, 18 Dec 2018 18:36:04 -0800