我是靠谱客的博主 醉熏水池,这篇文章主要介绍PMS简单学习【2.PMS开始安装APK-APK安装】,现在分享给大家,希望可以做个参考。

PMS简单学习【2.PMS开始安装APK-APK安装】

PMS实际对apk的处理的来源还是要从PackageInstallerSession谈起。之前在PackageInstallerSession进行完安装前的准备工作后,最后会进行
PackageInstallerSession#install()方法的调用,最后会调用PackageManagerService(PMS)的installStage()方法,接下来就到了PMS的旅程了。

在调用PMS的installStage方法后,就会发送一个INIT_COPY的消息。

复制代码
1
2
3
4
5
6
7
8
void installStage(InstallParams params) { final Message msg = mHandler.obtainMessage(INIT_COPY); params.setTraceMethod("installStage").setTraceCookie(System.identityHashCode(params)); msg.obj = params; ...... mHandler.sendMessage(msg); }

在发送消息后,就回去调用HandlerParamsstartCopy方法

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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()这两个方法。这两个方法是抽象方法,实际调用还是子类的这俩方法。

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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安装都会是分段安装,所以MultiPackageVerificationParamshandleStartCopy方法和handleReturnCode会去分段进行处理,最终分别会调用InstallParams的对应方法,Multi...Params持有一个InstallParams的列表成员变量,这个变量是否有值取决于PackageManagerSessioninstallStage调用的是单个还是多个包的方法。下面真多单个包进行考虑。

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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方法。

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
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时终止。
接下来就是要来异步操作并且排队来进行处理,因为包安装是需要一些时间的。

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
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,ReconcileCommit

Prepare : 分析当前安装的状态,分析包并对其进行初始验证
Scan : 根据prepare阶段中收集的上下文,查询已解析的包
Reconcile : 在彼此和当前系统状态的上下文中验证扫描的包,以确保安装成功
Commit : 提交所有扫描的包并且更新系统状态。这是唯一可以在安装流程中修改系统状态的地方,必须在此阶段确定所有可预测的错误。
从上面的步骤中能看到,这些步骤是环环相扣的,任何一个步骤失败就会导致安装失败。

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
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 的代码,安装部分代码可能有些变动,所以理解上可能有些偏差,这些理解上的偏差相信在之后的不断扩充中会弥补回来。奥里给 淦就完了

最后

以上就是醉熏水池最近收集整理的关于PMS简单学习【2.PMS开始安装APK-APK安装】的全部内容,更多相关PMS简单学习【2内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(53)

评论列表共有 0 条评论

立即
投稿
返回
顶部