Androidsystemrecoverywork use update.zip upgrade process analysis (7)-core install_package function of recovery service

Source: Internet
Author: User
Tags strtok ziparchive

Androidsystemrecoverywork use update.zip upgrade process analysis (7) --- core install_package function of recovery service


I. Core install_package(upgrade update.zip only) of recoveryservice)

Unlike wipe_data‑wipe_cachein recoveryservice, install_package(metadata is a unique part of update.zip and the core part. In this step, we started to process our update.zip package. Next we will start to analyze this part. Let's look at the legend first:

The source code file for this part is located at/gingerbread0919/bootable/recovery/install. C. This is a source code file without the main function, or post the source code as follows:

/* * Copyright (C) 2007 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 * *      http://www.apache.org/licenses/LICENSE-2.0 * * 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 <ctype.h>#include <errno.h>#include <fcntl.h>#include <limits.h>#include <sys/stat.h>#include <sys/wait.h>#include <unistd.h>#include "common.h"#include "install.h"#include "mincrypt/rsa.h"#include "minui/minui.h"#include "minzip/SysUtil.h"#include "minzip/Zip.h"#include "mtdutils/mounts.h"#include "mtdutils/mtdutils.h"#include "roots.h"#include "verifier.h"#define ASSUMED_UPDATE_BINARY_NAME  "META-INF/com/google/android/update-binary"#define PUBLIC_KEYS_FILE "/res/keys"// If the package contains an update binary, extract it and run it.static inttry_update_binary(const char *path, ZipArchive *zip) {    const ZipEntry* binary_entry =            mzFindZipEntry(zip, ASSUMED_UPDATE_BINARY_NAME);    if (binary_entry == NULL) {        mzCloseZipArchive(zip);        return INSTALL_CORRUPT;    }    char* binary = "/tmp/update_binary";    unlink(binary);    int fd = creat(binary, 0755);    if (fd < 0) {        mzCloseZipArchive(zip);        LOGE("Can't make %s\n", binary);        return 1;    }    bool ok = mzExtractZipEntryToFile(zip, binary_entry, fd);    close(fd);    mzCloseZipArchive(zip);    if (!ok) {        LOGE("Can't copy %s\n", ASSUMED_UPDATE_BINARY_NAME);        return 1;    }    int pipefd[2];    pipe(pipefd);    // When executing the update binary contained in the package, the    // arguments passed are:    //    //   - the version number for this interface    //    //   - an fd to which the program can write in order to update the    //     progress bar.  The program can write single-line commands:    //    //        progress <frac> <secs>    //            fill up the next <frac> part of of the progress bar    //            over <secs> seconds.  If <secs> is zero, use    //            set_progress commands to manually control the    //            progress of this segment of the bar    //    //        set_progress <frac>    //            <frac> should be between 0.0 and 1.0; sets the    //            progress bar within the segment defined by the most    //            recent progress command.    //    //        firmware <"hboot"|"radio"> <filename>    //            arrange to install the contents of <filename> in the    //            given partition on reboot.    //    //            (API v2: <filename> may start with "PACKAGE:" to    //            indicate taking a file from the OTA package.)    //    //            (API v3: this command no longer exists.)    //    //        ui_print <string>    //            display <string> on the screen.    //    //   - the name of the package zip file.    //    char** args = malloc(sizeof(char*) * 5);    args[0] = binary;    args[1] = EXPAND(RECOVERY_API_VERSION);   // defined in Android.mk    args[2] = malloc(10);    sprintf(args[2], "%d", pipefd[1]);    args[3] = (char*)path;    args[4] = NULL;    pid_t pid = fork();    if (pid == 0) {        close(pipefd[0]);        execv(binary, args);        fprintf(stdout, "E:Can't run %s (%s)\n", binary, strerror(errno));        _exit(-1);    }    close(pipefd[1]);    char buffer[1024];    FILE* from_child = fdopen(pipefd[0], "r");    while (fgets(buffer, sizeof(buffer), from_child) != NULL) {        char* command = strtok(buffer, " \n");        if (command == NULL) {            continue;        } else if (strcmp(command, "progress") == 0) {            char* fraction_s = strtok(NULL, " \n");            char* seconds_s = strtok(NULL, " \n");            float fraction = strtof(fraction_s, NULL);            int seconds = strtol(seconds_s, NULL, 10);            ui_show_progress(fraction * (1-VERIFICATION_PROGRESS_FRACTION),                             seconds);        } else if (strcmp(command, "set_progress") == 0) {            char* fraction_s = strtok(NULL, " \n");            float fraction = strtof(fraction_s, NULL);            ui_set_progress(fraction);        } else if (strcmp(command, "ui_print") == 0) {            char* str = strtok(NULL, "\n");            if (str) {                ui_print("%s", str);            } else {                ui_print("\n");            }        } else {            LOGE("unknown command [%s]\n", command);        }    }    fclose(from_child);    int status;    waitpid(pid, &status, 0);    if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {        LOGE("Error in %s\n(Status %d)\n", path, WEXITSTATUS(status));        return INSTALL_ERROR;    }    return INSTALL_SUCCESS;}// Reads a file containing one or more public keys as produced by// DumpPublicKey:  this is an RSAPublicKey struct as it would appear// as a C source literal, eg:////  "{64,0xc926ad21,{1795090719,...,-695002876},{-857949815,...,1175080310}}"//// (Note that the braces and commas in this example are actual// characters the parser expects to find in the file; the ellipses// indicate more numbers omitted from this example.)//// The file may contain multiple keys in this format, separated by// commas.  The last key must not be followed by a comma.//// Returns NULL if the file failed to parse, or if it contain zero keys.static RSAPublicKey*load_keys(const char* filename, int* numKeys) {    RSAPublicKey* out = NULL;    *numKeys = 0;    FILE* f = fopen(filename, "r");    if (f == NULL) {        LOGE("opening %s: %s\n", filename, strerror(errno));        goto exit;    }    int i;    bool done = false;    while (!done) {        ++*numKeys;        out = realloc(out, *numKeys * sizeof(RSAPublicKey));        RSAPublicKey* key = out + (*numKeys - 1);        if (fscanf(f, " { %i , 0x%x , { %u",                   &(key->len), &(key->n0inv), &(key->n[0])) != 3) {            goto exit;        }        if (key->len != RSANUMWORDS) {            LOGE("key length (%d) does not match expected size\n", key->len);            goto exit;        }        for (i = 1; i < key->len; ++i) {            if (fscanf(f, " , %u", &(key->n[i])) != 1) goto exit;        }        if (fscanf(f, " } , { %u", &(key->rr[0])) != 1) goto exit;        for (i = 1; i < key->len; ++i) {            if (fscanf(f, " , %u", &(key->rr[i])) != 1) goto exit;        }        fscanf(f, " } } ");        // if the line ends in a comma, this file has more keys.        switch (fgetc(f)) {            case ',':                // more keys to come.                break;            case EOF:                done = true;                break;            default:                LOGE("unexpected character between keys\n");                goto exit;        }    }    fclose(f);    return out;exit:    if (f) fclose(f);    free(out);    *numKeys = 0;    return NULL;}intinstall_package(const char *path){    ui_set_background(BACKGROUND_ICON_INSTALLING);    ui_print("Finding update package...\n");    ui_show_indeterminate_progress();    LOGI("Update location: %s\n", path);    if (ensure_path_mounted(path) != 0) {        LOGE("Can't mount %s\n", path);        return INSTALL_CORRUPT;    }    ui_print("Opening update package...\n");    int numKeys;    RSAPublicKey* loadedKeys = load_keys(PUBLIC_KEYS_FILE, &numKeys);    if (loadedKeys == NULL) {        LOGE("Failed to load keys\n");        return INSTALL_CORRUPT;    }    LOGI("%d key(s) loaded from %s\n", numKeys, PUBLIC_KEYS_FILE);    // Give verification half the progress bar...    ui_print("Verifying update package...\n");    ui_show_progress(            VERIFICATION_PROGRESS_FRACTION,            VERIFICATION_PROGRESS_TIME);    int err;    err = verify_file(path, loadedKeys, numKeys);    free(loadedKeys);    LOGI("verify_file returned %d\n", err);    if (err != VERIFY_SUCCESS) {        LOGE("signature verification failed\n");        return INSTALL_CORRUPT;    }    /* Try to open the package.     */    ZipArchive zip;    err = mzOpenZipArchive(path, &zip);    if (err != 0) {        LOGE("Can't open %s\n(%s)\n", path, err != -1 ? strerror(err) : "bad");        return INSTALL_CORRUPT;    }    /* Verify and install the contents of the package.     */    ui_print("Installing update...\n");    return try_update_binary(path, &zip);}

