Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1306173
  • 博文数量: 478
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 4833
  • 用 户 组: 普通用户
  • 注册时间: 2014-06-28 11:12
文章分类

全部博文(478)

文章存档

2019年(1)

2018年(27)

2017年(21)

2016年(171)

2015年(258)

我的朋友

分类: Android平台

2016-05-27 19:08:33

http://blog.csdn.net/huangyabin001/article/details/43968979
写在前面:

    首先当我们执行升级脚本updater-script的时候,就表示我们已经进入了升级安装状态。那么在我们就从实际的安装作为入口开始分析。也就是说我们从install.cpp中的install_package函数开始一步步来分析。

    这里主要分析与脚本相关的部分,其他的请参考这位朋友的博文http://blog.chinaunix.net/uid-22028566-id-3533856.html,我也很受启发。这里也借用一张图来帮助流程上的分析。

   下面是调用的流程:install_package()-->really_install_package(),那么在really_install_package()函数中真正开始安装的逻辑如下:


[cpp] view plain copy
 print?
  1. /* Verify and install the contents of the package. 
  2.  */  
  3. ui->Print("Installing update...\n");  
  4. err = try_update_binary(path, &zip, wipe_cache);  
  5. if(err != INSTALL_SUCCESS)  
  6.     return err;  
    try_update_binary是真正实现读取升级包中的脚本文件并执行相应的函数。在此函数中,通过调用fork函数创建出一个子进程,在子进程中开始读取并执行升级脚本文件。在此需要注意的是函数fork的用法,fork被调用一次,将做两次返回,在父进程中返回的是子进程的进程ID,为正数;而在子进程中,则返回0。子进程中所进行的操作,即execv(binary, args)。子进程创建成功后,开始执行升级代码,并通过管道与父进程交互(创建管道,并将pipefd[1]作为参数传递给子进程,子进程则将相关信息写入到此管道描述符中);而父进程则通过读取子进程传递过来的信息更新UI。


    那么下面我们来具体来分析一下这个方法具体的逻辑。


