从源码角度看Android应用安装

简介

我之前的文章里,一般都是集中分析AMS, IMS, WMS以及View控件方面的原理,然而这些组件的分析其实有一个前提:PMS中需要预先加载应用相关的组件、库以及资源文件。可以这么说,倘若没有PMS的服务的话,所有应用是无法被加载到系统中运行的。

PMS提供的所有功能中,最核心的当属应用安装服务。作为一个普通的用户,最常见的场景是通过应用商店,或者自己手动从网络下载apk,在文件管理器中手动安装应用。作为一个开发者,最常用的是AS的Run按钮,本质上最终会使用脚本调用adb install服务来实现应用的安装。

这篇文章里,我将会从源码的角度,着重梳理、分析各个场景下的安装功能实现流程。最终我们能发现,所有的安装场景其实是殊途同归,最终调用到了PMS的scanPackageDirtyLI来实现安装功能,而所谓的安装,其实是对apk文件的解析、加载。

Android 应用安装场景总结

安卓安装源码大部分逻辑都在PMS中,相对比与IMS与View控件花哨的设计,PMS安装实现比较”原始”,常常会调用到巨无霸”方法”。因为调用流程并不复杂,这里就不画类图、时序图了,直接上一张安装场景总结图:

安装场景 入口函数 触发时机
系统应用安装 SystemServer.main() 系统启动时
通过安装器安装 PackageInstallerActivity.startInstall() 在安装器界面点击安装
通过adb install安装 PM.runInstall() 输入adb install xxx.apk进行安装
应用商店自动安装 通过Accessibility自动点击安装按钮 AcessibilityService监测到安装界面并触发点击

安装流程

1. 系统应用安装

开机时PMS的启动流程和其它系统Service的流程是一样的:从init进程被拉起,再到zygote进程,再到SystemServer进程,进入到SystemServer.main方法后,开始初始化包含PMS在内的各大系统Service

SystemServer.run()

frameworks/base/services/java/com/android/server/SystemServer.java

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
// system_server 进程的入口函数
public static void main(String[] args) {
// 注意这个run方法只是个普通的run函数,和线程自动调用的run并没有联系
new SystemServer().run();
}
private void run() {
...
try {
Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "StartServices");
// 在这里启动PMS服务
startBootstrapServices();
startCoreServices();
startOtherServices();
SystemServerInitThreadPool.shutdown();
} catch (Throwable ex) {
Slog.e("System", "******************************************");
Slog.e("System", "************ Failure starting system services", ex);
throw ex;
} finally {
Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
}
...
}
private void startBootstrapServices() {
...
// 通过调用PMS的静态main方法来初始化并返回实例
// 注意这里的main方法和SystemServer这种的main方法还是不同的,并不是由反射进行调用的
mPackageManagerService = PackageManagerService.main(mSystemContext, installer,
mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);
...
}

PMS.main()

frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java

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
public static PackageManagerService main(Context context, Installer installer,
boolean factoryTest, boolean onlyCore) {
...
// 包相关的处理操作将在PMS构造器中完成,整个流程很长
PackageManagerService m = new PackageManagerService(context, installer,
factoryTest, onlyCore);
...
// 在ServiceManager进行注册
ServiceManager.addService("package", m);
return m;
}
public PackageManagerService(Context context, Installer installer,
boolean factoryTest, boolean onlyCore) {
...
// 收集 priv-app 目录下apk信息
final File privilegedAppDir = new File(Environment.getRootDirectory(), "priv-app");
scanDirTracedLI(privilegedAppDir, mDefParseFlags
| PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR
| PackageParser.PARSE_IS_PRIVILEGED, scanFlags, 0);
// 收集 app 目录下apk信息
final File systemAppDir = new File(Environment.getRootDirectory(), "app");
scanDirTracedLI(systemAppDir, mDefParseFlags
| PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);
// 收集 /vendor/app 目录下apk信息
File vendorAppDir = new File("/vendor/app");
try {
vendorAppDir = vendorAppDir.getCanonicalFile();
} catch (IOException e) {
// failed to look up canonical path, continue with original one
}
scanDirTracedLI(vendorAppDir, mDefParseFlags
| PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);
...
}
private void scanDirTracedLI(File dir, final int parseFlags, int scanFlags, long currentTime) {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanDir");
try {
scanDirLI(dir, parseFlags, scanFlags, currentTime);
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
}
private void scanDirLI(File dir, final int parseFlags, int scanFlags, long currentTime) {
final MultiTaskDealer dealer = (iMultitaskNum > 1) ? MultiTaskDealer.startDealer(
MultiTaskDealer.PACKAGEMANAGER_SCANER, iMultitaskNum) : null;
// 初始化一个扫描任务
Runnable scanTask = new Runnable() {
public void run() {
try {
scanPackageTracedLI(ref_file, ref_parseFlags |
PackageParser.PARSE_MUST_BE_APK, ref_scanFlags, ref_currentTime, null);
} catch (PackageManagerException e) {
...
}
}
};
// 将任务放置到线程池中进行处理
if (dealer != null)
dealer.addTask(scanTask);
else
scanTask.run();
}
private PackageParser.Package scanPackageTracedLI(File scanFile, final int parseFlags,
int scanFlags, long currentTime, UserHandle user) throws PackageManagerException {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanPackage");
try {
return scanPackageLI(scanFile, parseFlags, scanFlags, currentTime, user);
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
}
// 扫描apk文件方法
private PackageParser.Package scanPackageLI(File scanFile, int parseFlags, int scanFlags,
long currentTime, UserHandle user) throws PackageManagerException {
...
final PackageParser.Package pkg;
try {
pkg = pp.parsePackage(scanFile, parseFlags);
} catch (PackageParserException e) {
throw PackageManagerException.from(e);
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
...
return scanPackageLI(pkg, scanFile, parseFlags, scanFlags, currentTime, user);
}

Package.parsePacakge()

frameworks/base/core/java/android/content/pm/PackageParser.java

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
public Package parsePackage(File packageFile, int flags) throws PackageParserException {
if (packageFile.isDirectory()) {
return parseClusterPackage(packageFile, flags);
} else {
return parseMonolithicPackage(packageFile, flags);
}
}
private Package parseClusterPackage(File packageDir, int flags) throws PackageParserException {
...
// 该方法将会解析Manifest.xml文件,将apk组件信息进行保存
final Package pkg = parseBaseApk(baseApk, assets, flags);
...
}
private Package parseBaseApk(Resources res, XmlResourceParser parser, int flags,
String[] outError) throws XmlPullParserException, IOException {
...
return parseBaseApkCommon(pkg, null, res, parser, flags, outError);
}
// 该方法为组件解析的核心方法,因为篇幅较长不详细分析了,无非就是解析xml文件提取出组件信息,封装成Package返回
private Package parseBaseApkCommon(Package pkg, Set<String> acceptedTags, Resources res,
XmlResourceParser parser, int flags, String[] outError) throws XmlPullParserException,
IOException {
...
}

frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java

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
private PackageParser.Package scanPackageLI(PackageParser.Package pkg, File scanFile,
final int policyFlags, int scanFlags, long currentTime, UserHandle user)
throws PackageManagerException {
...
// 将应用组件信息提取出来后,调用Internel方法进行应用安装
PackageParser.Package scannedPkg = scanPackageInternalLI(pkg, scanFile, policyFlags,
scanFlags, currentTime, user);
...
return scannedPkg;
}
private PackageParser.Package scanPackageInternalLI(PackageParser.Package pkg, File scanFile,
int policyFlags, int scanFlags, long currentTime, UserHandle user)
throws PackageManagerException {
...
// Note that we invoke the following method only if we are about to unpack an application
PackageParser.Package scannedPkg = scanPackageLI(pkg, policyFlags, scanFlags
| SCAN_UPDATE_SIGNATURE, currentTime, user);
...
}
private PackageParser.Package scanPackageLI(PackageParser.Package pkg, final int policyFlags,
int scanFlags, long currentTime, UserHandle user) throws PackageManagerException {
boolean success = false;
try {
// 最终调用到了核心安装方法
final PackageParser.Package res = scanPackageDirtyLI(pkg, policyFlags, scanFlags,
currentTime, user);
success = true;
return res;
} finally {
...
}
}

2. 通过安装器安装

PackageInstallerActivity.startInstall()

packages/apps/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
private void startInstall() {
// Start subactivity to actually install the application
Intent newIntent = new Intent();
newIntent.putExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO,
mPkgInfo.applicationInfo);
newIntent.setData(mPackageURI);
if(!TextUtils.isEmpty(mInstallFromPkgName)){
newIntent.putExtra(InstallAppProgress.EXTRA_INSTALL_SOURCE,mInstallFromPkgName);
}
newIntent.putExtra(InstallAppProgress.EXTRA_NEWINSTALL,mNewInstall);
newIntent.putExtra(AdDataHelper.INTENT_EXTRA_PI_ID, mPid);
newIntent.setClass(this, InstallAppProgress.class);
String installerPackageName = getIntent().getStringExtra(
Intent.EXTRA_INSTALLER_PACKAGE_NAME);
...
// 通过启动Activity到InstallAppProgress进行PMS调用
startActivity(newIntent);
finish();
}

InstallAppProgress.startInstall()

packages/apps/PackageInstaller/src/com/android/packageinstaller/InstallAppProgress.java

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
private void startInstall() {
...
// 异步进行安装
mInstallHandler.post(new Runnable() {
@Override
public void run() {
doPackageStage(pm, params);
}
});
}
private void doPackageStage(PackageManager pm, PackageInstaller.SessionParams params) {
final PackageInstaller packageInstaller = pm.getPackageInstaller();
PackageInstaller.Session session = null;
try {
...
Intent broadcastIntent = new Intent(BROADCAST_ACTION + mInstallId);
PendingIntent pendingIntent = PendingIntent.getBroadcast(
InstallAppProgress.this /*context*/,
sessionId,
broadcastIntent,
PendingIntent.FLAG_UPDATE_CURRENT);
// binder call 到PacakgeInstallerSession进行处理
session.commit(pendingIntent.getIntentSender());
mInstallStartTime = SystemClock.elapsedRealtime();
} catch (IOException e) {
...
} finally {
IoUtils.closeQuietly(session);
}
}

PackageInstallerSesson.commit()

frameworks/base/services/core/java/com/android/server/pm/PackageInstallerSession.java

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
@Override
public void commit(IntentSender statusReceiver) {
...
final PackageInstallObserverAdapter adapter = new PackageInstallObserverAdapter(mContext,
statusReceiver, sessionId, mIsInstallerDeviceOwner, userId);
// 因为在server端,此时仍为binder线程在处理,post个message异步进行处理
mHandler.obtainMessage(MSG_COMMIT, adapter.getBinder()).sendToTarget();
}
private final Handler.Callback mHandlerCallback = new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
...
synchronized (mLock) {
...
try {
commitLocked();
} catch (PackageManagerException e) {
...
}
return true;
}
}
};
private void commitLocked() throws PackageManagerException {
...
// 最终调用pm.installStage方法进行安装
mPm.installStage(mPackageName, stageDir, stageCid, localObserver, params,
installerPackageName, installerUid, user, mCertificates);
}

