recovery代码分析(二)

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;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值