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.

  1. art runtime

    art runime may call `exec(dex2oat)` directly to dexopt some jar/apk/dex files

    1. for boot image

      compiled-filer is controled by `dalvik.vm.image-dex2oat-filter`

    2. for dex/apk

      compiled-filer is controled by `dalvik.vm.dex2oat-filter`

  2. 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
  3. 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
    
  4. build time dexpreopt
    • WITH_DEXPREOPT
    • PRODUCT_DEX_PREOPT_DEFAULT_FLAGS
    • WITH_DEXPREOPT_BOOT_IMG_ONLY
    • WITH_DEXPREOPT_PIC
  5. 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
  1. 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…

  2. delete oat files in data/dalvik-cache and /data/app/oat
  3. 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
  1. disable global aot
  2. disable global jit
1.4.1.4. disable aot for app
  1. delete package oat file in /data/app/oat
  2. 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

Author: [email protected]
Date: 2017-02-03 Fri 00:00
Last updated: 2023-11-20 Mon 16:08

知识共享许可协议