PMS.installStage()

frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java

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
void installStage(String packageName, File stagedDir, String stagedCid,
IPackageInstallObserver2 observer, PackageInstaller.SessionParams sessionParams,
String installerPackageName, int installerUid, UserHandle user,
Certificate[][] certificates) {
...
// 异步进行文件拷贝
final Message msg = mHandler.obtainMessage(INIT_COPY);
...
mHandler.sendMessage(msg);
}
void doHandleMessage(Message msg) {
switch (msg.what) {
case INIT_COPY: {
HandlerParams params = (HandlerParams) msg.obj;
if (!mBound) {
...
} else {
mPendingInstalls.add(idx, params);
if (idx == 0) {
mHandler.sendEmptyMessage(MCS_BOUND);
}
}
break;
}
...
case MCS_BOUND: {
...
if (mContainerService == null) {
...
} else if (mPendingInstalls.size() > 0) {
HandlerParams params = mPendingInstalls.get(0);
if (params != null) {
Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
System.identityHashCode(params));
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "startCopy");
// 开始拷贝apk文件
if (params.startCopy()) {
...
}
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
}
break;
}
final boolean startCopy() {
...
try {
if (DEBUG_INSTALL) Slog.i(TAG, "startCopy " + mUser + ": " + this);
if (++mRetries > MAX_RETRIES) {
...
} else {
// 拷贝文件
handleStartCopy();
res = true;
}
} catch (RemoteException e) {
if (DEBUG_INSTALL) Slog.i(TAG, "Posting install MCS_RECONNECT");
mHandler.sendEmptyMessage(MCS_RECONNECT);
res = false;
}
// 拷贝完成后进入安装阶段
handleReturnCode();
return res;
}
@Override
void handleReturnCode() {
if (mArgs != null) {
processPendingInstall(mArgs, mRet);
}
}
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) {
args.doPreInstall(res.returnCode);
synchronized (mInstallLock) {
// 进行安装操作
installPackageTracedLI(args, res);
}
args.doPostInstall(res.returnCode, res.uid);
}
...
}
}
}
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);
}
}
private void installPackageLI(InstallArgs args, PackageInstalledInfo res) {
try (PackageFreezer freezer = freezePackageForInstall(pkgName, installFlags,
"installPackageLI")) {
if (replace) {
// 应用升级或降级
replacePackageLIF(pkg, parseFlags, scanFlags | SCAN_REPLACING, args.user,
installerPackageName, res);
} else {
// 应用从未被安装
installNewPackageLIF(pkg, parseFlags, scanFlags | SCAN_DELETE_DATA_ON_FAILURES,
args.user, installerPackageName, volumeUuid, res);
}
}
}
private void installNewPackageLIF(PackageParser.Package pkg, final int policyFlags,
int scanFlags, UserHandle user, String installerPackageName, String volumeUuid,
PackageInstalledInfo res) {
...
try {
// 最终调用到了scanPackageTracedLI方法,和系统启动的扫描场景殊途同归
PackageParser.Package newPackage = scanPackageTracedLI(pkg, policyFlags, scanFlags,
System.currentTimeMillis(), user);
...
} catch (PackageManagerException e) {
res.setError("Package couldn't be installed in " + pkg.codePath, e);
}
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}