[python] view plain copy
 print?
  1. static int  
  2. try_update_binary(const char *path, ZipArchive *zip, int* wipe_cache) {  
  3.     //定义一个常量用来封装查找相zip关信息的结果如“META-INF/com/google/android/update-binary”,便于后面进行解压,因为之前mzOpenZipArchive函数并没有对更新包进行解压操作,*zip是之前mzOpenZipArchive方法返回的一个ZipArchive对象。mzOpenZipArchive是打开升级包,并将相关的信息拷贝到一个临时的ZipArchinve变量中。  
  4.     //ASSUMED_UPDATE_BINARY_NAME="META-INF/com/google/android/update-binary"  
  5.     const ZipEntry* binary_entry =  
  6.             mzFindZipEntry(zip, ASSUMED_UPDATE_BINARY_NAME);  
  7.     if (binary_entry == NULL) {  
  8.         mzCloseZipArchive(zip);  
  9.         return INSTALL_CORRUPT;  
  10.     }  
  11.   
  12.     const char* binary = "/tmp/update_binary";  
  13.     unlink(binary);  
  14.     //创建“/tmp/update_binary”文件  
  15.     int fd = creat(binary, 0755);  
  16.     if (fd < 0) {  
  17.         mzCloseZipArchive(zip);  
  18.         LOGE("Can't make %s\n", binary);  
  19.         return INSTALL_ERROR;  
  20.     }  
  21.     //将META-INF/com/google/android/update-binary中的内容解压缩到"/tmp/update_binary"下面。其实这个方法中主要是对update_binary操作的,如解压和执行等。  
  22.     bool ok = mzExtractZipEntryToFile(zip, binary_entry, fd);  
  23.     close(fd);  
  24.     mzCloseZipArchive(zip);  
  25.   
  26.     if (!ok) {  
  27.         LOGE("Can't copy %s\n", ASSUMED_UPDATE_BINARY_NAME);  
  28.         return INSTALL_ERROR;  
  29.     }  
  30.   
  31.     int pipefd[2];  
  32.     //创建管道,用于下面的子进程和父进程之间的通信  
  33.     pipe(pipefd);  
  34.   
  35.     // When executing the update binary contained in the package, the  
  36.     // arguments passed are:  
  37.     //  
  38.     //   - the version number for this interface  
  39.     //  
  40.     //   - an fd to which the program can write in order to update the  
  41.     //     progress bar.  The program can write single-line commands:  
  42.     //  
  43.     //        progress    
  44.     //            fill up the next  part of of the progress bar  
  45.     //            over  seconds.  If  is zero, use  
  46.     //            set_progress commands to manually control the  
  47.     //            progress of this segment of the bar  
  48.     //  
  49.     //        set_progress   
  50.     //             should be between 0.0 and 1.0; sets the  
  51.     //            progress bar within the segment defined by the most  
  52.     //            recent progress command.  
  53.     //  
  54.     //        firmware <"hboot"|"radio">   
  55.     //            arrange to install the contents of  in the  
  56.     //            given partition on reboot.  
  57.     //  
  58.     //            (API v2:  may start with "PACKAGE:" to  
  59.     //            indicate taking a file from the OTA package.)  
  60.     //  
  61.     //            (API v3: this command no longer exists.)  
  62.     //  
  63.     //        ui_print   
  64.     //            display  on the screen.  
  65.     //  
  66.     //   - the name of the package zip file.  
  67.     //  
  68.   
  69.     const char** args = (const char**)malloc(sizeof(char*) * 5);  
  70.     args[0] = binary;  
  71.     args[1] = EXPAND(RECOVERY_API_VERSION);   // defined in Android.mk  
  72.     char* temp = (char*)malloc(10);  
  73.     sprintf(temp, "%d", pipefd[1]);  
  74.     args[2] = temp;  
  75.     args[3] = (char*)path;  
  76.     args[4] = NULL;  
  77.   
  78.     //创建子进程。其中的子进程主要负责执行binary(execv(binary,args),即执行我们的安装命令脚本),父进程负责接受子进程发送的命令去更新ui显示(显示当前的进度)。子父进程间通信依靠管道。  
  79.     pid_t pid = fork();  
  80.     if (pid == 0) {  
  81.         close(pipefd[0]);  
  82.         //执行"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;">  
  83. 此外,如果应用程序正常执行完毕,那么execv是永远不会返回的;当execv在调用进程中返回时,那么这个应用程序应该出错了(可能是程序本身没找到,权限不够...),此时它的返回值应该是-1,具体的错误代码可以通过全局变量errno查看,还可以通过stderr得到具体的错误描述字符串。  
  84.         execv(binary, (char* const*)args);//其实我的理解就是"font-family: Arial, Helvetica, sans-serif;">update-binary相当一个exe可执行程序,这里就是一个双击可执行程序的动作  
  85.         fprintf(stdout, "E:Can't run %s (%s)\n", binary, strerror(errno));  
  86.         _exit(-1);  
  87.     }  
  88.     close(pipefd[1]);  
  89.   
  90.     *wipe_cache = 0;  
  91.   
  92.     char buffer[1024];  
  93.     FILE* from_child = fdopen(pipefd[0], "r");  
  94.     while (fgets(buffer, sizeof(buffer), from_child) != NULL) {  
  95.         char* command = strtok(buffer, " \n");  
  96.         if (command == NULL) {  
  97.             continue;  
  98.         } else if (strcmp(command, "progress") == 0) {  
  99.             char* fraction_s = strtok(NULL, " \n");  
  100.             char* seconds_s = strtok(NULL, " \n");  
  101.   
  102.             float fraction = strtof(fraction_s, NULL);  
  103.             int seconds = strtol(seconds_s, NULL, 10);  
  104.   
  105.             ui->ShowProgress(fraction * (1-VERIFICATION_PROGRESS_FRACTION), seconds);  
  106.         } else if (strcmp(command, "set_progress") == 0) {  
  107.             char* fraction_s = strtok(NULL, " \n");  
  108.             float fraction = strtof(fraction_s, NULL);  
  109.             ui->SetProgress(fraction);  
  110.         } else if (strcmp(command, "ui_print") == 0) {  
  111.             char* str = strtok(NULL, "\n");  
  112.             if (str) {  
  113.                 ui->Print("%s", str);  
  114.             } else {  
  115.                 ui->Print("\n");  
  116.             }  
  117.             fflush(stdout);  
  118.         } else if (strcmp(command, "wipe_cache") == 0) {  
  119.             *wipe_cache = 1;  
  120. #if 1 //wschen 2012-07-25  
  121.         } else if (strcmp(command, "special_factory_reset") == 0) {  
  122.             *wipe_cache = 2;  
  123. #endif  
  124.         } else if (strcmp(command, "clear_display") == 0) {  
  125.             ui->SetBackground(RecoveryUI::NONE);  
  126.         } else {  
  127.             LOGE("unknown command [%s]\n", command);  
  128.         }  
  129.     }  
  130.     fclose(from_child);  
  131.   
  132.     int status;  
  133.     waitpid(pid, &status, 0);  
  134.     if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {  
  135.         LOGE("Error in %s\n(Status %d)\n", path, WEXITSTATUS(status));  
  136.         return INSTALL_ERROR;  
  137.     }  
  138.   
  139. #ifdef SUPPORT_DATA_BACKUP_RESTORE //wschen 2011-03-09   
  140. //Skip userdata restore if updating from /data with no /data layout change  
  141. if(!usrdata_changed && update_from_data){  
  142.     ui->Print("/data offset remains the same no need to restore usrdata\n");  
  143. }else{  
  144.     if (part_size_changed) {  
  145.         if (ensure_path_mounted("/sdcard") != 0) {  
  146.             LOGE("Can't mount %s\n", path);  
  147.             return INSTALL_NO_SDCARD;  
  148.         }  
  149.   
  150.         if (userdata_restore(backup_path, 1)) {  
  151.             return INSTALL_FILE_SYSTEM_ERROR;  
  152.         }  
  153.     }  
  154. }  
  155. #endif //SUPPORT_DATA_BACKUP_RESTORE  
  156.   
  157.     /* ----------------------------- */  
  158.     /* SECURE BOOT UPDATE            */      
  159.     /* ----------------------------- */              
  160. #ifdef SUPPORT_SBOOT_UPDATE  
  161.     sec_update(false);  
  162. #endif  
  163.   
  164.     return INSTALL_SUCCESS;  
  165. }  
阅读(1480) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~