Android啓動流程、app啓動原理

從頭分析整理學習底層知識。

Android 衆多基於Linux內核的系統類似, 啓動系統時, bootloader啓動內核和init進程. init進程分裂出更多名爲"daemons(守護進程)"的底層的Linux進程, 諸如android debug deamon, USB deamon等. 這些守護進程處理底層硬件相關的接口.隨後, init進程會啓動一個非常有意思的進程---"Zygote". 顧名思義, 這是一個Android平臺的非常基礎的進程. 這個進程初始化了第一個VM, 並且預加載了framework和衆多App所需要的通用資源. 然後它開啓一個Socket接口來監聽請求, 根據請求孵化出新的VM來管理新的App進程. 一旦收到新的請求, Zygote會基於自身預先加載的VM來孵化出一個新的VM創建一個新的進程.

啓動Zygote之後, init進程會啓動runtime進程. Zygote會孵化出一個超級管理進程---System Server. SystemServer會啓動所有系統核心服務, 例如Activity Manager Service, 硬件相關的Service等. 到此, 系統準備好啓動它的第一個App進程---Home進程了.

Zygote 進程

Zygote 的中文意思是受精卵,從這個意思裏也可以看出 Zygote 進程是用來分裂複製(fork)的,實際上所有的 App 進程都是通過對 Zygote 進程的 Fork 得來的。當 app_process 啓動 Zygote 時,Zygote 會在其啓動後,預加載必要的 Java Classes(相關列表查看 預加載文件) 和 Resources,並啓動 System Server ,並打開 /dev/socket/zygote socket 去監聽啓動應用程序的請求,日後。在下面的代碼中,顯示了 Zygote 進程如何啓動,和加載 System Server 的。

Android進程與Linux進程一樣. 默認情況下, 每個apk運行在自己的Linux進程中. 另外, 默認一個進程裏面只有一個線程---主線程. 這個主線程中有一個Looper實例, 通過調用Looper.loop()從Message隊列裏面取出Message來做相應的處理.

那麼, 這個進程何時啓動的呢?

簡單的說, 進程在其需要的時候被啓動. 任意時候, 當用戶或者其他組件調取你的apk中的任意組件時, 如果你的apk沒有運行, 系統會爲其創建一個新的進程並啓動. 通常, 這個進程會持續運行直到被系統殺死. 關鍵是: 進程是在被需要的時候才創建的.

點擊圖標 啓動應用

app launch.png

Click事件會調用startActivity(Intent), 會通過Binder IPC機制, 最終調用到ActivityManagerService. 該Service會執行如下操作:

第一步通過PackageManager的resolveIntent()收集這個intent對象的指向信息.
指向信息被存儲在一個intent對象中.
下面重要的一步是通過grantUriPermissionLocked()方法來驗證用戶是否有足夠的權限去調用該intent對象指向的Activity.
如果有權限, ActivityManagerService會檢查並在新的task中啓動目標activity.
現在, 是時候檢查這個進程的Proce***ecord是否存在了.
如果Proce***ecord是null, ActivityManagerService會創建新的進程來實例化目標activity.

ActivityManager 架構

在我們編程過程中,涉及到許多 Activity 跳轉的事情,在 Launcher 中點擊 Icon 進行跳轉也是同樣的道理,調用 context.startActivity(intent) 方法。Launcher 出於一個線程,而啓動的 App 則運行在另一個進程中,在這其中勢必牽涉到跨進程 (IPC) 調用,這樣複雜的過程顯然需要一種中介者,或者一個系統來進行中轉和管理,而這個服務就是 ActivityManagerService。

ActivityManagerService 作爲一個守護進程運行在 Android Framework 中,如果讓開發者直接接觸這個類的話,就需要開發者自行處理 IPC 調用的問題,且這有不利於 Android 系統進行安全校驗等工作。因而 Android 系統實現了 ActivityManager,通過這個 ActivityManager 作爲一個入口,變相地和 ActivityManagerService 打交道。

