在 APK安裝概述 中曾提及apk有四種安裝場景,但無論是哪壹種方式,最終會提交給 PackageManagerService 處理,只是前置的處理鏈路 不同,所以本篇先對 PMS 這壹主要過程進行分析。 frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java 基於Android 9.0
1、對特定的壹些系統進程信息進行設置處理,並保存到 Settings 中
2、解析 /etc/permissions 下相關xml文件取得系統相關權限、系統具備的相關功能等信息
3、解析 /data/system/package.xml 文件獲取已安裝應用的相關信息
4、對相關的 apk 和 jar 進行 dex 優化處理,主要是 /system/framework 目錄下的相關jar和apk
5、依據 sharedUserId 這個配置來確定 apk 運行在哪個進程,然後把運行的相關進程信息加入到 Settings 中,使得系統可以知道每個 apk 運行在哪個進程中
6、解析 AndroidManifest.xml 文件,提煉文件中的節點信息
7、掃描本地文件,主要針對系統應用、本地安裝應用等等
8、管理本地 apk ,包括安裝、刪除等
前面說到 APK 的信息會提交給 PMS 進行安裝的壹系列工作,具體是通過 PackageHandler 發送消息來驅動 APK 的復制和安裝,其時序圖如下:
上相過程中有幾點需要說明:
1、在 installStage 方法中創建了 InstallParams 對象,它對應於包的安裝數據,並創建 INIT_COPY 消息並發送給 PackageHandler 進行處理;
2、 PackageHandler 在處理 INIT_COPY 消息時,會先判斷是否綁定了 DefaultContainerService ,這是用於檢查和賦值可移動文件的服務,比較耗時,所以和 PMS 並沒有運行在同壹個進程中,它們之間通過 IMediaContainerService 進行 IPC 通信,沒有綁定則會進行綁定,之後
DefaultContainerConnection 同樣是定義在 PMS 中,執行鏈路如下:
3、發送 MCS_BOUND 消息時,根據發送的 Message 是否帶 Object 分為兩種,如下所示:
4、 MCS_BOUND 消息的處理:
HandlerParams 是 PMS 中的抽象類,它的實現類為 PMS 的內部類 InstallParams 。 HandlerParams 的 startCopy 方法如下所示:
PackageManagerService.java#HandlerParams
在 註釋① 處調用抽象方法 handleStartCopy ,具體實現在 InstallParams 中,如下所示:
PackageManagerService.java#InstallParams
1、 註釋① 處確定了 APK 的安裝位置。
2、 註釋② 處創建 InstallArgs 對象,此對象是壹個抽象類,定義了 APK 的復制和重命名APK等安裝邏輯,在 Android 8.x 及之前的版本中有三個子類: FileInstallArgs、AsecInstallArgs、MoveInstallArgs 。其中 FileInstallArgs 用於處理安裝到非ASEC的存儲空間的APK,即內部存儲空間(Data分區); AsecInstallArgs 用於處理安裝到ASEC(mnt/asec)即SD卡中的APK; MoveInstallArgs 用於處理已安裝APK的移動的邏輯;但在 Android 9.x 之後已經去掉了 AsecInstallArgs ,
3、 註釋③ 處調用 InstallArgs 的 copyApk 方法,這裏以 FileInstallArgs 的實現為例,內部會調用 FileInstallArgs 的 doCopyApk 方法:
1、 註釋① 處用於創建臨時存儲目錄,比如 /data/app/vmdl18300388.tmp ,其中 18300388 是安裝的 sessionId ;
2、 註釋② 處通過 IMediaContainerService 跨進程調用 DefaultContainerService 的 copyPackage 方法,這個方法會在 DefaultContainerService 所在的進程中將 APK 復制到臨時存儲目錄,比如 /data/app/vmdl18300388.tmp/base.apk ,至此 APK 的復制工作結束。
在上述 APK 的賦值調用鏈的過程中,在 HandlerParams 的 startCopy 方法中,會調用 handleReturnCode 方法,時序圖如下:
PackageManagerService#handleReturnCode :
註釋① 處檢查APK的狀態,在安裝前確保安裝環境的可靠,如果不可靠會清除復制的APK文件, 註釋③ 處會檢測是否安裝成功,失敗則刪除安裝相關的目錄和文件。安裝完成之後在 註釋⑤ 處會發送 POST_INSALL 消息通知已安裝完成,此處稍後會說明。
註釋② 處的 installPackageTracedLI 會調用 PMS 的 installPackageLI 方法:
PackageManagerService.java#installPackageLI :
這裏需要說明幾點:
1、 註釋③ 處,會先檢測 Settings 中保存有要安裝的 APK 信息,則說明安裝該 APK ,因此需要檢驗APK 的簽名信息,確保安全的進行替換。
2、 註釋④ 處,會對臨時文件重新命名,例如 /data/app/vmdl18300388.tmp/base.apk ,重命名為 /data/app/包名-oONlnRRPYyleU63AveqbYA==/base.apk 。新的包名後面帶上的壹串字母和數字的混合字符串,是使用MD5的方式對隨機生成的16個字符進行加密之後的產物。
3、 註釋⑤ 處,根據 replace 來做區分,如果是替換安裝就會調用replacePackageLIF方法,其方法內部還會對系統APP和非系統APP進行區分處理,如果是新安裝APK會調用installNewPackageLIF方法
PackageManagerService.java#installNewPackageLIF :
在上面 processPendingInstall 方法的源碼分析中,在 註釋⑤ 處會發送 POST_INSTALL 消息通知安裝完成,那麽接下來就來具體看壹看在 PackageHandler 中是怎麽處理這個消息的。
以上為主要的方法摘要,具體可總結為:
1、第壹步:這裏主要是先將安裝信息從安裝列列表中移除,這個也是前面在processPendingInstall中添加的
2、第二步:安裝成功後,獲取運行時權限
3、第三步:獲取權限後,發送ACTION_PACKAGE_ADDED廣播,告訴Laucher之流,更新icon
4、第四步:如果是升級更新則在發送兩條廣播
5、第五步:如果安裝包中設置了PRIVATE_FLAG_FORWARD_LOCK或者被要求安裝在SD卡上,則調用sendResourcesChangedBroadcast方法來發送壹個資源更改的廣播
6、第六步:如果該應用是壹個瀏覽器,則要清除瀏覽器設置,重新檢查瀏覽器設置
7、第七步:強制調用gc,出發JVM進行垃圾回收操作
8、第八步:刪除舊的安裝信息
9、回調回調 IPackageInstallObserver2 的 packageInstalled 方法。告訴 PackageInstaller 安裝結果。從而實現了安裝回調到UI層
上述幾部分大致說明 PMS 處理 APK 的主要步驟,可總結如下:
1、當 PackageInstaller 將 APK 的信息提交給 PMS 處理, PMS 會通過向 PackageHandler 發送消息來驅動 APK 的復制和安裝工作
2、 PMS 發送 INIT_COPY 和 MCS_BOUND 類型的消息,控制 PackageHandler 來綁定 DefaultContainerService 來完成 APK 的復制等工作
3、復制 APK 完成之後,則開始進行安裝 APK 的流程,包括安裝前的檢查、安裝 APK 和安裝後的收尾工作。
[ 1 ] /framework/pms/3-pms-install.html
[ 4 ] /article/5119749905/
[ 5 ] /p/9ddb930153b7