Android Framework 框架系列之 Dalvik

本文深入解析Android系统中Dex2Oat的工作原理,包括何时触发、如何优化及影响手机性能的因素。探讨了不同模式下Dex2Oat的行为,以及如何通过白名单策略调整编译模式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

640?wx_fmt=gif

640?wx_fmt=gif

极力推荐Android 开发大总结文章:欢迎收藏程序员Android 力荐 ,Android 开发者需要的必备技能

640?wx_fmt=jpeg

Android虚拟机 是app运行的基石,本篇主要参考MTK解决方案,部分方案仅适合MTK平台手机。

通过本篇文章阅读,你将收获以下知识点:

1.Java 语言在Android 上运行流程

1.Java 语言在Android 上运行流程

640?wx_fmt=png

Java语言在android 运行流程

2.虚拟机发展过程

  • 1.初期Dalvik

  • 2.中期Dalvik

  • 3.后期ART模式

    为了让APK在不同的虚拟机都可以运行,Google 采取了适配器模式,在让虚拟机运行之前先执行 dexopt ,即将dex 文件优化成odex 文件,可以让虚拟机更加优化的执行。

    在ART 虚拟机中,dexopt 将dex文件优化成二进制格式的问题,从而可以让ART虚拟机执行。

3.Android Dalvik 模式

根据优化Method量的多少分的模式

640?wx_fmt=png

Android Dalvik

4. Android N 中dex2oat 原理以及模式

N版本当中强化了JIT模式。JIT模式是Just in time 的简称。意思是在运行的时候,根据method有使用频率来决定是否要对某一个方法进行优化。虚拟机会统计每一个方法被执行的次数。如果某一个方法执行的次数比较多,达到一定的阈值,就会将升级为hot method,并将其记录在一个profile当中。在系统空闲并且在充电的时候,只将这些方法进行优化。在运行的时候,也会对这些方法进行优化,以方便在运行的时候使用。

  • 1.Android N dex2oat 模式图

640?wx_fmt=png

Android N dex2oat 模式图

  • 2.Android N dex2 oat 原理图

640?wx_fmt=png

Android N dex2oat 原理图

5. 如何判断dex2oat 采用的相关参数

dex2oat 的参数会在代码中通过如下函数打印

  1. L 版本

L版本会无条件打印

 timings.StartTiming("dex2oat Setup");
1436  LOG(INFO) << CommandLine();
  • 2 . M 和N版本

在M和N当中会有条件的打印不同的内容。

if (kIsDebugBuild || dex2oat.IsImage() || dex2oat.IsHost() || !kIsTargetBuild) {2144    LOG(INFO) << CommandLine();2145  } else {2146    LOG(INFO) << StrippedCommandLine();2147  }

6.如何查看dex2oat 的log

搜索关键字

  • dex2oat

  • dex-file

  • oat-fd

  • oat-location

  • compiler-filter

eg1:

 01-01 04:28:03.471265  5654  5654 I dex2oat : Starting dex2oat.01-01 04:28:37.548439  5654  5654 I dex2oat : dex2oat took 34.077s (threads: 4) arena alloc=23MB java alloc=14MB native alloc=88MB free=5MB 01-01其中:dex2oat tokk 34.077s表示 dex2oat的耗时情况,(threads:4)表示,一共用了4个线程做这件事情。

eg2:

01-01 08:34:27.063 I/dex2oat ( 7714): /system/bin/dex2oat --runtime-arg -classpath 
--runtime-arg --instruction-set=arm --instruction-set-features=default --runtime-arg -Xrelocate --boot-image=/system/framework/boot.art 
--dex-file=/data/data/com.tencent.mm/app_dex/secondary-2.dex.jar --oat-fd=62 --oat-location=/data/data/com.tencent.mm/app_cache/secondary-2.dex.dex 
--runtime-arg -Xms64m --runtime-arg -Xmx512m  --compiler-filter=speed

M 和 N 版本,可以通过会打印出较多的dex2oat参数。

