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的实现,本书不做分析。