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对象
PackageInfoLite pkgLite = null;
//获取PackageInfoLite对象
pkgLite = PackageManagerServiceUtils.getMinimalPackageInfo(mContext,
origin.resolvedPath, installFlags, packageAbiOverride);
PackageInfoLite对象和PackageLite对象类似,也是存放了一些安装包的关键信息,比如packageName,versionCode,installLocation等信息
- 计算/data目录是否有足够的空间安装应用
//计算/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);
}
}
- 确定安装位置,一般就是安装到/data/app目录
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<ResolveInfo> 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<ComponentName> 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<ResolveInfo> 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);
}
}
在该代码中,主要做的是三件事:
- 判断是否为模拟运行,模拟运行不会安装,一般用来测试安装的正确性,正常安装不会进入该逻辑
- 调用InstallArgs的copyApk方法复制apk包
- 准备安装工作,完成apk安装
在上面三个步骤中,第一步一般不用考虑,所以主要是第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<InstallRequest> 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<InstallRequest> 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<InstallRequest> requests) {
final Map<String, ScanResult> preparedScans = new ArrayMap<>(requests.size());
final Map<String, InstallArgs> installArgs = new ArrayMap<>(requests.size());
final Map<String, PackageInstalledInfo> installResults = new ArrayMap<>(requests.size());
final Map<String, PrepareResult> prepareResults = new ArrayMap<>(requests.size());
final Map<String, VersionInfo> versionInfos = new ArrayMap<>(requests.size());
final Map<String, PackageSetting> lastStaticSharedLibSettings =
new ArrayMap<>(requests.size());
final Map<String, Boolean> 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<ScanResult> 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<String, ReconciledPackage> 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方法用于对安装包做一些检查和初始化准备工作,该方法较长,下面我们分段分析
- 构造scanFlags
@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);
}
- 解析安装包信息和校验dex
@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");
}
}
- 若有静态共享库,则将包名修改为“包名_pkg.staticSharedLibVersion“的形式
//静态库处理
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);
}
}
}
- 检查apk的cpuabi信息,如arm64-v8a
// 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 <= Build.VERSION_CODES.LOLLIPOP_MR1) {
throw new PrepareFailure(
PackageManager.INSTALL_FAILED_PERMISSION_MODEL_DOWNGRADE,
"Package " + pkg.packageName + " new target SDK " + newTargetSdk
+ " doesn't support runtime permissions but the old"
+ " target SDK " + oldTargetSdk + " does.");
}
// Prevent persistent apps from being updated
if (((oldPackage.applicationInfo.flags & ApplicationInfo.FLAG_PERSISTENT) != 0)
&& ((installFlags & PackageManager.INSTALL_STAGED) == 0)) {
throw new PrepareFailure(PackageManager.INSTALL_FAILED_INVALID_APK,
"Package " + oldPackage.packageName + " is a persistent app. "
+ "Persistent apps are not updateable.");
}
// Prevent installing of child packages
if (oldPackage.parentPackage != null) {
throw new PrepareFailure(
PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME,
"Package " + pkg.packageName + " is child of package "
+ oldPackage.parentPackage + ". Child packages "
+ "can be updated only through the parent package.");
}
}
}
- 若是安装包已经存在,则检查其签名
//从PackageSetting中获取package的信息,若能获取到,则说明该安装包已经存在
//PackageSetting用于描述应用程序包的设置和属性的类
PackageSetting ps = mSettings.mPackages.get(pkgName);
if (ps != null) {
if (DEBUG_INSTALL) Slog.d(TAG, "Existing package: " + ps);
Slog.d(TAG, "Existing package: " + ps);
// Static shared libs have same package with different versions where
// we internally use a synthetic package name to allow multiple versions
// of the same package, therefore we need to compare signatures against
// the package setting for the latest library version.
PackageSetting signatureCheckPs = ps;
if (pkg.applicationInfo.isStaticSharedLibrary()) {
SharedLibraryInfo libraryInfo = getLatestSharedLibraVersionLPr(pkg);
if (libraryInfo != null) {
signatureCheckPs = mSettings.getPackageLPr(libraryInfo.getPackageName());
}
}
// Quick sanity check that we're signed correctly if updating;
// we'll check this again later when scanning, but we want to
// bail early here before tripping over redefined permissions.
//快速校验签名
final KeySetManagerService ksms = mSettings.mKeySetManagerService;
if (ksms.shouldCheckUpgradeKeySetLocked(signatureCheckPs, scanFlags)) {
if (!ksms.checkUpgradeKeySetLocked(signatureCheckPs, pkg)) {
throw new PrepareFailure(INSTALL_FAILED_UPDATE_INCOMPATIBLE, "Package "
+ pkg.packageName + " upgrade keys do not match the "
+ "previously installed version");
}
} else {
try {
final boolean compareCompat = isCompatSignatureUpdateNeeded(pkg);
final boolean compareRecover = isRecoverSignatureUpdateNeeded(pkg);
// We don't care about disabledPkgSetting on install for now.
final boolean compatMatch = verifySignatures(
signatureCheckPs, null, pkg.mSigningDetails, compareCompat,
compareRecover);
// The new KeySets will be re-added later in the scanning process.
if (compatMatch) {
synchronized (mPackages) {
ksms.removeAppKeySetDataLPw(pkg.packageName);
}
}
} catch (PackageManagerException e) {
throw new PrepareFailure(e.error, e.getMessage());
}
}
if (ps.pkg != null && ps.pkg.applicationInfo != null) {
systemApp = (ps.pkg.applicationInfo.flags &
ApplicationInfo.FLAG_SYSTEM) != 0;
}
res.origUsers = ps.queryInstalledUsers(sUserManager.getUserIds(), true);
}
- 设置apk需要的权限
int N = pkg.permissions.size();
for (int i = N - 1; i >= 0; i--) {
final PackageParser.Permission perm = pkg.permissions.get(i);
final BasePermission bp =
(BasePermission) mPermissionManager.getPermissionTEMP(perm.info.name);
// Don't allow anyone but the system to define ephemeral permissions.
if ((perm.info.protectionLevel & PermissionInfo.PROTECTION_FLAG_INSTANT) != 0
&& !systemApp) {
Slog.w(TAG, "Non-System package " + pkg.packageName
+ " attempting to delcare ephemeral permission "
+ perm.info.name + "; Removing ephemeral.");
perm.info.protectionLevel &= ~PermissionInfo.PROTECTION_FLAG_INSTANT;
}
// Check whether the newly-scanned package wants to define an already-defined perm
if (bp != null) {
// If the defining package is signed with our cert, it's okay. This
// also includes the "updating the same package" case, of course.
// "updating same package" could also involve key-rotation.
final boolean sigsOk;
final String sourcePackageName = bp.getSourcePackageName();
final PackageSettingBase sourcePackageSetting = bp.getSourcePackageSetting();
final KeySetManagerService ksms = mSettings.mKeySetManagerService;
Slog.i(TAG,"sourcePackageName="+sourcePackageName);
if (sourcePackageName.equals(pkg.packageName)
&& (ksms.shouldCheckUpgradeKeySetLocked(
sourcePackageSetting, scanFlags))) {
sigsOk = ksms.checkUpgradeKeySetLocked(sourcePackageSetting, pkg);
} else {
// in the event of signing certificate rotation, we need to see if the
// package's certificate has rotated from the current one, or if it is an
// older certificate with which the current is ok with sharing permissions
if (sourcePackageSetting.signatures.mSigningDetails.checkCapability(
pkg.mSigningDetails,
PackageParser.SigningDetails.CertCapabilities.PERMISSION)) {
sigsOk = true;
} else if (pkg.mSigningDetails.checkCapability(
sourcePackageSetting.signatures.mSigningDetails,
PackageParser.SigningDetails.CertCapabilities.PERMISSION)) {
// the scanned package checks out, has signing certificate rotation
// history, and is newer; bring it over
sourcePackageSetting.signatures.mSigningDetails = pkg.mSigningDetails;
sigsOk = true;
} else {
sigsOk = false;
}
}
if (!sigsOk) {
// If the owning package is the system itself, we log but allow
// install to proceed; we fail the install on all other permission
// redefinitions.
if (!sourcePackageName.equals("android")) {
throw new PrepareFailure(INSTALL_FAILED_DUPLICATE_PERMISSION, "Package "
+ pkg.packageName
+ " attempting to redeclare permission "
+ perm.info.name + " already owned by "
+ sourcePackageName)
.conflictsWithExistingPermission(perm.info.name,
sourcePackageName);
} else {
Slog.w(TAG, "Package " + pkg.packageName
+ " attempting to redeclare system permission "
+ perm.info.name + "; ignoring new declaration");
pkg.permissions.remove(i);
}
} else if (!PLATFORM_PACKAGE_NAME.equals(pkg.packageName)) {
// Prevent apps to change protection level to dangerous from any other
// type as this would allow a privilege escalation where an app adds a
// normal/signature permission in other app's group and later redefines
// it as dangerous leading to the group auto-grant.
if ((perm.info.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE)
== PermissionInfo.PROTECTION_DANGEROUS) {
if (bp != null && !bp.isRuntime()) {
Slog.w(TAG, "Package " + pkg.packageName + " trying to change a "
+ "non-runtime permission " + perm.info.name
+ " to runtime; keeping old protection level");
perm.info.protectionLevel = bp.getProtectionLevel();
}
}
}
}
}
- 若是系统apk,不能在外部存储,且不能是即时app
if (systemApp) {
if (onExternal) {
// Abort update; system app can't be replaced with app on sdcard
throw new PrepareFailure(INSTALL_FAILED_INVALID_INSTALL_LOCATION,
"Cannot install updates to system apps on sdcard");
} else if (instantApp) {
// Abort update; system app can't be replaced with an instant app
throw new PrepareFailure(INSTALL_FAILED_INSTANT_APP_INVALID,
"Cannot update a system app with an instant app");
}
}
- 生成Abi信息
if (args.move != null) {
// We did an in-place move, so dex is ready to roll
scanFlags |= SCAN_NO_DEX;
scanFlags |= SCAN_MOVE;
synchronized (mPackages) {
final PackageSetting ps = mSettings.mPackages.get(pkgName);
if (ps == null) {
res.setError(INSTALL_FAILED_INTERNAL_ERROR,
"Missing settings for moved package " + pkgName);
}
// We moved the entire application as-is, so bring over the
// previously derived ABI information.
pkg.applicationInfo.primaryCpuAbi = ps.primaryCpuAbiString;
pkg.applicationInfo.secondaryCpuAbi = ps.secondaryCpuAbiString;
}
} else {
// Enable SCAN_NO_DEX flag to skip dexopt at a later stage
scanFlags |= SCAN_NO_DEX;
try {
String abiOverride = (TextUtils.isEmpty(pkg.cpuAbiOverride) ?
args.abiOverride : pkg.cpuAbiOverride);
final boolean extractNativeLibs = !pkg.isLibrary();
// haima mod begin
// derivePackageAbi(pkg, abiOverride, extractNativeLibs);
derivePackageAbi(pkg, abiOverride, extractNativeLibs, scanFlags);
// haima mod end
} catch (PackageManagerException pme) {
Slog.e(TAG, "Error deriving application ABI", pme);
throw new PrepareFailure(INSTALL_FAILED_INTERNAL_ERROR,
"Error deriving application ABI");
}
}
- 更改安装包的位置,一般会将安装包位置更改为“/data/app/packageName-随机字符串”
if (!args.doRename(res.returnCode, pkg)) {
throw new PrepareFailure(INSTALL_FAILED_INSUFFICIENT_STORAGE, "Failed rename");
}
FileInstallArgs的doRename方法如下:
boolean doRename(int status, PackageParser.Package pkg) {
if (status != PackageManager.INSTALL_SUCCEEDED) {
cleanUp();
return false;
}
final File targetDir = codeFile.getParentFile();
final File beforeCodeFile = codeFile;
//生成新的apk安装路径
final File afterCodeFile = getNextCodePath(targetDir, pkg.packageName);
if (DEBUG_INSTALL) Slog.d(TAG, "Renaming " + beforeCodeFile + " to " + afterCodeFile);
try {
Os.rename(beforeCodeFile.getAbsolutePath(), afterCodeFile.getAbsolutePath());
} catch (ErrnoException e) {
Slog.w(TAG, "Failed to rename", e);
return false;
}
if (!SELinux.restoreconRecursive(afterCodeFile)) {
Slog.w(TAG, "Failed to restorecon");
return false;
}
// Reflect the rename internally
codeFile = afterCodeFile;
resourceFile = afterCodeFile;
// Reflect the rename in scanned details
try {
pkg.setCodePath(afterCodeFile.getCanonicalPath());
} catch (IOException e) {
Slog.e(TAG, "Failed to get path: " + afterCodeFile, e);
return false;
}
pkg.setBaseCodePath(FileUtils.rewriteAfterRename(beforeCodeFile,
afterCodeFile, pkg.baseCodePath));
pkg.setSplitCodePaths(FileUtils.rewriteAfterRename(beforeCodeFile,
afterCodeFile, pkg.splitCodePaths));
// Reflect the rename in app info
pkg.setApplicationVolumeUuid(pkg.volumeUuid);
pkg.setApplicationInfoCodePath(pkg.codePath);
pkg.setApplicationInfoBaseCodePath(pkg.baseCodePath);
pkg.setApplicationInfoSplitCodePaths(pkg.splitCodePaths);
pkg.setApplicationInfoResourcePath(pkg.codePath);
pkg.setApplicationInfoBaseResourcePath(pkg.baseCodePath);
pkg.setApplicationInfoSplitResourcePaths(pkg.splitCodePaths);
return true;
}
在该方法中,核心代码就是调用getNextCodePath获取到新的apk路径,然后更换apk路径,该方法代码如下:
private File getNextCodePath(File targetDir, String packageName) {
File result;
SecureRandom random = new SecureRandom();
byte[] bytes = new byte[16];
do {
//获取一个随机数组
random.nextBytes(bytes);
//将该随机字节数组编码为一个字符串
String suffix = Base64.encodeToString(bytes, Base64.URL_SAFE | Base64.NO_WRAP);
//新的路径即为/data/app/packageName-suffix
result = new File(targetDir, packageName + "-" + suffix);
} while (result.exists());
return result;
}
- 为apk设置fs-verify保护
try {
setUpFsVerityIfPossible(pkg);
} catch (InstallerException | IOException | DigestException | NoSuchAlgorithmException e) {
throw new PrepareFailure(INSTALL_FAILED_INTERNAL_ERROR,
"Failed to set up verity: " + e);
}
- 发送验证Intent过滤器的消息给mHandler
if (!instantApp) {
startIntentFilterVerifications(args.user.getIdentifier(), replace, pkg);
} else {
if (DEBUG_DOMAIN_VERIFICATION) {
Slog.d(TAG, "Not verifying instant app install for app links: " + pkgName);
}
}
private void startIntentFilterVerifications(int userId, boolean replacing,PackageParser.Package pkg) {
if (mIntentFilterVerifierComponent == null) {
Slog.w(TAG, "No IntentFilter verification will not be done as "
+ "there is no IntentFilterVerifier available!");
return;
}
final int verifierUid = getPackageUid(mIntentFilterVerifierComponent.getPackageName(),
MATCH_DEBUG_TRIAGED_MISSING,
(userId == UserHandle.USER_ALL) ? UserHandle.USER_SYSTEM : userId);
Message msg = mHandler.obtainMessage(START_INTENT_FILTER_VERIFICATIONS);
msg.obj = new IFVerificationParams(pkg, replacing, userId, verifierUid);
mHandler.sendMessage(msg);
final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
for (int i = 0; i < childCount; i++) {
PackageParser.Package childPkg = pkg.childPackages.get(i);
msg = mHandler.obtainMessage(START_INTENT_FILTER_VERIFICATIONS);
msg.obj = new IFVerificationParams(childPkg, replacing, userId, verifierUid);
mHandler.sendMessage(msg);
}
}
- 冻结apk,并决定是替换已有的安装包,还是新安装
final PackageFreezer freezer =freezePackageForInstall(pkgName, installFlags, "installPackageLI");
boolean shouldCloseFreezerBeforeReturn = true;
try {
...//省略
//替换安装
if (replace) {
...//省略具体代码
} else { // new package install安装新的aok
...//省略具体代码
}
} finally {
if (shouldCloseFreezerBeforeReturn) {
freezer.close();
}
}
2.3.1.2 scanPackageTracedLI
scanPackageTracedLI中实际调用了scanPackageLI方法扫描apk,该方法的核心逻辑是,调用PackageParser的parsePackage方法生成一个Package对象,该对象中包含了apk的基本信息,如baseapk,packageName等信息,若该apk有子包,则还要扫描子包:
/**
* Traces a package scan.
* @see #scanPackageLI(File, int, int, long, UserHandle)
*/
@GuardedBy({"mInstallLock", "mPackages"})
private PackageParser.Package scanPackageTracedLI(File scanFile, final int parseFlags,
int scanFlags, long currentTime, UserHandle user) throws PackageManagerException {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanPackage [" + scanFile.toString() + "]");
try {
return scanPackageLI(scanFile, parseFlags, scanFlags, currentTime, user);
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
}
/**
* Scans a package and returns the newly parsed package.
* Returns {@code null} in case of errors and the error code is stored in mLastScanError
*/
@GuardedBy({"mInstallLock", "mPackages"})
private PackageParser.Package scanPackageLI(File scanFile, int parseFlags, int scanFlags,
long currentTime, UserHandle user) throws PackageManagerException {
if (DEBUG_INSTALL) Slog.d(TAG, "Parsing: " + scanFile);
PackageParser pp = new PackageParser();
pp.setSeparateProcesses(mSeparateProcesses);
pp.setOnlyCoreApps(mOnlyCore);
pp.setDisplayMetrics(mMetrics);
pp.setCallback(mPackageParserCallback);
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parsePackage");
final PackageParser.Package pkg;
try {
//解析为Package,其中存放了apk的信息,如主包,子包等信息
pkg = pp.parsePackage(scanFile, parseFlags);
} catch (PackageParserException e) {
throw PackageManagerException.from(e);
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
// Static shared libraries have synthetic package names
if (pkg.applicationInfo.isStaticSharedLibrary()) {
renameStaticSharedLibraryPackage(pkg);
}
//如果有子包,继续扫描子包
return scanPackageChildLI(pkg, parseFlags, scanFlags, currentTime, user);
}
/**
* Scans a package and returns the newly parsed package.
* @throws PackageManagerException on a parse error.
*/
@GuardedBy({"mInstallLock", "mPackages"})
private PackageParser.Package scanPackageChildLI(PackageParser.Package pkg,
final @ParseFlags int parseFlags, @ScanFlags int scanFlags, long currentTime,
@Nullable UserHandle user)
throws PackageManagerException {
// If the package has children and this is the first dive in the function
// we scan the package with the SCAN_CHECK_ONLY flag set to see whether all
// packages (parent and children) would be successfully scanned before the
// actual scan since scanning mutates internal state and we want to atomically
// install the package and its children.
if ((scanFlags & SCAN_CHECK_ONLY) == 0) {
if (pkg.childPackages != null && pkg.childPackages.size() > 0) {
scanFlags |= SCAN_CHECK_ONLY;
}
} else {
scanFlags &= ~SCAN_CHECK_ONLY;
}
// Scan the parent
PackageParser.Package scannedPkg = addForInitLI(pkg, parseFlags,
scanFlags, currentTime, user);
// Scan the children
final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
for (int i = 0; i < childCount; i++) {
PackageParser.Package childPackage = pkg.childPackages.get(i);
addForInitLI(childPackage, parseFlags, scanFlags,
currentTime, user);
}
if ((scanFlags & SCAN_CHECK_ONLY) != 0) {
return scanPackageChildLI(pkg, parseFlags, scanFlags, currentTime, user);
}
return scannedPkg;
}
2.3.1.3 reconcilePackagesLocked
该方法主要是对安装包再做一次检查,确保已经安装成功,该部分代码较长,且都是一些校验检查代码,考虑到篇幅太长,本文略过本部分代码
2.3.1.4 commitPackagesLocked
该方法主要是更新PackageSettings,并提交给系统本次安装
@GuardedBy({"mPackages", "mInstallLock"})
private void commitReconciledScanResultLocked(@NonNull ReconciledPackage reconciledPkg) {
final ScanResult result = reconciledPkg.scanResult;
final ScanRequest request = result.request;
final PackageParser.Package pkg = request.pkg;
final PackageParser.Package oldPkg = request.oldPkg;
final @ParseFlags int parseFlags = request.parseFlags;
final @ScanFlags int scanFlags = request.scanFlags;
final PackageSetting oldPkgSetting = request.oldPkgSetting;
final PackageSetting originalPkgSetting = request.originalPkgSetting;
final UserHandle user = request.user;
final String realPkgName = request.realPkgName;
final List<String> changedAbiCodePath = result.changedAbiCodePath;
final PackageSetting pkgSetting;
//移除掉shared user中旧的packageSettings,并更新为新的packagsetting
if (request.pkgSetting != null && request.pkgSetting.sharedUser != null
&& request.pkgSetting.sharedUser != result.pkgSetting.sharedUser) {
// shared user changed, remove from old shared user
request.pkgSetting.sharedUser.removePackage(request.pkgSetting);
}
if (result.existingSettingCopied) {
pkgSetting = request.pkgSetting;
pkgSetting.updateFrom(result.pkgSetting);
pkg.mExtras = pkgSetting;
} else {
pkgSetting = result.pkgSetting;
if (originalPkgSetting != null) {
mSettings.addRenamedPackageLPw(pkg.packageName, originalPkgSetting.name);
}
if (originalPkgSetting != null && (scanFlags & SCAN_CHECK_ONLY) == 0) {
mTransferedPackages.add(originalPkgSetting.name);
}
}
if (pkgSetting.sharedUser != null) {
pkgSetting.sharedUser.addPackage(pkgSetting);
}
// TODO(toddke): Consider a method specifically for modifying the Package object
// post scan; or, moving this stuff out of the Package object since it has nothing
// to do with the package on disk.
// We need to have this here because addUserToSettingLPw() is sometimes responsible
// for creating the application ID. If we did this earlier, we would be saving the
// correct ID.
pkg.applicationInfo.uid = pkgSetting.appId;
mSettings.writeUserRestrictionsLPw(pkgSetting, oldPkgSetting);
if ((scanFlags & SCAN_CHECK_ONLY) == 0 && realPkgName != null) {
mTransferedPackages.add(pkg.packageName);
}
//更新共享库,签名,权限,abi等信息
if (reconciledPkg.collectedSharedLibraryInfos != null) {
executeSharedLibrariesUpdateLPr(pkg, null, reconciledPkg.collectedSharedLibraryInfos);
}
final KeySetManagerService ksms = mSettings.mKeySetManagerService;
if (reconciledPkg.removeAppKeySetData) {
ksms.removeAppKeySetDataLPw(pkg.packageName);
}
if (reconciledPkg.sharedUserSignaturesChanged) {
pkgSetting.sharedUser.signaturesChanged = Boolean.TRUE;
pkgSetting.sharedUser.signatures.mSigningDetails = reconciledPkg.signingDetails;
}
pkgSetting.signatures.mSigningDetails = reconciledPkg.signingDetails;
if ((scanFlags & SCAN_CHECK_ONLY) == 0 && pkg.mAdoptPermissions != null) {
// This package wants to adopt ownership of permissions from
// another package.
for (int i = pkg.mAdoptPermissions.size() - 1; i >= 0; i--) {
final String origName = pkg.mAdoptPermissions.get(i);
final PackageSetting orig = mSettings.getPackageLPr(origName);
if (orig != null) {
if (verifyPackageUpdateLPr(orig, pkg)) {
Slog.i(TAG, "Adopting permissions from " + origName + " to "
+ pkg.packageName);
mSettings.mPermissions.transferPermissions(origName, pkg.packageName);
}
}
}
}
if (changedAbiCodePath != null && changedAbiCodePath.size() > 0) {
for (int i = changedAbiCodePath.size() - 1; i >= 0; --i) {
final String codePathString = changedAbiCodePath.get(i);
try {
mInstaller.rmdex(codePathString,
getDexCodeInstructionSet(getPreferredInstructionSet()));
} catch (InstallerException ignored) {
}
}
}
if ((scanFlags & SCAN_CHECK_ONLY) != 0) {
if (oldPkgSetting != null) {
synchronized (mPackages) {
mSettings.mPackages.put(oldPkgSetting.name, oldPkgSetting);
}
}
} else {
final int userId = user == null ? 0 : user.getIdentifier();
// Modify state for the given package setting
//提交更新后的packageSettings
commitPackageSettings(pkg, oldPkg, pkgSetting, scanFlags,
(parseFlags & PackageParser.PARSE_CHATTY) != 0 /*chatty*/, reconciledPkg);
if (pkgSetting.getInstantApp(userId)) {
mInstantAppRegistry.addInstantAppLPw(userId, pkgSetting.appId);
}
}
}
2.3.1.5 executePostCommitSteps
在完成apk安装后,该方法做一些收尾工作
/**
* On successful install, executes remaining steps after commit completes and the package lock
* is released. These are typically more expensive or require calls to installd, which often
* locks on {@link #mPackages}.
*/
private void executePostCommitSteps(CommitRequest commitRequest) {
for (ReconciledPackage reconciledPkg : commitRequest.reconciledPackages.values()) {
final boolean instantApp = ((reconciledPkg.scanResult.request.scanFlags
& PackageManagerService.SCAN_AS_INSTANT_APP) != 0);
final PackageParser.Package pkg = reconciledPkg.pkgSetting.pkg;
final String packageName = pkg.packageName;
//创建/data/data/packageName目录
prepareAppDataAfterInstallLIF(pkg);
//清理掉缓存数据
if (reconciledPkg.prepareResult.clearCodeCache) {
clearAppDataLIF(pkg, UserHandle.USER_ALL, FLAG_STORAGE_DE | FLAG_STORAGE_CE
| FLAG_STORAGE_EXTERNAL | Installer.FLAG_CLEAR_CODE_CACHE_ONLY);
}
//如果是更新包,则发送更新包通知
if (reconciledPkg.prepareResult.replace) {
mDexManager.notifyPackageUpdated(pkg.packageName,
pkg.baseCodePath, pkg.splitCodePaths);
}
// Prepare the application profiles for the new code paths.
// This needs to be done before invoking dexopt so that any install-time profile
// can be used for optimizations.
mArtManagerService.prepareAppProfiles(
pkg,
resolveUserIds(reconciledPkg.installArgs.user.getIdentifier()),
/* updateReferenceProfileContent= */ true);
// Check whether we need to dexopt the app.
//
// NOTE: it is IMPORTANT to call dexopt:
// - after doRename which will sync the package data from PackageParser.Package and
// its corresponding ApplicationInfo.
// - after installNewPackageLIF or replacePackageLIF which will update result with the
// uid of the application (pkg.applicationInfo.uid).
// This update happens in place!
//
// We only need to dexopt if the package meets ALL of the following conditions:
// 1) it is not an instant app or if it is then dexopt is enabled via gservices.
// 2) it is not debuggable.
//
// Note that we do not dexopt instant apps by default. dexopt can take some time to
// complete, so we skip this step during installation. Instead, we'll take extra time
// the first time the instant app starts. It's preferred to do it this way to provide
// continuous progress to the useur instead of mysteriously blocking somewhere in the
// middle of running an instant app. The default behaviour can be overridden
// via gservices.
final boolean performDexopt =
(!instantApp || Global.getInt(mContext.getContentResolver(),
Global.INSTANT_APP_DEXOPT_ENABLED, 0) != 0)
&& ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) == 0);
if (performDexopt) {
// Compile the layout resources.
if (SystemProperties.getBoolean(PRECOMPILE_LAYOUTS, false)) {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "compileLayouts");
mViewCompiler.compileLayouts(pkg);
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "dexopt");
// Do not run PackageDexOptimizer through the local performDexOpt
// method because `pkg` may not be in `mPackages` yet.
//
// Also, don't fail application installs if the dexopt step fails.
DexoptOptions dexoptOptions = new DexoptOptions(packageName,
REASON_INSTALL,
DexoptOptions.DEXOPT_BOOT_COMPLETE
| DexoptOptions.DEXOPT_INSTALL_WITH_DEX_METADATA_FILE);
mPackageDexOptimizer.performDexOpt(pkg,
null /* instructionSets */,
getOrCreateCompilerPackageStats(pkg),
mDexManager.getPackageUseInfoOrDefault(packageName),
dexoptOptions);
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
// Notify BackgroundDexOptService that the package has been changed.
// If this is an update of a package which used to fail to compile,
// BackgroundDexOptService will remove it from its blacklist.
// TODO: Layering violation
/通知package changed
BackgroundDexOptService.notifyPackageChanged(packageName);
}
}
2.3.2 restoreAndPostInstall
在完成apk安装后,若有需要,该方法会恢复apk的备份存档等数据,若无需恢复存档,最后会向mHandler发送一个POST_INSTALL的Messgae
/** @param data Post-install is performed only if this is non-null. */
private void restoreAndPostInstall(
int userId, PackageInstalledInfo res, @Nullable PostInstallData data) {
...//省略代码
//如果需要恢复存档,则恢复存档
if (res.returnCode == PackageManager.INSTALL_SUCCEEDED && doRestore) {
... //省去恢复存档代码代码
}
if (!doRestore) {
//如果无需恢复存档,则发送一个POST_INSTALL的messgae
// No restore possible, or the Backup Manager was mysteriously not
// available -- just fire the post-install work request directly.
if (DEBUG_INSTALL) Log.v(TAG, "No restore - queue post-install for " + token);
Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "postInstall", token);
Message msg = mHandler.obtainMessage(POST_INSTALL, token, 0);
mHandler.sendMessage(msg);
}
}
在Handler中对POST_INSTALL的Messgae处理逻辑如下:
case POST_INSTALL: {
...//省去无关代码
handlePackagePostInstall(parentRes, grantPermissions,killApp, virtualPreload, grantedPermissions,
whitelistedRestrictedPermissions, didRestore,
args.installerPackageName, args.observer);
// Handle the child packages
final int childCount = (parentRes.addedChildPackages != null)? parentRes.addedChildPackages.size() : 0;
for (int i = 0; i < childCount; i++) {
PackageInstalledInfo childRes = parentRes.addedChildPackages.valueAt(i);
handlePackagePostInstall(childRes, grantPermissions,
killApp, virtualPreload, grantedPermissions,
whitelistedRestrictedPermissions, false /*didRestore*/,
args.installerPackageName, args.observer);
}
}
在对该方法的处理逻辑中,会调用 handlePackagePostInstall方法,在该方法中,主要是设置apk的一些权限,以及发送安装成功的通知。
3 总结
至此,我们就分析完成了安装xapk的全部代码,分析过程中省略了不少无关的逻辑,主要是从整体流程出发,关注apk是怎么安装到系统中的。