android apk安裝過程原始碼解析

petterchx發表於2021-09-09

前言:

前一篇部落格分析了一下PackageManagerService是如何解析apk的以及我們如何解析未安裝apk中的androidManifest.xml檔案。解析完肯定要安裝的,索性寫一篇關於android系統是如何安裝我們apk的流程分析。不過這裡僅僅只分析java層面的程式碼,C層方面的就跳過了。

圖片描述

這裡有2個重點,第一個紅框可以看到與我們的PackageManagerService有關,獲取PackageManagerService的binder物件,與PackageManagerService進行通訊。並且如果這個物件為null 則輸出異常資訊直接返回,其實也不難理解,PackageManagerService把我們的apk給掃描了,那安裝應該也會在其中。所以這裡可以肯定的是apk的安裝實現就在我們的PackageManagerService中;第二點就是根據這個install標識來執行安裝的方法了。那我們就進入到runInstall()中來看下,它的內部是呼叫了PackageManagerService的什麼方法來進行apk安裝的。


runInstall()

圖片描述


從上面的runInstall()方法的程式碼可以看到 有3個標紅框的地方需要了解,第一個obs物件,用於接收PackageManagerService安裝結果,其實從第三個紅框就一目瞭然的瞭解INSTALL_SUCCEEDED,安裝成功!就輸出Success;第二個紅框就是透過binder來調起PackageManagerService中的installPackageWithVerificationAndEncryption()方法。


那接下來看下PackageManagerService中的installPackageWithVerificationAndEncryption()方法是如何操作的


圖片描述


這個方法程式碼並不是很多,重點在最後一部分,透過handler傳送一個INIT_COPY的訊息,訊息的內容是一個InstallParams物件。(這裡要注意下InstallParams,等下會說下這個)

那我們就只要找到handleMessage中處理這個INIT_COPY的訊息程式碼就行了


圖片描述

這裡值得一提的是,安裝apk的操作還需要一個服務,只有這個服務被bind了,才行進行下一步的工作,也就是透過handler繼續傳送一個訊息。(這個服務是com.android.defcontainer.DefaultContainerService這裡就不深層次分析了,它的作用就是用來解析APK,以及獲取推薦安裝路徑的,安裝的路徑與記憶體情況以及一些標識來決定)

繞來繞去,開啟服務之後又傳送了一個訊息,那隻好繼續看下這個MCS_BOUND訊息是如何處理的。


圖片描述


從程式碼中就能明顯看到,這裡又對服務進行了一次判斷,是否已經連線,所以這個服務於我們的apk安裝是共存的,其中mPendingInstalls就是用於儲存需要安裝的請求,只有當這個佇列為空時才斷開連線。(在INIT_COPY訊息處理中被新增到mPendingInstalls中的),然後又呼叫了HandlerParams的startCopy()方法執行安裝。

圖片描述

可以看到以下幾個重點

1.HandlerParams是個抽象類

2.箭頭那可以知道,這個安裝會嘗試4次,超過4次就GG了

3.執行handleStartCopy()方法

4.執行handleReturnCode()方法


在這之前值得一提的是前面installPackageWithVerificationAndEncryption()方法中透過handler傳送訊息,訊息的內容是InstallParams,而InstallParams又是繼承自HandlerParams這個抽象類,所以具體執行的是handleStartCopy()與handleReturnCode()的是InstallParams。


不過InstallParams這個方法的程式碼很長,這裡大致說下,InstallParams的handleStartCopy()的主要內容是透過com.android.defcontainer.DefaultContainerService來獲取apk的推薦安裝路徑,透過這個路徑來確定是內部安裝還是SD卡安裝,並且在這個方法的末尾,根據路徑來建立不同的InstallArgs,分別是FileInstallArgs/SdInstallArgs執行各自的copyApk()方法!


圖片描述



這裡就從FileInstallArgs的copyApk()這條路線來分析。


FileInstallArgs.copyApk()


圖片描述


這個方法的重點部分就在紅框位置,它的作用就是把我們的APK給複製到/data/app下,這個的路徑可以透過context.getPackageCodePath()獲取到,命名規則一般都是XXX.base.apk,不過這裡是個臨時檔案,在安裝的時候會對其進行改名操作。

到這就分析完了InstallParams的handleStartCopy()方法,還有一個重點部分是handleReturnCode方法,所以接著分析handleReturnCode();


圖片描述


這裡很簡單,呼叫了processPendingInstall()方法


圖片描述

圖片描述

這裡分為兩部分:

第一張圖可以看到標紅框部分執行了doPreInstall()和installPackageLI(),doPostInstall();

doPreInstall和doPostInstall內部很簡單,他的作用就是把我們安裝過程中的臨時檔案刪除,installPackageLI就是我們的正真安裝操作。

第二張圖則是安裝之後,傳送一個POST_INTALL訊息,告訴系統是否安裝完畢。


一系列的安裝流程終於走到最後了,看下最終的install操作的方法

圖片描述


下面兩個紅框可以看到,分別透過兩種不同的方式進行安裝,具體的判斷邏輯是根據包名來判斷的,如果存在包名則是覆蓋安裝,而不存在就是安裝一個新的apk。replacePackageLI()和installNewPackageLI()內部就和掃描系統中的package資訊一樣,  它把APK進行掃描,然後把apk中的資訊儲存到PackageManagerService中。瞭解4大元件的啟動過程就會知道,有一段流程是在PackageManagerService中獲取四大元件資訊,這些資訊就是透過把我們apk掃描安裝然後儲存到PackageMangerService中的。這樣我們的apk就已經安裝完成了。


圖中還有一個紅框,args.doRename()方法(這個args就是我們的FileInstallArgs),前面提到過我們的apk檔案會被複制到/data/app下,當複製進來的時候命名格式不是xx.apk,而這裡的doRename()方法就是把這個複製進來的檔案改名成XXXbase.apk。所以我們context.getPackageCodePath()獲取到的路徑就是改名後的資訊。



APK安裝的原始碼分析就分析到這,大致的流程就是獲取我們的安裝位置,然後複製我們的apk檔案到特定目錄,然後安裝我們的apk把apk的資訊儲存到PackageManagerService中。跟著上面的程式碼走一遍,相信還是很好理解的。

原文連結:http://www.apkbus.com/blog-822715-77667.html

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/4606/viewspace-2806988/,如需轉載,請註明出處,否則將追究法律責任。

相關文章