PMS安裝APP流程解析
PMS(PackageManagerService)是Android包管理機制的核心,負責對包進行管理。
PMS安裝APP流程
- 獲取APK文件:在應(yīng)用程序安裝之前,需要先獲取APK文件。APK文件是Android應(yīng)用程序的安裝包,包含了應(yīng)用程序的代碼和資源文件。
- 解析APK文件:PMS需要對APK文件進行解析,以獲取應(yīng)用程序的信息和組件信息,例如應(yīng)用程序包名、版本號、權(quán)限列表、組件列表(如Activity、Service、Receiver等)。這一步通常由PackageParser類完成。
- 校驗應(yīng)用程序簽名:在安裝之前,PMS會校驗應(yīng)用程序的簽名,以確保應(yīng)用程序沒有被篡改或偽裝。簽名校驗是保證應(yīng)用程序安全性的重要步驟。
- 安裝應(yīng)用:如果校驗通過,PMS會為應(yīng)用程序分配一個UID,并繼續(xù)進行安裝過程。這通常涉及文件復制、處理安裝參數(shù)等步驟。
文件復制
PackageManagerService.java#installStage安裝階段:
- 創(chuàng)建了一個InstallParams對象
- 創(chuàng)建并發(fā)送了一個INIT_COPY的Message消息。
- InstallParams繼承自HandlerParams,用來記錄安裝應(yīng)用的參數(shù)。
InstallParams中有一個成員變量mArgs,是一個抽象類型InstallArgs,主要是用來執(zhí)行APK的復制,真正的實現(xiàn)類包括FileInstallArgs用來完成非ASEC應(yīng)用的安裝,ASEC全稱是Android Secure External Cache,MoveInstallArgs用來完成已安裝應(yīng)用的移動安裝。
void installStage(String packageName, File stagedDir, String stagedCid,
IPackageInstallObserver2 observer, PackageInstaller.SessionParams sessionParams,
String installerPackageName, int installerUid, UserHandle user,
Certificate[][] certificates) {
...
final Message msg = mHandler.obtainMessage(INIT_COPY);
final int installReason = fixUpInstallReason(installerPackageName, installerUid,
sessionParams.installReason);
final InstallParams params = new InstallParams(origin, null, observer,
sessionParams.installFlags, installerPackageName, sessionParams.volumeUuid,
verificationInfo, user, sessionParams.abiOverride,
sessionParams.grantedRuntimePermissions, certificates, installReason);
params.setTraceMethod("installStage").setTraceCookie(System.identityHashCode(params));
msg.obj = params;
...
//發(fā)送信息拷貝INIT_COPY 信息
mHandler.sendMessage(msg);
}
PackageManagerService.java#PackageHandler包處理:connectToService()用于檢查和復制可移動文件的服務(wù)發(fā)送MCS_BOUND信息,觸發(fā)處理第一個安裝請求。
void doHandleMessage(Message msg) {
switch (msg.what) {
case INIT_COPY:
HandlerParams params = (HandlerParams) msg.obj;
int idx = mPendingInstalls.size();
if (DEBUG_INSTALL) Slog.i(TAG, "init_copy idx=" + idx + ": " + params);
//mBound用于標識是否綁定了服務(wù),默認值為false
if (!mBound) {
Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "bindingMCS", System.identityHashCode(mHandler));
//connectToService里面的DefaultContainerService是用于檢查和復制可移動文件的服務(wù)
if (!connectToService()) {
Slog.e(TAG, "Failed to bind to media container service");
params.serviceError();
Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "bindingMCS", System.identityHashCode(mHandler));
if (params.traceMethod != null) {
Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, params.traceMethod, params.traceCookie);
}
//綁定服務(wù)失敗則return
return;
} else {
//綁定服務(wù)成功,將請求添加到ArrayList類型的mPendingInstalls中,等待處理
mPendingInstalls.add(idx, params);
}
} else {
//已經(jīng)綁定服務(wù)
mPendingInstalls.add(idx, params);
if (idx == 0) { //5
//發(fā)送MCS_BOUND類型的消息,觸發(fā)處理第一個安裝請求
mHandler.sendEmptyMessage(MCS_BOUND);
}
}
break;
....
}
}
MCS_BOUND 流程處理:
case MCS_BOUND:
if (mContainerService == null) { //判斷是否已經(jīng)綁定了服務(wù)
if (!mBound) { //綁定服務(wù)的標識位,沒有綁定成功
Slog.e(TAG, "Cannot bind to media container service");
for (HandlerParams params : mPendingInstalls) {
params.serviceError();
Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "queueInstall", System.identityHashCode(params));
if (params.traceMethod != null) {
Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, params.traceMethod, params.traceCookie);
}
return;
}
//綁定失敗,清空安裝請求隊列
mPendingInstalls.clear();
} else { // 綁定成功
//繼續(xù)等待綁定服務(wù)
Slog.w(TAG, "Waiting to connect to media container service");
}
} else if (mPendingInstalls.size() > 0) { //安裝APK的隊列
HandlerParams params = mPendingInstalls.get(0); //安裝隊列有參數(shù)
if (params != null) {
Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "queueInstall", System.identityHashCode(params));
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "startCopy");
if (params.startCopy()) { //HandlerParams開始拷貝
if (DEBUG_SD_INSTALL) Log.i(TAG, "Checking for more work or unbind...");
//如果APK安裝成功,刪除本次安裝請求
if (mPendingInstalls.size() > 0) {
mPendingInstalls.remove(0);
}
if (mPendingInstalls.size() == 0) { //安裝隊列沒有參數(shù)
if (mBound) { //已經(jīng)綁定服務(wù),需要發(fā)送一個解綁MCS_UNBIND的message
//如果沒有安裝請求了,發(fā)送解綁服務(wù)的請求
if (DEBUG_SD_INSTALL) Log.i(TAG, "Posting delayed MCS_UNBIND");
removeMessages(MCS_UNBIND);
Message ubmsg = obtainMessage(MCS_UNBIND);
sendMessageDelayed(ubmsg, 10000);
}
} else {
if (DEBUG_SD_INSTALL) Log.i(TAG, "Posting MCS_BOUND for next work");
//如果還有其他的安裝請求,接著發(fā)送MCS_BOUND消息繼續(xù)處理剩余的安裝請求
mHandler.sendEmptyMessage(MCS_BOUND);
}
}
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}else {
Slog.w(TAG, "Empty queue");
}
break;
DefaultContainerService: 真正處理復制APP文件的類
PackageManagerService.java#HandlerParams#startCopy開始復制:
- 嘗試安裝次數(shù)是否超過4次,超過就移除安裝的列表數(shù)據(jù)
- handleStartCopy : //復制APK文件
- handleReturnCode : //開始安裝APK
final boolean startCopy() {
boolean res;
try {
if (DEBUG_INSTALL) Slog.i(TAG, "startCopy " + mUser + ": " + this);
//startCopy方法嘗試的次數(shù),超過了4次,就放棄這個安裝請求
if (++mRetries > MAX_RETRIES) {
Slog.w(TAG, "Failed to invoke remote methods on default container service. Giving up");
mHandler.sendEmptyMessage(MCS_GIVE_UP); //發(fā)送放棄安裝信息
handleServiceError();
return false;
} else {
handleStartCopy(); //復制APK文件
res = true;
}
} catch (RemoteException e) {
if (DEBUG_INSTALL) Slog.i(TAG, "Posting install MCS_RECONNECT");
mHandler.sendEmptyMessage(MCS_RECONNECT);
res = false;
}
handleReturnCode(); //處理復制APK后的安裝APK邏輯
return res;
}
}
PackageManagerService.java#InstallParams#handleStartCopy復制apk文件:
- 獲取APP的部分安裝信息
- 獲取APP的安裝位置
- InstallArgs復制APP----> FileInstallArgs復制APP---->DefaultContainerService復制APP
InstallArgs做為抽象類,F(xiàn)ileInstallArgs和MoveInstallArgs繼承InstallArgs FileInstallArgs對data/data/包名(系統(tǒng)應(yīng)用),MoveInstallArgs用于處理已安裝APK的移動:
public void handleStartCopy() throws RemoteException {
...
//確定APK的安裝位置。onSd:安裝到SD卡, onInt:內(nèi)部存儲即Data分區(qū),ephemeral:安裝到臨時存儲(Instant Apps安裝)
final boolean onSd = (installFlags & PackageManager.INSTALL_EXTERNAL) != 0;
final boolean onInt = (installFlags & PackageManager.INSTALL_INTERNAL) != 0;
final boolean ephemeral = (installFlags & PackageManager.INSTALL_INSTANT_APP) != 0;
PackageInfoLite pkgLite = null;
if (onInt && onSd) {
// APK不能同時安裝在SD卡和Data分區(qū)
Slog.w(TAG, "Conflicting flags specified for installing on both internal and external");
ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
//安裝標志沖突,Instant Apps不能安裝到SD卡中
} else if (onSd && ephemeral) {
Slog.w(TAG, "Conflicting flags specified for installing ephemeral on external");
ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
} else {
//獲取APK的少量的信息
pkgLite = mContainerService.getMinimalPackageInfo(origin.resolvedPath, installFlags, packageAbiOverride);
if (DEBUG_EPHEMERAL && ephemeral) {
Slog.v(TAG, "pkgLite for install: " + pkgLite);
}
...
if (ret == PackageManager.INSTALL_SUCCEEDED) {
//判斷安裝的位置
int loc = pkgLite.recommendedInstallLocation;
if (loc == PackageHelper.RECOMMEND_FAILED_INVALID_LOCATION) {
ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
} else if (loc == PackageHelper.RECOMMEND_FAILED_ALREADY_EXISTS) {
ret = PackageManager.INSTALL_FAILED_ALREADY_EXISTS;
}
...
}else {
loc = installLocationPolicy(pkgLite); //確定APP安裝的位置
...
}
}
//根據(jù)InstallParams創(chuàng)建InstallArgs對象
final InstallArgs args = createInstallArgs(this); InstallArgs作用時:復制和重命名APK
mArgs = args;
if (ret == PackageManager.INSTALL_SUCCEEDED) {
...
if (!origin.existing && requiredUid != -1 && isVerificationEnabled(verifierUser.getIdentifier(), installFlags, installerUid)) {
...
} else{
ret = args.copyApk(mContainerService, true); // InstallArgs開始復制APP
}
}
mRet = ret;
}
private int doCopyApk(IMediaContainerService imcs, boolean temp) throws RemoteException {
...
try {
final boolean isEphemeral = (installFlags & PackageManager.INSTALL_INSTANT_APP) != 0;
//創(chuàng)建臨時文件存儲目錄
final File tempDir = mInstallerService.allocateStageDirLegacy(volumeUuid, isEphemeral);
codeFile = tempDir;
resourceFile = tempDir;
} catch (IOException e) {
Slog.w(TAG, "Failed to create copy file: " + e);
return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
}
...
int ret = PackageManager.INSTALL_SUCCEEDED;
ret = imcs.copyPackage(origin.file.getAbsolutePath(), target);
...
return ret;
}
安裝APK
- 在安裝前檢查是否環(huán)境的可靠,如果不可靠會清除復制的APK文件。
- installPackageTracedLI其內(nèi)部會調(diào)用PMS的installPackageLI方法,進行APP安裝。
- 處理安裝后操作,如果安裝不成功,刪除掉安裝相關(guān)的目錄與文件。
final boolean startCopy() {
......
handleStartCopy(); //APP文件復制拷貝
.....
//開始安裝APP
handleReturnCode();
}
void handleReturnCode() {
........
if (mArgs != null) {
processPendingInstall(mArgs, mRet);
}
}
private void processPendingInstall(final InstallArgs args, final int currentStatus) {
mHandler.post(new Runnable() {
public void run() {
mHandler.removeCallbacks(this);
PackageInstalledInfo res = new PackageInstalledInfo();
res.setReturnCode(currentStatus);
res.uid = -1;
res.pkg = null;
res.removedInfo = null;
if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
//安裝前處理
args.doPreInstall(res.returnCode);
synchronized (mInstallLock) {
//開始安裝
installPackageTracedLI(args, res);
}
//安裝后收尾
args.doPostInstall(res.returnCode, res.uid);
}
...
}
});
}