天天看點

recovery代碼分析(二)really_install_package()函數try_update_binary()函數update_binary_command()函數

really_install_package()函數

really_install_package()函數位于install.cpp。

static int really_install_package(const std::string &path, bool *wipe_cache, bool needs_mount,
                                  std::vector<std::string> *log_buffer, int retry_count,
                                  int *max_temperature) {
    // Timothy:這部分跟UI相關
    ui->SetBackground(RecoveryUI::INSTALLING_UPDATE);
    ui->Print("Finding update package...\n");
    // Give verification half the progress bar...
    ui->SetProgressType(RecoveryUI::DETERMINATE);
    ui->ShowProgress(VERIFICATION_PROGRESS_FRACTION, VERIFICATION_PROGRESS_TIME);
    LOG(INFO) << "Update location: " << path;

    // Map the update package into memory.
    ui->Print("Opening update package...\n");

    if (needs_mount) {
        if (path[0] == '@') {
            ensure_path_mounted(path.substr(1).c_str());
        } else {
            ensure_path_mounted(path.c_str());
        }
    }

    MemMapping map;
    if (!map.MapFile(path)) {
        LOG(ERROR) << "failed to map file";
        return INSTALL_CORRUPT;
    }

    // Timothy:對安裝包進行驗證,粗看應該是驗證簽名,具體的後面再分析。
    // Verify package.
    if (!verify_package(map.addr, map.length)) {
        log_buffer->push_back(android::base::StringPrintf("error: %d", kZipVerificationFailure));
        return INSTALL_CORRUPT;
    }

    // Try to open the package.
    ZipArchiveHandle zip;
    int err = OpenArchiveFromMemory(map.addr, map.length, path.c_str(), &zip);
    if (err != 0) {
        LOG(ERROR) << "Can't open " << path << " : " << ErrorCodeString(err);
        log_buffer->push_back(android::base::StringPrintf("error: %d", kZipOpenFailure));
        CloseArchive(zip);
        return INSTALL_CORRUPT;
    }

    // Timothy:AB_OTA_UPDATER應該控制做AB更新的,這裡沒有定義。
    // Check partition size between source and target
#ifndef AB_OTA_UPDATER
    int ret = INSTALL_SUCCESS;
    if (mt_really_install_package_check_part_size(ret, path.c_str(), needs_mount, zip)) {
        CloseArchive(zip);
        return ret;
    }
#endif

    // Timothy:這裡的驗證是驗證ota包中的一個包含相容性資訊的zip檔案。從日志看,我們的ota包裡面不含
    // 這個zip檔案,是以直接傳回了true。
    // Additionally verify the compatibility of the package.
    if (!verify_package_compatibility(zip)) {
        log_buffer->push_back(android::base::StringPrintf("error: %d", kPackageCompatibilityFailure));
        CloseArchive(zip);
        return INSTALL_CORRUPT;
    }

    // Verify and install the contents of the package.
    ui->Print("Installing update...\n");
    if (retry_count > 0) {
        ui->Print("Retry attempt: %d\n", retry_count);
    }

    // Timothy:這裡實際上是設定了一個UI用的全局變量,這個變量為false時,不能有軟體控制的重新開機。
    ui->SetEnableReboot(false);
    // Timothy:這裡釋放二進制檔案并運作它。
    int result = try_update_binary(path, zip, wipe_cache, log_buffer, retry_count, max_temperature);
    ui->SetEnableReboot(true);
    ui->Print("\n");

    CloseArchive(zip);
    return result;
}
           

try_update_binary()函數

try_update_binary()函數位于install.cpp。

