1、Android系统Recovery工作原理之使用updatezip升级过程分析七Android系统Recovery工作原理之使用update.zip升级过程分析(七) 置顶Android系统Recovery工作原理之使用update.zip升级过程分析(七)-Recovery服务的核心install_package函数分类:Andriod2012-04-16 13:554480人阅读评论(3)收藏举报android工作commandnullpathfile Android系统Recovery工作原理之使用update.zip升级过程分析(七)-Recovery服务的核心install_pack
2、age函数一、 Recovery服务的核心install_package(升级update.zip特有) 和Recovery服务中的wipe_data、wipe_cache不同,install_package()是升级update.zip特有的一部分,也是最核心的部分。在这一步才真正开始对我们的update.zip包进行处理。下面就开始分析这一部分。还是先看图例: 这一部分的源码文件位于:/gingerbread0919/bootable/recovery/install.c。这是一个没有main函数的源码文件,还是把源码先贴出来如下:cpp view plaincopy?/* * Copyr
3、ight (C) 2007 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the License); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http:/www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable
4、 law or agreed to in writing, software * distributed under the License is distributed on an AS IS BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include <c
5、type.h> #include <errno.h> #include <fcntl.h> #include <limits.h> #include <sys/stat.h> #include <sys/wait.h> #include <unistd.h> #include common.h #include install.h #include mincrypt/rsa.h #include minui/minui.h #include minzip/SysUtil.h #include minzip/Zip.h
6、 #include mtdutils/mounts.h #include mtdutils/mtdutils.h #include roots.h #include verifier.h #define ASSUMED_UPDATE_BINARY_NAME META-INF/com/google/android/update-binary #define PUBLIC_KEYS_FILE /res/keys / If the package contains an update binary, extract it and run it. static int try_update_binar
7、y(const char *path, ZipArchive *zip) const ZipEntry* binary_entry = mzFindZipEntry(zip, ASSUMED_UPDATE_BINARY_NAME); if (binary_entry = NULL) mzCloseZipArchive(zip); return INSTALL_CORRUPT; char* binary = /tmp/update_binary; unlink(binary); int fd = creat(binary, 0755); if (fd < 0) mzCloseZipArch
8、ive(zip); LOGE(Cant make %sn, binary); return 1; bool ok = mzExtractZipEntryToFile(zip, binary_entry, fd); close(fd); mzCloseZipArchive(zip); if (!ok) LOGE(Cant copy %sn, ASSUMED_UPDATE_BINARY_NAME); return 1; int pipefd2; pipe(pipefd); / When executing the update binary contained in the package, th
9、e / 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 / ove
10、r <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 comm
11、and. / / firmware <hboot|radio> <filename> / arrange to install the contents of <filename> in the / given partition on reboot. / / (API v2: <filename> may start with PACKAGE: to / indicate taking a file from the OTA package.) / / (API v3: this command no longer exists.) / / u
12、i_print <string> / display <string> on the screen. / / - the name of the package zip file. / char* args = malloc(sizeof(char*) * 5); args0 = binary; args1 = EXPAND(RECOVERY_API_VERSION); / defined in Android.mk args2 = malloc(10); sprintf(args2, %d, pipefd1); args3 = (char*)path; args4 =
13、 NULL; pid_t pid = fork(); if (pid = 0) close(pipefd0); execv(binary, args); fprintf(stdout, E:Cant run %s (%s)n, binary, strerror(errno); _exit(-1); close(pipefd1); char buffer1024; FILE* from_child = fdopen(pipefd0, r); while (fgets(buffer, sizeof(buffer), from_child) != NULL) char* command = strt
14、ok(buffer, n); if (command = NULL) continue; else if (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_show_progress(fraction * (1-VERIFICATION_PROGRESS_FRACT
15、ION), seconds); else if (strcmp(command, set_progress) = 0) char* fraction_s = strtok(NULL, n); float fraction = strtof(fraction_s, NULL); ui_set_progress(fraction); else if (strcmp(command, ui_print) = 0) char* str = strtok(NULL, n); if (str) ui_print(%s, str); else ui_print(n); else LOGE(unknown c
16、ommand %sn, command); fclose(from_child); int status; waitpid(pid, &status, 0); if (!WIFEXITED(status) | WEXITSTATUS(status) != 0) LOGE(Error in %sn(Status %d)n, path, WEXITSTATUS(status); return INSTALL_ERROR; return INSTALL_SUCCESS; / Reads a file containing one or more public keys as produced
17、 by / DumpPublicKey: this is an RSAPublicKey struct as it would appear / as a C source literal, eg: / / 64,0xc926ad21,1795090719,.,-695002876,-857949815,.,1175080310 / / (Note that the braces and commas in this example are actual / characters the parser expects to find in the file; the ellipses / in
18、dicate more numbers omitted from this example.) / / The file may contain multiple keys in this format, separated by / commas. The last key must not be followed by a comma. / / Returns NULL if the file failed to parse, or if it contain zero keys. static RSAPublicKey* load_keys(const char* filename, i
19、nt* numKeys) RSAPublicKey* out = NULL; *numKeys = 0; FILE* f = fopen(filename, r); if (f = NULL) LOGE(opening %s: %sn, filename, strerror(errno); goto exit; int i; bool done = false; while (!done) +*numKeys; out = realloc(out, *numKeys * sizeof(RSAPublicKey); RSAPublicKey* key = out + (*numKeys - 1)
20、; if (fscanf(f, %i , 0x%x , %u, &(key->len), &(key->n0inv), &(key->n0) != 3) goto exit; if (key->len != RSANUMWORDS) LOGE(key length (%d) does not match expected sizen, key->len); goto exit; for (i = 1; i < key->len; +i) if (fscanf(f, , %u, &(key->ni) != 1) go
21、to exit; if (fscanf(f, , %u, &(key->rr0) != 1) goto exit; for (i = 1; i < key->len; +i) if (fscanf(f, , %u, &(key->rri) != 1) goto exit; fscanf(f, ); / if the line ends in a comma, this file has more keys. switch (fgetc(f) case ,: / more keys to come. break; case EOF: done = true
22、; break; default: LOGE(unexpected character between keysn); goto exit; fclose(f); return out; exit: if (f) fclose(f); free(out); *numKeys = 0; return NULL; int install_package(const char *path) ui_set_background(BACKGROUND_ICON_INSTALLING); ui_print(Finding update package.n); ui_show_indeterminate_p
23、rogress(); LOGI(Update location: %sn, path); if (ensure_path_mounted(path) != 0) LOGE(Cant mount %sn, path); return INSTALL_CORRUPT; ui_print(Opening update package.n); int numKeys; RSAPublicKey* loadedKeys = load_keys(PUBLIC_KEYS_FILE, &numKeys); if (loadedKeys = NULL) LOGE(Failed to load keysn
24、); return INSTALL_CORRUPT; LOGI(%d key(s) loaded from %sn, numKeys, PUBLIC_KEYS_FILE); / Give verification half the progress bar. ui_print(Verifying update package.n); ui_show_progress( VERIFICATION_PROGRESS_FRACTION, VERIFICATION_PROGRESS_TIME); int err; err = verify_file(path, loadedKeys, numKeys)
25、; free(loadedKeys); LOGI(verify_file returned %dn, err); if (err != VERIFY_SUCCESS) LOGE(signature verification failedn); return INSTALL_CORRUPT; /* Try to open the package. */ ZipArchive zip; err = mzOpenZipArchive(path, &zip); if (err != 0) LOGE(Cant open %sn(%s)n, path, err != -1 ? strerror(e
26、rr) : bad); return INSTALL_CORRUPT; /* Verify and install the contents of the package. */ ui_print(Installing update.n); return try_update_binary(path, &zip); 下面顺着上面的流程图和源码来分析这一流程: ensure_path_mount():先判断所传的update.zip包路径所在的分区是否已经挂载。如果没有则先挂载。 load_keys():加载公钥源文件,路径位于/res/keys。这个文件在Recovery镜像的根文件系
27、统中。 verify_file():对升级包update.zip包进行签名验证。 mzOpenZipArchive():打开升级包,并将相关的信息拷贝到一个临时的ZipArchinve变量中。这一步并未对我们的update.zip包解压。 try_update_binary():在这个函数中才是对我们的update.zip升级的地方。这个函数一开始先根据我们上一步获得的zip包信息,以及升级包的绝对路径将update_binary文件拷贝到内存文件系统的/tmp/update_binary中。以便后面使用。 pipe():创建管道,用于下面的子进程和父进程之间的通信。 fork():创建子进程
28、。其中的子进程主要负责执行binary(execv(binary,args),即执行我们的安装命令脚本),父进程负责接受子进程发送的命令去更新ui显示(显示当前的进度)。子父进程间通信依靠管道。 其中,在创建子进程后,父进程有两个作用。一是通过管道接受子进程发送的命令来更新UI显示。二是等待子进程退出并返回INSTALL SUCCESS。其中子进程在解析执行安装脚本的同时所发送的命令有以下几种: progress <frac> <secs>:根据第二个参数secs(秒)来设置进度条。 set_progress <frac>:直接设置进度条,frac取值在0.0到0.1之间。 firmware <”hboot”|”radio”><filename>:升级firmware时使用,在API V3中不再使用。 ui_print <string>:在屏幕上显示字符串,即打印更新过程。 execv(binary,args)的作用就是去执行binary程序,这个程序的实质就是去解析update.zip包中的updater-script脚本中的命令并执行。由此,Recovery服务就进入了实际安装update.zip包的过程。 下一篇继续分析使用update-binary解析并执行updater-script的过程。
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1