Android M PackageManager對於應用程序apk的安裝流程分析

上篇文章我們分析了android M PackageManagerService 啓動過程,今天我們繼續深入瞭解下對於apk的安裝,PackageManager又是怎樣做的呢?

應用程序安裝有很多種方法,開發者最常見的就是使用adb install命令或者pm install腳本命令。

很多的應用市場也都有自己的封裝,android原生的安裝應用爲PackageInsteller。


本篇涉及源碼路徑:

system/core/adb/ commandline.cpp
frameworks/base/cmds/pm/src/com/android/commands/pm/Pm.java
frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
frameworks/base/services/core/java/com/android/server/pm/PackageInstallerService.java
frameworks/base/packages/DefaultContainerService/
frameworks/base/core/java/android/content/pm/PackageParser.java

adb install原理

我們先看adb install原理


adb install命令來源於/android/system/core/adb工具,從上面的代碼看到,adb install實際執行的是install_app()。



Install_app會根據存儲路徑將apk文件copy到/data/local/temp或者sd卡中的路徑,後面進行apk複製時會從這個路徑裏面取。

這裏我們可以看到adb命令最終調用的是pm腳本來進行apk的安裝。

PM腳本

pm是android中的一個腳本,由pm.java編譯生成,最終被放到system/bin下的,其代碼路徑爲:

frameworks/base/cmds/pm


pm腳本的main方法中創建一個Pm對象,然後調用其run方法跑起來。

run方法中獲取到package包管理器的binder客戶端本地代理Proxy,就可以和IPackageManager服務端通信了。

 

這裏還通過binder通信獲取到之前在PKMS構造函數最後完成時創建的PackageInstallerService服務,後面安裝時會用到它。

接着,解析arg參數,匹配到install時,會執行runInstall。

這裏先創建了一個LocalPackageInstallObserver,這個obs將用於接收PKMS返回的安裝消息。

最終,我們通過installPackageAsUser調用到了PKMS中。

怎麼過去的?


this指的是mRemote, mRemote即是package的服務端PKMS。

installPackageAsUser方法

前面講到PM腳本通過binder將安裝命令發送到了PKMS中,接下來看PKMS是怎樣進行apk安裝的。

說明:

  • 檢查是否具有安裝權限,或者是否用戶禁止安裝等;
  • 封裝一個INIT_COPY的消息,並且創建InstallParams對象,然後把消息通過handler發送出去;

根據PKMS啓動過程,我們知道,之前創建了PackageHandler,且其消息處理線程已經運行起來,很確定,INIT_COPY就是在PackageHandler的handleMessage中處理的。

PackageHandler的handleMessage方法直接調用的是doHandleMessage,根據msg類型匹配到INIT_COPY分支。

Apk的安裝需要依賴一個apk提供的服務來支持,這個服務就是DefaultContainerService,即源碼中的DefaultCotainerService.apk。

第一次安裝的時候,由於服務還未啓動,需要bindService來啓動該服務,如果已經啓動,則將安裝信息通過MCS_BOUND觸發。

關於DefaultContainerService怎麼啓動就不說了哈,我們直接看對MCS_BOUND消息的處理。


在MCS_BOUND中,調用了startCopy方法。

startCopy方法中會緊接着調用handleStartCopy,這個方法是個抽象方法,具體的實現由子類完成,之前我們創建的handleParams爲InstallParams,所以這裏會調用到InstallParams的handleStartCopy方法中,如果安裝完成,則調用handleReturnCode,返回處理結果。

handleStartCopy

 


說明:

  • DCS的getMinimalPackageInfo方法會去解析apk文件,得到一個PackageLite對象,該對象是一個輕量級(相對於pkg)的用於描述APK的結構,這裏面會取到recommendedInstallLocation,表示apk推薦的安裝路徑。
  • 計算apk的大小,檢查存儲空間是否足夠;
  • installLocationPolicy檢查檢查推薦的安裝路徑,例如系統apk不允許安裝在SD卡上;
  • createInstallArgs將根據不同的安裝位置創建不同的InstallArgs,如果是內部存儲則返回FileInstallArgs,外部則是AsecInstallArgs(SD卡),其中還有負責移動的MoveInstallArgs;
  • 最後調用args的copyApk開始進行apk的拷貝;

