[DESCRIPTION]
自L版本之後,所有的APP要經過dex2oat處理過之後,才能運行。而dex2oat的任務是將原來的dex文件做預先的翻譯,從而可以加快APP運行的時間。但是由於某些APP比較複雜,所以優化的時間就比較長。優化是以dex文件中的method爲單位。dex2oat在優化時,會根據需要優化一定量的method。也就是說並不是優化的method都會被翻譯成oat模式。根據優化的method的量的多少,可以分爲如下的幾種模式:
對APP的優化是通過dex2oat去執行的,而優化模式則是由於外界調用dex2oat通過參數的方式傳遞進去的,如果調用命令的時間沒有傳遞參數那麼,默認採用speed模式。
而調用dex2oat的路徑一般有兩種:安裝APP的時候,由packagemanagerservice將參數傳遞給installd,由於installd調用dex2oat,也就是說優化模式由PMS決定。另外一種是APP自身優化插件,這時候,往往會指定爲speed或者不指定。
前一種方式將APK的路徑,優化之後的oat存放路徑傳遞給dex2oat,但是由於內容可能發生改變,我們有可能無法在dex2oat對APP加以識別,所以,這時候,可以在installd或者pms中加以判斷是否是我們認爲爲安裝比較慢的APP,如果是的話,則想改變其優化的模式。
如果是後一種方式,往往會在優化之後的保存路徑中攜帶APP的包名。
目前有些apk像facebook、微信等apk,本身應用較大且code複雜度高,往往會出現安裝失敗,安裝慢等問題。
安裝失敗是由於dex2oat進程編譯時間過久打到了timeout,安裝慢當然就是dex2oat做的compiler久的原因。
還有像微信 這種在啓動應用的時候是會優化插件的(而不是在安裝的時候優化),這樣就會導致應用lunch時間過久,給用戶的感覺就是很晚才入。
說明:app 安裝/ lunch時間的長短取決於CPU核心數,8核心的肯定是必4核心的優化要快,還取決於EMMC的性能 ,memory等系統因素。
目前解決安裝慢或者啓動慢主要從如下幾個方面着手:
首先:保證系統方面已經沒有可以優化的空間,例如,各種對應的patch已經合入,art是最新版本。如果已經沒有優化空間,這時候,就需要考慮更改優化的模式以加快安裝的時間,但是會降低app運行的性能。
1. 請先確保以下patch合入
L版本:
patch: ALPS02522543(L1.MP9不需要合入)
ALPS02861966(dependency 了所以重要的patch)
M版本:
ALPS02894769
2. 發現:6735平臺上dex2oat慢:demo 機 k35m 就比 k35 慢, 原因是CPU 頻率影響,PS有說明, 參考以下FAQ嘗試修改freq:
[FAQ17683]如何調整CPU corenum, freq, policy
[FAQ09538][CPU DVFS/Hotplug]運行時,把CPU固定在特定頻率/特定核數的辦法
更改dex2oat的模式:
如上面討論那樣,dex2oat發生的時機有兩種情況:一是APP安裝 ,二是APP自身優化插件。
更改優化模式的難點在於:如何識別進行優化的APP就是我們希望優化成指定模式的APP或得jar包。
目前在android中可以在三個地方進行判斷 :
PackageManagerService當中,這個地方是安裝APP必經之路
installd的commands.cpp當中,這也是安裝APP的必經之路
dex2oat當中,dex2oat是所有APP或者jar包的必經之路,但是由於傳遞給dex2oat的參數有限,所以可能無法識別。
所以對於安裝APP可以在pms當中修改,而對於jar包可以在dex2oat當中修改。
因爲pms中我們可以知道APP的pkg信息,這個是每一個APP唯一的。
而對jar包來說,由於每一個APP在優化的時候,喜歡把優化之後的jar包放在自己安裝的APP路徑下面。所以,可以利用這個特性進行判斷 。
[SOLUTION M版本]
- 在PMS中修改
在L和M版本不適用。
N版本中經過層層調用,會調用到如下的函數,因此需要修改如下的文件:
/frameworks/base/services/core/java/com/android/server/pm/PackageDexOptimizer.java
private int performDexOptLI(PackageParser.Package pkg, String[] sharedLibraries, 153 String[] targetInstructionSets, boolean checkProfiles, String targetCompilerFilter) { 在這函數中,可以判斷傳遞下來的pkg是否是我們需要的package,如果是的話,將targetCompilerFilter設置爲speed-profile。 speed-profile會在安裝的時候採用interperter-only,然後,運行一段時間之後,會將那些常用的方法優化成爲speed模式。也就是說是有選擇性的優化。
2.修改
L版本:
方法1:
// mtk add begin
if ((!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 end
if (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 } 1425 1426//mtk_add_begin 1427 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_end 1433 1434 return true; 1435 } 1436 1437 // 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;
}
}
#endif
static 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);
.......
}
----------------------------------------------------------------------------------------------------------------------------------------------------
PS: 新發現6735平臺上dex2oat慢:demo 機 k35m 就比 k35 慢, 原因是CPU 頻率影響, 與ART 優化影響不大
- k35m M版本測試版本:
\\10.15.11.230\public1\ALPS_load\alps-mp-m0.mp1\alps-mp-m0.mp1-V2.23\k35mv1_64_op01_alps-mp-m0.mp1-V2.23_user
- tencent.mm 版本V6.3.8.56_re6b2553
- 當時的CPU主頻221000/ 988000KHz:
01-01 04:28:43.565 <7>[16560.006725] (0)[56:cfinteractive][name:mt_cpufreq&][Power/cpufreq] @_mt_cpufreq_set_locked(): Vproc = 950mv, freq = 221000 KHz
01-01 04:28:44.366 <7>[16560.806949] (0)[56:cfinteractive][name:mt_cpufreq&][Power/cpufreq] @_mt_cpufreq_set_locked(): Vproc = 1250mv, freq = 988000 KHz
- M版本測試數據耗時install(34.077s)+launch(61.369ms+19.889s)=54s:
01-01 04:28:03.349302 1617 1661 I PackageManager.DexOptimizer: Running dexopt (dex2oat) on: /data/app/vmdl1857097406.tmp/base.apk pkg=com.tencent.mm isa=arm vmSafeMode=false debuggable=false oatDir = /data/app/vmdl1857097406.tmp/oat
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 04:28:54.538837 5725 5725 I dex2oat : /system/bin/dex2oat --dex-file=/data/user/0/com.tencent.mm/app_dex/secondary-1.dex.jar --oat-file=/data/user/0/com.tencent.mm/app_cache/secondary-1.dex.dex
01-01 04:28:54.538837 5725 5725 I dex2oat : /system/bin/dex2oat --dex-file=/data/user/0/com.tencent.mm/app_dex/secondary-1.dex.jar --oat-file=/data/user/0/com.tencent.mm/app_cache/secondary-1.dex.dex
01-01 04:28:54.599338 5725 5725 I dex2oat : dex2oat took 61.369ms (threads: 4) arena alloc=3KB java alloc=20KB native alloc=921KB free=870KB
01-01 04:28:54.675067 5730 5730 I dex2oat : /system/bin/dex2oat --dex-file=/data/user/0/com.tencent.mm/app_dex/secondary-2.dex.jar --oat-file=/data/user/0/com.tencent.mm/app_cache/secondary-2.dex.dex
01-01 04:29:14.563627 5730 5730 I dex2oat : dex2oat took 19.889s (threads: 4) arena alloc=5MB java alloc=8MB native alloc=45MB free=4MB
- k35 M版本測試版本:
\\10.15.11.230\public1\ALPS_load\alps-mp-m0.mp1\alps-mp-m0.mp1-V2.27\k35v1_64_op02_alps-mp-m0.mp1-V2.27_user
- tencent.mm 版本V6.3.8.56_re6b2553
- 當時的CPU主頻299000/1300000 KHz:
01-01 01:29:08.957 <7>[ 5573.215146] (1)[57:cfinteractive][name:mt_cpufreq&][Power/cpufreq] @_mt_cpufreq_set_locked(): Vproc = 950mv, freq = 299000 KHz
01-01 01:29:08.967 <7>[ 5573.225164] (1)[57:cfinteractive][name:mt_cpufreq&][Power/cpufreq] @_mt_cpufreq_set_locked(): Vproc = 1118mv, freq = 1300000 KHz
- M版本測試數據耗時install(24.303s)+launch(45.461ms+13.574s)=38s, 可以看到K35比K35m快16s:
01-01 01:28:46.130507 2948 3018 I PackageManager.DexOptimizer: Running dexopt (dex2oat) on: /data/app/vmdl1834204165.tmp/base.apk pkg=com.tencent.mm isa=arm vmSafeMode=false debuggable=false oatDir = /data/app/vmdl1834204165.tmp/oat
01-01 01:28:46.215408 5590 5590 I dex2oat : Starting dex2oat.
0-01 01:29:10.519144 5590 5590 I dex2oat : dex2oat took 24.303s (threads: 4) arena alloc=22MB java alloc=14MB native alloc=88MB free=5MB
01-01 01:29:23.273697 5677 5677 I dex2oat : /system/bin/dex2oat --dex-file=/data/user/0/com.tencent.mm/app_dex/secondary-1.dex.jar --oat-file=/data/user/0/com.tencent.mm/app_cache/secondary-1.dex.dex
01-01 01:29:23.318485 5677 5677 I dex2oat : dex2oat took 45.461ms (threads: 4) arena alloc=3KB java alloc=20KB native alloc=921KB free=870KB
01-01 01:29:23.379928 5682 5682 I dex2oat : /system/bin/dex2oat --dex-file=/data/user/0/com.tencent.mm/app_dex/secondary-2.dex.jar --oat-file=/data/user/0/com.tencent.mm/app_cache/secondary-2.dex.dex
- 01:29:36.954313 5682 5682 I dex2oat : dex2oat took 13.574s (threads: 4) arena alloc=4MB java alloc=8MB native alloc=45MB free=4MB
- 因此碰到6735平臺dex2oat慢,先判斷是35m還是35, 再嘗試修改CPU 頻率測試
[FAQ17683]如何調整CPU corenum, freq, policy
[FAQ09538][CPU DVFS/Hotplug]運行時,把CPU固定在特定頻率/特定核數的辦法
M版本:
由於APK安裝時傳遞下來的APK路徑不包含PKG信息無法生效,但是對於一些jar包,可以判斷oat保存的路徑,因爲往往會在路徑中透露pkg的信息。可以利用此判斷是否是我們關注的jar包在優化插件。
如下的Log所示:
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
--dex-file,--oat-location都透露了pkg的信息。
因此,可以判斷這兩個參數是否包含了我們的要求的pkg信息,如果有的話,可以設置
compiler_filter_string爲interpreter-only
N版本上面,也是判斷上面的參數,這後,滿足條件之後,可以想辦法調用
compiler_options_->SetCompilerFilter(kSpaceProfile);
對於L和M版本中如果是安裝APP可以在commands.cpp或者commands.c(L版本)中進行修改:
47static void run_dex2oat(int zip_fd, int oat_fd, const char* input_file_name, 748 const char* output_file_name, int swap_fd, const char *pkgname, const char *instruction_set, 749 bool vm_safe_mode, bool debuggable) 中判斷pkg name然後,設置:have_dex2oat_compiler_filter_flag的值爲interpreter-only