上一章分析了PMS的APP安装流程,APK经过复制、创建对应包文件夹、安装之后,还剩一个比较重要的点需要分析,那就是dex编译,本章将结合Android 11继续探究dex的编译流程。
在executePostCommitSteps中,存在如下代码:
private void executePostCommitSteps(CommitRequest commitRequest) {
// 判断是否需要dex优化
final boolean performDexopt =(!instantApp || Global.getInt(mContext.getContentResolver(),
Global.INSTANT_APP_DEXOPT_ENABLED, 0) != 0)
&& !pkg.isDebuggable()
&& (!onIncremental)
&& dexoptOptions.isCompilationEnabled();
// 如有必要,执行dex优化
if (performDexopt){
// Compile the layout resources.
if(SystemProperties.getBoolean(PRECOMPILE_LAYOUTS,false)){
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER,"compileLayouts");
mViewCompiler.compileLayouts(pkg);
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER,"dexopt");
ScanResult result=reconciledPkg.scanResult;
PackageSetting realPkgSetting=result.existingSettingCopied?result.request.pkgSetting:result.pkgSetting;
if(realPkgSetting==null){
realPkgSetting=reconciledPkg.pkgSetting;
}
// Unfortunately, the updated system app flag is only tracked on this PackageSetting
boolean isUpdatedSystemApp=reconciledPkg.pkgSetting.getPkgState().isUpdatedSystemApp();
realPkgSetting.getPkgState().setUpdatedSystemApp(isUpdatedSystemApp);
...
}
}
在这其中存在dex优化方法performDexOpt()
,下面继续深入分析该方法。
1、performDexOpt
frameworks/base/services/core/java/com/android/server/pm/PackageDexOptimizer.java
int performDexOpt(AndroidPackage pkg, @NonNull PackageSetting pkgSetting,
String[] instructionSets, CompilerStats.PackageStats packageStats,
PackageDexUsage.PackageUseInfo packageUseInfo, DexoptOptions options) {
...
// 开始执行dex优化
synchronized (mInstallLock) {
final long acquireTime = acquireWakeLockLI(pkg.getUid());
try {
return performDexOptLI(pkg, pkgSetting, instructionSets,packageStats, packageUseInfo, options);
} finally {
releaseWakeLockLI(acquireTime);
}
}
...
}
可以看到,该方法调用了performDexOptLI()
方法
2、performDexOptLI
frameworks/base/services/core/java/com/android/server/pm/PackageDexOptimizer.java
private int performDexOptLI(AndroidPackage pkg, @NonNull PackageSetting pkgSetting,
String[] targetInstructionSets, CompilerStats.PackageStats packageStats,
PackageDexUsage.PackageUseInfo packageUseInfo, DexoptOptions options) {
...
for (String dexCodeIsa : dexCodeInstructionSets) {
// 执行dexOptPath
int newResult = dexOptPath(pkg, pkgSetting, path, dexCodeIsa, compilerFilter,profileAnalysisResult, classLoaderContexts[i], dexoptFlags, sharedGid,packageStats, options.isDowngrade(), profileName, dexMetadataPath,
options.getCompilationReason());
...
if ((result != DEX_OPT_FAILED) && (newResult != DEX_OPT_SKIPPED)) {
result = newResult;
}
}
...
}
3、 dexOptPath
frameworks/base/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@GuardedBy("mInstallLock")
private int dexOptPath(AndroidPackage pkg, @NonNull PackageSetting pkgSetting, String path,
String isa, String compilerFilter, int profileAnalysisResult, String classLoaderContext,
int dexoptFlags, int uid, CompilerStats.PackageStats packageStats, boolean downgrade,
String profileName, String dexMetadataPath, int compilationReason) {
...
mInstaller.dexopt(path, uid, pkg.getPackageName(), isa, dexoptNeeded, oatDir,
dexoptFlags, compilerFilter, pkg.getVolumeUuid(), classLoaderContext,
seInfo, false /* downgrade*/, pkg.getTargetSdkVersion(),
profileName, dexMetadataPath,
getAugmentedReasonName(compilationReason, dexMetadataPath != null));
...
}
// [frameworks/base/services/core/java/com/android/server/pm/Installer.java]
// dexopt优化方法, 该方法通过binder与 frameworks/native/cmds/installd/installd.cpp 进行通信
public void dexopt(String apkPath, int uid, @Nullable String pkgName, String instructionSet,
int dexoptNeeded, @Nullable String outputPath, int dexFlags,
String compilerFilter, @Nullable String volumeUuid, @Nullable String sharedLibraries,
@Nullable String seInfo, boolean downgrade, int targetSdkVersion,
@Nullable String profileName, @Nullable String dexMetadataPath,
@Nullable String compilationReason) throws InstallerException {
assertValidInstructionSet(instructionSet);
BlockGuard.getVmPolicy().onPathAccess(apkPath);
BlockGuard.getVmPolicy().onPathAccess(outputPath);
BlockGuard.getVmPolicy().onPathAccess(dexMetadataPath);
if (!checkBeforeRemote()) return;
try {
mInstalld.dexopt(apkPath, uid, pkgName, instructionSet, dexoptNeeded, outputPath,
dexFlags, compilerFilter, volumeUuid, sharedLibraries, seInfo, downgrade,
targetSdkVersion, profileName, dexMetadataPath, compilationReason);
} catch (Exception e) {
throw InstallerException.from(e);
}
}
在这里可以看出,dexopt方法通过binder与frameworks/native/cmds/installd/installd.cpp
进行通信,调用了installd.cpp的dexopt方法。
4、dexopt
frameworks/native/cmds/installd/dexopt.cpp
int dexopt(const char* dex_path, uid_t uid, const char* pkgname, const char* instruction_set,
int dexopt_needed, const char* oat_dir, int dexopt_flags, const char* compiler_filter,
const char* volume_uuid, const char* class_loader_context, const char* se_info,
bool downgrade, int target_sdk_version, const char* profile_name,
const char* dex_metadata_path, const char* compilation_reason, std::string* error_msg,
/* out */ bool* completed) {
...
// 使用dex2opt进行dex优化
RunDex2Oat runner(dex2oat_bin, execv_helper.get());
runner.Initialize(out_oat.GetUniqueFile(), out_vdex.GetUniqueFile(), out_image.GetUniqueFile(),
in_dex, in_vdex, dex_metadata, reference_profile, class_loader_context,
join_fds(context_input_fds), swap_fd.get(), instruction_set, compiler_filter,
debuggable, boot_complete, for_restore, target_sdk_version,
enable_hidden_api_checks, generate_compact_dex, use_jitzygote_image,
compilation_reason);
...
}
这个方法最终调用了dex2opt
对dex文件进行优化,值得注意的时,dex2opt
在targetSdkVersion>=29且**Android 10+**的系统上不再允许在应用进程上触发dex2oat编译。其原因是系统在targetSdkVersion=29的时候,对此做了限制,不允许应用进程上触发dex2oat编译,通过应用进程触发dex2oat编译来弥补系统触发dex2oat编译的不足的方式,已经在andorid 10+的系统上不再适用,这点需要特别注意。