1. 程式人生 > >Android 優化OTA包大小和開機啟動時間

Android 優化OTA包大小和開機啟動時間

問題說明

在Android 升級到 5.0 (Lollipop/L)之後,虛擬機器例項換成了ART,這加快了應用執行時的速度,但是在系統升級中卻引入了一些不便之處:

  1. 在生成升級包時,因為ART採用了預編譯優化功能,會把 APK 及JAR等通過dex2ota預編譯成odex檔案,這樣極大的增加了升級包的大小,動輒上G的大小不方便使用者的下載和網路的傳播;
  2. 如果不進行預編譯優化,則這部分操作會轉移到刷機完成後第一次開機時間,十幾分鍾甚至更多的時間,讓使用者不確認是否升級出問題;

預編譯配置-兼顧大小和時間

上述問題,Android系統設計者,早已考慮周全,尤其是針對儲存空間有限的裝置,提供了豐富的編譯配置選項,方便開發者根據自己實際情況進行鍼對性的配置修改;

下面就針對這些配置選項進行說明和標記,方便後續開發人員參考;

開啟odex編譯優化

首先,可以完全關閉預編譯優化功能,跟dalvik虛擬機器時代的升級包相同:

product BoardConfig.mk 檔案中,新增編譯變數: WITH_DEXPREOPT := true

當然,這樣的結果就是升級包小了,第一次開機時間極其慢;

預編譯的包不進行優化

預編譯的包是指那些在模組編譯檔案中指定為:include $(BUILD_PREBUILT) 的APK和JAR包等,這在升級包中佔了一大部門;
DONT_DEXPREOPT_PREBUILTS 變數就可以配置這部門程式碼是否進行預編譯優化;

DONT_DEXPREOPT_PREBUILTS := true 後,編譯系統將會阻止 prebuild 包的odex優化;

只進行BOOT.img 優化

Android啟動過程中,boot.img包含了大部分底層系統的啟動和初始化,主要包含在boot.art檔案中;
使用 WITH_DEXPREOPT_BOOT_IMG_ONLY 編譯變數,可以控制編譯系統只進行boot.img的優化;
使能該變數後,將會大量節省system分割槽的大小,但同時意味著所有的app都需要在第一次重啟的時候進行odex優化;

所以最好是通過 DONT_DEXPREOPT_PREBUILTS 進行更精確的控制;

LOCAL_DEX_PREOPT 編譯變數使用

每個app應用,可以通過該編譯變數進行控制是否進行odex優化;
在 app’s Android.mk,進行變數賦值 LOCAL_DEX_PREOPT := false

PRODUCT_DEX_PREOPT_ 編譯變數使用

在 post-L 發行版本之後,添加了這個系列的編譯變數,進行更深入控制預編譯的優化;

  1. PRODUCT_DEX_PREOPT_BOOT_FLAGS 傳遞引數給 dex2oat 命令,控制boot.img的編譯
  2. PRODUCT_DEX_PREOPT_DEFAULT_FLAGS 傳遞預設引數給 dex2oat 命令,控制除了 boot.img的編譯,即jar包和apk檔案
 $(call add-product-dex-preopt-module-config,services,--compiler-filter=space) 

或者 直接關閉模組的預編譯優化

$(call add-product-dex-preopt-module-config,Calculator,disable) 

Android 7.0 之後的優化

7.0後,系統可以分為A/B兩個分割槽,OTA升級以及APK的優化不影響使用者前臺的正常使用,這樣既減小了升級包的大小,又提升了第一次開機速度;

預載入類檔案

預載入類會由zygote統一初始化,這樣使後續使用到這些類的app開啟速度加快;但是預載入類的使用在實際專案中要非常注意,需要仔細評估後確認權衡值,太多的預載入類會導致一些不常用的類消耗寶貴的記憶體資源,相反則會導致常用的類在不同應用中獨立載入,各自有一個備份,既減慢應用開啟速度,也是浪費記憶體;

預載入類的定義列表,預設放置在 frameworks/base/preloaded-classes ,也可以在產品的devic.mk中新增自行定義的預載入列表:

PRODUCT_COPY_FILES += <filename>:system/etc/preloaded-classes

編譯類列表

結合 PRODUCT_DEX_PREOPT_BOOT_FLAGS 和 compiled-classes 可以控制編譯系統是否在預編譯優化中編譯這些類;
不過上述列表只能定義啟動類的一個子集,適合用於那些儲存空間非常有限,不能全域性優化編譯整個boot.img 分割槽的裝置,所以對我們來說並不適合;