static int try_update_binary(const std::string &package, ZipArchiveHandle zip, bool *wipe_cache,
                             std::vector<std::string> *log_buffer, int retry_count,
                             int *max_temperature) {
	// Timothy:從ota更新包中讀取build.version.incremental并列印到日志。這個應該是隻有增量包更新的時候才有。
    read_source_target_build(zip, log_buffer);

	// Timothy:初始化管道,用于主程序和安裝程序通信。主程序用于更新UI,子程序是實際幹活的程序。
    int pipefd[2];
    pipe(pipefd);

    std::vector<std::string> args;
	// Timothy:因為宏AB_OTA_UPDATER沒有有定義,是以走了第二個分支。
#ifdef AB_OTA_UPDATER
	// Timothy:這裡從更新包裡面釋放META-INF/com/google/android/update-binary這個二進制檔案,
	// 然後把資訊存儲在args裡面。
    int ret = update_binary_command(package, zip, "/sbin/update_engine_sideload", retry_count,
                                    pipefd[1], &args);
#else
    int ret = update_binary_command(package, zip, "/tmp/update-binary", retry_count, pipefd[1],
                                    &args);
#endif
    if (ret) {
        close(pipefd[0]);
        close(pipefd[1]);
        return ret;
    }

    // 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.
    //
    //        ui_print <string>
    //            display <string> on the screen.
    //
    //        wipe_cache
    //            a wipe of cache will be performed following a successful
    //            installation.
    //
    //        clear_display
    //            turn off the text display.
    //
    //        enable_reboot
    //            packages can explicitly request that they want the user
    //            to be able to reboot during installation (useful for
    //            debugging packages that don't exit).
    //
    //        retry_update
    //            updater encounters some issue during the update. It requests
    //            a reboot to retry the same package automatically.
    //
    //        log <string>
    //            updater requests logging the string (e.g. cause of the
    //            failure).
    //
    //   - the name of the package zip file.
    //
    //   - an optional argument "retry" if this update is a retry of a failed
    //   update attempt.
    //

	// Timothy:将前面得到的二進制檔案轉換成execv可以執行的字元串。
    // Convert the vector to a NULL-terminated char* array suitable for execv.
    const char *chr_args[args.size() + 1];
    chr_args[args.size()] = nullptr;
    for (size_t i = 0; i < args.size(); i++) {
        chr_args[i] = args[i].c_str();
    }

    pid_t pid = fork();

    if (pid == -1) {
        close(pipefd[0]);
        close(pipefd[1]);
        PLOG(ERROR) << "Failed to fork update binary";
        return INSTALL_ERROR;
    }

	// Timothy:子程序裡面執行chr_args裡面存儲的指令
    if (pid == 0) {
        umask(022);
        close(pipefd[0]);
        execv(chr_args[0], const_cast<char **>(chr_args));
        // Bug: 34769056
        // We shouldn't use LOG/PLOG in the forked process, since they may cause
        // the child process to hang. This deadlock results from an improperly
        // copied mutex in the ui functions.
        fprintf(stdout, "E:Can't run %s (%s)\n", chr_args[0], strerror(errno));
        _exit(EXIT_FAILURE);
    }
    close(pipefd[1]);

    std::atomic<bool> logger_finished(false);
    std::thread temperature_logger(log_max_temperature, max_temperature, std::ref(logger_finished));

    *wipe_cache = false;
    bool retry_update = false;

	// Timothy:根據子程序從通道裡面傳過來的值,進行不同的顯示。
    char buffer[1024];
    FILE *from_child = fdopen(pipefd[0], "r");
    while (fgets(buffer, sizeof(buffer), from_child) != nullptr) {
        std::string line(buffer);
        size_t space = line.find_first_of(" \n");
        std::string command(line.substr(0, space));
        if (command.empty()) continue;

        // Get rid of the leading and trailing space and/or newline.
        std::string args = space == std::string::npos ? "" : android::base::Trim(line.substr(space));

        if (command == "progress") {
            std::vector<std::string> tokens = android::base::Split(args, " ");
            double fraction;
            int seconds;
            if (tokens.size() == 2 && android::base::ParseDouble(tokens[0].c_str(), &fraction) &&
                    android::base::ParseInt(tokens[1], &seconds)) {
                ui->ShowProgress(fraction * (1 - VERIFICATION_PROGRESS_FRACTION), seconds);
            } else {
                LOG(ERROR) << "invalid \"progress\" parameters: " << line;
            }
        } else if (command == "set_progress") {
            std::vector<std::string> tokens = android::base::Split(args, " ");
            double fraction;
            if (tokens.size() == 1 && android::base::ParseDouble(tokens[0].c_str(), &fraction)) {
                ui->SetProgress(fraction);
            } else {
                LOG(ERROR) << "invalid \"set_progress\" parameters: " << line;
            }
        } else if (command == "ui_print") {
            ui->PrintOnScreenOnly("%s\n", args.c_str());
            fflush(stdout);
        } else if (command == "wipe_cache") {
            *wipe_cache = true;
        } else if (command == "clear_display") {
            ui->SetBackground(RecoveryUI::NONE);
        } else if (command == "enable_reboot") {
            // packages can explicitly request that they want the user
            // to be able to reboot during installation (useful for
            // debugging packages that don't exit).
            ui->SetEnableReboot(true);
        } else if (command == "retry_update") {
            retry_update = true;
        } else if (command == "log") {
            if (!args.empty()) {
                // Save the logging request from updater and write to last_install later.
                log_buffer->push_back(args);
            } else {
                LOG(ERROR) << "invalid \"log\" parameters: " << line;
            }
        } else {
            LOG(ERROR) << "unknown command [" << command << "]";
        }
    }
    fclose(from_child);

    int status;
    waitpid(pid, &status, 0);

    logger_finished.store(true);
    finish_log_temperature.notify_one();
    temperature_logger.join();

    if (retry_update) {
        return INSTALL_RETRY;
    }
    if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
        LOG(ERROR) << "Error in " << package << " (Status " << WEXITSTATUS(status) << ")";
        return INSTALL_ERROR;
    }

    return INSTALL_SUCCESS;
}
           

update_binary_command()函數

update_binary_command()函數位于install.cpp。

int update_binary_command(const std::string &package, ZipArchiveHandle zip,
                          const std::string &binary_path, int retry_count, int status_fd,
                          std::vector<std::string> *cmd) {
    CHECK(cmd != nullptr);

	// Timothy:從zip包中解壓下面的更新檔案
    // On traditional updates we extract the update binary from the package.
    static constexpr const char *UPDATE_BINARY_NAME = "META-INF/com/google/android/update-binary";
    ZipString binary_name(UPDATE_BINARY_NAME);
    ZipEntry binary_entry;
    if (FindEntry(zip, binary_name, &binary_entry) != 0) {
        LOG(ERROR) << "Failed to find update binary " << UPDATE_BINARY_NAME;
        return INSTALL_CORRUPT;
    }

    unlink(binary_path.c_str());
    int fd = open(binary_path.c_str(), O_CREAT | O_WRONLY | O_TRUNC | O_CLOEXEC, 0755);
    if (fd == -1) {
        PLOG(ERROR) << "Failed to create " << binary_path;
        return INSTALL_ERROR;
    }

    int32_t error = ExtractEntryToFile(zip, &binary_entry, fd);
    close(fd);
    if (error != 0) {
        LOG(ERROR) << "Failed to extract " << UPDATE_BINARY_NAME << ": " << ErrorCodeString(error);
        return INSTALL_ERROR;
    }

	// Timothy:拼接更新指令。這個就是前面提到的子線程執行execv執行的指令。
    *cmd = {
        binary_path,
        EXPAND(RECOVERY_API_VERSION),  // defined in Android.mk
        std::to_string(status_fd),
        package,
    };
    if (retry_count > 0) {
        cmd->push_back("retry");
    }
    return 0;
}