PKMS 钻研(8) - APK 安装(下)

一、开篇

1.1 核心源码

关键类 路径
PackageInstallerSession.java /frameworks/base/services/core/java/com/android/server/pm/PackageInstallerSession.java
PackageManagerService.java /frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java

1.2 前言

在本系列上一篇文章 《PackageManagerService 钻研(7)- APK 安装(中)》 中,我们了解了 PackageInstaller 安装 APK 的流程,最后会将 APK 的信息交由 PMS 处理。那么 PMS 是如何处理的?这就是我们这篇文章需要分析的。

一、安装 APK

1.1 handleReturnCode

我们回到 APK 的复制调用链的头部方法:HandlerParams 的 startCopy 方法,在最后 调用了 handleReturnCode 方法,进行 APK 的安装。

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
private abstract class HandlerParams {
private static final int MAX_RETRIES = 4;

private int mRetries = 0;
... ...

final boolean startCopy() {
boolean res;
try {
if (++mRetries > MAX_RETRIES) {
... ...
} else {
handleStartCopy();
res = true;
}
} catch (RemoteException e) {
... ...
}
// 处理复制 APK 后的安装 APK 逻辑
handleReturnCode(); // 💥 💥 💥 💥 💥 💥
return res;
}
... ...

abstract void handleReturnCode();
}

handleReturnCode 也是一个抽象方法,那么在哪里实现?同样,它的实现在 InstallParams 中。

1
2
3
4
5
6
7
8
9
10
@Override
void handleReturnCode() {
// If mArgs is null, then MCS couldn't be reached. When it
// reconnects, it will try again to install. At that point, this
// will succeed.
if (mArgs != null) {
// "装载代码"的入口是 processPendingInstall(InstallArgs,int) 方法
processPendingInstall(mArgs, mRet);
}
}

我们发现调用了 processPendingInstall 方法,继续跟!

