美文网首页Android开发Android开发经验谈Android技术知识
Android Q ART-Google Play安装时优化原理

Android Q ART-Google Play安装时优化原理

作者: 十八砖 | 来源:发表于2019-10-31 20:42 被阅读0次

    Google Play现在除了APK文件之外,还会交付一套基于云端的ART Profile配置文件Dex Metadata(.dm)。

    这个dm文件是从大数据用户那里搜集整理的APK对应的"热代码"文件,在通过GP安装apk时,会跟据dm文件提前进行优化编译,而不必等到用户使用一段时间生成热代码后再编译,可以显著提升首次启动速度。

    Android P或更高版本系统的设备目前已提供相关支持。

    1. 查看.prof、.dm文件
    dex metadata(.dm)内容跟.prof一致,其实是一个jar(zip)压缩包,里面包含一个primary.prof。
    安装apk时传.prof不识别,只识别.dm格式。

    1. 手动编译和清除一个APK:profile模式
      cmd package compile -m speed-profile -f com.whatsapp
      cmd package compile --reset com.whatsapp

    2. 手动编译和清除所有APK:profile模式
      cmd package compile -m speed-profile -f -a
      cmd package compile --reset -a

    3. 查看profile、dex metadata文件
      profman --profile-file=xxx.prof --dump-only
      profman --profile-file=xxx.dm --dump-only

      === profile ===
      ProfileInfo:
      base.apk [index=0]
              hot methods:
              startup methods: 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56,
              post startup methods: 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56,
              classes: 13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,
      

    2. 对比使用.dm安装前后差异
    以whatsapp为例,我们先运行一会儿whatsapp生成primary.prof文件,然后压缩成zip改名为WhatsApp.dm,我们就自己制作了dex metdata。

    如下实验可以看到加上.dm后生成的.art、.odex文件明显变大了,安装时就进行了oat编译提高启动速度。
    before: 279K 2019-10-31 10:18 base.odex
    after: 1.7M 2019-10-31 10:14 base.odex

    默认安装
    pm install WhatsApp.apk

    /data/app/com.whatsapp/oat/x86
    -rw-r--r-- 1 system all_a71 40K 2019-10-31 10:18 base.art
    -rw-r--r-- 1 system all_a71 279K 2019-10-31 10:18 base.odex
    -rw-r--r-- 1 system all_a71 11M 2019-10-31 10:18 base.vdex

    /data/misc/profiles/cur/0/com.whatsapp/primary.prof 大小为0
    /data/misc/profiles/ref/com.whatsapp 目录为空

    带有.dm安装
    pm install-create : created install session [1918895757]
    pm install-write 1918895757 WhatsApp.apk /data/local/tmp/WhatsApp.apk
    pm install-write 1918895757 WhatsApp.dm /data/local/tmp/WhatsApp.dm //传入dm参数
    pm install-commit 1918895757

    /data/app/com.whatsapp
    base.apk base.dm lib oat

    /data/app/com.whatsapp/oat/x86
    -rw-r--r-- 1 system all_a70 304K 2019-10-31 10:14 base.art
    -rw-r--r-- 1 system all_a70 1.7M 2019-10-31 10:14 base.odex
    -rw-r--r-- 1 system all_a70 11M 2019-10-31 10:14 base.vdex

    /data/misc/profiles/cur/0/com.whatsapp/primary.prof 大小为0
    /data/misc/profiles/ref/com.whatsapp/primary.prof 内容与.dm一致

    3. 代码中如何使用profile文件

    • 3.1 prepareAppProfiles()生成primary.prof

      1. PMS:installPackageLI():
      
      mArtManagerService.prepareAppProfiles(pkg, resolveUserIds(args.user.getIdentifier()));
      
      
      2. ArtManagerService:prepareAppProfiles():
      
      String codePath = codePathsProfileNames.keyAt(i);///data/app/com.whatsapp-SA9Yu-bYC8NLh1_b2iKULg==/base.apk
      String profileName = codePathsProfileNames.valueAt(i);//primary.prof
      File dexMetadata = DexMetadataHelper.findDexMetadataForFile(new File(codePath));//null or base.dm
      String dexMetadataPath = dexMetadata == null ? null : dexMetadata.getAbsolutePath();//null or base.dm
      synchronized (mInstaller) {
          boolean result = mInstaller.prepareAppProfile(pkg.packageName, user, appId,
                  profileName, codePath, dexMetadataPath);
      }
      
      3. dexopt.cpp:prepare_app_profile():
      //code_path= /data/app/com.whatsapp-l1rTMW3FR7a81Q7SkZoAZQ==/base.apk
      //cur_profile= /data/misc/profiles/cur/0/com.whatsapp/primary.prof
      //ref_profile= /data/misc/profiles/ref/com.whatsapp/primary.prof
      
      //1.创建primary.prof文件
      std::string cur_profile  = create_current_profile_path(user_id, package_name, profile_name,
              /*is_secondary_dex*/ false);
      if (fs_prepare_file_strict(cur_profile.c_str(), 0600, uid, uid) != 0) {
          return false;
      }
      
      // 2. 没有dex metadata不再往下走
      // Check if we need to install the profile from the dex metadata.
      if (dex_metadata == nullptr) {
          return true;
      }
      
      // 3. 将dex metadata和cur primary.prof合并到ref primary.prof
      // 第一次安装apk时,dex metadata==ref profile
      // 启动whatsapp自动生成热文件,执行cmd package compile -m speed-profile后,cur下primary.prof变为0,转移到了ref
      
      unique_fd ref_profile_fd = open_reference_profile(uid, package_name, profile_name,
              /*read_write*/ true, /*is_secondary_dex*/ false);
      unique_fd dex_metadata_fd(TEMP_FAILURE_RETRY(
              open(dex_metadata->c_str(), O_RDONLY | O_NOFOLLOW)));
      unique_fd apk_fd(TEMP_FAILURE_RETRY(open(code_path.c_str(), O_RDONLY | O_NOFOLLOW)));
      
      pid_t pid = fork();
      if (pid == 0) {
          /* child -- drop privileges before continuing */
          gid_t app_shared_gid = multiuser_get_shared_gid(user_id, app_id);
          drop_capabilities(app_shared_gid);
      
          // The copy and update takes ownership over the fds.
          run_profman_copy_and_update(std::move(dex_metadata_fd),
                                      std::move(ref_profile_fd),
                                      std::move(apk_fd),
                                      code_path);
      }
      
      
    • 3.2 dex2oat调用.prof编译
      cur_profile和ref_profile只能传入一个,两个都传会报错。
      第一次安装apk时,如果有dex metadata文件,那么ref_profile不为空,dex2oat就会以ref_profile为热代码文件进行编译。

      1. PackageDexOptimizer.java:dexOptPath():
      mInstaller.dexopt(path, uid, pkg.packageName, isa, dexoptNeeded, oatDir, dexoptFlags,
              compilerFilter, pkg.volumeUuid, classLoaderContext, pkg.applicationInfo.seInfo,
              false /* downgrade*/, pkg.applicationInfo.targetSdkVersion,
              profileName, dexMetadataPath, getReasonName(compilationReason));
      
      2. installd/dexopt.cpp:dexopt():
      // 打开ref profile
      Dex2oatFileWrapper reference_profile_fd = maybe_open_reference_profile(
              pkgname, dex_path, profile_name, profile_guided, is_public, uid, is_secondary_dex);
      
      //打开dex_metadata文件
      unique_fd dex_metadata_fd;
      if (dex_metadata_path != nullptr) {
          dex_metadata_fd.reset(TEMP_FAILURE_RETRY(open(dex_metadata_path, O_RDONLY | O_NOFOLLOW)));
          if (dex_metadata_fd.get() < 0) {
              PLOG(ERROR) << "Failed to open dex metadata file " << dex_metadata_path;
          }
      }
      //执行dex2oat编译
      run_dex2oat(input_fd.get(),
                  out_oat_fd.get(),
                  in_vdex_fd.get(),
                  out_vdex_fd.get(),
                  image_fd.get(),
                  dex_path,
                  out_oat_path,
                  swap_fd.get(),
                  instruction_set,
                  compiler_filter,
                  debuggable,
                  boot_complete,
                  background_job_compile,
                  reference_profile_fd.get(),
                  class_loader_context,
                  target_sdk_version,
                  enable_hidden_api_checks,
                  generate_compact_dex,
                  dex_metadata_fd.get(),
                  compilation_reason);
      
      
      3. dex2oat/dex2oat.cc:Dex2oat():
      //加载profile文件
      if (dex2oat->UseProfile()) {
          if (!dex2oat->LoadProfile()) {
          return dex2oat::ReturnCode::kOther;
          }
      }
      
      4. dex2oat.cc:LoadProfile():
      //profile_file_fd_指ref profile,第一次安装dex metadata==ref profile
      if (profile_file_fd_ != -1) {
          profile_file = LockedFile::DupOf(profile_file_fd_, "profile",
                                          true /* read_only_mode */, &error);
      } else if (profile_file_ != "") {
          profile_file = LockedFile::Open(profile_file_.c_str(), O_RDONLY, true, &error);
      }
      

    相关文章

      网友评论

        本文标题:Android Q ART-Google Play安装时优化原理

        本文链接:https://www.haomeiwen.com/subject/xeqxbctx.html