AndroidART分析MindMac2014/1/111目录ZIP文件结构....................................................2LocalFileHeader..............................................3FileData.....................................................4CentralDirectoryHeader........................................5EndofCentralDirectoryRecord...................................6ARTRuntime.....................................................6PackageManagerService...........................................11dex2oat........................................................20参数解析...................................................21创建OAT文件指针..........................................25dex2oat准备工作............................................26提取classes.dex文件........................................27创建OAT文件..............................................38APK文件的转换.................................................40总结...........................................................412Google在Android4.4中新增加了ART(AndroidRunTime)用来替代之前的Dalvik,关于ART的基本知识可以参考Google官方的Introduction,XDA的Android4.4KitKat’sARTandAppCompatibility以及AndroidPolice对ART的相关介绍。在Settings-Developeroptions中可以选择运行时环境,默认为Dalvik,可以选择ART,改变运行时环境后系统会重新启动,如图1。图1Android4.4选择ART运行环境与Dalvik不同的是,ART不再使用DEX文件,而是OAT格式的文件,所以在重启过程中,系统会完成从DEX到OAT格式的转换。本文主要分析Android4.4中DEX到OAT的转换过程。ZIP文件结构在开始分析AndroidART之前有必要先介绍下ZIP文件的格式。关于ZIP文件的结构可以参考TheGreatAndroidSecurityHoleOf’08?–PartOne:ZIPFiles,更详细的解释可以参看.ZIPFileFormatSpecification。一个ZIP文件的基本结构如图2所示。No.1到No.n分别代表了ZIP压缩文件中的文件,n表示所有的文件个数(包含文件目录)。新建一个hello文件夹,并在其下创建两个名为helloone.txt和hello2.txt的文件,其中内容分别为contentone和contenttwo,将hello文件夹压缩为hello.zip文件,以便后面的分析。3......LocalFileHeaderEncryptionHeaderDataDescriptorFileDataLocalFileHeaderEncryptionHeaderDataDescriptorFileDataNo.1No.nArchiveDecryptionHeaderArchiveExtraDataRecordCentralDirectoryHeaderNo.1......CentralDirectoryHeaderNo.nEndofCentralDirectoryRecord图2ZIP文件基本结构LocalFileHeaderLocalFileHeader的结构如表1所示。其中localfileheadersignature值固定为0x04034b50。使用010Editor打开,并应用ZIP模板,hellotwo.txt文件的LocalFileHeader如图3所示,由于没有extra内容,因此extrafieldlength为0且没有extrafield字段。另外要注意的是,hellotwo.txt的LocalFileHeader起始地址是0x39,也就是57,如图4所示。表1LocalFileHeader各字段及大小字段字节数localfileheadersignature4versionneededtoextract2generalpurposebitflag24compressionmethod2lastmodfiletime2lastmodfiledate2crc-324compressedsize4uncompressedsize4filenamelength2extrafiledlength2filename可变长度(sizeoffilename)extrafiled可变长度(sizeofextrafield)图3hellotwo.txt文件的LocalFileHeader图4hellotwo.txtLocalFileHeader的起始地址FileDataFileData包含了文件的实际内容。helloone.txt的FileData如图5所示,从图中可知其内容为contentone。图5helloone.txt的FileData内容5CentralDirectoryHeaderCentralDirectoryHeader的结构如表2所示,其中centralfileheadersignature值固定为0x02014b50。helloone.txt的CentralDirectoryHeader如图6所示,其中deHeaderOffset即是对应relativeoffsetoflocalheader字段,值为57,与hellotwo.txt的LocalFileHeader的起始地址一致。表2CentralDirectoryHeader各字段和大小字段字节数centralfileheadersignature4versionmadeby2versionneededtoextract2generalpurposebitflag2compressionmethod2lastmodfiletime2lastmodfiledate2crc-324compressedsize4uncompressedsize4filenamelength2extrafieldlength2filecommentlength2disknumberstart2internalfileattributes2externalfileattributes4relativeoffsetoflocalheader4filename可变长度(sizeoffilename)extrafield可变长度(sizeofextrafield)filecomment可变长度(sizeoffilecomment)图6hellotwo.txt的CentralDirectoryHeader6EndofCentralDirectoryRecordEndOfCentralDirectoryRecord的结构如表3所示。endofcentraldirectorysignature值固定为0x06054b50,offsetofstartofcentraldirectory值为第一个CentralDirectoryHeader的起始地址。因此解析ZIP文件时,可以从文件尾开始读取数据,首先根据0x06054b50确定EndofCentralDirectoryRecord的位置,然后读取offsetofstartofcentraldirectory的值,拿到该值后就可以定位到CentralDirectoryHeader,而CentralDirectoryHeader中又包含了LocalFileHeader的起始地址,这样从LocalFileHeader中就能读取到FileData了。hello.zip的EndofCentralDirectoryRecord如图7所示,第一个CentralDirectoryHeader的起始地址是150。表3EndofCentralDirectoryRecord各字段和大小字段字节数endofcentraldirectorysignature4numberofthisdisk2numberofthediskwiththestartofthecentraldirectory2totalnumberofentriesinthecentraldirectoryonthisdisk2totalnumberofentriesinthecentraldirectory2sizeofthecentraldirectory4offsetofstartofcentraldirectory4ZIPfilecommentlength2ZIPfilecomment可变长度图7hello.zip的EndofCentralDirectoryRecordARTRuntime在未启用ART环境的情况下,Android系统启动时会运行Dalvik虚拟机,ART号称可以取代Dalvik,那么在启动ART后,虚拟机部分又会有何变化呢?Android系统init进程启动过程中会运行app_process进程,app_process对应的源码位于/frameworks/base/cmds/app_process/app_main.cpp,在main函数中会启动Zygote(关于Zygote此文不会涉及太多,主要是分析和ART相关部分,Zygote的分析可以参考),代码如下。其中1.if(zygote){2.runtime.start(com.android.internal.os.ZygoteInit,3.startSystemServer?start-system-server:);74.}runtime是AppRuntime的实例,AppRuntime继承自AndroidRuntime,进入AndroidRuntime类的start函数(/frameworks/base/core/jni/AndroidRuntime.cpp),部分代码如下:1.voidAndroidRuntime::start(constchar*className,constchar*options)2.{3.......4.JniInvocationjni_invocation;5.jni_invocation.Init(NULL);6.JNIEnv*env;7.if(startVm(&mJavaVM,&env)!=0){8.return;9.}10.......11.}第4行声明JniInvocation类(/libnativehelper/JniInvocation.cpp)变量;第5行调用JniInvocation类的Init函数,该函数部分代码如下:1.boolJniInvocation::Init(