1.2 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
private void processPendingInstall(final InstallArgs args, final int currentStatus) {
mHandler.post(new Runnable() {
public void run() {
mHandler.removeCallbacks(this);
PackageInstalledInfo res = new PackageInstalledInfo();
res.setReturnCode(currentStatus);
res.uid = -1;
res.pkg = null;
res.removedInfo = null;
if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
/**
* 安装前处理
* 用于检查 APK 的状态的,在安装前确保安装环境的可靠,如果不可靠会清除复制的 APK 文件
args.doPreInstall(res.returnCode);
synchronized (mInstallLock) {
installPackageTracedLI(args, res); // 💥 💥 💥 💥 💥 💥
}
/**
* 安装后收尾
* 用于处理安装后的收尾操作,如果安装不成功,删除掉安装相关的目录与文件
args.doPostInstall(res.returnCode, res.uid);
}
... ...
}
});
}

1.3 installPackageTracedLI

1
2
3
4
5
6
7
8
private void installPackageTracedLI(InstallArgs args, PackageInstalledInfo res) {
try {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installPackage");
installPackageLI(args, res);
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
}

1.4 installPackageLI

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
private void installPackageLI(InstallArgs args, PackageInstalledInfo res) {
... ...

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 {
// 解析 APK
pkg = pp.parsePackage(tmpPackageFile, parseFlags);
} catch (PackageParserException e) {
res.setError("Failed parse during installPackageLI", e);
return;
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
... ...

// Get rid of all references to package scan path via parser.
pp = null;
String oldCodePath = null;
boolean systemApp = false;
synchronized (mPackages) {
// 检查 APK 是否存在
if ((installFlags & PackageManager.INSTALL_REPLACE_EXISTING) != 0) {
// 获取没被改名前的包名
String oldName = mSettings.getRenamedPackageLPr(pkgName);
if (pkg.mOriginalPackages != null
&& pkg.mOriginalPackages.contains(oldName)
&& mPackages.containsKey(oldName)) {
pkg.setPackageName(oldName);
pkgName = pkg.packageName;
// 设置标志位表示是替换安装
replace = true;
if (DEBUG_INSTALL) Slog.d(TAG, "Replacing existing renamed package: oldName="
+ oldName + " pkgName=" + pkgName);
}
... ...
}

PackageSetting ps = mSettings.mPackages.get(pkgName);
// 查看 Settings 中是否存有要安装的 APK 的信息,如果有就获取签名信息
if (ps != null) {
if (DEBUG_INSTALL) Slog.d(TAG, "Existing package: " + ps);

PackageSetting signatureCheckPs = ps;
if (pkg.applicationInfo.isStaticSharedLibrary()) {
SharedLibraryEntry libraryEntry = getLatestSharedLibraVersionLPr(pkg);
if (libraryEntry != null) {
signatureCheckPs = mSettings.getPackageLPr(libraryEntry.apk);
}
}

// 检查签名的正确性
if (shouldCheckUpgradeKeySetLP(signatureCheckPs, scanFlags)) {
if (!checkUpgradeKeySetLP(signatureCheckPs, pkg)) {
res.setError(INSTALL_FAILED_UPDATE_INCOMPATIBLE, "Package "
+ pkg.packageName + " upgrade keys do not match the "
+ "previously installed version");
return;
}
}
... ...
}

int N = pkg.permissions.size();
for (int i = N-1; i >= 0; i--) {
// 遍历每个权限,对权限进行处理
PackageParser.Permission perm = pkg.permissions.get(i);
BasePermission bp = mSettings.mPermissions.get(perm.info.name);
... ...
}
}

if (systemApp || sPmsExt.isOperatorApp(mPackages, mSettings.mPackages, pkgName)) {
if (onExternal) {
// 系统APP不能在SD卡上替换安装
res.setError(INSTALL_FAILED_INVALID_INSTALL_LOCATION,
"Cannot install updates to system apps on sdcard");
return;
} else if (instantApp) {
// 系统 APP 不能被 Instant App 替换
res.setError(INSTALL_FAILED_INSTANT_APP_INVALID,
"Cannot update a system app with an instant app");
return;
}
}

... ...

// 重命名临时文件
if (!args.doRename(res.returnCode, pkg, oldCodePath)) {
res.setError(INSTALL_FAILED_INSUFFICIENT_STORAGE, "Failed rename");
return;
}

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);
}
}

try (PackageFreezer freezer = freezePackageForInstall(pkgName, installFlags,
"installPackageLI")) {
if (replace) {
// 替换安装
if (pkg.applicationInfo.isStaticSharedLibrary()) {
PackageParser.Package existingPkg = mPackages.get(pkg.packageName);
if (existingPkg != null && existingPkg.mVersionCode != pkg.mVersionCode) {
res.setError(INSTALL_FAILED_DUPLICATE_PACKAGE, "Packages declaring "
+ "static-shared libs cannot be updated");
return;
}
}
replacePackageLIF(pkg, parseFlags, scanFlags | SCAN_REPLACING, args.user,
installerPackageName, res, args.installReason);
} else {
// 安装新的 APK
installNewPackageLIF(pkg, parseFlags, scanFlags | SCAN_DELETE_DATA_ON_FAILURES,
args.user, installerPackageName, volumeUuid, res, args.installReason);
}
}

// 更新应用程序所属的用户
synchronized (mPackages) {
final PackageSetting ps = mSettings.mPackages.get(pkgName);
if (ps != null) {
res.newUsers = ps.queryInstalledUsers(sUserManager.getUserIds(), true);
ps.setUpdateAvailable(false /*updateAvailable*/);
}
... ...
}
}

installPackageLI 方法的代码很长,这里截取主要的部分,主要做了几件事:

        ✨ 1、创建 PackageParser 解析 APK 。
        ✨ 2、检查 APK 是否存在,如果存在就获取此前没被改名前的包名,赋值给 PackageParser.Package 类型的 pkg ,将标志位 replace 置为 true 表示是替换安装。
        ✨ 3、如果 Settings 中保存有要安装的 APK 的信息,说明此前安装过该 APK ,则需要校验 APK 的签名信息,确保安全的进行替换。
        ✨ 4、将临时文件重新命名,比如前面提到的 /data/app/vmdl18300388.tmp/base.apk ,重命名为 /data/app/包名-1/base.apk 。这个新命名的包名会带上一个数字后缀 1,每次升级一个已有的 App ,这个数字会不断的累加。
        ✨ 5、系统 APP 的更新安装会有两个限制,一个是系统 APP 不能在 SD 卡上替换安装,另一个是系统 APP 不能被 Instant App 替换。
        ✨ 6、根据 replace 来做区分,如果是替换安装就会调用 replacePackageLIF 方法,其方法内部还会对系统 APP 和非系统 APP 进行区分处理,如果是新安装 APK 会调用 installNewPackageLIF 方法。

