8.2.7 dexopt优化判定

检查bootClassPath、mSharedLibraries以及/system/framework目录下的JAR和APK文件是否需要dexopt优化,代码如下:


final boolean mNoDexOpt;//eng版,设置为true

……

public PackageManagerService(Context context, boolean factoryTest,

boolean onlyCore){

……

mNoDexOpt="eng".equals(SystemProperties.get("ro.build.type"));

……

synchronized(mInstallLock){

synchronized(mPackages){

……

int scanMode=SCAN_MONITOR|SCAN_NO_PATHS|SCAN_DEFER_DEX|SCAN_BOOTING;

if(mNoDexOpt){//eng版不需要做DEX预优化

scanMode|=SCAN_NO_DEX;//设置不需要DEX优化的标记

}

……

String bootClassPath=System.getProperty("java.boot.class.path");

if(bootClassPath!=null){

String[]paths=splitString(bootClassPath,':');

for(int i=0;i<paths.length;i++){

try{

/*判断该路径下的JAR包是否需要DEX优化,如果需要则将其路径存入

libFiles中,然后调用Installer的dexopt方法优化之/

if(dalvik.system.DexFile.isDexOptNeeded(paths[i])){

libFiles.add(paths[i]);

mInstaller.dexopt(paths[i],Process.SYSTEM_UID, true);

didDexOpt=true;

}

}catch(FileNotFoundException e){

……

if(mSharedLibraries.size()>0){//platform.xml指定的共享库

Iterator<String>libs=mSharedLibraries.values().iterator();

……//判断mSharedLibraries中的JAR文件是否需要DEX优化

}

//framework-res.apk是资源包,不需要优化,其路径直接存入libFiles

libFiles.add(mFrameworkDir.getPath()+"/framework-res.apk");

//mFrameworkDir表示/system/frameworks目录,优化其APK和JAR文件

String[]frameworkFiles=mFrameworkDir.list();

if(frameworkFiles!=null){

……//处理方法同上

}

if(didDexOpt){//didDexOpt为true,说明做过DEX优化

//mDalvikCacheDir表示/data/dalvik-cache

String[]files=mDalvikCacheDir.list();

if(files!=null){

for(int i=0;i<files.length;i++){

String fn=files[i];

//执行DEX优化,需要删除旧的缓存数据

if(fn.startsWith("data@app@")

||fn.startsWith("data@app-private@")){

(new File(mDalvikCacheDir, fn)).delete();

}

……


bootClassPath即java.boot.class.path中定义的系统核心JAR包的路径,以“:”分割。该值由libcore\luni\src\main\java\java\lang\System.java设置,可以通过VMRuntime.getRuntime().bootClassPath()获取。该路径默认指定以下JAR包:/system/framework/core.jar和/system/framework/core-junit.jar等。

遍历bootClassPath指定的所有JAR包,调用dalvik.system.DexFile.isDexOptNeeded方法判断每个JAR包是否需要dexopt优化,如果需要,则将该JAR包的路径存入libFiles中,然后调用mInstaller的dexopt方法进行优化。这里的mInstaller便是Installer对象。其他路径的处理流程与bootClassPath相似,步骤如下:

1)如果PackageManagerService.mSharedLibraries中存储的共享库需要dexopt,调用mInstaller.dexopt方法进行优化。mSharedLibraries变量中存储的是/etc/permissions目录中的XML文件的<library>标签指定的JAR包。

2)/system/framework/framework-res. apk中没有代码,不需要进行dexopt操作,直接存入libFiles。

3)如果/system/framework目录下其他APK和JAR包需要优化,调用mInstaller.dexopt方法进行优化。

上述目录中只要有任何一个目录中的文件需要优化,即didDexOpt变量赋值为true,就需要删除/data/dalvik-cache目录下所有以data@app@和data@app-private@开头的文件。

检查JAR包是否需要dexopt的isDexOptNeeded方法位于libcore/dalvik/src/main/java/dalvik/system/DexFile.java中,这是一个Native方法,其JNI实现方法位于dalvik/vm/native/dalvik_system_DexFile.cpp中,方法名为Dalvik_dalvik_system_DexFile_isDexOptNeeded,在该方法中调用了dalvik/vm/JarFile.cpp中的dvmDexCacheStatus方法,判断传入的APK或者JAR是否需要dexopt,代码如下:


DexCacheStatus dvmDexCacheStatus(const char*fileName)

{

ZipArchive archive;

char*cachedName=NULL;

int fd;

DexCacheStatus result=DEX_CACHE_ERROR;

ZipEntry entry;

//bootClassPath关联的JAR不需要DEX优化

if(dvmClassPathContains(gDvm.bootClassPath, fileName)){

return DEX_CACHE_OK;//不优化

}

//打开压缩文件出错,需要DEX优化

if(dexZipOpenArchive(fileName,&archive)!=0){

return DEX_CACHE_BAD_ARCHIVE;//优化

}

//kDexInJarName表示classes.dex文件,从压缩包里找到该文件

entry=dexZipFindEntry(&archive, kDexInJarName);

if(entry!=NULL){//判断classes.dex文件

bool newFile=false;

//在data/dalvik-cache目录下创建classes.dex缓存文件

cachedName=dexOptGenerateCacheFileName(fileName, kDexInJarName);

if(cachedName==NULL)

return DEX_CACHE_BAD_ARCHIVE;//cache文件为空,需要DEX优化

//dvmOpenCachedDexFile会锁住文件

fd=dvmOpenCachedDexFile(fileName, cachedName,

dexGetZipEntryModTime(&archive, entry),

dexGetZipEntryCrc32(&archive, entry),

if(fd<0){//dex cache文件需要更新

result=DEX_CACHE_STALE;//DEX_CACHE_STALE表示需要DEX优化

goto bail;

}

if(!dvmUnlockCachedDexFile(fd)){//文件解锁

goto bail;

}

}else{//判断jar或者apk目录下是否存在同名的ODEX文件

fd=openAlternateSuffix(fileName,"odex",O_RDONLY,&cachedName);

if(fd<0){//无ODEX文件,需要优化

result=DEX_CACHE_BAD_ARCHIVE;

goto bail;

}

if(!dvmCheckOptHeaderAndDependencies(fd, false,0,0,true, true)){

result=DEX_CACHE_STALE_ODEX;//优化

goto bail;

}else{

LOGV("%s odex has good dependencies",fileName);

}

}

result=DEX_CACHE_OK;//不优化

bail:

……//关闭文件回收资源

return result;

}


可见,dvmDexCacheStatus根据bootClassPath、classes.dex、odex以及dalvik-cache的状态,判断是否需要DEX优化。对于需要DEX优化的压缩包,则调用Installer的dexopt方法进行优化。对于Installer,本章后续小节将分析,具体的优化过程涉及Dalvik的实现,本书不做分析。