應(yīng)用啟動流程梳理(一)-應(yīng)用安裝流程

想針對啟動耗時&卡頓優(yōu)化做一個專題,一來是復(fù)習(xí)二來是構(gòu)建完整知識結(jié)構(gòu)。分析應(yīng)用的啟動勢必需要先了解整個啟動的流程,那么在分析前,需要先簡單總結(jié)下整個啟動流程的梳理大綱,基于android 9.0版本:


梳理大綱

那么我梳理的場景整體流程是:安裝一個應(yīng)用,完成安裝之后點(diǎn)擊Launcher桌面某App圖標(biāo),應(yīng)用啟動到主界面顯示完成整個過程。過程不涉及代碼,具體分析可以去看之前對應(yīng)的文章,里面有詳細(xì)的源碼分析。

一、應(yīng)用安裝流程

應(yīng)用安裝過程簡單說就兩步:

1.1 復(fù)制Apk到指定目錄

主Apk復(fù)制路徑如下:
system/app 系統(tǒng)應(yīng)用存放目錄
data/app 三方應(yīng)用存放目錄

~:/system/app/Bluetooth # ls -al
total 4048
drwxr-xr-x   4 root root    4096 2009-01-01 08:00 .
drwxr-xr-x 103 root root    4096 2009-01-01 08:00 ..
-rw-r--r--   1 root root 4124698 2009-01-01 08:00 Bluetooth.apk
drwxr-xr-x   3 root root    4096 2009-01-01 08:00 lib
drwxr-xr-x   3 root root    4096 2009-01-01 08:00 oat

~:/data/app/com.ss.android.article.news-kk9ZSokxPMvccIA7c41aJA== # ls -al
total 26108
drwxrwxr-x  4 system system      3488 2019-10-31 23:57 .
drwxrwx--x 41 system system      3488 2019-10-31 23:57 ..
-rw-r--r--  1 system system  26690526 2019-10-31 23:57 base.apk
drwxr-xr-x  3 system system      3488 2019-10-31 23:57 lib
drwxrwx--x  3 system install     3488 2019-10-31 23:57 oat

內(nèi)容與權(quán)限一目了然,這里就不贅述了。另外再關(guān)注一個目錄,data/data,這是各三方應(yīng)用的私有目錄,自然是用戶權(quán)限的,那么是不是root權(quán)限的進(jìn)程就可以隨意訪問了呢?其實(shí)也不然,在鎖屏解鎖前,data/data目錄內(nèi)的文件都是按FBE加密的,但是在解鎖之后會解密。這屬于文件系統(tǒng)的東西了,沒有深入研究。

但是我總結(jié)的結(jié)論是:/data目錄下,凡是_ce結(jié)尾的是一直加密的,_de結(jié)尾是不加密的。其他的沒有調(diào)研,但是data/data是在鎖屏解鎖前加密,解鎖后解密。感興趣的可以自行研究Android的文件系統(tǒng)加密。
[FBE加密官方介紹]https://source.android.google.cn/security/encryption/file-based

~:/data/data/com.ss.android.article.news # ls -al
total 73
drwx------  13 u0_a214 u0_a214        3488 2019-11-01 00:08 .
drwxrwx--x 322 system  system        24576 2019-10-31 23:57 ..
drwxrwx--x   2 u0_a214 u0_a214        3488 2019-11-01 00:08 app_textures
drwx------   3 u0_a214 u0_a214        3488 2019-11-01 00:08 app_webview
drwx------   2 u0_a214 u0_a214        3488 2019-11-01 00:08 app_webview_2930
drwx------   2 u0_a214 u0_a214        3488 2019-11-01 00:08 app_webview_3017
drwx------   4 u0_a214 u0_a214        3488 2019-11-01 00:08 app_webview_3298
drwxrws--x  10 u0_a214 u0_a214_cache  3488 2019-11-01 00:08 cache
drwxrws--x   2 u0_a214 u0_a214_cache  3488 2019-10-31 23:57 code_cache
drwxrwx--x   2 u0_a214 u0_a214        3488 2019-11-01 00:08 databases
drwxrwx--x  26 u0_a214 u0_a214        3488 2019-11-01 00:08 files
lrwxrwxrwx   1 root    root             74 2019-10-31 23:57 lib -> /data/app/com.ss.android.article.news-kk9ZSokxPMvccIA7c41aJA==/lib/arm
drwx------   2 u0_a214 u0_a214        3488 2019-11-01 00:08 lib-main
drwxrwx--x   2 u0_a214 u0_a214       20480 2019-11-01 00:09 shared_prefs

