dex2oat
Table of Contents
1. dex2oat
1.1. when dex2oat MAYBE invoked
1.1.1. zygote init [zygote]
Runtime::Init(): Heap::Heap() CreateBootImage() GenerateImage() Exec("dex2oat")
zygote init 是会确定的调用 dex2oat 来编译
1.1.2. performDexOpt [installd]
1.1.2.1. post first boot
SystemServer::startOtherServices: mPackageManagerService.updatePackagesIfNeeded(); performDexOpt(pkgs, mIsPreNUpgrade /* showDialog */, getCompilerFilterForReason(causeFirstBoot ? REASON_FIRST_BOOT : REASON_BOOT));
pm.dexopt.first-boot 默认为 interpret-only, 所以会 verify 所有函数, 并编译 jni stub
1.1.2.2. post boot
BackgroundDexOptService::runPostBootUpdate: pm.performDexOpt(pkg, /* checkProfiles */ false, PackageManagerService.REASON_BOOT, /* force */ false);
pm.dexopt.boot 默认为 verify-profile, 只会生成 jni stub, 所以会生成oat 文件, 但除了 jni, 其它函数并没有被编译.
1.1.2.3. idle optimization
BackgroundDexOptService::runIdleOptimization: pm.performDexOpt(pkg,/* checkProfiles */ true,PackageManagerService.REASON_BACKGROUND_DEXOPT,/* force */ false) pm.performDexOptLI(pkg,....,checkProfiles) mInstaller.dexopt(...)
pm.dexopt.bg-dexopt 默认为 speed-profile, 所以 runIdleOptimization会真正的调用 dex2oat 编译
1.1.2.4. post package install
installPackageLI: mPackageDexOptimizer.performDexOpt(pkg, pkg.usesLibraryFiles, null /* instructionSets */, false /* checkProfiles */, getCompilerFilterForReason(REASON_INSTALL));
pm.dexopt.install 默认为 interpret-only, 所以 installPackageLI 只会做 verify 和 编译 jni stub
1.1.3. app launch [app]
ClassLinker::OpenDexFilesFromOat: OatFileAssistant oat_file_assistant(dex_location, oat_location, kRuntimeISA, ...); oat_file_assistant.MakeUpToDate(&error_msg) GenerateOatFile(error_msg); Dex2Oat(args, error_msg)
实际上, app 启动时并不能对 app 自身的 apk 进行 dex2oat, 因为它并没有写文件的权限. 若 apk 的 oat 被手动删除, 则通常 post boot 时会负责重新生成它.
1.2. dex2oat
dex2oat
dexopt: run_dex2oat(input_fd, out_fd, image_fd, input_file_name, out_path, swap_fd,...); dex2oat: if (dex2oat->IsImage()): result = CompileImage(*dex2oat); else: result = CompileApp(*dex2oat); CompileImage: dex2oat.Compile(); dex2oat.WriteOatFiles(); Compile: driver_= new CompilerDriver(...) driver_->CompileAll(class_loader_, dex_files_, ...);
CompileDriver
CompileAll: PreCompile(class_loader, dex_files, timings); Compile(class_loader, dex_files, timings); Compile: for (const DexFile* dex_file : dex_files): CompileDexFile(class_loader, *dex_file, dex_files, parallel_thread_pool_.get(), parallel_thread_count_, timings); CompileDexFile: CompileClassVisitor visitor; visitor.visit() CompileMethod(soa.Self(), driver, it.GetMethodCodeItem(),...); CompileMethod: if ((access_flags & kAccNative) != 0) { compiled_method = driver->GetCompiler()->JniCompile(access_flags, method_idx, dex_file); else: compiled_method = driver->GetCompiler()->Compile(code_item, access_flags, invoke_type, class_def_idx, method_idx, class_loader, dex_file, dex_cache);
1.3. compilation reason
- REASON_FIRST_BOOT
- REASON_BOOT
- REASON_INSTALL
- REASON_BACKGROUND_DEXOPT
- REASON_AB_OTA
- REASON_NON_SYSTEM_LIBRARY
- REASON_SHARED_APK
- REASON_FORCED_DEXOPT
- REASON_CORE_APP
上层调用 mPackageDexOptimizer.performDexOpt 时会传入相应的 reason, PackageDexOptimizer 根据 pm.dexopt.xxx 的值决定使用何种 compiler_filter
1.4. control compilation
because dex2oat is invoked in serveral different ways, for each way, we need use different approach to control the compilation.
art runtime
art runime may call `exec(dex2oat)` directly to dexopt some jar/apk/dex files
for boot image
compiled-filer is controled by `dalvik.vm.image-dex2oat-filter`
for dex/apk
compiled-filer is controled by `dalvik.vm.dex2oat-filter`
PackageDexOptimizer
in most cases, dex2oat is invoked through `PackageManagerService -> PackageDexOptimizer -> installed`, the compiled-filer is controled by:
- pm.dexopt.ab-ota
- pm.dexopt.bg-dexopt
- pm.dexopt.boot
- pm.dexopt.core-app
- pm.dexopt.first-boot
- pm.dexopt.forced-dexopt
- pm.dexopt.install
- pm.dexopt.nsys-library
- pm.dexopt.shared-apk
force compilation
# force compile my-package adb shell cmd package compile -m speed -f my-package # force compile all packages adb shell cmd package compile -m speed -f -a
- build time dexpreopt
- WITH_DEXPREOPT
- PRODUCT_DEX_PREOPT_DEFAULT_FLAGS
- WITH_DEXPREOPT_BOOT_IMG_ONLY
- WITH_DEXPREOPT_PIC
jit
jit is controled by system property: `dalvik.vm.usejit`
1.4.1. practice
1.4.1.1. disable global jit
adb shell stop adb shell setprop dalvik.vm.usejit false adb shell start
1.4.1.2. disable global aot
disable WITH_DEXPREOPT and rebuild android
build-time dexpreopt will strip dex from jar/apk, if we want disable aot for all package (boot.oat and app), we must keep the dex for framework.jar…
- delete oat files in data/dalvik-cache and /data/app/oat
- change system properties like `pm.dexopt.xxx` and `dalvikvm.vm.[image-]dex2oat-filter` to `interpret-only` or lower value
1.4.1.3. global interpret-only
- disable global aot
- disable global jit
1.4.1.4. disable aot for app
- delete package oat file in /data/app/oat
- it's better to change those `pm.dexopt.xxx` system properties to make sure app is not re-compiled
1.4.1.5. disable jit for app
there is no easy way to disable jit locally. we must change the AndroidManifest.xml of the apk.
the AndroidManifest.xml need add `android:vmSafeMode="true"` under the `<application>` tag