App安裝過程

Dalvik和ART是什麼,有啥區別?
Davlivk

Dalvik是Google公司自己設計用於Android平臺的虛擬機。支持已轉換爲** .dex格式**的Java應用程序的運行,.dex格式是專爲Dalvik設計的一種壓縮格式,適合內存和處理器速度有限的系統。
Dalvik 經過優化,允許在有限的內存中同時運行多個虛擬機的實例,並且每一個Dalvik 應用作爲一個獨立的Linux 進程執行。獨立的進程可以防止在虛擬機崩潰的時候所有程序都被關閉。
很長時間以來,Dalvik虛擬機一直被用戶指責爲拖慢安卓系統運行速度不如IOS的根源。
2014年6月25日,Android L 正式亮相於召開的谷歌I/O大會,Android L 改動幅度較大,谷歌將直接刪除Dalvik,代替它的是傳聞已久的ART。

ART

即Android Runtime
ART 的機制與 Dalvik 不同。在Dalvik下,應用每次運行的時候,字節碼都需要通過即時編譯器(just in time ,JIT)轉換爲機器碼,這會拖慢應用的運行效率,而在ART 環境中,應用在第一次安裝的時候,字節碼就會預先編譯成機器碼,使其成爲真正的本地應用。這個過程叫做預編譯(AOT,Ahead-Of-Time)。這樣的話,應用的啓動(首次)和執行都會變得更加快速。

區別:

Dalvik是基於寄存器的,而JVM是基於棧的。
Dalvik運行dex文件,而JVM運行java字節碼
自Android 2.2開始,Dalvik支持JIT(just-in-time,即時編譯技術)。
優化後的Dalvik較其他標準虛擬機存在一些不同特性: 
1.佔用更少空間 
2.爲簡化翻譯,常量池只使用32位索引  
3.標準Java字節碼實行8位堆棧指令,Dalvik使用16位指令集直接作用於局部變量。局部變量通常來自4位的“虛擬寄存器”區。這樣減少了Dalvik的指令計數,提高了翻譯速度。 
 當Android啓動時,Dalvik VM 監視所有的程序(APK),並且創建依存關係樹,爲每個程序優化代碼並存儲在Dalvik緩存中。Dalvik第一次加載後會生成Cache文件,以提供下次快速加載,所以第一次會很慢。
 Dalvik解釋器採用預先算好的Goto地址,每個指令對內存的訪問都在64字節邊界上對齊。這樣可以節省一個指令後進行查表的時間。爲了強化功能, Dalvik還提供了快速翻譯器(Fast Interpreter)。

對比

ART有什麼優缺點呢?

優點:
1、系統性能的顯著提升。
2、應用啓動更快、運行更快、體驗更流暢、觸感反饋更及時。
3、更長的電池續航能力。
4、支持更低的硬件。
缺點:
1.機器碼佔用的存儲空間更大,字節碼變爲機器碼之後,可能會增加10%-20%
2.應用的安裝時間會變長

安裝過程

Android應用安裝有如下四種方式
1.系統應用安裝――開機時完成,沒有安裝界面
2.網絡下載應用安裝――通過market應用完成,沒有安裝界面
3.ADB工具安裝――沒有安裝界面。
4.第三方應用安裝――通過SD卡里的APK文件安裝,有安裝界面,由packageinstaller.apk應用處理安裝及卸載過程的界面。

應用安裝的流程及路徑
應用安裝涉及到如下幾個目錄:
system/app
系統自帶的應用程序,無法刪除

data/app
用戶程序安裝的目錄,有刪除權限。
安裝時把apk文件複製到此目錄

data/data
存放應用程序的數據