上面的Log中,可以得出很多信息来:1.被优化的dex文件信息,可以通过 --dex-file获取,形如上面我们就知道优化的是微信里面的内容,因为--dex-file参数的dex文件位于
   com.tencent.mm目录下面的。2.优化之后oat存储的位置,可以看到--oat-location其是保存在包名下面的app_cache目录下面的。3.是对插件优化还是对APK本身优化。在L的时候所有的PMS优化的内容都会放在data/dalvik-cache目录下面,所以如果oat放的位置是data/
  dalvik-cache目录下面,那么就是优化主APK,否则就是优化插件的。
  而在M和N当中,优化的结果会放在自己的包下面,但是不会是这种类似app_cache这种,根据这个可以判断是对插件的优化。4.优化采用的模式
   根据--compiler-filter可以判断采用的是哪种模式。

如果我们关注的信息没有打印出来,可以修改上面打印这些Log的条件。

7.什么时候进行dex2oat

dex2oat一般发生在如下的时候:

  • 第一次开机

当第一次开机的时间,PackageManagerService会扫描手机中的各个目录,
当检测到APK之后,就会执行安装流程,在安装的时候,就会对这些APP进行dex2oat操作。
如果说APP比较多,或者dex2oat比较慢,那么开机时间就会比较长。
  • 安装APP

当系统开机之后,我们安装APP的时候,也会进dex2oat。
实质上这时候也是走到了PackageManagerService的流程。
由PMS执行安装的运行,并发起dex2oat的动作。
  • 优化插件

当APP运行的时候,会根据自己的需要,优化自己需要的插件文件。
例如自己引用到的非系统类的jar包。

综上来看,系统执行dex2oat的主解有两类,一类是system server中的Packagemanagerservice发起的并让installd执行的;另一类是APP自身根据需要优化自己的插件。

8. 手机反应慢的原因

慢的原因如下

  • 工作量

  • CPU

  • EMMC

  • Memory

  • Patch

9. 解决手机反应慢的方法

遇到慢的问题的时候,先从上面几个方面找原因,如果无法解决,那么就只好调整APP的安装策略。例如原来为speed模式,就改为interpreter-only模式。

  1. N版本(L /M 不适用) 在PMS中添加白名单

private int performDexOptLI(PackageParser.Package pkg, String[] sharedLibraries,String[] targetInstructionSets, boolean checkProfiles, String targetCompilerFilter) {//在这函数中,可以判断传递下来的pkg是否是我们需要的package,如果是的话,将targetCompilerFilter设置为speed-profile。//speed-profile会在安装的时候采用interperter-only,然后,运行一段时间之后,会将那些常用的方法优化成为speed模式。也就是说是有选择性的优化。

 if (isProfileGuidedFilter && isUsedByOtherApps(pkg)) {
 checkProfiles = false;

 targetCompilerFilter = getNonProfileGuidedCompilerFilter(targetCompilerFilter); if (DexFile.isProfileGuidedCompilerFilter(targetCompilerFilter)) { throw new IllegalStateException(targetCompilerFilter);
 }
 isProfileGuidedFilter = false;
}// If we're asked to take profile updates into account, check now.boolean newProfile = false;


###  mtk add begin
 if(pkg.contains("com.tencent.mm")){
 targetCompilerFilter="interpret-only";
 }
### mtk add end   
  • 2.在Installd中进行白名单处理

//1.通过 property来增加白名单//注意Facebook是apk的名字,后面不用带后缀,但是大小写一定要匹配。adb shell setprop ro.mtk.dex2oat_white_list Facebook://2.如果需要增加到开机启动当中,可以如下修改在device.mk中加入//多个APK名字之间用冒号隔开。PRODUCT_PROPERTY_OVERRIDES += ro.mtk.dex2oat_white_list=facebook:Facebook:youtube:skype:twitter: 

修改点

static int shouldUseInterpretonly(const char* input_file_name);static void run_dex2oat(int zip_fd, int oat_fd, const char* input_file_name,const char* output_file_name, int swap_fd, const char *pkgname, const char *instruction_set,bool vm_safe_mode){

......

######## MTK add start//适当的时候,进行调用if(shouldUseInterpretonly(input_file_name))
{strcpy(dex2oat_compiler_filter_arg, "--compiler-filter=interpret-only");
have_dex2oat_compiler_filter_flag = true;   //关键是设置这个参数的值ALOGW("%s is in whitelist from property so set interpret-only",input_file_name);
}
######## MTK add endALOGV("Running %s in=%s out=%s\n", DEX2OAT_BIN, input_file_name, output_file_name);

.....

}
######MTK add start/**
*函数功能,根据input的file name判断,当前来优化的APK名字判断是否在白名单当中。
*白名单来自于property
*/static int shouldUseInterpretonly(const char* input_file_name){char prop_buf[PROPERTY_VALUE_MAX];memset(prop_buf,0,PROPERTY_VALUE_MAX);bool have_whitelist = property_get("ro.mtk.dex2oat_white_list", prop_buf, NULL) > 0;if(!have_whitelist)return false;char *str = prop_buf;char appname[128],*ptrname = appname;memset(appname,0,128);while(*str)
{if(*str != ':')
{
*ptrname = *str;
ptrname ++;
str++;
}else{

str++;if(*appname != 0)
{if(strstr(input_file_name,appname)) //found{return 1; 
}else{memset(appname,0,sizeof(appname));
ptrname = appname;
}
}
}
}return 0;
}
### MTK add end
  • 3 . 在dex2oat.cc 中进行白名单处理

