static int
try_update_binary(const char *path, ZipArchive *zip, int* wipe_cache) {
//定义一个常量用来封装查找相zip关信息的结果如“META-INF/com/google/android/update-binary”,便于后面进行解压,因为之前mzOpenZipArchive函数并没有对更新包进行解压操作,*zip是之前mzOpenZipArchive方法返回的一个ZipArchive对象。mzOpenZipArchive是打开升级包,并将相关的信息拷贝到一个临时的ZipArchinve变量中。
//ASSUMED_UPDATE_BINARY_NAME="META-INF/com/google/android/update-binary"
const ZipEntry* binary_entry =
mzFindZipEntry(zip, ASSUMED_UPDATE_BINARY_NAME);
if(binary_entry == NULL) {
mzCloseZipArchive(zip);
returnINSTALL_CORRUPT;
}
const char* binary = "/tmp/update_binary";
unlink(binary);
//创建“/tmp/update_binary”文件
int fd = creat(binary, 0755);
if(fd 0) {
mzCloseZipArchive(zip);
LOGE("Can't make %s\n", binary);
returnINSTALL_ERROR;
}
//将META-INF/com/google/android/update-binary中的内容解压缩到"/tmp/update_binary"下面。其实这个方法中主要是对update_binary操作的,如解压和执行等。
bool ok = mzExtractZipEntryToFile(zip, binary_entry, fd);
close(fd);
mzCloseZipArchive(zip);
if(!ok) {
LOGE("Can't copy %s\n", ASSUMED_UPDATE_BINARY_NAME);
returnINSTALL_ERROR;
}
int pipefd[2];
//创建管道,用于下面的子进程和父进程之间的通信
pipe(pipefd);
// When executing the update binary contained inthe package, the
// arguments passed are:
//
// - the version number forthis interface
//
// - an fd to which the program can write inorder to update the
// progress bar. The program can write single-line commands:
//
// progress
// fill up the next part of of the progress bar
// over seconds. If iszero, use
// set_progress commands to manually control the
// progress of this segment of the bar
//
// set_progress
// should be between 0.0and1.0; sets the
// progress bar within the segment defined by the most
// recent progress command.
//
// firmware
// arrange to install the contents of inthe
// given partition on reboot.
//
// (API v2: may start with "PACKAGE:"to
// indicate taking a file fromthe OTA package.)
//
// (API v3: this command no longer exists.)
//
// ui_print
// display on the screen.
//
// - the name of the package zip file.
//
const char** args = (const char**)malloc(sizeof(char*) * 5);
args[0] = binary;
args[1] = EXPAND(RECOVERY_API_VERSION); // definedinAndroid.mk
char* temp = (char*)malloc(10);
sprintf(temp, "%d", pipefd[1]);
args[2] = temp;
args[3] = (char*)path;
args[4] = NULL;
//创建子进程。其中的子进程主要负责执行binary(execv(binary,args),即执行我们的安装命令脚本),父进程负责接受子进程发送的命令去更新ui显示(显示当前的进度)。子父进程间通信依靠管道。
pid_t pid = fork();
if(pid ==0) {
close(pipefd[0]);
//执行"font-family: Arial, Helvetica, sans-serif;">update-binary"font-family: Arial, Helvetica, sans-serif;">,这个程序的实质就是去解析update.zip包中的updater-script脚本中的命令并执行。由此,Recovery服务就进入了实际安装update.zip包的过程。"font-family: Arial, Helvetica, sans-serif;">在执行execv函数时,execv会停止执行当前的进程,并且以progname应用进程替换被停止执行的进程,进程ID没有改变。这里的progname就是指"font-family: Arial, Helvetica, sans-serif;">update-binary"font-family: Arial, Helvetica, sans-serif;">,也就是被执行的应用程序。第二个参数argv,是指运行"font-family: Arial, Helvetica, sans-serif;">update-binary"font-family: Arial, Helvetica, sans-serif;">t时,传递给执行程序的参数列表, 注意,这个数组的第一个参数应该是应用程序名字本身,并且最后一个参数应该为NULL,不参将多个参数合并为一个参数放入数组。"font-family: Arial, Helvetica, sans-serif;">
此外,如果应用程序正常执行完毕,那么execv是永远不会返回的;当execv在调用进程中返回时,那么这个应用程序应该出错了(可能是程序本身没找到,权限不够...),此时它的返回值应该是-1,具体的错误代码可以通过全局变量errno查看,还可以通过stderr得到具体的错误描述字符串。
execv(binary, (char* const*)args);//其实我的理解就是"font-family: Arial, Helvetica, sans-serif;">update-binary相当一个exe可执行程序,这里就是一个双击可执行程序的动作
fprintf(stdout, "E:Can't run %s (%s)\n", binary, strerror(errno));
_exit(-1);
}
close(pipefd[1]);
*wipe_cache = 0;
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;
} elseif(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->ShowProgress(fraction * (1-VERIFICATION_PROGRESS_FRACTION), seconds);
} elseif(strcmp(command,"set_progress") ==0) {
char* fraction_s = strtok(NULL, " \n");
float fraction = strtof(fraction_s, NULL);
ui->SetProgress(fraction);
} elseif(strcmp(command,"ui_print") ==0) {
char* str = strtok(NULL, "\n");
if(str) {
ui->Print("%s", str);
} else{
ui->Print("\n");
}
fflush(stdout);
} elseif(strcmp(command,"wipe_cache") ==0) {
*wipe_cache = 1;
#if 1 //wschen 2012-07-25
} elseif(strcmp(command,"special_factory_reset") ==0) {
*wipe_cache = 2;
#endif
} elseif(strcmp(command,"clear_display") ==0) {
ui->SetBackground(RecoveryUI::NONE);
} 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));
returnINSTALL_ERROR;
}
#ifdef SUPPORT_DATA_BACKUP_RESTORE //wschen 2011-03-09
//Skip userdata restore ifupdatingfrom/data with no /data layout change
if(!usrdata_changed && update_from_data){
ui->Print("/data offset remains the same no need to restore usrdata\n");
}else{
if(part_size_changed) {
if(ensure_path_mounted("/sdcard") !=0) {
LOGE("Can't mount %s\n", path);
returnINSTALL_NO_SDCARD;
}
if(userdata_restore(backup_path,1)) {
returnINSTALL_FILE_SYSTEM_ERROR;
}
}
}
#endif //SUPPORT_DATA_BACKUP_RESTORE
/* ----------------------------- */
/* SECURE BOOT UPDATE */
/* ----------------------------- */
#ifdef SUPPORT_SBOOT_UPDATE
sec_update(false);
#endif
returnINSTALL_SUCCESS;
}