當前位置:
首頁 > 最新 > Android PMS處理APK的複製

Android PMS處理APK的複製

前言

在上一篇文章Android包管理機制之PackageInstaller安裝APK中,我們學習了PackageInstaller是如何安裝APK的,最後會將APK的信息交由PMS處理。那麼PMS是如何處理的呢?主要是APK的複製和安裝,由於公號文章字數的限制,這篇文章只能介紹 PMS處理APK的複製,APK安裝過程會在後續文章講解。

1.PackageHandler處理安裝消息

APK的信息交由PMS後,PMS通過向PackageHandler發送消息來驅動APK的複製和安裝工作。

先來查看PackageHandler處理安裝消息的調用時序圖。

接著上一篇文章的代碼邏輯來查看PMS的installStage方法。

frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java

注釋2處創建InstallParams,它對應於包的安裝數據。注釋1處創建了類型為INIT_COPY的消息,在注釋3處將InstallParams通過消息發送出去。

1.1 對INIT_COPY的消息的處理

處理INIT_COPY類型的消息的代碼如下所示。

frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java#PackageHandler

注釋2處的connectToService方法用來綁定DefaultContainerService,注釋3處發送MCS_BOUND類型的消息,觸發處理第一個安裝請求。

查看注釋2處的connectToService方法:

frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java#PackageHandler

注釋2處如果綁定DefaultContainerService成功,mBound會置為ture 。注釋1處的bindServiceAsUser方法會傳入mDefContainerConn,bindServiceAsUser方法的處理邏輯和我們調用bindService是類似的,服務建立連接後,會調用onServiceConnected方法:

frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java

注釋1處發送了MCS_BOUND類型的消息,與方法的注釋3處不同的是,這裡發送消息帶了Object類型的參數,這裡會對這兩種情況來進行講解,一種是消息不帶Object類型的參數,一種是消息帶Object類型的參數。

1.2 對MCS_BOUND類型的消息的處理

消息不帶Object類型的參數

查看對MCS_BOUND類型消息的處理:

frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java

如果消息不帶Object類型的參數,就無法滿足注釋1處的條件,注釋2處的IMediaContainerService類型的mContainerService也無法被賦值,這樣就滿足了注釋3處的條件。

如果滿足注釋4處的條件,說明還沒有綁定服務,而此前已經在方法的注釋2處調用綁定服務的方法了,這顯然是不正常的,因此在注釋5處負責處理服務發生錯誤的情況。如果不滿足注釋4處的條件,說明已經綁定服務了,就會列印出系統log,告知用戶等待系統綁定服務。

消息帶Object類型的參數

frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java

如果MCS_BOUND類型消息帶Object類型的參數就不會滿足注釋1處的條件,就會調用注釋2處的判斷,如果安裝請求數不大於0就會列印出注釋6處的log,說明安裝請求隊列是空的。安裝完一個APK後,就會在注釋5處發出MSC_BOUND消息,繼續處理剩下的安裝請求直到安裝請求隊列為空。

注釋3處得到安裝請求隊列第一個請求HandlerParams ,如果HandlerParams 不為null就會調用注釋4處的HandlerParams的startCopy方法,用於開始複製APK的流程。

2.複製APK

先來查看複製APK的時序圖。

HandlerParams是PMS中的抽象類,它的實現類為PMS的內部類InstallParams。HandlerParams的startCopy方法如下所示。

frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java#HandlerParams

注釋1處的mRetries用於記錄startCopy方法調用的次數,調用startCopy方法時會先自動加1,如果次數大於4次就放棄這個安裝請求:在注釋2處發送MCS_GIVE_UP類型消息,將第一個安裝請求(本次安裝請求)從安裝請求隊列mPendingInstalls中移除掉。注釋4處用於處理複製APK後的安裝APK邏輯,第3小節中會再次提到它。注釋3處調用了抽象方法handleStartCopy,它的實現在InstallParams中,如下所示。

frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java#InstallParams

handleStartCopy方法的代碼很多,這裡截取關鍵的部分。

注釋1處通過IMediaContainerService跨進程調用DefaultContainerService的getMinimalPackageInfo方法,該方法輕量解析APK並得到APK的少量信息,輕量解析的原因是這裡不需要得到APK的全部信息,APK的少量信息會封裝到PackageInfoLite中。接著在注釋2處確定APK的安裝位置。注釋3處創建了InstallArgs,InstallArgs 是一個抽象類,定義了APK的安裝邏輯,比如複製和重命名APK等,它有3個子類,都被定義在PMS中,如下圖所示。

其中FileInstallArgs用於處理安裝到非ASEC的存儲空間的APK,也就是內部存儲空間(Data分區),AsecInstallArgs用於處理安裝到ASEC中(mnt/asec)即SD卡中的APK。MoveInstallArgs用於處理已安裝APK的移動的邏輯。

對APK進行檢查後就會在注釋4處調用InstallArgs的copyApk方法進行安裝。

不同的InstallArgs子類會有著不同的處理,這裡以FileInstallArgs為例。FileInstallArgs的copyApk方法中會直接return FileInstallArgs的doCopyApk方法:

frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java#FileInstallArgs

注釋1處用於創建臨時存儲目錄,比如/data/app/vmdl18300388.tmp,其中18300388是安裝的sessionId。注釋2處通過IMediaContainerService跨進程調用DefaultContainerService的copyPackage方法,這個方法會在DefaultContainerService所在的進程中將APK複製到臨時存儲目錄,比如/data/app/vmdl18300388.tmp/base.apk。目前為止APK的複製工作就完成了,接著就是APK的安裝過程了。

3.總結

本文主要講解了PMS是如何處理APK安裝的,主要有兩個步驟:

PackageInstaller安裝APK時會將APK的信息交由PMS處理,PMS通過向PackageHandler發送消息來驅動APK的複製和安裝工作。

PMS發送INIT_COPY和MCS_BOUND類型的消息,控制PackageHandler來綁定DefaultContainerService,完成複製APK等工作。


喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 劉望舒 的精彩文章:

手動實現Android熱修復

TAG:劉望舒 |