The following describes the process and the source code:

① Ensure_path_mount (): indicates whether the partition where the path of the update.zip package is mounted. If not, mount the file first.

② Load_keys (): load the Public Key source file. The path is in/RES/keys. This file is in the root file system of the recovery image.

③ Verify_file (): Verify the signature of the update.zip package.

④ Mzopenziparchive (): Open the upgrade package and copy relevant information to a temporary ziparchinve variable. This step does not decompress our update.zip package.

⑤ Try_update_binary (): In this example, we upgraded update.zip. At the beginning, this function copies the update_binary file to/tmp/update_binary in the memory file system based on the zip package information we obtained in the previous step and the absolute path of the upgrade package. For later use.

⑥ Pipe (): creates an MPS queue for communication between the following sub-processes and the parent process.

7. Fork (): create a sub-process. The sub-processes are mainly responsible for executing binary (execv (binary, argS), that is, executing our installation Command Script ), the parent process is responsible for updating the UI display (displaying the current progress) by receiving commands sent by the child process ). The sub-parent process relies on pipelines for inter-process communication.

After a child process is created, the parent process has two roles. First, update the UI display by receiving commands sent by sub-processes in the pipeline. Second, wait for the sub-process to exit and return install success. The sub-process sends the following commands while parsing and executing the installation script:

Progress <frac> <secs>: Set the progress bar based on the second parameter secs (seconds.

Set_progress <frac>: directly sets the progress bar. The frac value ranges from 0.0 to 0.1.

Firmware <"hboot" | "radio"> <FILENAME>: Used to upgrade firmware, which is no longer used in API V3.

Ui_print <string>: display the string on the screen to print the update process.

Execv(binary,argsimplements the binaryprogram, and the actual quality of this program goes to the commands in the Updater-Script script in update.zip package and runs them. Then, the recoveryservice enters the process of installing the update.zip package in the supervisor.

Next, we will continue to analyze the process of parsing and executing Updater-script using Update-binary.


Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.