1.5 installNewPackageLIF

我们以安装新 APK 为例,查看 installNewPackageLIF 的源码:

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
/*
* Install a non-existing package.
*/
private void installNewPackageLIF(PackageParser.Package pkg, final int policyFlags,
int scanFlags, UserHandle user, String installerPackageName, String volumeUuid,
PackageInstalledInfo res, int installReason) {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installNewPackage");

... ...

try {
// 扫描 APK
PackageParser.Package newPackage = scanPackageTracedLI(pkg, policyFlags, scanFlags,
System.currentTimeMillis(), user);

// 更新 Settings 信息
updateSettingsLI(newPackage, installerPackageName, null, res, user, installReason);

if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
// 安装成功后,为新安装的应用程序准备数据
prepareAppDataAfterInstallLIF(newPackage);

} else {
// 安装失败则删除 APK
deletePackageLIF(pkgName, UserHandle.ALL, false, null,
PackageManager.DELETE_KEEP_DATA, res.removedInfo, true, null);
}
} catch (PackageManagerException e) {
res.setError("Package couldn't be installed in " + pkg.codePath, e);
}

Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}

installNewPackageLIF 主要做了以下 3 件事:

        ✨ 1、扫描 APK,将 APK 的信息存储在 PackageParser.Package 类型的 newPackage 中,一个 Package 的信息包含了 1 个 base APK 以及 0 个或者多个 split APK 。
        ✨ 2、更新该 APK 对应的 Settings 信息,Settings 用于保存所有包的动态设置。
        ✨ 3、如果安装成功就为新安装的应用程序准备数据,安装失败就删除APK。

1.6 scanPackageTracedLI

调用 scanPackageTracedLI() 进行安装 :

1
2
3
4
5
6
7
8
9
public 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);
}
}

1.7 scanPackageLI - 01

scanPackageTracedLI() 调用了 scanPackageLI() 方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
* Scans a package and returns the newly parsed package.
* Returns {@code null} in case of errors and the error code is stored in mLastScanError
*/
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);
... ...

return scanPackageLI(pkg, scanFile, parseFlags, scanFlags, currentTime, user);
}

1.8 scanPackageLI - 02

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
private PackageParser.Package scanPackageLI(PackageParser.Package pkg, final int policyFlags,
int scanFlags, long currentTime, @Nullable UserHandle user)
throws PackageManagerException {
boolean success = false;
try {
// scanPackageDirtyLI 实际安装 package 的方法
final PackageParser.Package res = scanPackageDirtyLI(pkg, policyFlags, scanFlags,
currentTime, user);
success = true;
return res;
} finally {
if (!success && (scanFlags & SCAN_DELETE_DATA_ON_FAILURES) != 0) {
// DELETE_DATA_ON_FAILURES is only used by frozen paths
destroyAppDataLIF(pkg, UserHandle.USER_ALL,
StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE);
destroyAppProfilesLIF(pkg, UserHandle.USER_ALL);
}
}
}

最终调用 scanPackageLI 方法!

二、总结

本文主要讲解了 PMS 是如何处理 APK 安装的流程,主要有几个步骤:

        ✨ PackageInstaller 安装 APK 时会将 APK 的信息交由 PMS 处理,PMS 通过向 PackageHandler 发送消息来驱动 APK 的复制和安装工作。
        ✨ PMS 发送 INIT_COPY 和 MCS_BOUND 类型的消息,控制 PackageHandler 来绑定 DefaultContainerService ,完成复制 APK 等工作。
        ✨ 复制 APK 完成后,会开始进行安装 APK 的流程,包括安装前的检查、安装 APK 和安装后的收尾工作。