PMS简单学习【2.PMS开始安装APK-APK安装】
PMS实际对apk的处理的来源还是要从
PackageInstallerSession
谈起。之前在PackageInstallerSession
进行完安装前的准备工作后,最后会进行
PackageInstallerSession#install()
方法的调用,最后会调用PackageManagerService(PMS)的installStage()
方法,接下来就到了PMS的旅程了。
在调用PMS的installStage
方法后,就会发送一个INIT_COPY
的消息。
void installStage(InstallParams params) {
final Message msg = mHandler.obtainMessage(INIT_COPY);
params.setTraceMethod("installStage").setTraceCookie(System.identityHashCode(params));
msg.obj = params;
......
mHandler.sendMessage(msg);
}
在发送消息后,就回去调用HandlerParams
的startCopy
方法
class PackageHandler extends Handler {
void doHandleMessage(Message msg) {
switch (msg.what) {
case INIT_COPY: {
HandlerParams params = (HandlerParams) msg.obj;
if (params != null) {
if (DEBUG_INSTALL) Slog.i(TAG, "init_copy: " + params);
Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
System.identityHashCode(params));
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "startCopy");
// 会调用 HandlerParams的startCopy()方法
params.startCopy();
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
break;
}
}
}
}
接着来看下HandlerParams
这个类。这是用来处理用户请求或者是安装的类。其中上面调用的startCopy
方法会调用handleStartCopy()
和handleReturnCode()
这两个方法。这两个方法是抽象方法,实际调用还是子类的这俩方法。
private abstract class HandlerParams {
/** User handle for the user requesting the information or installation. */
private final UserHandle mUser;
String traceMethod;
int traceCookie;
......
final void startCopy() {
if (DEBUG_INSTALL) Slog.i(TAG, "startCopy " + mUser + ": " + this);
handleStartCopy();
handleReturnCode();
}
abstract void handleStartCopy();
abstract void handleReturnCode();
}
上面说的子类有MultiPackageVerificationParams
,用来处理多个包的安装。另一个是InstallParams
,相对比而言,这是针对一个apk所需要参数的定义。对于handleStartCopy
方法来说,这个方法是调用远程方法来获取包信息和安装位置的值。对于分段Session,验证和安装之间可能存在差异,所以这一段也算是重新验证一下某些条件。由于现在大部分APK大小都比较大,所以很多apk安装都会是分段安装,所以MultiPackageVerificationParams
的handleStartCopy
方法和handleReturnCode
会去分段进行处理,最终分别会调用InstallParams
的对应方法,Multi...Params
持有一个InstallParams
的列表成员变量,这个变量是否有值取决于PackageManagerSession
的installStage
调用的是单个还是多个包的方法。下面真多单个包进行考虑。
class InstallParams extends HandlerParams {
public void handleStartCopy() {
if ((installFlags & PackageManager.INSTALL_APEX) != 0) {
mRet = INSTALL_SUCCEEDED;
return;
}
PackageInfoLite pkgLite = PackageManagerServiceUtils.getMinimalPackageInfo(mContext,
mPackageLite, origin.resolvedPath, installFlags, packageAbiOverride);
boolean isStaged = (installFlags & INSTALL_STAGED) != 0;
if (isStaged) {
mRet = verifyReplacingVersionCode(
pkgLite, requiredInstalledVersionCode, installFlags);
if (mRet != INSTALL_SUCCEEDED) {
return;
}
}
// 调用overrideInstallLocation方法,如果需要的话,根据默认安装策略覆盖安装
mRet = overrideInstallLocation(pkgLite);
}
}
接着来看下handleReturnCode
方法,handleReturnCode
方法接着会调用processPendingInstall
方法。
class InstallParams extends HandlerParams {
@Override
void handleReturnCode() {
processPendingInstall();
}
private void processPendingInstall() {
//创建一个安装参数
InstallArgs args = createInstallArgs(this);
if (mRet == PackageManager.INSTALL_SUCCEEDED) {
mRet = args.copyApk();
}
if (mRet == PackageManager.INSTALL_SUCCEEDED) {
F2fsUtils.releaseCompressedBlocks(
mContext.getContentResolver(), new File(args.getCodePath()));
}
// 如果mParentInstallParams不为null,则说明是多个安装包,我们这里关注else,其实最后都调用`processInstallRequestAsync`
if (mParentInstallParams != null) {
mParentInstallParams.tryProcessInstallRequest(args, mRet);
} else {
PackageInstalledInfo res = createPackageInstalledInfo(mRet);
processInstallRequestsAsync(
res.returnCode == PackageManager.INSTALL_SUCCEEDED,
Collections.singletonList(new InstallRequest(args, res)));
}
}
}
上面的mRet
变量存储着在进行检查是的结果,如果不为PackageManager.INSTALL_SUCCEEDED
,那么就会在调用processInstallRequestsAsync
时终止。
接下来就是要来异步操作并且排队来进行处理,因为包安装是需要一些时间的。
private void processInstallRequestsAsync(boolean success,
List<InstallRequest> installRequests) {
mHandler.post(() -> {
List<InstallRequest> apexInstallRequests = new ArrayList<>();
List<InstallRequest> apkInstallRequests = new ArrayList<>();
for (InstallRequest request : installRequests) {
if ((request.args.installFlags & PackageManager.INSTALL_APEX) != 0) {
apexInstallRequests.add(request);
} else {
apkInstallRequests.add(request);
}
}
//对于APEX和APK的多包情况进行检查
if (success) {
for (InstallRequest request : apkInstallRequests) {
request.args.doPreInstall(request.installResult.returnCode);
}
synchronized (mInstallLock) {
installPackagesTracedLI(apkInstallRequests);
}
for (InstallRequest request : apkInstallRequests) {
request.args.doPostInstall(
request.installResult.returnCode, request.installResult.uid);
}
}
for (InstallRequest request : apkInstallRequests) {
restoreAndPostInstall(request.args.user.getIdentifier(), request.installResult,
new PostInstallData(request.args, request.installResult, null));
}
});
}
从上面的方法中,我们可以简单的直到了在这里就准备要分发安装事件了,到最后restoreAndPostInstall
接着会去进行POST_INSTALL
事件的发送。我们可以看一下installPackagesTracedLI()
方法干了些什么事情。其实这里可以省略一些内容,最后会调用到installPackagesLI
方法,这个才是主角。这个方法以原子方式安装一个或多个包。主要是干了四件事情,Prepare
,Scan
,Reconcile
和Commit
。
Prepare : 分析当前安装的状态,分析包并对其进行初始验证
Scan : 根据prepare阶段中收集的上下文,查询已解析的包
Reconcile : 在彼此和当前系统状态的上下文中验证扫描的包
,以确保安装成功
Commit : 提交所有扫描的包并且更新系统状态。这是唯一可以在安装流程中修改系统状态
的地方,必须在此阶段确定所有可预测的错误。
从上面的步骤中能看到,这些步骤是环环相扣的,任何一个步骤失败就会导致安装失败。
private void installPackagesLI(List<InstallRequest> requests) {
// 通过多个ArrayMap 对request的信息进行存储,request信息是保存在一个List当中。分别存储其扫描结果,安装参数,安装信息,准备结果,版本信息,Setting信息。
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");
// 对每一个请求进行处理,在准备阶段和扫描阶段对所有的request进行处理,最后存入到ArrayMap当中。
for (InstallRequest request : requests) {
final PrepareResult prepareResult;
try {
// 准备阶段,调用preparePackageLI方法分析安装的状态,分析包并且进行验证
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "preparePackage");
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.installSource.installerPackageName;
// 准备阶段结束会对对应的准备结果进行存储,接着吧安装信息从request当中取出进行存储,以及安装参数信息
final String packageName = prepareResult.packageToScan.getPackageName();
prepareResults.put(packageName, prepareResult);
installResults.put(packageName, request.installResult);
installArgs.put(packageName, request.args);
try {
// 接着就进入了扫描阶段,同上,扫描阶段的结果也会存储到对应的Map当中。
final ScanResult result = scanPackageTracedLI(
prepareResult.packageToScan, prepareResult.parseFlags,
prepareResult.scanFlags, System.currentTimeMillis(),
request.args.user, request.args.abiOverride);
if (null != preparedScans.put(result.pkgSetting.pkg.getPackageName(), result)) {
request.installResult.setError(
PackageManager.INSTALL_FAILED_DUPLICATE_PACKAGE,
"Duplicate package " + result.pkgSetting.pkg.getPackageName()
+ " in multi-package install request.");
return;
}
createdAppId.put(packageName, optimisticallyRegisterAppId(result));
versionInfos.put(result.pkgSetting.pkg.getPackageName(),
getSettingsVersionForPackage(result.pkgSetting.pkg));
if (result.staticSharedLibraryInfo != null) {
final PackageSetting sharedLibLatestVersionSetting =
getSharedLibLatestVersionSetting(result);
if (sharedLibLatestVersionSetting != null) {
lastStaticSharedLibSettings.put(result.pkgSetting.pkg.getPackageName(),
sharedLibLatestVersionSetting);
}
}
} catch (PackageManagerException e) {
request.installResult.setError("Scanning Failed.", e);
return;
}
}
// 根据准备阶段和扫描阶段的处理结果进行调和工作
ReconcileRequest reconcileRequest = new ReconcileRequest(preparedScans, installArgs,
installResults,
prepareResults,
mSharedLibraries,
Collections.unmodifiableMap(mPackages), versionInfos,
lastStaticSharedLibSettings);
CommitRequest commitRequest = null;
synchronized (mLock) {
Map<String, ReconciledPackage> reconciledPackages;
try {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "reconcilePackages");
reconciledPackages = reconcilePackagesLocked(
reconcileRequest, mSettings.getKeySetManagerService(), mInjector);
} 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,
mUserManager.getUserIds());
commitPackagesLocked(commitRequest);
success = true;
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
}
executePostCommitSteps(commitRequest);
} finally {
if (success) {
for (InstallRequest request : requests) {
final InstallArgs args = request.args;
if (args.mDataLoaderType != DataLoaderType.INCREMENTAL) {
continue;
}
if (args.signingDetails.signatureSchemeVersion != SIGNING_BLOCK_V4) {
continue;
}
// 对于增量安装,安装之前绕过验证器。如果此时我们知道包是有效的,向验证者发送通知 base.apk的根哈希。
final String baseCodePath = request.installResult.pkg.getBaseApkPath();
final String[] splitCodePaths = request.installResult.pkg.getSplitCodePaths();
final Uri originUri = Uri.fromFile(args.origin.resolvedFile);
final int verificationId = mPendingVerificationToken++;
final String rootHashString = PackageManagerServiceUtils
.buildVerificationRootHashString(baseCodePath, splitCodePaths);
broadcastPackageVerified(verificationId, originUri,
PackageManager.VERIFICATION_ALLOW, rootHashString,
args.mDataLoaderType, args.getUser());
}
} else {
for (ScanResult result : preparedScans.values()) {
if (createdAppId.getOrDefault(result.request.parsedPackage.getPackageName(),
false)) {
cleanUpAppIdCreation(result);
}
}
// TODO(patb): create a more descriptive reason than unknown in future release
// mark all non-failure installs as UNKNOWN so we do not treat them as success
for (InstallRequest request : requests) {
if (request.installResult.freezer != null) {
request.installResult.freezer.close();
}
if (request.installResult.returnCode == PackageManager.INSTALL_SUCCEEDED) {
request.installResult.returnCode = PackageManager.INSTALL_UNKNOWN;
}
}
}
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
}
从installPackagesLI
方法中能够看到,主要是干了准备,扫描,调和以及提交的工作。
准备阶段主要是通过
preparePackageLI
方法来进行实现的,会根据传入的安装参数进行确认,根据安装参数的flag进行一些权限的判断。这一段代码的篇幅较大,简单来说下个人认为可值得一说的,比如检测到是系统App,并且是sdcard上的apk,就会终止更新,是不被允许的,也不能够被临时apk安装。同时还会在根据Setting来通过已安装包名来确定是更新apk还是新建apk。
扫描阶段主要是通过scanPackageTracedLI
方法来对在准备阶段的信息进行扫描,根据传入的request信息和准备阶段的结果对包来进行扫描。
调和阶段主要是通过reconcilePackagesLocked
来进行的,会根据准备阶段和扫描阶段的结果对所有的request进行调和,确保能够正确安装。
最后提交阶段通过commitPackagesLocked
来进行,这里会根据安装的包名确定如果是系统app的更新操作,则会对旧的进行替换。
小结一下:
到这里大概的安装工作就已经完成了,其实有很多APK解析的过程,这里先是对大概流程进行梳理,回顾一下,这一段代码主要干的事情是从Session接受到安装请求后,发送一个
INIT_COPY
消息,随后就主要进行handleStartCopy()
来进行拷贝以及通过handleReturnCode()
来进行安装。
由于本篇文章是基于Android12的源码看的,相比于Android8 的代码,安装部分代码可能有些变动,所以理解上可能有些偏差,这些理解上的偏差相信在之后的不断扩充中会弥补回来。奥里给 淦就完了