copyApk

通過前面的分析,我們已經得到apk適合的安裝位置,接下來就由copyApk來完成apk的複製工作。

說明:

  • 首先會通過installService的方法allocateStageDirLegacy在/data/app下創建臨時文件,臨時文件名爲 臨時文件名爲vmdl-隨機數.tmp;
  • 調用DCS的copyFile執行復制操作,最終將/data/local/temp下的apk文件複製到/data/app/下,文件名爲base.apk, 然後修改相關文件的讀寫權限等。
  • 調用copyNativeBinariesWithOverride對lib庫進行復制;
DefContainer:Copying /data/app/com.iflytek.inputmethod.gionee-1/base.apk to base.apk

至此,handleStartCopy就完成了,apk拷貝完了,其實apk並沒有完全解析並且歸檔到PKMS的數據結構中,因此,接下來我們還要對apk文件解析歸檔。

handleReturnCode

由於最初創建的handleParams爲InstallParams,所以handleReturnCode也是installParams的子類方法。

該方法中mArgs爲FileInstallArgs,所以會直接調用processPendingInstall進行接下來的處理。

 

說明:

  • 在mHandler中拋一個Runnable對象,如果之前handleStartCopy中沒有出現問題,則返回碼應該是INSTALL_SUCCEEDED,就會調用doPreInstall對安裝路徑進行清理,如果是success,則什麼都不做;
  • 調用installPackageLI進行掃描安裝,即我們之前的scanPackageLI ==> parsePackage==> parseBaseApk ==> parseBaseApplication…
  • 最後會調用doRename對文件進行命名;
  • 調用doPostInstall進行安裝文件的處理。
  • 如果允許backup則通過BackupManager對其進行備份處理;
  • 向handr拋一個POST_INSTALL消息;

進入POST_INSTALL消息處理環節:

說明:

  • 依次發送PACKAGE_ADDED,ACTION_PACKAGE_REPLACED廣播;
  • 強制執行依次GC進行資源回收;
  • 調用FileInstallArgs的doPostDeleteLI進行資源清理;
  • 調用onPackageInstalled向PM通知安裝的結果(obs);

之前的obs在調用完install請求後,進入wait狀態等待PKMS的返回,在onPackageInstalled方法中notifyAll將其喚醒輸出安裝結果。


安裝返回值結果

常見的APK安裝結果(返回值)通常有以下幾種。

返回值

說明

解決方式

INSTALL_SUCCEEDED

安裝成功

-

INSTALL_FAILED_ALREADY_EXISTS

apk已經安裝過

加-r參數

INSTALL_FAILED_INVALID_APK

apk安裝包無效

確認apk文件是否有效

INSTALL_FAILED_INVALID_URI

uri無效,路徑不對..

確認apk的絕對路徑

INSTALL_FAILED_INSUFFICIENT_STORAGE

空間不足,中間文件vmdl無法創建

清除空間

INSTALL_FAILED_DUPLICATE_PACKAGE

主要檢查版本號

 

INSTALL_FAILED_NO_SHARED_USER

請求的SharedUserId不存在

 

INSTALL_FAILED_UPDATE_INCOMPATIBLE

與之前安裝的簽名不對

將之前的app刪除後再安裝

INSTALL_FAILED_SHARED_USER_INCOMPATIBLE

與sharedUserId的簽名不匹配

 

INSTALL_FAILED_MISSING_SHARED_LIBRARY

使用的共享庫不存在

 確認所使用的共享庫系統是否已支持。

INSTALL_FAILED_OLDER_SDK

INSTALL_FAILED_NEWER_SDK

Sdk版本不匹配<uses-sdk>

 請使用正確的targetsdk

INSTALL_FAILED_CONFLICTING_PROVIDER

provider衝突

確認manifest中使用的provider

INSTALL_FAILED_TEST_ONLY

android:testOnly="true"

Android studio中請使用build生成apk安裝,或者adb install –t參數

INSTALL_FAILED_VERSION_DOWNGRADE

VersionCode低了

 

………………

 

 

安裝流程小結 

此,apk的安裝流程就基本上完成了,下面的流程圖可以完整展現該過程。


後續將會繼續分析權限管理部分,歡迎關注。


發佈了36 篇原創文章 · 獲贊 22 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章