Android系统Recovery工作原理之使用updatezip升级过程分析七.docx
《Android系统Recovery工作原理之使用updatezip升级过程分析七.docx》由会员分享,可在线阅读,更多相关《Android系统Recovery工作原理之使用updatezip升级过程分析七.docx(5页珍藏版)》请在冰豆网上搜索。
![Android系统Recovery工作原理之使用updatezip升级过程分析七.docx](https://file1.bdocx.com/fileroot1/2023-2/13/a836d87a-a871-4201-b52b-785b5ce1e32e/a836d87a-a871-4201-b52b-785b5ce1e32e1.gif)
Android系统Recovery工作原理之使用updatezip升级过程分析七
Android系统Recovery工作原理之使用update.zip升级过程分析(七)
[置顶]
Android系统Recovery工作原理之使用update.zip升级过程分析(七)---Recovery服务的核心install_package函数分类:
Andriod
2012-04-1613:
55
4480人阅读
评论(3)
收藏
举报
android工作commandnullpathfile
Android系统Recovery工作原理之使用update.zip升级过程分析(七)---Recovery服务的核心install_package函数一、Recovery服务的核心install_package(升级update.zip特有)和Recovery服务中的wipe_data、wipe_cache不同,install_package()是升级update.zip特有的一部分,也是最核心的部分。
在这一步才真正开始对我们的update.zip包进行处理。
下面就开始分析这一部分。
还是先看图例:
这一部分的源码文件位于:
/gingerbread0919/bootable/recovery/install.c。
这是一个没有main函数的源码文件,还是把源码先贴出来如下:
[cpp]viewplaincopy?
/**Copyright(C)2007TheAndroidOpenSourceProject**LicensedundertheApacheLicense,Version2.0(the"License");*youmaynotusethisfileexceptincompliancewiththeLicense.*YoumayobtainacopyoftheLicenseat**http:
//www.apache.org/licenses/LICENSE-2.0**Unlessrequiredbyapplicablelaworagreedtoinwriting,software*distributedundertheLicenseisdistributedonan"ASIS"BASIS,*WITHOUTWARRANTIESORCONDITIONSOFANYKIND,eitherexpressorimplied.*SeetheLicenseforthespecificlanguagegoverningpermissionsand*limitationsundertheLicense.*/#include<ctype.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"#include"mtdutils/mounts.h"#include"mtdutils/mtdutils.h"#include"roots.h"#include"verifier.h"#defineASSUMED_UPDATE_BINARY_NAME"META-INF/com/google/android/update-binary"#definePUBLIC_KEYS_FILE"/res/keys"//Ifthepackagecontainsanupdatebinary,extractitandrunit.staticinttry_update_binary(constchar*path,ZipArchive*zip){constZipEntry*binary_entry=mzFindZipEntry(zip,ASSUMED_UPDATE_BINARY_NAME);if(binary_entry==NULL){mzCloseZipArchive(zip);returnINSTALL_CORRUPT;}char*binary="/tmp/update_binary";unlink(binary);intfd=creat(binary,0755);if(fd<0){mzCloseZipArchive(zip);LOGE("Can'tmake%s\n",binary);return1;}boolok=mzExtractZipEntryToFile(zip,binary_entry,fd);close(fd);mzCloseZipArchive(zip);if(!
ok){LOGE("Can'tcopy%s\n",ASSUMED_UPDATE_BINARY_NAME);return1;}intpipefd[2];pipe(pipefd);//Whenexecutingtheupdatebinarycontainedinthepackage,the//argumentspassedare:
////-theversionnumberforthisinterface////-anfdtowhichtheprogramcanwriteinordertoupdatethe//progressbar.Theprogramcanwritesingle-linecommands:
////progress<frac><secs>//fillupthenext<frac>partofoftheprogressbar//over<secs>seconds.If<secs>iszero,use//set_progresscommandstomanuallycontrolthe//progressofthissegmentofthebar////set_progress<frac>//<frac>shouldbebetween0.0and1.0;setsthe//progressbarwithinthesegmentdefinedbythemost//recentprogresscommand.////firmware<"hboot"|"radio"><filename>//arrangetoinstallthecontentsof<filename>inthe//givenpartitiononreboot.////(APIv2:
<filename>maystartwith"PACKAGE:
"to//indicatetakingafilefromtheOTApackage.)////(APIv3:
thiscommandnolongerexists.)////ui_print<string>//display<string>onthescreen.////-thenameofthepackagezipfile.//char**args=malloc(sizeof(char*)*5);args[0]=binary;args[1]=EXPAND(RECOVERY_API_VERSION);//definedinAndroid.mkargs[2]=malloc(10);sprintf(args[2],"%d",pipefd[1]);args[3]=(char*)path;args[4]=NULL;pid_tpid=fork();if(pid==0){close(pipefd[0]);execv(binary,args);fprintf(stdout,"E:
Can'trun%s(%s)\n",binary,strerror(errno));_exit(-1);}close(pipefd[1]);charbuffer[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");floatfraction=strtof(fraction_s,NULL);intseconds=strtol(seconds_s,NULL,10);ui_show_progress(fraction*(1-VERIFICATION_PROGRESS_FRACTION),seconds);}elseif(strcmp(command,"set_progress")==0){char*fraction_s=strtok(NULL,"\n");floatfraction=strtof(fraction_s,NULL);ui_set_progress(fraction);}elseif(strcmp(command,"ui_print")==0){char*str=strtok(NULL,"\n");if(str){ui_print("%s",str);}else{ui_print("\n");}}else{LOGE("unknowncommand[%s]\n",command);}}fclose(from_child);intstatus;waitpid(pid,&status,0);if(!
WIFEXITED(status)||WEXITSTATUS(status)!
=0){LOGE("Errorin%s\n(Status%d)\n",path,WEXITSTATUS(status));returnINSTALL_ERROR;}returnINSTALL_SUCCESS;}//Readsafilecontainingoneormorepublickeysasproducedby//DumpPublicKey:
thisisanRSAPublicKeystructasitwouldappear//asaCsourceliteral,eg:
////"{64,0xc926ad21,{1795090719,...,-695002876},{-857949815,...,1175080310}}"////(Notethatthebracesandcommasinthisexampleareactual//characterstheparserexpectstofindinthefile;theellipses//indicatemorenumbersomittedfromthisexample.)////Thefilemaycontainmultiplekeysinthisformat,separatedby//commas.Thelastkeymustnotbefollowedbyacomma.////ReturnsNULLifthefilefailedtoparse,orifitcontainzerokeys.staticRSAPublicKey*load_keys(constchar*filename,int*numKeys){RSAPublicKey*out=NULL;*numKeys=0;FILE*f=fopen(filename,"r");if(f==NULL){LOGE("opening%s:
%s\n",filename,strerror(errno));gotoexit;}inti;booldone=false;while(!
done){++*numKeys;out=realloc(out,*numKeys*sizeof(RSAPublicKey));RSAPublicKey*key=out+(*numKeys-1);if(fscanf(f,"{%i,0x%x,{%u",&(key->len),&(key->n0inv),&(key->n[0]))!
=3){gotoexit;}if(key->len!
=RSANUMWORDS){LOGE("keylength(%d)doesnotmatchexpectedsize\n",key->len);gotoexit;}for(i=1;i<key->len;++i){if(fscanf(f,",%u",&(key->n[i]))!
=1)gotoexit;}if(fscanf(f,"},{%u",&(key->rr[0]))!
=1)gotoexit;for(i=1;i<key->len;++i){if(fscanf(f,",%u",&(key->rr[i]))!
=1)gotoexit;}fscanf(f,"}}");//ifthelineendsinacomma,thisfilehasmorekeys.switch(fgetc(f)){case',':
//morekeystocome.break;caseEOF:
done=true;break;default:
LOGE("unexpectedcharacterbetweenkeys\n");gotoexit;}}fclose(f);returnout;exit:
if(f)fclose(f);free(out);*numKeys=0;returnNULL;}intinstall_package(constchar*path){ui_set_background(BACKGROUND_ICON_INSTALLING);ui_print("Findingupdatepackage...\n");ui_show_indeterminate_progress();LOGI("Updatelocation:
%s\n",path);if(ensure_path_mounted(path)!
=0){LOGE("Can'tmount%s\n",path);returnINSTALL_CORRUPT;}ui_print("Openingupdatepackage...\n");intnumKeys;RSAPublicKey*loadedKeys=load_keys(PUBLIC_KEYS_FILE,&numKeys);if(loadedKeys==NULL){LOGE("Failedtoloadkeys\n");returnINSTALL_CORRUPT;}LOGI("%dkey(s)loadedfrom%s\n",numKeys,PUBLIC_KEYS_FILE);//Giveverificationhalftheprogressbar...ui_print("Verifyingupdatepackage...\n");ui_show_progress(VERIFICATION_PROGRESS_FRACTION,VERIFICATION_PROGRESS_TIME);interr;err=verify_file(path,loadedKeys,numKeys);free(loadedKeys);LOGI("verify_filereturned%d\n",err);if(err!
=VERIFY_SUCCESS){LOGE("signatureverificationfailed\n");returnINSTALL_CORRUPT;}/*Trytoopenthepackage.*/ZipArchivezip;err=mzOpenZipArchive(path,&zip);if(err!
=0){LOGE("Can'topen%s\n(%s)\n",path,err!
=-1?
strerror(err):
"bad");returnINSTALL_CORRUPT;}/*Verifyandinstallthecontentsofthepackage.*/ui_print("Installingupdate...\n");returntry_update_binary(path,&zip);}下面顺着上面的流程图和源码来分析这一流程:
①ensure_path_mount():
先判断所传的update.zip包路径所在的分区是否已经挂载。
如果没有则先挂载。
②load_keys():
加载公钥源文件,路径位于/res/keys。
这个文件在Recovery镜像的根文件系统中。
③verify_file():
对升级包update.zip包进行签名验证。
④mzOpenZipArchive():
打开升级包,并将相关的信息拷贝到一个临时的ZipArchinve变量中。
这一步并未对我们的update.zip包解压。
⑤try_update_binary():
在这个函数中才是对我们的update.zip升级的地方。
这个函数一开始先根据我们上一步获得的zip包信息,以及升级包的绝对路径将update_binary文件拷贝到内存文件系统的/tmp/update_binary中。
以便后面使用。
⑥pipe():
创建管道,用于下面的子进程和父进程之间的通信。
⑦fork():
创建子进程。
其中的子进程主要负责执行binary(execv(binary,args),即执行我们的安装命令脚本),父进程负责接受子进程发送的命令去更新ui显示(显示当前的进度)。
子父进程间通信依靠管道。
⑧其中,在创建子进程后,父进程有两个作用。
一是通过管道接受子进程发送的命令来更新UI显示。
二是等待子进程退出并返回INSTALLSUCCESS。
其中子进程在解析执行安装脚本的同时所发送的命令有以下几种:
progress<frac><secs>:
根据第二个参数secs(秒)来设置进度条。
set_progress<frac>:
直接设置进度条,frac取值在0.0到0.1之间。
firmware<”hboot”|”radio”><filename>:
升级firmware时使用,在APIV3中不再使用。
ui_print<string>:
在屏幕上显示字符串,即打印更新过程。
execv(binary,args)的作用就是去执行binary程序,这个程序的实质就是去解析update.zip包中的updater-script脚本中的命令并执行。
由此,Recovery服务就进入了实际安装update.zip包的过程。
下一篇继续分析使用update-binary解析并执行updater-script的过程。