1.2 安裝APK:

安裝過程簡單說就是AndroidManifest.xml的解析,包括名字、版本、權(quán)限、四大組件等信息。然后分別做了內(nèi)存存儲和文件持久化。Launcher會獲取<action android:name="android.intent.action.MAIN" />和<category android:name="android.intent.category.LAUNCHER" />的Activity,并綁定一個應(yīng)用圖標(biāo),點(diǎn)擊Launcher對應(yīng)的應(yīng)用圖標(biāo),實(shí)際上就是做了一次Activity的隱式啟動。

當(dāng)然應(yīng)用安裝過程是很復(fù)雜的,包括權(quán)限的檢查、文件夾的創(chuàng)建、安裝邏輯判斷、數(shù)據(jù)結(jié)構(gòu)的封裝等等內(nèi)容。我這只是挑了幾點(diǎn)與啟動相關(guān)的總結(jié)一下。

1.3 其他APK相關(guān)知識點(diǎn)

1)APK組成

  • AndroidManifest.xml 應(yīng)用整體配置信息。

  • META-INF 簽名信息。

  • lib 應(yīng)用依賴的native .so庫,也包括一些插件。根據(jù)手機(jī)CPU的架構(gòu),lib庫大體上可以分為4種:ARM、ARM-V7、MIPS和X86,分別對應(yīng)著4種CPU架構(gòu)。實(shí)際上,市面上的手機(jī)幾乎全都是ARM架構(gòu)的,所以大多數(shù)情況下我們只需要有armeabi和armeabi-v7a兩種類型的庫就足夠了。

  • res 系統(tǒng)資源目錄,與工程對應(yīng)目錄內(nèi)容一致。

  • assets 跟res目錄有點(diǎn)相似,但實(shí)際上二者還是有區(qū)別的。res目錄中的文件會映射到R文件中,每個資源文件都有自己的ID,而assets中的文件則直接通過AssetManager類進(jìn)行訪問,而且assets目錄你可以添加任意深度的子目錄,這一點(diǎn)會比較方便管理和歸類文件。相比較之下,res目錄目前不能支持更深級的子目錄。附帶了解assets與raw的區(qū)別:assets不做任何處理被打包,資源通過AssetManager訪問,目錄可以分層。raw通過資源ID訪問,不參與編譯,目錄不可分層。

  • classes.dex .java文件通過javac編譯生成.class,多個.class通過dex生成.dex文件。.dex是面向Android虛擬機(jī)的標(biāo)準(zhǔn)字節(jié)碼。

  • resources.arsc 編譯后的二進(jìn)制資源文件索引,記錄了資源文件(即res目錄中的文件)和資源文件ID的映射關(guān)系,這樣程序運(yùn)行的時候就可以根據(jù)資源的ID獲取到相應(yīng)的資源。

2)編譯

  App在android上運(yùn)行,首先需要dex加載到內(nèi)存,dex執(zhí)行方式主要有兩種:解釋器執(zhí)行 和 執(zhí)行編譯后的機(jī)器碼 兩種執(zhí)行方式。解釋執(zhí)行就是及時編譯,運(yùn)行到哪解釋到哪,這樣效率不高,所以google在2.2版本引入了JIT,在解釋執(zhí)行過程中針對熱點(diǎn)代碼編譯為機(jī)器碼并且優(yōu)化,然后緩存在內(nèi)存中,下次執(zhí)行到相同代碼直接調(diào)用緩存的機(jī)器碼,提升效率。但是app進(jìn)程消亡下次重新冷啟就沒了。google4.4.推出art虛擬機(jī)替換Dalvik,推出AOT編譯,即生成的機(jī)器碼緩存為文件,作為持久化優(yōu)化,每次編譯會更新文件,但是更新頻率并不高。優(yōu)點(diǎn)是機(jī)器碼持久化保證下次使用也能直接跑機(jī)器碼,提升執(zhí)行效率,缺點(diǎn)是編譯耗時且CPU搶占嚴(yán)重。為了不影響用戶體驗(yàn),編譯時機(jī)非常關(guān)鍵。