Data/dalvik-cache
將apk中的dex文件安裝到dalvik-cache目錄下(dex文件是dalvik虛擬機的可執行文件,其大小約爲原始apk文件大小的四分之一)

   安裝過程:複製APK安裝包到data/app目錄下,解壓並掃描安裝包,把dex文件(Dalvik字節碼)保存到dalvik-cache目錄,並data/data目錄下創建對應的應用數據目錄。
   卸載過程:刪除安裝過程中在上述三個目錄下創建的文件及目錄。 
12

把APK安裝包保存在SD卡中,從手機裏訪問SD卡中的APK安裝包,點擊就可以啓動安裝界面,系統應用Packageinstaller.apk處理這種方式下的安裝及卸載界面流程,如下圖:

PackageInstallerActivity負責解析包,判斷是否是可用的Apk文件
創建臨時安裝文件/data/data/com.android.packageinstaller/files/ApiDemos.apk
並啓動安裝確認界面startInstallConfirm,列出解析得到的該應用基本信息。如果手機上已安裝有同名應用,則需要用戶確認是否要替換安裝(校驗簽名)。
確認安裝後,啓動InstallAppProgress,調用安裝接口完成安裝。
pm.installPackage(mPackageURI,observer, installFlags);

具體步驟

  1. 將apk文件copy至data/app目錄

1.1 installPackageAsUser 這個方法主要是判斷安裝來源,包括adb,shell,all_user,然後向PMS的mHandler發送INIT_COPY的消息,這個mHandler運行在一個HandlerThread中。


image.png

1.2handleMessage(INIT_COPY)&handleMessage(MCS_BOUND)
INIT_COPY主要是確保DefaultContainerService已bound,DefaultContainerService是一個應用服務,具體負責實現APK等相關資源文件在內部或外部存儲器上的存儲工作。而MCS_BOUND中則執行了


image.png

params.startCopy()這句,也是最關鍵的開始copy文件。
1.3handleStartCopy()handleStartCopy的核心就是copyApk,其他的都是些存儲空間檢查,權限檢查等等安全校驗
2 .解析apk信息

完成apk copy到data/app目錄的操作後,下一步就到了 handleReturnCode,這個方法又跳轉到processPendingInstall()方法,
解析了package包,然後做了大量簽名和權限校驗的工作,最終會走到
覆蓋安裝和安裝新應用對應的具體執行.

  if (replace) {
        replacePackageLI(pkg, parseFlags, scanFlags | SCAN_REPLACING, args.user,
                installerPackageName, res);
    } else {
        installNewPackageLI(pkg, parseFlags, scanFlags | SCAN_DELETE_DATA_ON_FAILURES,
                args.user, installerPackageName, res);
    }12345671234567

scanPackageLI負責安裝,而updateSettingLI則是完成安裝後的設置信息更新

dexopt操作

Apk文件其實只是一個歸檔zip壓縮包,而我們編寫的代碼最終都編譯成了.dex文件,但爲了提高運行性能,android系統並不會直接執行.dex,而是會在安裝過程中執行dexopt操作來優化.dex文件,最終android系統執行的時優化後的'odex'文件(注意:這個odex文件的後綴也是.dex,其路徑在data/dalvik-cache)。對於dalvik虛擬機,dexopt就是優化操作,而對於art虛擬機,dexopt執行的則是dex2oat操作,既將.dex文件翻譯成oat文件。

dexopt操作執行完後,installNewPackageLI()方法就會走到updateSettingsLI()來更新設置信息,而更新設置信息主要是權限信息,所以直接來看updatePermissionsLPw();

最終會發送Intent.ACTION_PACKAGE_ADDED廣播,apk的安裝就到到此結束了。

todo 待完善 2018年3月
其它:

  1. PackageManagerService.java的內部類AppDirObserver實現了監聽app目錄的功能:當把某個APK拖到app目錄下時,可以直接調用scanPackageLI完成安裝。
    2.手機數據區目錄“data/system/packages.xml”文件中,包含了手機上所有已安裝


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章