whitelist: 針對個別apk由於的dex2oat原因安裝失敗/ 安裝慢 / lunch慢的處理方法

[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版本]

 

  1. 在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版本:

/art/dex2oat/dex2oat.cc

方法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 優化影響不大

 

  1. 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

 

  1. 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

 

  1. 因此碰到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
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章