Android推出4種編譯filter:

  • verify:只運(yùn)行 DEX 代碼驗(yàn)證。
  • quicken:運(yùn)行 DEX 代碼驗(yàn)證,并優(yōu)化一些 DEX 指令,以獲得更好的解釋器性能。
  • speed-profile:運(yùn)行 DEX 代碼驗(yàn)證,并對配置文件中列出的方法進(jìn)行 AOT 編譯。
  • speed:運(yùn)行 DEX 代碼驗(yàn)證,并對所有方法進(jìn)行 AOT 編譯。
    執(zhí)行效率上:
    verify < quicken < speed-profile < speed
    編譯速度上:
    verify > quicken > speed-profile > speed
    編譯觸發(fā)的幾個時機(jī):
路徑 描述 編譯方式 編譯內(nèi)容
Install 應(yīng)用安裝通過installd觸發(fā)的編譯 speed-profile 主apk
OTA升級 系統(tǒng)升級通過installd觸發(fā)的編譯 verify 主apk
load dexFile 動態(tài)加載插件直接通過虛擬機(jī)觸發(fā)的編譯 quicken 插件
postboot 開機(jī)1分鐘后,針對全部安裝的7天內(nèi)未使用且過期的應(yīng)用通過installd觸發(fā)的編譯 verify 主apk
idle 同時滿足充電、idle狀態(tài)且24小時內(nèi)只觸發(fā)一次,主apk通過installd觸發(fā)編譯,插件通過虛擬機(jī)觸發(fā)編譯 speed-profile 主apk 和 插件

另外,編譯的內(nèi)存除了主apk之外還包含應(yīng)用的插件,主apk間距通過PMS交由installd來觸發(fā)dex2oat編譯,插件則通過動態(tài)加載直接由虛擬機(jī)觸發(fā)dex2oat編譯。

3)動態(tài)加載插件

核心流程在于loadDexFile,這個過程核心邏輯是:先判斷是否有.odex文件,然后判斷是否過期,如果既有.odex又沒過期,那么直接加載,如果不滿足則先執(zhí)行dex2oat編譯,編譯完之后將.odex加載到內(nèi)存才開始執(zhí)行。另外.dex編譯過程是持鎖的,個人感覺目的可能是防止多處同時觸發(fā)loadDexFile,避免重復(fù)編譯。到了Android Q之后,動態(tài)加載插件去掉了編譯邏輯,也就是如果沒有.odex或者有但是過期,直接跳出去加載.dex文件走解釋模式,不再進(jìn)行編譯了。 好處是減少第一次加載等鎖造成的卡頓,壞處就是解釋模式執(zhí)行效率不高。

這里其實(shí)我多加了很多內(nèi)容,不光是關(guān)于應(yīng)用安裝流程的,好了這部分先到這。

上面牽涉到的部分知識點(diǎn)詳細(xì)細(xì)節(jié)可以參看之前寫過的文章:
Android PMS(一)-啟動流程
Android PMS(二)-Apk安裝流程
Android PMS(三)-Installd執(zhí)行dexopt流程
Android PMS(四)-安裝微信
啟動耗時分析(三)-ART編譯分析
Android 9.0 ART編譯分析(一)-編譯通路梳理
Android 9.0 ART編譯分析(二)-Installd觸發(fā)dex2oat編譯流程
Android 9.0 ART編譯分析(三)-虛擬機(jī)觸發(fā)dex2oat編譯流程

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
禁止轉(zhuǎn)載,如需轉(zhuǎn)載請通過簡信或評論聯(lián)系作者。

友情鏈接更多精彩內(nèi)容