3. 通过adb install安装

关于adb的实现原理及分析,我准备过几天再进行分析。

当前在命令行输入adb install xxx.apk文件后,最终会调用到framework的PM.main()方法,进行相关处理

PM.main

frameworks/base/cmds/pm/src/com/android/commands/pm/Pm.java

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
public static void main(String[] args) {
int exitCode = 1;
try {
exitCode = new Pm().run(args);
} catch (Exception e) {
...
}
System.exit(exitCode);
}
public int run(String[] args) throws RemoteException {
...
if ("install".equals(op)) {
return runInstall();
}
...
}
private int runInstall() throws RemoteException {
final InstallParams params = makeInstallParams();
// 获取 session 服务连接
final int sessionId = doCreateSession(params.sessionParams,
params.installerPackageName, params.userId);
try {
...
if (doCommitSession(sessionId, false /*logSuccess*/)
!= PackageInstaller.STATUS_SUCCESS) {
return 1;
}
System.out.println("Success");
return 0;
} finally {
...
}
}
private int doCommitSession(int sessionId, boolean logSuccess) throws RemoteException {
PackageInstaller.Session session = null;
try {
session = new PackageInstaller.Session(
mInstaller.openSession(sessionId));
final LocalIntentReceiver receiver = new LocalIntentReceiver();
// 通过binder call到PackageInstallerSession来实现安装,和安装器场景一致
session.commit(receiver.getIntentSender());
...
} finally {
IoUtils.closeQuietly(session);
}
}

4. 应用商店自动安装

以豌豆荚为代表的应用商店是能否不需要用户自动点击安装按钮来实现自动安装的

这里的核心实现思路是使用到了AcessibilityService的功能

Android 提供AcessibilityService服务的初衷是希望将其运用给视力、听力欠缺人群,但是国内开发者使用它做了很多”黑科技”,代表作如微信自动抢红包。

关于AcessibilityService的实现原理,之后我会有计划分析,这篇里就不展开了

核心安装方法: PMS.scanPackageDirtyLI()

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
private PackageParser.Package scanPackageDirtyLI(PackageParser.Package pkg,
final int policyFlags, final int scanFlags, long currentTime, UserHandle user)
throws PackageManagerException {
...
// 将保存在Package中的解析信息取出,存入PMS,自此安装基本成功,AMS可以查询到组件信息并调用
int N = pkg.providers.size();
StringBuilder r = null;
int i;
for (i = 0; i < N; i++) {
PackageParser.Provider p = pkg.providers.get(i);
p.info.processName = fixProcessName(pkg.applicationInfo.processName,
p.info.processName, pkg.applicationInfo.uid);
// 将provider信息放入PMS
mProviders.addProvider(p);
...
}
if (r != null) {
if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, " Providers: " + r);
}
N = pkg.services.size();
r = null;
for (i = 0; i < N; i++) {
PackageParser.Service s = pkg.services.get(i);
s.info.processName = fixProcessName(pkg.applicationInfo.processName,
s.info.processName, pkg.applicationInfo.uid);
// 将service信息放入PMS
mServices.addService(s);
...
}
if (r != null) {
if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, " Services: " + r);
}
N = pkg.receivers.size();
r = null;
for (i = 0; i < N; i++) {
PackageParser.Activity a = pkg.receivers.get(i);
a.info.processName = fixProcessName(pkg.applicationInfo.processName,
a.info.processName, pkg.applicationInfo.uid);
// 将receiver信息放入PMS
mReceivers.addActivity(a, "receiver");
...
}
if (r != null) {
if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, " Receivers: " + r);
}
N = pkg.activities.size();
r = null;
for (i = 0; i < N; i++) {
PackageParser.Activity a = pkg.activities.get(i);
a.info.processName = fixProcessName(pkg.applicationInfo.processName,
a.info.processName, pkg.applicationInfo.uid);
// 将activity信息放入PMS
mActivities.addActivity(a, "activity");
...
}
...
}

总结

  • /system/priv-app, /system/priv-app, /vendor/app/ 下的应用在系统启动时扫描并安装
  • adb install 与使用应用安装器安装,本质上都使用到了PackageInstallerSession的服务进行安装
  • 国内应用商店如豌豆荚,常用AcessibilityService来实现自动安装功能
扫码支持0.99元,您的支持将鼓励我继续创作!