/art/dex2oat/dex2oat.cc

  • 通过判断dex2oat进程的父pid来判断是插件

以N版本为例,建议的代码如下:

/*
 *调整编译的模式,规则:如果当前进程的父进程是installd,不做修改,否则修改为interpreter-only。
 *因为插件类的,都是进程本来fork的dex2oat.
 *only for device end
 *
 */
 void adjustCompilerOptions(const CompilerOptions* compiler_options){ 
 int ppid = getppid(); //获取当前进程的parent pid
 char cmdline_path[256]; char contents[256]; memset(cmdline_path,0,sizeof(cmdline_path)); memset(contents,0,sizeof(contents)); snprintf(cmdline_path,"/proc/%d/cmdline");
 FILE *fd = fopen(cmdline_path,"r"); // 打开proc/pid/cmdline文件,以读取对应ppid进程的名字
 
 if(fd == NULL){
 LOG(ERROR) < return;
 }
 
 fgets(contents,sizeof(contents),fd); //读取文件中的内容
 fclose(fd); if(strstr(contents,"installd")){ //判断是否是installd
 return;
 }
 
 Log(INFO)<<"parent is not installd,may be is a plugin adjust it to interpret-only";
 compiler_options->SetCompilerFilter(kInterpretOnly); //如果是的话,强行调整编译模式为interpreteronly模式
 
 
 }

在ParseArgs函数中对dex2oat的模式进行调整:
 ProcessOptions(parser_options.get()); // Insert some compiler things.
 InsertCompileOptions(argc, argv); 
 if(!IsHost())  //注意一定要判断非host端,否则会有问题
 adjustCompilerOptions(compiler_options_.get());
 
 }
  • 根据dex文件名字或者oatlocation名字来判断

L版本:
/art/dex2oat/dex2oat.cc

方法1:// mtk add beginif ((!oat_filename_.empty() && (oat_filename_.find("facebook") != std::string::npos))||(!zip_location_.empty() && (zip_location_.find("facebook") !=std::string::npos))||((!oat_location_.empty()) && oat_location_.find("facebook") != std::string::npos)){  // mtk modify 2016-06-06

                                    compiler_filter_string = "interpret-only";

                                    LOG(INFO) <<" This apk is in whitelist from property so set interpret-only ";

            }// mtk add endif (compiler_filter_string = nullptr){

      compiler_filter_string = "speed";

}

 注意:CTS测项用的包不能使用interpret-only模式,因为一些CTS测项是性能相关的,如果改为interpret模式,会导致CTS不过。之前有客户为了追求更快的安装速度,将所有的包都改为interpret-only的,结果CTS就不过了,针对这种情况,可以把CTS的包再放到speed模式的白名单当中。cts的关键字为test.

 

方法2(若上述方法无效):1420 if (num_methods <= compiler_options_->GetNumDexMethodsThreshold()) {1421 compiler_options_->SetCompilerFilter(CompilerOptions::kSpeed);1422 VLOG(compiler) << "Below method threshold, compiling anyways";1423 }1424 }14251426//mtk_add_begin1427 static constexpr size_t kMinCompileDexSize = 4;1428 if (!image_ && dex_files_.size() > kMinCompileDexSize) {1429 compiler_options_->SetCompilerFilter(CompilerOptions::kInterpretOnly);1430 LOG(INFO) << "Enable Whitelist Rules. Current Dex File Sizes:" << dex_files_.size();1431 }1432//mtk_add_end14331434 return true;1435 }14361437 // Create and invoke the compiler driver. This will compile all the dex files.1438 void Compile() {1439 TimingLogger::ScopedTiming t("dex2oat Compile", timings_);1440 compiler_phases_timings_.reset(new CumulativeLogger("compilation times"))

