1 引言
在前文Android xapk安装(二)中,我们提到,使用adb install-multiply
安装xapk
包时,最终会调用PackageManagerService#installStage
方法完成最终的应用安装,本文继续分析installStage
方法的执行过程。
2 PackageManagerService#installStage
installStage
方法的核心代码如下:
void installStage(ActiveInstallSession activeInstallSession) {
//...省略无关代码
final Message msg = mHandler.obtainMessage(INIT_COPY);
final InstallParams params = new InstallParams(activeInstallSession);
params.setTraceMethod("installStage").setTraceCookie(System.identityHashCode(params));
msg.obj = params;
//...省略无关代码
mHandler.sendMessage(msg);
}
可看到,在该方法中,先获取一个核心逻辑就是向PackageManagerService
的PackageHandler
发送一个INIT_COPY
类型的Message
,该Message
的obj
就是安装应用的安装参数InstallParams
,下面看PackageHandler
中对INIT_COPY
Message
的相关处理逻辑:
void doHandleMessage(Message msg) {
switch (msg.what) {
case INIT_COPY: {
HandlerParams params = (HandlerParams) msg.obj;
if (params != null) {
params.startCopy();
}
break;
}
//其他逻辑
从代码中可以看到,对于INIT_COPY
类型的Message
,处理逻辑就是调用HandlerParams#startCopy
方法,下面分析该方法的逻辑
2.1 HandlerParams#startCopy
HandlerParamsParams
是PackageManagerService
的一个内部类,startCopy
方法的逻辑如下:
final void startCopy() {
if (DEBUG_INSTALL) Slog.i(TAG, "startCopy " + mUser + ": " + this);
handleStartCopy();
handleReturnCode();
}
abstract void handleStartCopy();
abstract void handleReturnCode();
在startCopy
方法中,实际调用的是HandleStartCopy
和HandleReturnCode
这两个抽象方法,而方法的具体实现交给其子类,在此处,实际上调用的就是InstallParams
类的对应实现,下面分别看这两个方法
2.1.1 InstallParams#handleStartCopy
handleStartCopy
方法较长,我们分步骤来分析。
/data/app
目录 //是否将程序安装到内部存储,即/data/app目录,一般是true
final boolean onInt = (installFlags & PackageManager.INSTALL_INTERNAL) != 0;
//是否安装到临时存储区,一般是false
final boolean ephemeral = (installFlags & PackageManager.INSTALL_INSTANT_APP) != 0;
PackageInfoLite pkgLite = null;
PackageInfoLite pkgLite = null;
//获取PackageInfoLite对象
pkgLite = PackageManagerServiceUtils.getMinimalPackageInfo(mContext,
origin.resolvedPath, installFlags, packageAbiOverride);
PackageInfoLite
对象和PackageLite
对象类似,也是存放了一些安装包的关键信息,比如packageName
,versionCode
,installLocation
等信息
//计算/data目录存储空间是否足够
final StorageManager storage = StorageManager.from(mContext);
final long lowThreshold = storage.getStorageLowBytes(
Environment.getDataDirectory());
final long sizeBytes = PackageManagerServiceUtils.calculateInstalledSize(
origin.resolvedPath, packageAbiOverride);
if (sizeBytes >= 0) {
try {
mInstaller.freeCache(null, sizeBytes + lowThreshold, 0, 0);
pkgLite = PackageManagerServiceUtils.getMinimalPackageInfo(mContext,
origin.resolvedPath, installFlags, packageAbiOverride);
} catch (InstallerException e) {
Slog.w(TAG, "Failed to free cache", e);
}
}
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 if (loc == PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE) {
ret = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
} else if (loc == PackageHelper.RECOMMEND_FAILED_INVALID_APK) {
ret = PackageManager.INSTALL_FAILED_INVALID_APK;
} else if (loc == PackageHelper.RECOMMEND_FAILED_INVALID_URI) {
ret = PackageManager.INSTALL_FAILED_INVALID_URI;
} else if (loc == PackageHelper.RECOMMEND_MEDIA_UNAVAILABLE) {
ret = PackageManager.INSTALL_FAILED_MEDIA_UNAVAILABLE;
} else {
// Override with defaults if needed.
loc = installLocationPolicy(pkgLite);
if (loc == PackageHelper.RECOMMEND_FAILED_VERSION_DOWNGRADE) {
ret = PackageManager.INSTALL_FAILED_VERSION_DOWNGRADE;
} else if (loc == PackageHelper.RECOMMEND_FAILED_WRONG_INSTALLED_VERSION) {
ret = PackageManager.INSTALL_FAILED_WRONG_INSTALLED_VERSION;
} else if (!onInt) {
// Override install location with flags
if (loc == PackageHelper.RECOMMEND_INSTALL_EXTERNAL) {
// Set the flag to install on external media.
installFlags &= ~PackageManager.INSTALL_INTERNAL;
} else if (loc == PackageHelper.RECOMMEND_INSTALL_EPHEMERAL) {
if (DEBUG_INSTANT) {
Slog.v(TAG, "...setting INSTALL_EPHEMERAL install flag");
}
installFlags |= PackageManager.INSTALL_INSTANT_APP;
installFlags &= ~PackageManager.INSTALL_INTERNAL;
} else {
installFlags |= PackageManager.INSTALL_INTERNAL;
}
}
}
}
InstallArgs
对象并保存final InstallArgs args = createInstallArgs(this);
mVerificationCompleted = true;
mEnableRollbackCompleted = true;
mArgs = args;
生成的InstallArgs
对象一般是FileInstallArgs
子类
mPendingVerification
中添加待验证信息
if (ret == PackageManager.INSTALL_SUCCEEDED) {
// TODO: http://b/22976637
// Apps installed for "all" users use the device owner to verify the app
UserHandle verifierUser = getUser();
if (verifierUser == UserHandle.ALL) {
verifierUser = UserHandle.SYSTEM;
}
final int requiredUid = mRequiredVerifierPackage == null ? -1
: getPackageUid(mRequiredVerifierPackage, MATCH_DEBUG_TRIAGED_MISSING,
verifierUser.getIdentifier());
final int optionalUid = mOptionalVerifierPackage == null ? -1
: getPackageUid(mOptionalVerifierPackage, MATCH_DEBUG_TRIAGED_MISSING,
verifierUser.getIdentifier());
final int installerUid = verificationInfo == null ? -1 : verificationInfo.installerUid;
if (!origin.existing && (requiredUid != -1 || optionalUid != -1)
&& isVerificationEnabled(
verifierUser.getIdentifier(), installFlags, installerUid)) {
final Intent verification = new Intent(Intent.ACTION_PACKAGE_NEEDS_VERIFICATION);
verification.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
verification.setDataAndType(Uri.fromFile(new File(origin.resolvedPath)),PACKAGE_MIME_TYPE);
verification.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
// Query all live verifiers based on current user state
final List receivers = queryIntentReceiversInternal(verification,
PACKAGE_MIME_TYPE, 0, verifierUser.getIdentifier(),
false /*allowDynamicSplits*/);
final int verificationId = mPendingVerificationToken++;
verification.putExtra(PackageManager.EXTRA_VERIFICATION_ID, verificationId);
verification.putExtra(PackageManager.EXTRA_VERIFICATION_INSTALLER_PACKAGE,installerPackageName);
verification.putExtra(PackageManager.EXTRA_VERIFICATION_INSTALL_FLAGS,installFlags);
verification.putExtra(PackageManager.EXTRA_VERIFICATION_PACKAGE_NAME, pkgLite.packageName);
verification.putExtra(PackageManager.EXTRA_VERIFICATION_VERSION_CODE,pkgLite.versionCode);
verification.putExtra(PackageManager.EXTRA_VERIFICATION_LONG_VERSION_CODE,
pkgLite.getLongVersionCode());
if (verificationInfo != null) {
if (verificationInfo.originatingUri != null) {
verification.putExtra(Intent.EXTRA_ORIGINATING_URI,verificationInfo.originatingUri);
}
if (verificationInfo.referrer != null) {
verification.putExtra(Intent.EXTRA_REFERRER,
verificationInfo.referrer);
}
if (verificationInfo.originatingUid >= 0) {
verification.putExtra(Intent.EXTRA_ORIGINATING_UID,verificationInfo.originatingUid);
}
if (verificationInfo.installerUid >= 0) {
verification.putExtra(PackageManager.EXTRA_VERIFICATION_INSTALLER_UID,
verificationInfo.installerUid);
}
}
final PackageVerificationState verificationState = new PackageVerificationState(
requiredUid, this);
mPendingVerification.append(verificationId, verificationState);
当Android
系统安装一个应用程序时,它会进行安全验证以确保应用程序来源可靠。验证过程可能包括验证应用程序的数字签名和权限等。而mPendingVerification
变量则用于存储等待进行验证的应用程序的信息。
当PackageManagerService
收到验证请求时,它将相应的应用程序添加到mPendingVerification
中。然后,PackageManagerService
将根据验证器的配置来处理待验证的应用程序,以确保它们的签名和权限是合法的。一旦应用程序的验证通过,PackageManagerService
将继续进行应用程序的安装或其他处理。
mPendingVerification
变量的主要作用是在应用程序验证期间保留待处理的应用程序的信息,以便能够适时进行验证并完成后续的操作。这有助于保证系统安全性和应用程序的合法性.
final List sufficientVerifiers = matchVerifiers(pkgLite,
receivers, verificationState);
DeviceIdleController.LocalService idleController = getDeviceIdleController();
final long idleDuration = getVerificationTimeout();
/*
* If any sufficient verifiers were listed in the package
* manifest, attempt to ask them.
* 应用程序包的验证器,用于对应用程序包进行验证的数字证书机构,使用这些验证器对应用包进行验证,可能为null
* 向这些验证器发送广播
*/
if (sufficientVerifiers != null) {
final int N = sufficientVerifiers.size();
if (N == 0) {
ret = PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE;
} else {
for (int i = 0; i < N; i++) {
final ComponentName verifierComponent = sufficientVerifiers.get(i);
idleController.addPowerSaveTempWhitelistApp(Process.myUid(),
verifierComponent.getPackageName(), idleDuration,
verifierUser.getIdentifier(), false, "package verifier");
final Intent sufficientIntent = new Intent(verification);
sufficientIntent.setComponent(verifierComponent);
mContext.sendBroadcastAsUser(sufficientIntent, verifierUser);
}
}
}
//系统可选的应用程序包验证器包名
if (mOptionalVerifierPackage != null) {
optionalIntent.setAction("com.qualcomm.qti.intent.action.PACKAGE_NEEDS_OPTIONAL_VERIFICATION");
final List optional_receivers = queryIntentReceiversInternal(optionalIntent,
PACKAGE_MIME_TYPE, 0, verifierUser.getIdentifier(), false /*allowDynamicSplits*/);
final ComponentName optionalVerifierComponent = matchComponentForVerifier(
mOptionalVerifierPackage, optional_receivers);
optionalIntent.setComponent(optionalVerifierComponent);
verificationState.addOptionalVerifier(optionalUid);
if (mRequiredVerifierPackage != null) {
mContext.sendBroadcastAsUser(optionalIntent, verifierUser, android.Manifest.permission.PACKAGE_VERIFICATION_AGENT);
} else {
mContext.sendOrderedBroadcastAsUser(optionalIntent, verifierUser, android.Manifest.permission.PACKAGE_VERIFICATION_AGENT,
new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
final Message msg = mHandler.obtainMessage(CHECK_PENDING_VERIFICATION);
msg.arg1 = verificationId;
mHandler.sendMessageDelayed(msg, getVerificationTimeout());
}
}, null, 0, null, null);
mVerificationCompleted = false;
}
}
if (ret == PackageManager.INSTALL_SUCCEEDED && mRequiredVerifierPackage != null) {
final ComponentName requiredVerifierComponent = matchComponentForVerifier(mRequiredVerifierPackage, receivers);
verification.setComponent(requiredVerifierComponent);
idleController.addPowerSaveTempWhitelistApp(Process.myUid(),mRequiredVerifierPackage, idleDuration,verifierUser.getIdentifier(), false, "package verifier");
mContext.sendOrderedBroadcastAsUser(verification, verifierUser, android.Manifest.permission.PACKAGE_VERIFICATION_AGENT,
new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
final Message msg = mHandler.obtainMessage(CHECK_PENDING_VERIFICATION);
msg.arg1 = verificationId;
mHandler.sendMessageDelayed(msg, getVerificationTimeout());
}
}, null, 0, null, null);
mVerificationCompleted = false;
}
在构造完验证数据后,会向验证器发送验证数据来验证安装包,然后向系统预置的可选验证器发送验证广播,然后在验证超时时间过后向PackageHandler
发送一个CHECK_PENDING_VERIFICATION
的Message
,最后,还会向一些Component
发送验证广播等待这些Component
的验证结果,并在验证超时时间之后,向PackageHandler
发送一个CHECK_PENDING_VERIFICATION
的Message
。在上面的这些验证器中,一般只会进入requiredVerifierComponent
的逻辑中,但是不管进入哪个逻辑,最后都会发送一个CHECK_PENDING_VERIFICATION
的消息,该消息的处理我们放在下文分析
if ((installFlags & PackageManager.INSTALL_ENABLE_ROLLBACK) != 0) {
// TODO(ruhler) b/112431924: Don't do this in case of 'move'?
Slog.i(TAG, "enter enable rollback");
final int enableRollbackToken = mPendingEnableRollbackToken++;
Trace.asyncTraceBegin(
TRACE_TAG_PACKAGE_MANAGER, "enable_rollback", enableRollbackToken);
mPendingEnableRollback.append(enableRollbackToken, this);
final int[] installedUsers;
synchronized (mPackages) {
PackageSetting ps = mSettings.getPackageLPr(pkgLite.packageName);
if (ps != null) {
installedUsers = ps.queryInstalledUsers(sUserManager.getUserIds(),
true);
} else {
installedUsers = new int[0];
}
}
Intent enableRollbackIntent = new Intent(Intent.ACTION_PACKAGE_ENABLE_ROLLBACK);
enableRollbackIntent.putExtra(
PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_TOKEN,
enableRollbackToken);
enableRollbackIntent.putExtra(
PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_INSTALL_FLAGS,
installFlags);
enableRollbackIntent.putExtra(
PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_INSTALLED_USERS,
installedUsers);
enableRollbackIntent.putExtra(
PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_USER,
getRollbackUser().getIdentifier());
enableRollbackIntent.setDataAndType(Uri.fromFile(new File(origin.resolvedPath)),
PACKAGE_MIME_TYPE);
enableRollbackIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
// Allow the broadcast to be sent before boot complete.
// This is needed when committing the apk part of a staged
// session in early boot. The rollback manager registers
// its receiver early enough during the boot process that
// it will not miss the broadcast.
enableRollbackIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
Slog.i(TAG, "enableRollbackIntent="+enableRollbackIntent.toString());
mContext.sendOrderedBroadcastAsUser(enableRollbackIntent, UserHandle.SYSTEM,
android.Manifest.permission.PACKAGE_ROLLBACK_AGENT,
new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
// the duration to wait for rollback to be enabled, in millis
long rollbackTimeout = DeviceConfig.getLong(
DeviceConfig.NAMESPACE_ROLLBACK,
PROPERTY_ENABLE_ROLLBACK_TIMEOUT_MILLIS,
DEFAULT_ENABLE_ROLLBACK_TIMEOUT_MILLIS);
if (rollbackTimeout < 0) {
rollbackTimeout = DEFAULT_ENABLE_ROLLBACK_TIMEOUT_MILLIS;
}
final Message msg = mHandler.obtainMessage(
ENABLE_ROLLBACK_TIMEOUT);
msg.arg1 = enableRollbackToken;
mHandler.sendMessageDelayed(msg, rollbackTimeout);
}
}, null, 0, null, null);
mEnableRollbackCompleted = false;
}
同样,回滚广播会在回滚超时时间之后向PackageHandler
发送一个 ENABLE_ROLLBACK_TIMEOUT
类型的广播,一般情况下不会进入到该部分逻辑。
至此,HandleStartCopy
方法就分析完成了,从代码中我们知道,该方法主要的就是确认应用安装位置,对安装包进行数字验证,然后向PackageHandler
发送一个CHECK_PENDING_VERIFICATION
和ENABLE_ROLLBACK_TIMEOUT
类型的消息,下面先看CHECK_PENDING_VERIFICATION
消息的处理
case CHECK_PENDING_VERIFICATION: {
final int verificationId = msg.arg1;
final PackageVerificationState state = mPendingVerification.get(verificationId);
if ((state != null) && !state.timeoutExtended()) {
final InstallParams params = state.getInstallParams();
final InstallArgs args = params.mArgs;
final Uri originUri = Uri.fromFile(args.origin.resolvedFile);
Slog.i(TAG, "Verification timed out for " + originUri);
mPendingVerification.remove(verificationId);
final UserHandle user = args.getUser();
//如果允许该用户安装,就继续安装,发送相应的广播
if (getDefaultVerificationResponse(user)
== PackageManager.VERIFICATION_ALLOW) {
Slog.i(TAG, "Continuing with installation of " + originUri);
state.setVerifierResponse(Binder.getCallingUid(),
PackageManager.VERIFICATION_ALLOW_WITHOUT_SUFFICIENT);
broadcastPackageVerified(verificationId, originUri,
PackageManager.VERIFICATION_ALLOW, user);
//不允许安装,发送拒绝安装广播
} else {
broadcastPackageVerified(verificationId, originUri,
PackageManager.VERIFICATION_REJECT, user);
params.setReturnCode(
PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE);
}
Trace.asyncTraceEnd(
TRACE_TAG_PACKAGE_MANAGER, "verification", verificationId);
//验证安装包结束
params.handleVerificationFinished();
}
break;
}
从代码逻辑看,会发送对应的广播,然后调用InstallParams
的handleVerificationFinished
,广播的处理逻辑此处略去,下面看看handleVerificationFinished
方法的处理逻辑
void handleVerificationFinished() {
mVerificationCompleted = true;
handleReturnCode();
}
在该方法中,会将mVerificationCompleted
变量设为true,然后调用handleReturnCode
方法。
基于类似的逻辑,ENABLE_ROLLBACK_TIMEOUT
消息会调用InstallParams
的handleRollbackEnabled
方法,在该方法中,会将 mEnableRollbackCompleted
设为true,然后调用handleReturnCode
方法。下面我们看InstallParams
的handleReturnCode
方法
2.1.2 InstallParams#handleReturnCode
handleReturnCode
方法的源码如下
@Override
void handleReturnCode() {
if (mVerificationCompleted && mEnableRollbackCompleted) {
//1.判断是否为模拟运行,模拟运行不会安装,一般用来测试安装的正确性,正常安装不会进入该逻辑
if ((installFlags & PackageManager.INSTALL_DRY_RUN) != 0) {
String packageName = "";
try {
PackageLite packageInfo = new PackageParser().parsePackageLite(origin.file, 0);
packageName = packageInfo.packageName;
} catch (PackageParserException e) {
Slog.e(TAG, "Can't parse package at " + origin.file.getAbsolutePath(), e);
}
try {
observer.onPackageInstalled(packageName, mRet, "Dry run", new Bundle());
} catch (RemoteException e) {
Slog.i(TAG, "Observer no longer exists.");
}
return;
}
if (mRet == PackageManager.INSTALL_SUCCEEDED) {
//2. 调用InstallArgs的copyApk方法复制apk包
mRet = mArgs.copyApk();
}
//3.准备安装工作,完成apk安装
processPendingInstall(mArgs, mRet);
}
}
在该代码中,主要做的是三件事:
在上面三个步骤中,第一步一般不用考虑,所以主要是第2步和第3步,下面分别介绍这两个方法
2.2 InstallArgs#copyApk
InstallArgs
是PackageManagerService
内部类,该类是一个抽象类,实际使用的一般是FileInstallArgs
子类,其copyApk
代码如下
int copyApk() {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "copyApk");
try {
return doCopyApk();
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
}
在该方法中,实际是调用了docopyApk
完成实际操作
private int doCopyApk() {
//是否已经staged处理,本文此处为true
if (origin.staged) {
if (DEBUG_INSTALL) Slog.d(TAG, origin.file + " already staged; skipping copy");
return PackageManager.INSTALL_SUCCEEDED;
}
try {
//是否是即时应用
final boolean isEphemeral = (installFlags & PackageManager.INSTALL_INSTANT_APP) != 0;
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 = PackageManagerServiceUtils.copyPackage(origin.file.getAbsolutePath(), codeFile);
if (ret != PackageManager.INSTALL_SUCCEEDED) {
Slog.e(TAG, "Failed to copy package");
return ret;
}
final File libraryRoot = new File(codeFile, LIB_DIR_NAME);
NativeLibraryHelper.Handle handle = null;
try {
handle = NativeLibraryHelper.Handle.create(codeFile);
ret = NativeLibraryHelper.copyNativeBinariesWithOverride(handle, libraryRoot,abiOverride);
} catch (IOException e) {
Slog.e(TAG, "Copying native libraries failed", e);
ret = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
} finally {
IoUtils.closeQuietly(handle);
}
return ret;
}
在该方法中,会先判断源文件是否为staged,该标识位用于标识apk是否已经在内存中准备好,无需再复制。在install-multiple
命令中,最终会调用installStage
方法完成调用,在该方法中,构造InstallParams
对象时,会将其OriginInfo
的staged
属性标记为true
, 这样就无需再复制一次apk
。
若origin.staged
为fasle,则进一步判断是否为即时应用,即时应用一般是用来测试安装的,系统不会将其真正安装,一般为false.
若安装的apk的origin.staged
为false,也不是即时应用,系统就会调用PackageManagerServiceUtils
的copyPackage
方法copy apk包,并解析复制apk的so库到lib目录。
在完成apk复制后,hanldeReturenCode
下一步会调用processPendingInstall
方法完成apk安装
2.3 processPendingInstall
对processPendingInstall
方法的分析,参考了博客:# Android 10.0 PackageManagerService(四)APK安装流程-[Android取经之路]。
processPendingInstall
方法完成最后的apk安装操作:
private void processPendingInstall(final InstallArgs args, final int currentStatus) {
if (args.mMultiPackageInstallParams != null) {
args.mMultiPackageInstallParams.tryProcessInstallRequest(args, currentStatus);
} else {
PackageInstalledInfo res = createPackageInstalledInfo(currentStatus);
processInstallRequestsAsync(
res.returnCode == PackageManager.INSTALL_SUCCEEDED,
Collections.singletonList(new InstallRequest(args, res)));
}
}
在该方法中,首先会调用createPackageInstalledInfo
方创建一个PackageInstalledInfo
对象:
private PackageInstalledInfo createPackageInstalledInfo(
int currentStatus) {
PackageInstalledInfo res = new PackageInstalledInfo();
res.setReturnCode(currentStatus);
res.uid = -1;
res.pkg = null;
res.removedInfo = null;
return res;
}
在该方法中,创建一个PackageInstalledInfo
对象,将returnCode
设置为PackageManager.INSTALL_SUCCEEDED
或其他错误相关的错误码,然后将其他属性初始化。
创建好PackageInstalledInfo
对象后,下一步调用processInstallRequestsAsync
方法完成操作:
// Queue up an async operation since the package installation may take a little while.
private void processInstallRequestsAsync(boolean success,
List installRequests) {
mHandler.post(() -> {
if (success) {
for (InstallRequest request : installRequests) {
//1.清理之前安装失败的数据
request.args.doPreInstall(request.installResult.returnCode);
}
synchronized (mInstallLock) {
//2.安装核心方法
installPackagesTracedLI(installRequests);
}
for (InstallRequest request : installRequests) {
//3.若安装失败,清理掉数据
request.args.doPostInstall(
request.installResult.returnCode, request.installResult.uid);
}
}
for (InstallRequest request : installRequests) {
restoreAndPostInstall(request.args.user.getIdentifier(), request.installResult,
new PostInstallData(request.args, request.installResult, null));
}
});
}
在该方法中,会向mHandler
post一个异步任务。如果returnCode
为PackageManager.INSTALL_SUCCEEDED
,则遍历每一个InstallRequest
对象,调用其request.args.doPreInstall
方法,然后调用installPackagesTracedLI
方法,之后遍历每一个InstallRequest
对象,调用其request.args.doPostInstall
方法。在最后,会遍历每一个InstallRequest
对象,调用restoreAndPostInstall
方法。下面我们逐一分析这些方法
首先我们看看InstallRequest
的结构:
private static class InstallRequest {
public final InstallArgs args;
public final PackageInstalledInfo installResult;
private InstallRequest(InstallArgs args, PackageInstalledInfo res) {
this.args = args;
this.installResult = res;
}
}
可以看到,InstallRequest
就是对InstallArgs
和PackageInstalledInfo
的一个组合封装。所以request.args.doPreInstall
方法实际上就是InstallArgs
的doPreInstall
方法,最后实际会调用FileInstallArgs
的doPreInstall
方法:
int doPreInstall(int status) {
if (status != PackageManager.INSTALL_SUCCEEDED) {
cleanUp();
}
return status;
}
在该方法中,若status不是PackageManager.INSTALL_SUCCEEDED
,则调用cleanUp
方法清理掉安装包。
因为request.args.doPostInstall
实际上也是调用的FileInstallArgs
的doPostInstall
方法,下面先看看该方法:
int doPostInstall(int status, int uid) {
if (status != PackageManager.INSTALL_SUCCEEDED) {
cleanUp();
}
return status;
}
可以看到,在FileInstallArgs
中,doPreInstall
和doPostInstall
的逻辑是一样的。
在分析完FileInstallArgs
中的两个方法后,下面我们继续看installPackagesTracedLI
方法和restoreAndPostInstall
方法。
2.3.1 installPackagesTracedLI
installPackagesTracedLI
方法源码如下:
@GuardedBy({"mInstallLock", "mPackages"})
private void installPackagesTracedLI(List requests) {
try {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installPackages");
installPackagesLI(requests);
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
}
可以看到,该方法实际上是调用了installPackagesLI
方法。该方法是安装apk的一个关键方法:
@GuardedBy("mInstallLock")
private void installPackagesLI(List requests) {
final Map preparedScans = new ArrayMap(requests.size());
final Map installArgs = new ArrayMap(requests.size());
final Map installResults = new ArrayMap(requests.size());
final Map prepareResults = new ArrayMap(requests.size());
final Map versionInfos = new ArrayMap(requests.size());
final Map lastStaticSharedLibSettings =
new ArrayMap(requests.size());
final Map createdAppId = new ArrayMap(requests.size());
boolean success = false;
try {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installPackagesLI");
for (InstallRequest request : requests) {
// TODO(b/109941548): remove this once we've pulled everything from it and into
// scan, reconcile or commit.
final PrepareResult prepareResult;
try {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "preparePackage");
//1. 准备安装包,对安装状态进行分析(是新安装还是替换已有的安装包),做一些初始化操作
prepareResult = preparePackageLI(request.args, request.installResult);
} catch (PrepareFailure prepareFailure) {
request.installResult.setError(prepareFailure.error,
prepareFailure.getMessage());
request.installResult.origPackage = prepareFailure.conflictingPackage;
request.installResult.origPermission = prepareFailure.conflictingPermission;
return;
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
request.installResult.setReturnCode(PackageManager.INSTALL_SUCCEEDED);
request.installResult.installerPackageName = request.args.installerPackageName;
final String packageName = prepareResult.packageToScan.packageName;
prepareResults.put(packageName, prepareResult);
installResults.put(packageName, request.installResult);
installArgs.put(packageName, request.args);
try {
//2. 扫描安装包
final List scanResults = scanPackageTracedLI(
prepareResult.packageToScan, prepareResult.parseFlags,
prepareResult.scanFlags, System.currentTimeMillis(),
request.args.user);
for (ScanResult result : scanResults) {
if (null != preparedScans.put(result.pkgSetting.pkg.packageName, result)) {
request.installResult.setError(
PackageManager.INSTALL_FAILED_DUPLICATE_PACKAGE,
"Duplicate package " + result.pkgSetting.pkg.packageName
+ " in multi-package install request.");
return;
}
createdAppId.put(packageName, optimisticallyRegisterAppId(result));
versionInfos.put(result.pkgSetting.pkg.packageName,
getSettingsVersionForPackage(result.pkgSetting.pkg));
if (result.staticSharedLibraryInfo != null) {
final PackageSetting sharedLibLatestVersionSetting =
getSharedLibLatestVersionSetting(result);
if (sharedLibLatestVersionSetting != null) {
lastStaticSharedLibSettings.put(result.pkgSetting.pkg.packageName,
sharedLibLatestVersionSetting);
}
}
}
} catch (PackageManagerException e) {
request.installResult.setError("Scanning Failed.", e);
return;
}
}
//3 验证扫描的包,确保安装成功
ReconcileRequest reconcileRequest = new ReconcileRequest(preparedScans, installArgs,
installResults,
prepareResults,
mSharedLibraries,
Collections.unmodifiableMap(mPackages), versionInfos,
lastStaticSharedLibSettings);
CommitRequest commitRequest = null;
synchronized (mPackages) {
Map reconciledPackages;
try {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "reconcilePackages");
reconciledPackages = reconcilePackagesLocked(
reconcileRequest, mSettings.mKeySetManagerService);
} catch (ReconcileFailure e) {
for (InstallRequest request : requests) {
request.installResult.setError("Reconciliation failed...", e);
}
return;
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
try {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "commitPackages");
commitRequest = new CommitRequest(reconciledPackages,
sUserManager.getUserIds());
//4. 提交所有扫描的包并更新系统状态,是安装过程中唯一可以修改系统状态的地方
commitPackagesLocked(commitRequest);
success = true;
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
}
//5 apk成功安装后,完成剩下的工作
executePostCommitSteps(commitRequest);
}
...
从代码中可以看到,installPackagesTracedLI
主要有5个步骤,也对应着5个关键方法,下面逐一分析这5个方法
2.3.1.1 preparePackageLI
preparePackageLI
方法用于对安装包做一些检查和初始化准备工作,该方法较长,下面我们分段分析
@GuardedBy("mInstallLock")
private PrepareResult preparePackageLI(InstallArgs args, PackageInstalledInfo res)
throws PrepareFailure {
final int installFlags = args.installFlags;
final String installerPackageName = args.installerPackageName;
final String volumeUuid = args.volumeUuid;
final File tmpPackageFile = new File(args.getCodePath());
final boolean onExternal = args.volumeUuid != null;
final boolean instantApp = ((installFlags & PackageManager.INSTALL_INSTANT_APP) != 0);
final boolean fullApp = ((installFlags & PackageManager.INSTALL_FULL_APP) != 0);
final boolean virtualPreload =
((installFlags & PackageManager.INSTALL_VIRTUAL_PRELOAD) != 0);
@ScanFlags int scanFlags = SCAN_NEW_INSTALL | SCAN_UPDATE_SIGNATURE;
if (args.move != null) {
// moving a complete application; perform an initial scan on the new install location
scanFlags |= SCAN_INITIAL;
}
if ((installFlags & PackageManager.INSTALL_DONT_KILL_APP) != 0) {
scanFlags |= SCAN_DONT_KILL_APP;
}
//即时app,类似微信小程序,无需安装
if (instantApp) {
scanFlags |= SCAN_AS_INSTANT_APP;
}
//一般为ture
if (fullApp) {
scanFlags |= SCAN_AS_FULL_APP;
}
if (virtualPreload) {
scanFlags |= SCAN_AS_VIRTUAL_PRELOAD;
}
if (DEBUG_INSTALL) Slog.d(TAG, "installPackageLI: path=" + tmpPackageFile);
Slog.d(TAG, "installPackageLI: path=" + tmpPackageFile);
// Sanity check
if (instantApp && onExternal) {
Slog.i(TAG, "Incompatible ephemeral install; external=" + onExternal);
throw new PrepareFailure(PackageManager.INSTALL_FAILED_INSTANT_APP_INVALID);
}
@ParseFlags final int parseFlags = mDefParseFlags | PackageParser.PARSE_CHATTY
| PackageParser.PARSE_ENFORCE_CODE
| (onExternal ? PackageParser.PARSE_EXTERNAL_STORAGE : 0);
PackageParser pp = new PackageParser();
pp.setSeparateProcesses(mSeparateProcesses);
pp.setDisplayMetrics(mMetrics);
pp.setCallback(mPackageParserCallback);
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parsePackage");
final PackageParser.Package pkg;
try {
//和parsePackageLite类似,也会调用parseClusterPackage解析Package
pkg = pp.parsePackage(tmpPackageFile, parseFlags);
DexMetadataHelper.validatePackageDexMetadata(pkg);
} catch (PackageParserException e) {
throw new PrepareFailure("Failed parse during installPackageLI", e);
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
3.若app是即时app,其targetSdkVersion
需要大于0:
// Instant apps have several additional install-time checks.
//即时app,类似微信小程序,无需安装,其targetSdkVersion不能小于0
if (instantApp) {
if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.O) {
Slog.w(TAG,
"Instant app package " + pkg.packageName + " does not target at least O");
throw new PrepareFailure(INSTALL_FAILED_INSTANT_APP_INVALID,
"Instant app package must target at least O");
}
if (pkg.mSharedUserId != null) {
Slog.w(TAG, "Instant app package " + pkg.packageName
+ " may not declare sharedUserId.");
throw new PrepareFailure(INSTALL_FAILED_INSTANT_APP_INVALID,
"Instant app package may not declare a sharedUserId");
}
}
//静态库处理
if (pkg.applicationInfo.isStaticSharedLibrary()) {
// Static shared libraries have synthetic package names
Slog.i(TAG,"isStaticSharedLibrary");
renameStaticSharedLibraryPackage(pkg);
// No static shared libs on external storage
if (onExternal) {
Slog.i(TAG, "Static shared libs can only be installed on internal storage.");
throw new PrepareFailure(INSTALL_FAILED_INVALID_INSTALL_LOCATION,
"Packages declaring static-shared libs cannot be updated");
}
}
// If we are installing a clustered package add results for the children
if (pkg.childPackages != null) {
synchronized (mPackages) {
final int childCount = pkg.childPackages.size();
for (int i = 0; i < childCount; i++) {
PackageParser.Package childPkg = pkg.childPackages.get(i);
PackageInstalledInfo childRes = new PackageInstalledInfo();
childRes.setReturnCode(PackageManager.INSTALL_SUCCEEDED);
childRes.pkg = childPkg;
childRes.name = childPkg.packageName;
PackageSetting childPs = mSettings.getPackageLPr(childPkg.packageName);
if (childPs != null) {
childRes.origUsers = childPs.queryInstalledUsers(
sUserManager.getUserIds(), true);
}
if ((mPackages.containsKey(childPkg.packageName))) {
childRes.removedInfo = new PackageRemovedInfo(this);
childRes.removedInfo.removedPackage = childPkg.packageName;
childRes.removedInfo.installerPackageName = childPs.installerPackageName;
}
if (res.addedChildPackages == null) {
res.addedChildPackages = new ArrayMap();
}
res.addedChildPackages.put(childPkg.packageName, childRes);
}
}
}
// If package doesn't declare API override, mark that we have an install
// time CPU ABI override.
if (TextUtils.isEmpty(pkg.cpuAbiOverride)) {
pkg.cpuAbiOverride = args.abiOverride;
}
PackageManager.INSTALL_ALLOW_TEST
if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_TEST_ONLY) != 0) {
if ((installFlags & PackageManager.INSTALL_ALLOW_TEST) == 0) {
throw new PrepareFailure(INSTALL_FAILED_TEST_ONLY, "installPackageLI");
}
}
try {
// either use what we've been given or parse directly from the APK
if (args.signingDetails != PackageParser.SigningDetails.UNKNOWN) {
pkg.setSigningDetails(args.signingDetails);
} else {
PackageParser.collectCertificates(pkg, false /* skipVerify */);
}
} catch (PackageParserException e) {
throw new PrepareFailure("Failed collect during installPackageLI", e);
}
if (instantApp && pkg.mSigningDetails.signatureSchemeVersion
< SignatureSchemeVersion.SIGNING_BLOCK_V2) {
Slog.w(TAG, "Instant app package " + pkg.packageName
+ " is not signed with at least APK Signature Scheme v2");
throw new PrepareFailure(INSTALL_FAILED_INSTANT_APP_INVALID,
"Instant app package must be signed with APK Signature Scheme v2 or greater");
}
synchronized (mPackages) {
// Check if installing already existing package
if ((installFlags & PackageManager.INSTALL_REPLACE_EXISTING) != 0) {
Slog.i(TAG,"package is existing");
String oldName = mSettings.getRenamedPackageLPr(pkgName);
if (pkg.mOriginalPackages != null
&& pkg.mOriginalPackages.contains(oldName)
&& mPackages.containsKey(oldName)) {
// This package is derived from an original package,
// and this device has been updating from that original
// name. We must continue using the original name, so
// rename the new package here.
pkg.setPackageName(oldName);
pkgName = pkg.packageName;
replace = true;
if (DEBUG_INSTALL) {
Slog.d(TAG, "Replacing existing renamed package: oldName="
+ oldName + " pkgName=" + pkgName);
}
//系统应用中已经存在该包,需要将系统中包替换掉,常见的如使用自己下载的google play替换系统安装的google play
} else if (mPackages.containsKey(pkgName)) {
// This package, under its official name, already exists
// on the device; we should replace it.
replace = true;
if (DEBUG_INSTALL) Slog.d(TAG, "Replace existing pacakge: " + pkgName);
acquireUxPerfLock(BoostFramework.UXE_EVENT_PKG_INSTALL, pkgName, 1);
BoostFramework mPerf = new BoostFramework();
if (mPerf != null) {
mPerf.perfHint(BoostFramework.VENDOR_HINT_APP_UPDATE, pkgName, -1, 0);
}
}
// Child packages are installed through the parent package
//子安装包必须由父包更新,不能单独更新
if (pkg.parentPackage != null) {
throw new PrepareFailure(
PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME,
"Package " + pkg.packageName + " is child of package "
+ pkg.parentPackage.parentPackage + ". Child packages "
+ "can be updated only through the parent package.");
}
//如果是替换已经存在的包,则需要对旧包和新包做一些校验,看看是否允许替换
if (replace) {
// Prevent apps opting out from runtime permissions
PackageParser.Package oldPackage = mPackages.get(pkgName);
final int oldTargetSdk = oldPackage.applicationInfo.targetSdkVersion;
final int newTargetSdk = pkg.applicationInfo.targetSdkVersion;
if (oldTargetSdk > Build.VERSION_CODES.LOLLIPOP_MR1
&& newTargetSdk