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