或者如下

[SOLUTION L版本]

    在device.mk中加入PRODUCT_PROPERTY_OVERRIDES += ro.mtk.dex2oat_white_list=com.tencent.mm: (注意 包名后又冒号“:”
 
[添加source code](抱歉不能排版)
 /art/dex2oat/dex2oat.cc添加红色部分:
 
 #ifdef HAVE_ANDROID_OS extern "C"{                  static int shouldUseInterpretonly(const char* filename){                       char prop_buf[92];                       memset(prop_buf,0,92);                       bool have_whitelist = property_get("ro.mtk.dex2oat_white_list", prop_buf, NULL) > 0;                       if(!have_whitelist)                       return false;                       char *str = prop_buf;                       char appname[128],*ptrname = appname;                       memset(appname,0,128);                       while(*str)
{         if(*str != ':'){
                                     *ptrname = *str;
                                      ptrname ++;
                                      str++;
              } else{
                                       str++;                                      if(*appname != 0){                                                   if(strstr(filename,appname)) //found
                                                     {                                                              return 1; 
                                                      } else{                                                              memset(appname,0,sizeof(appname));
                                                              ptrname = appname;
                                                      }
                                         }
                         }
}return 0;
}
}#endifstatic int dex2oat(int argc, char** argv) {          std::string dex_filename; //mtk_add
           ......         if (option.starts_with("--dex-file=")) {
                    dex_filenames.push_back(option.substr(strlen("--dex-file=")).data());
                    dex_filename = option.substr(strlen("--dex-file=")).data(); //mtk_add
         } else if......         
         if (compiler_filter_string == nullptr) { 
         if (instruction_set == kMips64) {         // TODO: fix compiler for Mips64.
                     compiler_filter_string = "interpret-only";
         } else if (image) {
                     compiler_filter_string = "speed";
         } else {
                    #if ART_SMALL_MODE
                    compiler_filter_string = "interpret-only";        #else
          #ifdef HAVE_ANDROID_OS
                 if(shouldUseInterpretonly(zip_location.c_str())){
                              compiler_filter_string = "interpret-only";
                              LOG(INFO) <<" This apk is in whitelist from property so set interpret-only";
                  }else if(shouldUseInterpretonly(dex_filename.c_str())){
                              compiler_filter_string = "interpret-only";
                              LOG(INFO) <<" This jar is in whitelist from property so set interpret-only";
                   }else{
          #endif
                               compiler_filter_string = "speed";           #ifdef HAVE_ANDROID_OS
                    } 
        #endif#endif 
    }
}

CHECK(compiler_filter_string != nullptr);
.......

}

640?wx_fmt=jpeg

至此,本篇已结束,如有不对的地方,欢迎您的建议与指正。同时期待您的关注,感谢您的阅读,谢谢!

640?wx_fmt=jpeg

如有侵权,请联系小编,小编对此深感抱歉,届时小编会删除文章,立即停止侵权行为,请您多多包涵。

640?wx_fmt=other

既然都看到这里,领两个红包在走吧!以下两个红包每天都可以领取

1.支付宝搜索 522398497,或扫码支付宝红包海报。

支付宝扫一扫,每天领取大红包

2.微信红包,微信扫一扫即可领取红包

微信扫一扫,每天领取微信红包

小礼物走一走,来简书关注我

Android虚拟机Dalvik完整源码,宝贵资源,欢迎下载! This directory contains the Dalvik virtual machine and core class library, as well as related tools, libraries, and tests. A note about the licenses and header comments --------------------------------------------- Much of the code under this directory originally came from the Apache Harmony project, and as such contains the standard Apache header comment. Some of the code was written originally for the Android project, and as such contains the standard Android header comment. Some files contain code from both projects. In these cases, the header comment is a combination of the other two, and the portions of the code from Harmony are identified as indicated in the comment. Here is the combined header comment: /* * Copyright (C) The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * ---------- * * Portions of the code surrounded by "// BEGIN Harmony code" and * "// END Harmony code" are copyrighted and licensed separately, as * follows: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ Native SH call bridge --------------------- Native SH call bridge is written by Shin-ichiro KAWASAKI and Contributed to Android by Hitachi, Ltd. and Renesas Solutions Corp.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员Android

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值