声明

此次blog分析的源码是Android Q的代码,如果在Android Q以前找不到对应的方法,可以同步Android Q代码找找试试。PKMS服务在Android N/O/P三个版本变化不大,升级到Android Q有较大变化,有些方法名字一样,内部实现可能不一样了。

如下是Android Q pm目录下的源码分析笔记:PackageManagerService源码跟踪分析笔记传送门

1.PKMS概述

PackageManagerService(简称 PKMS),是 Android 系统中核心服务之一,负责应用程序的安装,卸载,包信息查询等工作。

Android系统启动时,会启动(应用程序管理服务器PKMS),此服务负责扫描系统中特定的目录,寻找里面的APK格式的文件,并对这些文件进行解析,然后得到应用程序相关信息,最后完成应用程序的安装。

PKMS在安装应用过程中, 会全面解析应用程序的AndroidManifest.xml文件, 来得到Activity, Service, BroadcastReceiver, ContextProvider 等信息, 在结合PKMS服务就可以在OS中正常的使用应用程序了。

在Android系统中, 系统启动时由SystemServer启动PKMS服务, 启动该服务后会执行应用程序的安装过程,
接下来后就会重点的分析SystemServer启动PKMS服务的过程, 叙述在Android系统中安装应用程序的过程。

PKMS从大方向上看主要完成以下三大功能:

  • 解析AndroidNanifest.xml清单文件,解析清单文件中的所有节点信息
  • 扫描.apk文件,安装系统应用,安装本地应用等
  • 管理本地应用,主要提供安装,卸载,应用信息查询等功能

所涉及到的源码如下:

1.重温PackageManagerService: 1.理解应用安装过程 2.理解签名校验过程 3.理解权限管理 (github.com)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/frameworks/base/core/java/android/app/ApplicationPackageManager.java
/frameworks/base/services/java/com/android/server/SystemServer.java
/frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.
java
/frameworks/base/services/core/java/com/android/server/pm/PackageDexOptimizer.ja
va
/frameworks/base/services/core/java/com/android/server/pm/Installer.java
/frameworks/base/services/core/java/com/android/server/pm/Settings.java
/frameworks/base/services/core/java/com/android/server/pm/permission/BasePermiss
ion.java
/frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.
java
/frameworks/base/services/core/java/com/android/server/pm/permission/DefaultPerm
issionGrantPolicy.java
/frameworks/base/services/core/java/com/android/server/pm/permission/PermissionM
anagerService.java
/frameworks/base/core/java/android/content/pm/IPackageManager.aidl
/frameworks/base/core/java/android/content/pm/PackageManager.java
/frameworks/base/core/java/com/android/server/SystemConfig.java

2.PKMS角色位置

PKMS简要架构.png

各个应用中可以通过Context.getPackageManager()获得ApplicationPackageManager对象, 而mPM指向的是Proxy代理,当调用到mPM.方法后,将会调用到IPackageManager的Proxy代理方法,然后通过Binder机制中的mRemote与服务端PackageManagerService通信 并调用到PackageManagerService的方法;

PackageManagerService是属于Binder机制的服务端角色 。

1
public class PackageManagerService extends IPackageManager.Stub implements PackageSender {}

3.PKMS 启动过程分析

PKMS启动流程.png

PackageManagerService启动是在SystemServer中启动的,启动分为两个阶段,7个过程。如下图

PackageManagerService启动流程.png

3.1 startBootstrapServices 启动阶段

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
private void startBootstrapServices() {
......
traceBeginAndSlog("StartInstaller");
//TODO =====================step1:创建安装器======================================
Installer installer = mSystemServiceManager.startService(Installer.class);
traceEnd();

......

// Only run "core" apps if we're encrypting the device.
//TODO =====================step2:获取用户是否设置了密码======================================
// 如果加密了,则mOnlyCore为true,系统只会加载核心服务
String cryptState = VoldProperties.decrypt().orElse("");
if (ENCRYPTING_STATE.equals(cryptState)) {
Slog.w(TAG, "Detected encryption in progress - only parsing core apps");
mOnlyCore = true;
} else if (ENCRYPTED_STATE.equals(cryptState)) {
Slog.w(TAG, "Device encrypted - only parsing core apps");
mOnlyCore = true;
}

// Start the package manager.
traceBeginAndSlog("StartPackageManagerService");
try {
Watchdog.getInstance().pauseWatchingCurrentThread("packagemanagermain");
//TODO =====================step3:启动PKMS,实例化PKMS====================================
mPackageManagerService = PackageManagerService.main(mSystemContext, installer,
mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);
} finally {
Watchdog.getInstance().resumeWatchingCurrentThread("packagemanagermain");
}
mFirstBoot = mPackageManagerService.isFirstBoot();
mPackageManager = mSystemContext.getPackageManager();
traceEnd();
if (!mRuntimeRestart && !isFirstBootOrUpgrade()) {
MetricsLogger.histogram(null, "boot_package_manager_init_ready",
(int) SystemClock.elapsedRealtime());
}
// Manages A/B OTA dexopting. This is a bootstrap service as we need it to rename
// A/B artifacts after boot, before anything else might touch/need them.
// Note: this isn't needed during decryption (we don't have /data anyways).
//TODO====================step4:如果没有加密,进行OTA dex优化======================
if (!mOnlyCore) {
boolean disableOtaDexopt = SystemProperties.getBoolean("config.disable_otadexopt",
false);
if (!disableOtaDexopt) {
traceBeginAndSlog("StartOtaDexOptService");
try {
Watchdog.getInstance().pauseWatchingCurrentThread("moveab");
// OTADexOpt(OTA下载dex并优化,用于OTA升级)使能时,启动OTA升级服务
OtaDexoptService.main(mSystemContext, mPackageManagerService);
} catch (Throwable e) {
reportWtf("starting OtaDexOptService", e);
} finally {
Watchdog.getInstance().resumeWatchingCurrentThread("moveab");
traceEnd();
}
}
}
......
}

startBootstrapServices()启动阶段首先启动Installer服务,也就是安装器,随后判断当前的设备是否处于加密状态,如果是则只是解析核心应用,接着调用PackageManagerService的静态方法main来创建pms对象。

  • 第一步: 启动Installer服务
  • 第二步: 获取设备是否加密(手机设置密码),如果设备加密了,则只解析”core”应用
  • 第三步: 调用PKMS main方法初始化PackageManagerService,其中调用PackageManagerService()构造函数创建了PKMS对象
  • 第四步: 如果设备没有加密,操作它。管理A/B OTA dexopting。

3.2 startOtherServices()阶段

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
private void startOtherServices() {
if (!mOnlyCore) {
traceBeginAndSlog("UpdatePackagesIfNeeded");
try {
Watchdog.getInstance().pauseWatchingCurrentThread("dexopt");
//TODO =========step5:如果设备没有加密,执行performDexOptUpdate完成Dex优化==========
mPackageManagerService.updatePackagesIfNeeded();
} catch (Throwable e) {
reportWtf("update packages", e);
} finally {
Watchdog.getInstance().resumeWatchingCurrentThread("dexopt");
}
traceEnd();
}

......
try {
//TODO =========step6:完成磁盘维护============================
mPackageManagerService.performFstrimIfNeeded();
} catch (Throwable e) {
reportWtf("performing fstrim", e);
}

......
//TODO ============================step7:PKMS启动完成==============
mPackageManagerService.systemReady();
}

在startOtherServices 阶段主要对dex进行优化,然后判断磁盘是否维护,最后通知PMKS准备就绪。

  • 第五步: 执行 updatePackagesIfNeeded ,完成dex优化;
  • 第六步: 执行 performFstrimIfNeeded ,完成磁盘维护;
  • 第七步: 调用systemReady,准备就绪。

4.逐步分析PKMS启动过程中完成的任务

根据第三节看到系统启动阶段,PKMS参与了七项事件。第一项,第二项没什么好说的,为PMKS启动做准备,我们直接从第三步开始分析。

4.1 调用PKMS main方法初始化PackageManagerService

第三步静态调用PackageManagerService的main方法,创建PKMS实例。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public static PackageManagerService main(Context context, Installer installer,
boolean factoryTest, boolean onlyCore) {
// Self-check for initial settings.
//检查编译相关的系统属性
PackageManagerServiceCompilerMapping.checkProperties();

//传入install和onlyCore来实例化PKMS
PackageManagerService m = new PackageManagerService(context, installer,
factoryTest, onlyCore);
m.enableSystemUserPackages();
//将PKMS服务增加到SM中
ServiceManager.addService("package", m);
final PackageManagerNative pmn = m.new PackageManagerNative();
ServiceManager.addService("package_native", pmn);
return m;
}

从上面方法中可以看到主要完成三件事情,最重要的是第二步传入install和onlyCore来实例化PKMS。

PKMS构造方法非常长,有1100多行代码,我们先看图,然后逐步分析各个阶段完成的任务。

PMKS构造方法.png

总览PKMS构造方法,在构造方法中完成了五个任务,其中还有两把锁需要说明一下。

两个重要的锁(mInstallLock、mPackages):
mInstallLock :用来保护所有安装apk的访问权限,此操作通常涉及繁重的磁盘数据读写等操作,并且是单线程操作,故有时候会处理很慢,此锁不会在已经持有mPackages锁的情况下获得,反之,在已经持有mInstallLock锁的情况下,立即获取mPackages是安全的。
mPackages:用来解析内存中所有apk的package信息及相关状态。

下面开始分阶段分析PKMS构造方法。

4.1.1 启动PKMS阶段

(1) 构造 DisplayMetrics ,保存分辨率等相关信息;
(2) 创建Installer对象,与installd交互;
(3) 创建mPermissionManager对象,进行权限管理;
(4) 构造Settings类,保存安装包信息,清除路径不存在的孤立应用,主要涉及/data/system/目录的
packages.xml,packages-backup.xml,packages.list,packages-stopped.xml,packages-stoppedbackup.xml等文件。
(5) 构造PackageDexOptimizer及DexManager类,处理dex优化;
(6) 创建SystemConfig实例,获取系统配置信息,配置共享lib库;
(7) 创建PackageManager的handler线程,循环处理外部安装相关消息。

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
145
146
147
148
149
150
151
152
public PackageManagerService(Context context, Installer installer,
boolean factoryTest, boolean onlyCore) {
LockGuard.installLock(mPackages, LockGuard.INDEX_PACKAGES);
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "create package manager");
//============================第一阶段:启动PKMS================================
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_START,
SystemClock.uptimeMillis());

mContext = context;
mFactoryTest = factoryTest;
mOnlyCore = onlyCore;
//创建DisplayMetrics保存分辨率相关的信息
mMetrics = new DisplayMetrics();
mInstaller = installer;

// Create sub-components that provide services / data. Order here is important.
synchronized (mInstallLock) {
synchronized (mPackages) {
// Expose private service for system components to use.
// 暴露私有服务给系统组件用
LocalServices.addService(
PackageManagerInternal.class, new PackageManagerInternalImpl());
sUserManager = new UserManagerService(context, this,
new UserDataPreparer(mInstaller, mInstallLock, mContext, mOnlyCore), mPackages);
mComponentResolver = new ComponentResolver(sUserManager,
LocalServices.getService(PackageManagerInternal.class),
mPackages);
//创建权限管理器
mPermissionManager = PermissionManagerService.create(context,
mPackages /*externalLock*/);
// getDefaultPermissionGrantPolicy权限分组,只要用户同意一个权限,就赋予那一组权限。
// 读取根|vendor|odm|oem|product/etc/default-permissions目录下的xml文件,给应用赋默认权限。
mDefaultPermissionPolicy = mPermissionManager.getDefaultPermissionGrantPolicy();
//创建Settings,保存安装包信息,清除路径不存在的孤立应用,主要涉及/data/system/目录的
//packages.xml,packages-backup.xml,packages.list,packages-stopped.xml,packages-stoppedbackup.
//xml等文件。
mSettings = new Settings(Environment.getDataDirectory(),
mPermissionManager.getPermissionSettings(), mPackages);
}
}
//将对应的UID赋值保存在settings中
mSettings.addSharedUserLPw("android.uid.system", Process.SYSTEM_UID,
ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.phone", RADIO_UID,
ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.log", LOG_UID,
ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.nfc", NFC_UID,
ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.bluetooth", BLUETOOTH_UID,
ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.shell", SHELL_UID,
ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.se", SE_UID,
ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.networkstack", NETWORKSTACK_UID,
ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);

......

mPackageDexOptimizer = new PackageDexOptimizer(installer, mInstallLock, context,
"*dexopt*");
mDexManager = new DexManager(mContext, this, mPackageDexOptimizer, installer, mInstallLock);
mArtManagerService = new ArtManagerService(mContext, this, installer, mInstallLock);
mMoveCallbacks = new MoveCallbacks(FgThread.get().getLooper());

mViewCompiler = new ViewCompiler(mInstallLock, mInstaller);

mOnPermissionChangeListeners = new OnPermissionChangeListeners(
FgThread.get().getLooper());

getDefaultDisplayMetrics(context, mMetrics);

Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "get system config");
// 创建SystemConfig实例,获取系统配置信息,配置共享lib库;
// 配置文件目录:/etc/sysconfig、/etc/permissions
// /vendor/etc/sysconfig、/vendor/etc/permissions
// /odm/etc/sysconfig、/odm/etc/permissions
// /oem/etc/sysconfig、/oem/etc/permissions
// /product/etc/sysconfig、/product/etc/permissions
SystemConfig systemConfig = SystemConfig.getInstance();
mAvailableFeatures = systemConfig.getAvailableFeatures();
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);

mProtectedPackages = new ProtectedPackages(mContext);

mApexManager = new ApexManager(context);
synchronized (mInstallLock) {
// writer
synchronized (mPackages) {
//创建PackageManager的handler线程,循环处理外部安装相关消息。
//就是一个HandlerThread,在子线程处理事件
mHandlerThread = new ServiceThread(TAG,
Process.THREAD_PRIORITY_BACKGROUND, true /*allowIo*/);
mHandlerThread.start();
// 应用handler
mHandler = new PackageHandler(mHandlerThread.getLooper());
// 进程记录handler
mProcessLoggingHandler = new ProcessLoggingHandler();
//将应用处理handler设置一个看门狗,超时时间10分钟,如果超时会重启这个线程,该线程里面会执行应用安装,拷贝,写设置等操作
Watchdog.getInstance().addThread(mHandler, WATCHDOG_TIMEOUT);
mInstantAppRegistry = new InstantAppRegistry(this);
// 共享lib库配置,将共享库
ArrayMap<String, SystemConfig.SharedLibraryEntry> libConfig
= systemConfig.getSharedLibraries();
final int builtInLibCount = libConfig.size();
for (int i = 0; i < builtInLibCount; i++) {
String name = libConfig.keyAt(i);
SystemConfig.SharedLibraryEntry entry = libConfig.valueAt(i);
addBuiltInSharedLibraryLocked(entry.filename, name);
}

......
// 读取安装相关SELinux策略
SELinuxMMAC.readInstallPolicy();

Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "loadFallbacks");
// 返回栈加载,读取/system/framework/framework-res.apk中的com.android.internal.R.raw.fallback_categories属性
FallbackCategoryProvider.loadFallbacks();
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);

Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "read user settings");
//读取并解析/data/system下的XML文件
mFirstBoot = !mSettings.readLPw(sUserManager.getUsers(false));
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);

// Clean up orphaned packages for which the code path doesn't exist
// and they are an update to a system app - caused by bug/32321269
// 清理代码路径不存在的孤立软件包
final int packageSettingCount = mSettings.mPackages.size();
for (int i = packageSettingCount - 1; i >= 0; i--) {
PackageSetting ps = mSettings.mPackages.valueAt(i);
if (!isExternal(ps) && (ps.codePath == null || !ps.codePath.exists())
&& mSettings.getDisabledSystemPkgLPr(ps.name) != null) {
mSettings.mPackages.removeAt(i);
mSettings.enableSystemPackageLPw(ps.name);
}
}

if (!mOnlyCore && mFirstBoot) {
// 如果是首次启动,也不是CORE应用,则拷贝预编译的DEX文件
requestCopyPreoptedFiles();
}

String customResolverActivityName = Resources.getSystem().getString(
R.string.config_customResolverActivity);
if (!TextUtils.isEmpty(customResolverActivityName)) {
mCustomResolverComponentName = ComponentName.unflattenFromString(
customResolverActivityName);
}
......// 以下是第二阶段代码
}

重点看一下主流程中mSettings.readLPw方法,读取上一次系统运行扫描过的包信息。

在看这个方法之前,需要先看看Settings中一些目录配置。首先看看构造方法。

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
Settings(File dataDir, PermissionSettings permission,
Object lock) {
mLock = lock;
mPermissions = permission;
mRuntimePermissionsPersistence = new RuntimePermissionPersistence(mLock);

mSystemDir = new File(dataDir, "system");
mSystemDir.mkdirs();
FileUtils.setPermissions(mSystemDir.toString(),
FileUtils.S_IRWXU|FileUtils.S_IRWXG
|FileUtils.S_IROTH|FileUtils.S_IXOTH,
-1, -1);
//读packages.xml
mSettingsFilename = new File(mSystemDir, "packages.xml");
mBackupSettingsFilename = new File(mSystemDir, "packages-backup.xml");
mPackageListFilename = new File(mSystemDir, "packages.list");
FileUtils.setPermissions(mPackageListFilename, 0640, SYSTEM_UID, PACKAGE_INFO_GID);

final File kernelDir = new File("/config/sdcardfs");
mKernelMappingFilename = kernelDir.exists() ? kernelDir : null;

// Deprecated: Needed for migration
mStoppedPackagesFilename = new File(mSystemDir, "packages-stopped.xml");
mBackupStoppedPackagesFilename = new File(mSystemDir, "packages-stopped-backup.xml");
}

从代码中可以看到一共有五个文件需要处理:

(1) “/data/system/packages.xml” 所有安装app信息
(2) “/data/system/packages-backup.xml” 所有安装app信息之备份的信息记录
(3) “/data/system/packages.list” 所有安装app信息
(4) “/data/system/packages-stopped.xml” 所有强制停止app信息
(5) “/data/system/packages-stopped-backup.xml” 所有强制停止app信息之备份的信息记录

以上5个文件共分为三组,简单的作用描述如下:

  • packages.xml:PKMS 扫描完目标文件夹后会创建该文件。当系统进行程序安装、卸载和更新等操作时,均会更新该文件。该文件保存了系统中与 package 相关的一些信息。
  • packages.list:描述系统中存在的所有非系统自带的 APK 的信息。当这些程序有变动时,PKMS 就会更新该文件。
  • packages-stopped.xml:从系统自带的设置程序中进入应用程序页面,然后在选择强制停止(ForceStop)某个应用时,系统会将该应用的相关信息记录到此文件中。也就是该文件保存系统中被用户强制停止的 Package 的信息。
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
boolean readLPw(@NonNull List<UserInfo> users) {
FileInputStream str = null;
// 处理备份package文件,防止package.xml被破坏了解析问题。

mPendingPackages.clear();
mPastSignatures.clear();
mKeySetRefs.clear();
mInstallerPackages.clear();

try {
// 确保"/data/system/packages.xml"存在
if (str == null) {
if (!mSettingsFilename.exists()) {
mReadMessages.append("No settings file found\n");
PackageManagerService.reportSettingsProblem(Log.INFO,
"No settings file; creating initial state");
// It's enough to just touch version details to create them
// with default values
findOrCreateVersion(StorageManager.UUID_PRIVATE_INTERNAL).forceCurrent();
findOrCreateVersion(StorageManager.UUID_PRIMARY_PHYSICAL).forceCurrent();
return false;
}
str = new FileInputStream(mSettingsFilename);
}
// 解析"/data/system/packages.xml"
XmlPullParser parser = Xml.newPullParser();
parser.setInput(str, StandardCharsets.UTF_8.name());

......
String tagName = parser.getName();
if (tagName.equals("package")) {
readPackageLPw(parser); // 解析package节点
} else if (tagName.equals("permissions")) {
mPermissions.readPermissions(parser); // 解析permissions节点,将系统应用权限读到mPermissions中,以后其他应用设置shareduid就可以共享这些权限。
} else if (tagName.equals("permission-trees")) {
mPermissions.readPermissionTrees(parser);
} else if (tagName.equals("shared-user")) {
//创建 SharedUserSetting 对象并添加到 Settings 的成员变量 mSharedUsers 中,在 Android 系统中,多个 package 通过设置 sharedUserId 属性可以运行在同一个进程,共享同一个 UID
readSharedUserLPw(parser);
} else if (tagName.equals("preferred-packages")) {
// no longer used.
} else if (tagName.equals("preferred-activities")) {
// Upgrading from old single-user implementation;

...... // 以上都是解析package.xml各个标签

// If the build is setup to drop runtime permissions
// on update drop the files before loading them.
// 开发阶段可以将该配置设置成true,取消所有用户的运行时权限校验。
if (PackageManagerService.CLEAR_RUNTIME_PERMISSIONS_ON_UPGRADE) {
final VersionInfo internal = getInternalVersion();
if (!Build.FINGERPRINT.equals(internal.fingerprint)) {
for (UserInfo user : users) {
mRuntimePermissionsPersistence.deleteUserRuntimePermissionsFile(user.id);
}
}
}

/*
* Make sure all the updated system packages have their shared users
* associated with them.
*/
// 确保所有更新的系统包都有与其关联的共享用户
final Iterator<PackageSetting> disabledIt = mDisabledSysPackages.values().iterator();
while (disabledIt.hasNext()) {
final PackageSetting disabledPs = disabledIt.next();
final Object id = getSettingLPr(disabledPs.appId);
if (id != null && id instanceof SharedUserSetting) {
disabledPs.sharedUser = (SharedUserSetting) id;
}
}
.......

return true;
}
4.1.2 扫描系统中的包

(1) 从init.rc中获取环境变量BOOTCLASSPATH和SYSTEMSERVERCLASSPATH;
(2) 对于旧版本升级的情况,将安装时获取权限变更为运行时申请权限;
(3) 扫描system/vendor/product/odm/oem等目录的priv-app、app、overlay包;
(4) 清除安装时临时文件以及其他不必要的信息。

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
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
public PackageManagerService(Context context, Installer installer,
boolean factoryTest, boolean onlyCore) {
// 记录开机扫描时间
long startTime = SystemClock.uptimeMillis();
//============第二阶段会扫描系统中所有应用,并且加入到对应的列表中============
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SYSTEM_SCAN_START,
startTime);

//从init.rc中获取环境变量
final String bootClassPath = System.getenv("BOOTCLASSPATH");
final String systemServerClassPath = System.getenv("SYSTEMSERVERCLASSPATH");
......

//获取system/framework目录
File frameworkDir = new File(Environment.getRootDirectory(), "framework");

// 获取内部版本
final VersionInfo ver = mSettings.getInternalVersion();
// 判断fingerprint是否有更新
mIsUpgrade = !Build.FINGERPRINT.equals(ver.fingerprint);
if (mIsUpgrade) {
logCriticalInfo(Log.INFO,
"Upgrading from " + ver.fingerprint + " to " + Build.FINGERPRINT);
}

// when upgrading from pre-M, promote system app permissions from install to runtime
//对于Android M之前版本升级上来的情况,需将系统应用程序权限从安装升级到运行时
mPromoteSystemApps =
mIsUpgrade && ver.sdkVersion <= Build.VERSION_CODES.LOLLIPOP_MR1;

// When upgrading from pre-N, we need to handle package extraction like first boot,
// as there is no profiling data available.
// 对于Android N之前版本升级上来的情况,需像首次启动一样处理package
mIsPreNUpgrade = mIsUpgrade && ver.sdkVersion < Build.VERSION_CODES.N;

mIsPreNMR1Upgrade = mIsUpgrade && ver.sdkVersion < Build.VERSION_CODES.N_MR1;
mIsPreQUpgrade = mIsUpgrade && ver.sdkVersion < Build.VERSION_CODES.Q;

int preUpgradeSdkVersion = ver.sdkVersion;

// save off the names of pre-existing system packages prior to scanning; we don't
// want to automatically grant runtime permissions for new system apps
// 在扫描之前保存预先存在的系统package的名称,不希望自动为新系统应用授予运行时权限
if (mPromoteSystemApps) {
Iterator<PackageSetting> pkgSettingIter = mSettings.mPackages.values().iterator();
while (pkgSettingIter.hasNext()) {
PackageSetting ps = pkgSettingIter.next();
if (isSystemApp(ps)) {
mExistingSystemPackages.add(ps.name);
}
}
}

// 解析package的缓存路径
mCacheDir = preparePackageParserCache();

// Set flag to monitor and not change apk file paths when
// scanning install directories.
// 设置flag,不在扫描安装时更改文件路径
int scanFlags = SCAN_BOOTING | SCAN_INITIAL;
if (mIsUpgrade || mFirstBoot) {
scanFlags = scanFlags | SCAN_FIRST_BOOT_OR_UPGRADE;
}

// Collect vendor/product/product_services overlay packages. (Do this before scanning
// any apps.)
// For security and version matching reason, only consider overlay packages if they
// reside in the right directory.
// 首先扫描vendor/product/product_services的overlay目录下的apk
// 路径包括:/vendor/overlay、/product/overlay、/product_services/overlay、/odm/overlay、/oem/overlay、 /system/framework、/system/priv-app、/system/app、/vendor/priv-app、/vendor/app、/odm/priv-app、/odm/app、/oem/app、/oem/priv-app、/product/priv-app、/product/app、/product_services/priv-app、/product_services/app、/product_services/priv-app
//扫描传入目录的所有apk文件
scanDirTracedLI(new File(VENDOR_OVERLAY_DIR),
mDefParseFlags
| PackageParser.PARSE_IS_SYSTEM_DIR,
scanFlags
| SCAN_AS_SYSTEM
| SCAN_AS_VENDOR,
0);
......

mParallelPackageParserCallback.findStaticOverlayPackages();

// Find base frameworks (resource packages without code).
// 扫描fw中的apk,
scanDirTracedLI(frameworkDir,
mDefParseFlags
| PackageParser.PARSE_IS_SYSTEM_DIR,
scanFlags
| SCAN_NO_DEX
| SCAN_AS_SYSTEM
| SCAN_AS_PRIVILEGED,
0);
if (!mPackages.containsKey("android")) {
throw new IllegalStateException(
"Failed to load frameworks package; check log for warnings");
}

// Collect privileged system packages.
// 扫描特权目录下的apk,即/system/framework/framework-res.apk,这个包里面全是资源文件,没有代码
final File privilegedAppDir = new File(Environment.getRootDirectory(), "priv-app");
scanDirTracedLI(privilegedAppDir,
mDefParseFlags
| PackageParser.PARSE_IS_SYSTEM_DIR,
scanFlags
| SCAN_AS_SYSTEM
| SCAN_AS_PRIVILEGED,
0);

// Collect ordinary system packages.
//扫描system/app目录下的apk
final File systemAppDir = new File(Environment.getRootDirectory(), "app");
scanDirTracedLI(systemAppDir,
mDefParseFlags
| PackageParser.PARSE_IS_SYSTEM_DIR,
scanFlags
| SCAN_AS_SYSTEM,
0);

...... // 这之间的代码都是扫描上面列出来目录中的apk

// Prune any system packages that no longer exist.
final List<String> possiblyDeletedUpdatedSystemApps = new ArrayList<>();
// Stub packages must either be replaced with full versions in the /data
// partition or be disabled.
final List<String> stubSystemApps = new ArrayList<>();
// 删掉不存在的package
if (!mOnlyCore) {
// do this first before mucking with mPackages for the "expecting better" case
final Iterator<PackageParser.Package> pkgIterator = mPackages.values().iterator();
while (pkgIterator.hasNext()) {
final PackageParser.Package pkg = pkgIterator.next();
if (pkg.isStub) {
stubSystemApps.add(pkg.packageName);
}
}

final Iterator<PackageSetting> psit = mSettings.mPackages.values().iterator();
while (psit.hasNext()) {
PackageSetting ps = psit.next();

/*
* If this is not a system app, it can't be a
* disable system app.
*/
// 如果不是系统应用,则不被允许disable
if ((ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0) {
continue;
}

/*
* If the package is scanned, it's not erased.
*/
// 如果应用被扫描,则不允许被删除
final PackageParser.Package scannedPkg = mPackages.get(ps.name);
if (scannedPkg != null) {
/*
* If the system app is both scanned and in the
* disabled packages list, then it must have been
* added via OTA. Remove it from the currently
* scanned package so the previously user-installed
* application can be scanned.
*/
//如果扫描出来的系统apk在禁用列表中,它将从扫描列表中删除,只能通过OTA再次添加进来
if (mSettings.isDisabledSystemPackageLPr(ps.name)) {
....
removePackageLI(scannedPkg, true);
mExpectingBetter.put(ps.name, ps.codePath);
}

continue;
}

if (!mSettings.isDisabledSystemPackageLPr(ps.name)) {
psit.remove();
logCriticalInfo(Log.WARN, "System package " + ps.name
+ " no longer exists; it's data will be wiped");
// Actual deletion of code and data will be handled by later
// reconciliation step
} else {
// we still have a disabled system package, but, it still might have
// been removed. check the code path still exists and check there's
// still a package. the latter can happen if an OTA keeps the same
// code path, but, changes the package name.
final PackageSetting disabledPs =
mSettings.getDisabledSystemPkgLPr(ps.name);
if (disabledPs.codePath == null || !disabledPs.codePath.exists()
|| disabledPs.pkg == null) {
//如果系统应用路径,apk包,代码都不存在的话,就把这个应用加到删除系统应用的列表中
possiblyDeletedUpdatedSystemApps.add(ps.name);
} else {
// We're expecting that the system app should remain disabled, but add
// it to expecting better to recover in case the data version cannot
// be scanned.
//如果apk还在,希望系统应用程序应该保持禁用状态,但是如果数据版本无法被扫描,则添加到恢复列表中。
mExpectingBetter.put(disabledPs.name, disabledPs.codePath);
}
}
}
}

//delete tmp files
// 删除临时文件
deleteTempPackageFiles();

final int cachedSystemApps = PackageParser.sCachedPackageReadCount.get();

// Remove any shared userIDs that have no associated packages
// 删除没有关联的UID标识
mSettings.pruneSharedUsersLPw();
final long systemScanTime = SystemClock.uptimeMillis() - startTime;
final int systemPackagesCount = mPackages.size();
Slog.i(TAG, "Finished scanning system apps. Time: " + systemScanTime
+ " ms, packageCount: " + systemPackagesCount
+ " , timePerPackage: "
+ (systemPackagesCount == 0 ? 0 : systemScanTime / systemPackagesCount)
+ " , cached: " + cachedSystemApps);
if (mIsUpgrade && systemPackagesCount > 0) {
MetricsLogger.histogram(null, "ota_package_manager_system_app_avg_scan_time",
((int) systemScanTime) / systemPackagesCount);
}

......// 以下代码是第三阶段
}
4.1.3 扫描data目录下的apk

对于不仅仅解析核心应用的情况下,还处理data目录的应用信息,及时更新,祛除不必要的数据。

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
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
public PackageManagerService(Context context, Installer installer,
boolean factoryTest, boolean onlyCore) {
if (!mOnlyCore) {
//=======================第三阶段:扫描data目录下的数据(用户自己安装的apk)扫描/data/app目录
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START,
SystemClock.uptimeMillis());
scanDirTracedLI(sAppInstallDir, 0, scanFlags | SCAN_REQUIRE_KNOWN, 0);

// Remove disable package settings for updated system apps that were
// removed via an OTA. If the update is no longer present, remove the
// app completely. Otherwise, revoke their system privileges.
// 这个for循环,移除通过OTA删除的更新系统应用程序的禁用package设置
// 如果更新不再存在,则完全删除该应用。否则,撤消其系统权限
for (int i = possiblyDeletedUpdatedSystemApps.size() - 1; i >= 0; --i) {
final String packageName = possiblyDeletedUpdatedSystemApps.get(i);
final PackageParser.Package pkg = mPackages.get(packageName);
final String msg;

// remove from the disabled system list; do this first so any future
// scans of this package are performed without this state
mSettings.removeDisabledSystemPackageLPw(packageName);

if (pkg == null) {
// should have found an update, but, we didn't; remove everything
msg = "Updated system package " + packageName
+ " no longer exists; removing its data";
// Actual deletion of code and data will be handled by later
// reconciliation step
// 如果进入到这个if语句,说明被更新的APK不存在了,需要清理他的data数据,但是这里原生什么也没做,意思是没有真正删除原来被禁用apk的数据
} else {
// found an update; revoke system privileges
msg = "Updated system package " + packageName
+ " no longer exists; rescanning package on data";

// NOTE: We don't do anything special if a stub is removed from the
// system image. But, if we were [like removing the uncompressed
// version from the /data partition], this is where it'd be done.

// remove the package from the system and re-scan it without any
// special privileges
// 删除应用包,并且重新扫描原来的APK路径
removePackageLI(pkg, true);
try {
final File codePath = new File(pkg.applicationInfo.getCodePath());
scanPackageTracedLI(codePath, 0, scanFlags, 0, null);
} catch (PackageManagerException e) {
Slog.e(TAG, "Failed to parse updated, ex-system package: "
+ e.getMessage());
}
}

// one final check. if we still have a package setting [ie. it was
// previously scanned and known to the system], but, we don't have
// a package [ie. there was an error scanning it from the /data
// partition], completely remove the package data.
// 删除应用包的数据
final PackageSetting ps = mSettings.mPackages.get(packageName);
if (ps != null && mPackages.get(packageName) == null) {
removePackageDataLIF(ps, null, null, 0, false);

}
logCriticalInfo(Log.WARN, msg);
}

/*
* Make sure all system apps that we expected to appear on
* the userdata partition actually showed up. If they never
* appeared, crawl back and revive the system version.
*/
// 确保所有在/data分区的应用都是真实存在的
for (int i = 0; i < mExpectingBetter.size(); i++) {
final String packageName = mExpectingBetter.keyAt(i);
if (!mPackages.containsKey(packageName)) {
final File scanFile = mExpectingBetter.valueAt(i);

logCriticalInfo(Log.WARN, "Expected better " + packageName
+ " but never showed up; reverting to system");

final @ParseFlags int reparseFlags;
final @ScanFlags int rescanFlags;
// 确保检查的apk在如上第二步列出的路径中
if (FileUtils.contains(privilegedAppDir, scanFile)) {
reparseFlags =
mDefParseFlags |
PackageParser.PARSE_IS_SYSTEM_DIR;
rescanFlags =
scanFlags
| SCAN_AS_SYSTEM
| SCAN_AS_PRIVILEGED;
} else if (FileUtils.contains(systemAppDir, scanFile)) {
......
}

//通过以上判断之后,该应用确实真实可用的,然后就把他从不可用列表中移除
mSettings.enableSystemPackageLPw(packageName);

try {
//重新扫描这个apk文件
scanPackageTracedLI(scanFile, reparseFlags, rescanFlags, 0, null);
} catch (PackageManagerException e) {
Slog.e(TAG, "Failed to parse original system package: "
+ e.getMessage());
}
}
}

// Uncompress and install any stubbed system applications.
// This must be done last to ensure all stubs are replaced or disabled.
// 解压缩并安装任何存根系统应用程序。这必须最后完成,以确保所有存根被替换或禁用。
installSystemStubPackages(stubSystemApps, scanFlags);

final int cachedNonSystemApps = PackageParser.sCachedPackageReadCount.get()
- cachedSystemApps;
// 打印扫描所有data分区中APK的时间
final long dataScanTime = SystemClock.uptimeMillis() - systemScanTime - startTime;
final int dataPackagesCount = mPackages.size() - systemPackagesCount;
Slog.i(TAG, "Finished scanning non-system apps. Time: " + dataScanTime
+ " ms, packageCount: " + dataPackagesCount
+ " , timePerPackage: "
+ (dataPackagesCount == 0 ? 0 : dataScanTime / dataPackagesCount)
+ " , cached: " + cachedNonSystemApps);
if (mIsUpgrade && dataPackagesCount > 0) {
MetricsLogger.histogram(null, "ota_package_manager_data_app_avg_scan_time",
((int) dataScanTime) / dataPackagesCount);
}
}
mExpectingBetter.clear();

// Resolve the storage manager.
// 获取StorageManager的包名
mStorageManagerPackage = getStorageManagerPackageName();

// Resolve protected action filters. Only the setup wizard is allowed to
// have a high priority filter for these actions.
// 处理受保护的action过滤器。只允许setup wizard(开机向导)为这些action设置高优先级过滤器
mSetupWizardPackage = getSetupWizardPackageName();
mComponentResolver.fixProtectedFilterPriorities();

mSystemTextClassifierPackage = getSystemTextClassifierPackageName();

mWellbeingPackage = getWellbeingPackageName();
mDocumenterPackage = getDocumenterPackageName();
mConfiguratorPackage =
mContext.getString(R.string.config_deviceConfiguratorPackageName);
mAppPredictionServicePackage = getAppPredictionServicePackageName();
mIncidentReportApproverPackage = getIncidentReportApproverPackageName();

// Now that we know all of the shared libraries, update all clients to have
// the correct library paths.
// 由于更新了所有共享库,更新所有的应用以确保这些更新库之后运行起没有问题
updateAllSharedLibrariesLocked(null, Collections.unmodifiableMap(mPackages));

for (SharedUserSetting setting : mSettings.getAllSharedUsersLPw()) {
// NOTE: We ignore potential failures here during a system scan (like
// the rest of the commands above) because there's precious little we
// can do about it. A settings error is reported, though.
// 调整Abis让所有拥有sharedUserId的app都能调用
final List<String> changedAbiCodePath =
adjustCpuAbisForSharedUserLPw(setting.packages, null /*scannedPackage*/);
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) {
}
}
}
// Adjust seInfo to ensure apps which share a sharedUserId are placed in the same
// SELinux domain.
// 调整seInfo,确保拥有一个sharedUserId的app属于SeLinux的域中
setting.fixSeInfoLocked();
}

// Now that we know all the packages we are keeping,
// read and update their last usage times.
// 更新用户的使用时间,数据埋点功能采集用户使用数据可以用到
mPackageUsage.read(mPackages);
mCompilerStats.read();
}
4.1.4 扫描结束,更新package.xml

(1) sdk版本变更,更新权限;
(2) OTA升级后首次启动,清除不必要的缓存数据;
(3) 权限等默认项更新完后,清理相关数据;
(4) 更新package.xml

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
public PackageManagerService(Context context, Installer installer,
boolean factoryTest, boolean onlyCore) {
//========================第四阶段:扫描结束,更新package.xml=======================
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SCAN_END,
SystemClock.uptimeMillis());
Slog.i(TAG, "Time to scan packages: "
+ ((SystemClock.uptimeMillis()-startTime)/1000f)
+ " seconds");

// If the platform SDK has changed since the last time we booted,
// we need to re-grant app permission to catch any new ones that
// appear. This is really a hack, and means that apps can in some
// cases get permissions that the user didn't initially explicitly
// allow... it would be nice to have some better way to handle
// this situation.
// 如果platform sdk从上次启动之后更新了,那需要重新给app更新权限
final boolean sdkUpdated = (ver.sdkVersion != mSdkVersion);
if (sdkUpdated) {
Slog.i(TAG, "Platform changed from " + ver.sdkVersion + " to "
+ mSdkVersion + "; regranting permissions for internal storage");
}
// 更新权限
mPermissionManager.updateAllPermissions(
StorageManager.UUID_PRIVATE_INTERNAL, sdkUpdated, mPackages.values(),
mPermissionCallback);
ver.sdkVersion = mSdkVersion;

// If this is the first boot or an update from pre-M, and it is a normal
// boot, then we need to initialize the default preferred apps across
// all defined users.
// 如果是第一次启动,或者从Android M之前升级上来的系统,并且启动正常。
// 那需要在所有已定义的用户中初始化默认的首选应用程序
if (!onlyCore && (mPromoteSystemApps || mFirstBoot)) {
for (UserInfo user : sUserManager.getUsers(true)) {
mSettings.applyDefaultPreferredAppsLPw(user.id);
primeDomainVerificationsLPw(user.id);
}
}

// Prepare storage for system user really early during boot,
// since core system apps like SettingsProvider and SystemUI
// can't wait for user to start
// 为系统用户准备内存,因为SettingsProvider和SystemUI不可能等待用户去启动
final int storageFlags;
if (StorageManager.isFileEncryptedNativeOrEmulated()) {
storageFlags = StorageManager.FLAG_STORAGE_DE;
} else {
storageFlags = StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE;
}
......

// If this is first boot after an OTA, and a normal boot, then
// we need to clear code cache directories.
// Note that we do *not* clear the application profiles. These remain valid
// across OTAs and are used to drive profile verification (post OTA) and
// profile compilation (without waiting to collect a fresh set of profiles).
// 如果是在OTA之后首次启动,并且正常启动,那需要清除代码缓存目录,但不清除应用程序配置文件
if (mIsUpgrade && !onlyCore) {
Slog.i(TAG, "Build fingerprint changed; clearing code caches");
for (int i = 0; i < mSettings.mPackages.size(); i++) {
final PackageSetting ps = mSettings.mPackages.valueAt(i);
if (Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, ps.volumeUuid)) {
// No apps are running this early, so no need to freeze
clearAppDataLIF(ps.pkg, UserHandle.USER_ALL,
FLAG_STORAGE_DE | FLAG_STORAGE_CE | FLAG_STORAGE_EXTERNAL
| Installer.FLAG_CLEAR_CODE_CACHE_ONLY);
}
}
ver.fingerprint = Build.FINGERPRINT;
}

// Grandfather existing (installed before Q) non-system apps to hide
// their icons in launcher.
// 安装Android-Q前的非系统应用程序在Launcher中隐藏他们的图标
if (!onlyCore && mIsPreQUpgrade) {
Slog.i(TAG, "Whitelisting all existing apps to hide their icons");
int size = mSettings.mPackages.size();
for (int i = 0; i < size; i++) {
final PackageSetting ps = mSettings.mPackages.valueAt(i);
if ((ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) != 0) {
continue;
}
ps.disableComponentLPw(PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME,
UserHandle.USER_SYSTEM);
}
}

// clear only after permissions and other defaults have been updated
// mExistingSystemPackages是在收到OTA之前跟踪现有的系统包列表,他将被清空,当权限和默认设置被更新处理完成之后
mExistingSystemPackages.clear();
mPromoteSystemApps = false;

// All the changes are done during package scanning.
ver.databaseVersion = Settings.CURRENT_DATABASE_VERSION;

// can downgrade to reader
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "write settings");
// 将settings中的数据写回到package.xml中
mSettings.writeLPr();
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
4.1.5 GC回收内存
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
public PackageManagerService(Context context, Installer installer,
boolean factoryTest, boolean onlyCore) {
//=========================第五阶段:GC回收内存================================
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_READY,
SystemClock.uptimeMillis());

if (!mOnlyCore) {
mRequiredVerifierPackage = getRequiredButNotReallyRequiredVerifierLPr();
mRequiredInstallerPackage = getRequiredInstallerLPr();
mRequiredUninstallerPackage = getRequiredUninstallerLPr();
mIntentFilterVerifierComponent = getIntentFilterVerifierComponentNameLPr();
if (mIntentFilterVerifierComponent != null) {
mIntentFilterVerifier = new IntentVerifierProxy(mContext,
mIntentFilterVerifierComponent);
} else {
mIntentFilterVerifier = null;
}
mServicesSystemSharedLibraryPackageName = getRequiredSharedLibraryLPr(
PackageManager.SYSTEM_SHARED_LIBRARY_SERVICES,
SharedLibraryInfo.VERSION_UNDEFINED);
mSharedSystemSharedLibraryPackageName = getRequiredSharedLibraryLPr(
PackageManager.SYSTEM_SHARED_LIBRARY_SHARED,
SharedLibraryInfo.VERSION_UNDEFINED);
} else {
mRequiredVerifierPackage = null;
mRequiredInstallerPackage = null;
mRequiredUninstallerPackage = null;
mIntentFilterVerifierComponent = null;
mIntentFilterVerifier = null;
mServicesSystemSharedLibraryPackageName = null;
mSharedSystemSharedLibraryPackageName = null;
}
// PermissionController hosts default permission granting and role management, so it's a
// critical part of the core system.
// PermissionController主持这授予默认权限和角色管理,他是系统的关键组成部分
mRequiredPermissionControllerPackage = getRequiredPermissionControllerLPr();

// Initialize InstantAppRegistry's Instant App list for all users.
final int[] userIds = UserManagerService.getInstance().getUserIds();
for (PackageParser.Package pkg : mPackages.values()) {
if (pkg.isSystem()) {
continue;
}
for (int userId : userIds) {
final PackageSetting ps = (PackageSetting) pkg.mExtras;
if (ps == null || !ps.getInstantApp(userId) || !ps.getInstalled(userId)) {
continue;
}
mInstantAppRegistry.addInstantAppLPw(userId, ps.appId);
}
}

mInstallerService = new PackageInstallerService(context, this, mApexManager);
final Pair<ComponentName, String> instantAppResolverComponent =
getInstantAppResolverLPr();
if (instantAppResolverComponent != null) {
if (DEBUG_INSTANT) {
Slog.d(TAG, "Set ephemeral resolver: " + instantAppResolverComponent);
}
mInstantAppResolverConnection = new InstantAppResolverConnection(
mContext, instantAppResolverComponent.first,
instantAppResolverComponent.second);
mInstantAppResolverSettingsComponent =
getInstantAppResolverSettingsLPr(instantAppResolverComponent.first);
} else {
mInstantAppResolverConnection = null;
mInstantAppResolverSettingsComponent = null;
}
updateInstantAppInstallerLocked(null);

// Read and update the usage of dex files.
// Do this at the end of PM init so that all the packages have their
// data directory reconciled.
// At this point we know the code paths of the packages, so we can validate
// the disk file and build the internal cache.
// The usage file is expected to be small so loading and verifying it
// should take a fairly small time compare to the other activities (e.g. package
// scanning).
// 阅读并更新dex文件的用法
// 在PM init结束时执行此操作,以便所有程序包都已协调其数据目录
// 此时知道了包的代码路径,因此可以验证磁盘文件并构建内部缓存
// 使用文件预计很小,因此与其他活动(例如包扫描)相比,加载和验证它应该花费相当小的时间
final Map<Integer, List<PackageInfo>> userPackages = new HashMap<>();
for (int userId : userIds) {
userPackages.put(userId, getInstalledPackages(/*flags*/ 0, userId).getList());
}
mDexManager.load(userPackages);
if (mIsUpgrade) {
MetricsLogger.histogram(null, "ota_package_manager_init_time",
(int) (SystemClock.uptimeMillis() - startTime));
}
} // synchronized (mPackages)
} // synchronized (mInstallLock)

mModuleInfoProvider = new ModuleInfoProvider(mContext, this);

// Now after opening every single application zip, make sure they
// are all flushed. Not really needed, but keeps things nice and
// tidy.
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "GC");
// 打开应用之后,及时回收处理
Runtime.getRuntime().gc();
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);

// The initial scanning above does many calls into installd while
// holding the mPackages lock, but we're mostly interested in yelling
// once we have a booted system.
// 上面的初始扫描在持有mPackage锁的同时对installd进行了多次调用
mInstaller.setWarnIfHeld(mPackages);

PackageParser.readConfigUseRoundIcon(mContext.getResources());

mServiceStartWithDelay = SystemClock.uptimeMillis() + (60 * 1000L);

Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}

4.2 APK的扫描

PKMS的构造函数中调用了 scanDirTracedLI方法 来扫描某个目录的apk文件。

Android10.0 和 其他低版本扫描的路径是不一样的:Android 10.0中,PKMS主要扫描以下路径的APK信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
vendor/overlay 系统的APP类别
/product/overlay 系统的APP类别
/product_services/overlay 系统的APP类别
/odm/overlay 系统的APP类别
/oem/overlay 系统的APP类别
/system/framework 系统的APP类别
/system/priv-app 系统的APP类别
/system/app 系统的APP类别
/vendor/priv-app 系统的APP类别
/vendor/app 系统的APP类别
/odm/priv-app 系统的APP类别
/odm/app 系统的APP类别
/oem/app 系统的APP类别
/oem/priv-app 系统的APP类别
/product/priv-app 系统的APP类别
/product/app 系统的APP类别
/product_services/priv-app 系统的APP类别
/product_services/app 系统的APP类别
/product_services/priv-app 系统的APP类别

APK扫描.png

扫描包的流程如上图所示,通过扫描apk,最终将扫描过的apk封装成Package对象。下面我们来看一下PKMS是如何完成扫描的。

4.2.1 scanDirLI
1
2
3
4
5
6
7
8
9
private void scanDirTracedLI(File scanDir, final int parseFlags, int scanFlags, long currentTime) {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanDir [" + scanDir.getAbsolutePath() + "]");
try {
// 透传调用
scanDirLI(scanDir, parseFlags, scanFlags, currentTime);
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
}
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
private void scanDirLI(File scanDir, int parseFlags, int scanFlags, long currentTime) {
......
// 创建并行扫描解析器
try (ParallelPackageParser parallelPackageParser = new ParallelPackageParser(
mSeparateProcesses, mOnlyCore, mMetrics, mCacheDir,
mParallelPackageParserCallback)) {
// Submit files for parsing in parallel
int fileCount = 0;
for (File file : files) {
final boolean isPackage = (isApkFile(file) || file.isDirectory())
&& !PackageInstallerService.isStageName(file.getName());
if (!isPackage) {
// Ignore entries which are not packages
continue;
}
//将APK文件交给submit准备解析
parallelPackageParser.submit(file, parseFlags);
fileCount++;
}

// Process results one by one
for (; fileCount > 0; fileCount--) {
ParallelPackageParser.ParseResult parseResult = parallelPackageParser.take();
Throwable throwable = parseResult.throwable;
int errorCode = PackageManager.INSTALL_SUCCEEDED;

if (throwable == null) {
// TODO(toddke): move lower in the scan chain
// Static shared libraries have synthetic package names
if (parseResult.pkg.applicationInfo.isStaticSharedLibrary()) {
renameStaticSharedLibraryPackage(parseResult.pkg);
}
try {
// 调用 scanPackageChildLI 方法扫描一个特定的 apk 文件
// 该类的实例代表一个 APK 文件,所以它就是和 apk 文件对应的数据结构
scanPackageChildLI(parseResult.pkg, parseFlags, scanFlags,
currentTime, null);
} catch (PackageManagerException e) {
errorCode = e.error;
Slog.w(TAG, "Failed to scan " + parseResult.scanFile + ": " + e.getMessage());
}
} else if (throwable instanceof PackageParser.PackageParserException) {
PackageParser.PackageParserException e = (PackageParser.PackageParserException)
throwable;
errorCode = e.error;
Slog.w(TAG, "Failed to parse " + parseResult.scanFile + ": " + e.getMessage());
} else {
throw new IllegalStateException("Unexpected exception occurred while parsing "
+ parseResult.scanFile, throwable);
}

// Delete invalid userdata apps
// 如果是非系统 apk 并且解析失败
if ((scanFlags & SCAN_AS_SYSTEM) == 0 &&
errorCode != PackageManager.INSTALL_SUCCEEDED) {
logCriticalInfo(Log.WARN,
"Deleting invalid package at " + parseResult.scanFile);
// 非系统 Package 扫描失败,删除文件
removeCodePathLI(parseResult.scanFile);
}
}
}
}
4.2.2 parallelPackageParser.submit
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
public void submit(File scanFile, int parseFlags) {
mService.submit(() -> {
ParseResult pr = new ParseResult();
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parallel parsePackage [" + scanFile + "]");
try {
PackageParser pp = new PackageParser();
pp.setSeparateProcesses(mSeparateProcesses);
pp.setOnlyCoreApps(mOnlyCore);
pp.setDisplayMetrics(mMetrics);
pp.setCacheDir(mCacheDir);
pp.setCallback(mPackageParserCallback);
pr.scanFile = scanFile;
// 解析APK
// 并把parsePackage()与pp 赋值ParseResult,用于后面的调用
pr.pkg = parsePackage(pp, scanFile, parseFlags);
} catch (Throwable e) {
pr.throwable = e;
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
try {
// 把扫描路径中的APK等内容,放入队列mQueue
mQueue.put(pr);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
// Propagate result to callers of take().
// This is helpful to prevent main thread from getting stuck waiting on
// ParallelPackageParser to finish in case of interruption
mInterruptedInThread = Thread.currentThread().getName();
}
});
}
1
2
3
4
5
protected PackageParser.Package parsePackage(PackageParser packageParser, File scanFile,
int parseFlags) throws PackageParser.PackageParserException {
// 解析package
return packageParser.parsePackage(scanFile, parseFlags, true /* useCaches */);
}

把扫描路径中的APK等内容,放入队列mQueue,并把parsePackage() pp 赋给ParseResult,用于后面的调用。

通过 PackageParser.parsePackage 进行apk解析:

  • 如果传入的packageFile是目录, 调用parseClusterPackage()解析
  • 如果传入的packageFile是APK文件, 调用parseMonolithicPackage()解析
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public Package parsePackage(File packageFile, int flags, boolean useCaches)
throws PackageParserException {
Package parsed = useCaches ? getCachedResult(packageFile, flags) : null;
if (parsed != null) {
return parsed;
}

if (packageFile.isDirectory()) {
parsed = parseClusterPackage(packageFile, flags);
} else {
//去解析manifest了
parsed = parseMonolithicPackage(packageFile, flags);
}

cacheResult(packageFile, flags, parsed);

return parsed;
}
4.2.3 parseMonolithicPackage解析manifest
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public Package parseMonolithicPackage(File apkFile, int flags) throws PackageParserException {
final AssetManager assets = newConfiguredAssetManager();
// 里面会收集签名信息
final PackageLite lite = parseMonolithicPackageLite(apkFile, flags);
if (mOnlyCoreApps) {
if (!lite.coreApp) {
throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
"Not a coreApp: " + apkFile);
}
}

try {
//解析Manifest
final Package pkg = parseBaseApk(apkFile, assets, flags);
pkg.setCodePath(apkFile.getAbsolutePath());
pkg.setUse32bitAbi(lite.use32bitAbi);
return pkg;
} finally {
IoUtils.closeQuietly(assets);
}
}

4.2.3.1 收集签名

1
2
3
4
5
6
7
8
9
private static PackageLite parseMonolithicPackageLite(File packageFile, int flags)
throws PackageParserException {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parseApkLite");
//在parseApkLite这个方法里面解析manifest
final ApkLite baseApk = parseApkLite(packageFile, flags);
final String packagePath = packageFile.getAbsolutePath();
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
return new PackageLite(packagePath, baseApk, null, null, null, null, null, null);
}
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
public static ApkLite parseApkLite(File apkFile, int flags)
throws PackageParserException {

......

parser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME);

final Signature[] signatures;
final Certificate[][] certificates;
if ((flags & PARSE_COLLECT_CERTIFICATES) != 0) {
// TODO: factor signature related items out of Package object
final Package tempPkg = new Package((String) null);
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "collectCertificates");
try {
// 收集签名信息,将证书和签名保存再tempPkg中
collectCertificates(tempPkg, apkFile, flags);
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
signatures = tempPkg.mSignatures;
certificates = tempPkg.mCertificates;
} else {
signatures = null;
certificates = null;
}

final AttributeSet attrs = parser;
return parseApkLite(apkPath, parser, attrs, flags, signatures, certificates);

} catch (XmlPullParserException | IOException | RuntimeException e) {
....
}
}

4.2.3.2 parseBaseApk解析manifest

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
private Package parseBaseApk(File apkFile, AssetManager assets, int flags)
throws PackageParserException {
final String apkPath = apkFile.getAbsolutePath();

String volumeUuid = null;
if (apkPath.startsWith(MNT_EXPAND)) {
final int end = apkPath.indexOf('/', MNT_EXPAND.length());
volumeUuid = apkPath.substring(MNT_EXPAND.length(), end);
}

mParseError = android.content.pm.PackageManager.INSTALL_SUCCEEDED;
mArchiveSourcePath = apkFile.getAbsolutePath();

if (DEBUG_JAR) Slog.d(TAG, "Scanning base APK: " + apkPath);

// 加载Apk到AssetManager中
final int cookie = loadApkIntoAssetManager(assets, apkPath, flags);

Resources res = null;
XmlResourceParser parser = null;
try {
res = new Resources(assets, mMetrics, null);
// 获得一个 XML 资源解析对象,该对象解析的是 APK 中的 AndroidManifest.xml 文件。
parser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME);

final String[] outError = new String[1];
//再调用重载函数parseBaseApk()最终到parseBaseApkCommon(),解析AndroidManifest.xml后得到一个Package对象。
final Package pkg = parseBaseApk(apkPath, res, parser, flags, outError);
if (pkg == null) {
throw new PackageParserException(mParseError,
apkPath + " (at " + parser.getPositionDescription() + "): " + outError[0]);
}

pkg.setVolumeUuid(volumeUuid);
pkg.setApplicationVolumeUuid(volumeUuid);
pkg.setBaseCodePath(apkPath);
pkg.setSignatures(null);

return pkg;

} catch (PackageParserException e) {
throw e;
} catch (Exception e) {
throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
"Failed to read manifest from " + apkPath, e);
} finally {
IoUtils.closeQuietly(parser);
}
}

PackageParser.parseBaseApkCommon 从AndroidManifest.xml中获取标签名,解析标签中的各个item的内容,存入Package对象中。例如:获取标签 “application”、”permission”、”package”、”manifest”

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
private Package parseBaseApkCommon(Package pkg, Set<String> acceptedTags, Resources res,
XmlResourceParser parser, int flags, String[] outError) throws XmlPullParserException,
IOException {
......

//拿到AndroidManifest.xml 中的sharedUserId, 一般情况下有“android.uid.system”等信息
String str = sa.getNonConfigurationString(
com.android.internal.R.styleable.AndroidManifest_sharedUserId, 0);
......
int outerDepth = parser.getDepth();
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
&& (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
continue;
}
//通过tagName一个一个解析标签里面的内容
String tagName = parser.getName();

......
//如果读到AndroidManifest.xml中的tag是"application",执行parseBaseApplication()进行解析
if (tagName.equals(TAG_APPLICATION)) {
if (foundApp) {
if (RIGID_PARSER) {
outError[0] = "<manifest> has more than one <application>";
mParseError = android.content.pm.PackageManager. INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
return null;
} else {
Slog.w(TAG, "<manifest> has more than one <application>");
XmlUtils.skipCurrentTag(parser);
continue;
}
}

foundApp = true;
// 解析四大组件,解析完成了之后交给package对象
// 解析"application"的信息,赋值给pkg
if (!parseBaseApplication(pkg, res, parser, flags, outError)) {
return null;
}
}
......
else if (tagName.equals(TAG_PERMISSION)) {
// 找到权限标签,进行"permission"的解析
if (!parsePermission(pkg, res, parser, outError)) {
return null;
}
}
......
}

上面解析AndroidManifest.xml,会得到 “application”、”overlay”、”permission”、”usespermission” 等信息 。

我们下面就针对”application”进行展开分析一下,进入 PackageParser.parseBaseApplication()函数。

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
private boolean parseBaseApplication(Package owner, Resources res,
XmlResourceParser parser, int flags, String[] outError)
throws XmlPullParserException, IOException {
......
// 解析各个android:xxx标志位
......
// 获取"application"子标签的标签内容
String tagName = parser.getName();
if (tagName.equals("activity")) {
// 解析activity标签
Activity a = parseActivity(owner, res, parser, flags, outError, false,
owner.baseHardwareAccelerated);
if (a == null) {
mParseError = android.content.pm.PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
return false;
}
// 接入到Package的activities列表中。
owner.activities.add(a);

} else if (tagName.equals("receiver")) {
Activity a = parseActivity(owner, res, parser, flags, outError, true, false);
if (a == null) {
mParseError = android.content.pm.PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
return false;
}

owner.receivers.add(a);

} else if (tagName.equals("service")) {
Service s = parseService(owner, res, parser, flags, outError);
if (s == null) {
mParseError = android.content.pm.PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
return false;
}

owner.services.add(s);

} else if (tagName.equals("provider")) {
Provider p = parseProvider(owner, res, parser, flags, outError);
if (p == null) {
mParseError = android.content.pm.PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
return false;
}

owner.providers.add(p);

}
......
}

在 PackageParser 扫描完一个 APK 后,此时系统已经根据该 APK 中 AndroidManifest.xml,创建了一个完整的 Package 对象。

4.2.3 APK扫描小结

第一步:扫描APK,解析AndroidManifest.xml文件,得到清单文件各个标签内容
第二步:解析清单文件到的信息由 Package 保存。从该类的成员变量可看出,和 Android 四大组件相关的信息分别由 activites、receivers、providers、services 保存,由于一个 APK 可声明多个组件,因此activites 和 receivers等均声明为 ArrayList 。

4.3 APK的安装

APK安装流程.png

Apk的安装分为三个步骤:

  • 把Apk的信息通过IO流的形式写入到PackageInstaller.Session中
  • 调用PackageInstaller.Session的commit方法, 把Apk的信息交给PKMS处理
  • 进行Apk的Copy操作, 进行安装

Apk安装时序图.png

当用户点击xxx.apk之后,APK的安装时序图如上,主要涉及到PackageInstaller.apk和PKMS交互。需要做包安装拦截就是在PackageInstaller里面做。

点击一个apk后,会弹出安装界面,点击确定按钮后,会进入PackageInstallerActivity 的 bindUi() 中的mAlert点击事件, 弹出的安装界面底部显示的是一个diaglog,主要由bindUi构成,上面有 ”取消“ 和 ”安装“ 两个按钮,点击安装后 调用startInstall()进行安装:

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
// packages/apps/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java
//安装还是取消安装
private void bindUi(int layout, boolean enableOk) {
setContentView(layout);

mOk = (Button) findViewById(R.id.ok_button);
mCancel = (Button)findViewById(R.id.cancel_button);
mOk.setOnClickListener(this); //回调中调用开始安装
mCancel.setOnClickListener(this);

mEnableOk = enableOk;
mOk.setEnabled(enableOk);

PackageUtil.initSnippetForNewApp(this, mAppSnippet, R.id.app_snippet);
}

public void onClick(View v) {
if (v == mOk) {
if (mOk.isEnabled()) {
if (mOkCanInstall || mScrollView == null) {
if (mSessionId != -1) {
mInstaller.setPermissionsResult(mSessionId, true);
finish();
} else {
// 开始安装
startInstall();
}
} else {
mScrollView.pageScroll(View.FOCUS_DOWN);
}
}
}
......
}
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
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);
// 设置Intent中的class为 InstallInstalling,用来进行Activity跳转
// class InstallInstalling extends AlertActivity,下面会分析InstallInstalling
newIntent.setClass(this, InstallInstalling.class);
String installerPackageName = getIntent().getStringExtra(
Intent.EXTRA_INSTALLER_PACKAGE_NAME);
if (mOriginatingURI != null) {
newIntent.putExtra(Intent.EXTRA_ORIGINATING_URI, mOriginatingURI);
}
if (mReferrerURI != null) {
newIntent.putExtra(Intent.EXTRA_REFERRER, mReferrerURI);
}
if (mOriginatingUid != PackageInstaller.SessionParams.UID_UNKNOWN) {
newIntent.putExtra(Intent.EXTRA_ORIGINATING_UID, mOriginatingUid);
}
if (installerPackageName != null) {
newIntent.putExtra(Intent.EXTRA_INSTALLER_PACKAGE_NAME,
installerPackageName);
}
if (getIntent().getBooleanExtra(Intent.EXTRA_RETURN_RESULT, false)) {
newIntent.putExtra(Intent.EXTRA_RETURN_RESULT, true);
newIntent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
}
if(localLOGV) Log.i(TAG, "downloaded app uri="+mPackageURI);
// 启动android.intent.extra.INSTALLER_PACKAGE_NAME InstallInstalling Activity
startActivity(newIntent);
finish();
}

跳到InstallInstalling这个activity

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
// packages/apps/PackageInstaller/src/com/android/packageinstaller/InstallInstalling.java
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

setContentView(R.layout.install_installing);

ApplicationInfo appInfo = getIntent()
.getParcelableExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO);
mPackageURI = getIntent().getData();

if ("package".equals(mPackageURI.getScheme())) {
try {
getPackageManager().installExistingPackage(appInfo.packageName);
launchSuccess();
} catch (PackageManager.NameNotFoundException e) {
launchFailure(PackageManager.INSTALL_FAILED_INTERNAL_ERROR, null);
}
} else {
// 根据mPackageURI创建一个对应的File
final File sourceFile = new File(mPackageURI.getPath());
PackageUtil.initSnippetForNewApp(this, PackageUtil.getAppSnippet(this, appInfo,
sourceFile), R.id.app_snippet);

// 第一步.如果savedInstanceState不为null,获取此前保存的mSessionId和mInstallId,其中mSessionId是安装包的会话id,mInstallId是等待的安装事件id
if (savedInstanceState != null) {
mSessionId = savedInstanceState.getInt(SESSION_ID);
mInstallId = savedInstanceState.getInt(INSTALL_ID);

// Reregister for result; might instantly call back if result was delivered while
// activity was destroyed
try {
// 第二步.根据mInstallId向InstallEventReceiver注册一个观察者,launchFinishBasedOnResult会接收到安装事件的回调,
//无论安装成功或者失败都会关闭当前的Activity(InstallInstalling)。如果savedInstanceState为null,代码的逻辑也是类似的
InstallEventReceiver.addObserver(this, mInstallId,
this::launchFinishBasedOnResult);
} catch (EventResultPersister.OutOfIdsException e) {
// Does not happen
}
} else {
// 第三步.创建SessionParams,它用来代表安装会话的参数,组装params
PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(
PackageInstaller.SessionParams.MODE_FULL_INSTALL);
params.installFlags = PackageManager.INSTALL_FULL_APP;
params.referrerUri = getIntent().getParcelableExtra(Intent.EXTRA_REFERRER);
params.originatingUri = getIntent()
.getParcelableExtra(Intent.EXTRA_ORIGINATING_URI);
params.originatingUid = getIntent().getIntExtra(Intent.EXTRA_ORIGINATING_UID,
UID_UNKNOWN);
params.installerPackageName =
getIntent().getStringExtra(Intent.EXTRA_INSTALLER_PACKAGE_NAME);

// 第四步.根据mPackageUri对包(APK)进行轻量级的解析,并将解析的参数赋值给SessionParams
File file = new File(mPackageURI.getPath());
try {
PackageParser.PackageLite pkg = PackageParser.parsePackageLite(file, 0);
params.setAppPackageName(pkg.packageName);
params.setInstallLocation(pkg.installLocation);
params.setSize(
PackageHelper.calculateInstalledSize(pkg, false, params.abiOverride));
} catch (PackageParser.PackageParserException e) {
Log.e(LOG_TAG, "Cannot parse package " + file + ". Assuming defaults.");
Log.e(LOG_TAG,
"Cannot calculate installed size " + file + ". Try only apk size.");
params.setSize(file.length());
} catch (IOException e) {
Log.e(LOG_TAG,
"Cannot calculate installed size " + file + ". Try only apk size.");
params.setSize(file.length());
}

try {
// 第五步.向InstallEventReceiver注册一个观察者返回一个新的mInstallId,
// 其中InstallEventReceiver继承自BroadcastReceiver,用于接收安装事件并回调给EventResultPersister。
mInstallId = InstallEventReceiver
.addObserver(this, EventResultPersister.GENERATE_NEW_ID,
this::launchFinishBasedOnResult);
} catch (EventResultPersister.OutOfIdsException e) {
launchFailure(PackageManager.INSTALL_FAILED_INTERNAL_ERROR, null);
}

try {
// 第六步.PackageInstaller的createSession方法内部会通过IPackageInstaller与PackageInstallerService进行进程间通信,
//最终调用的是PackageInstallerService的createSession方法来创建并返回mSessionId
mSessionId = getPackageManager().getPackageInstaller().createSession(params);
} catch (IOException e) {
launchFailure(PackageManager.INSTALL_FAILED_INTERNAL_ERROR, null);
}
}

mCancelButton = (Button) findViewById(R.id.cancel_button);

mCancelButton.setOnClickListener(view -> {
if (mInstallingTask != null) {
mInstallingTask.cancel(true);
}

if (mSessionId > 0) {
getPackageManager().getPackageInstaller().abandonSession(mSessionId);
mSessionId = 0;
}

setResult(RESULT_CANCELED);
finish();
});

mSessionCallback = new InstallSessionCallback();
}
}

以上第六步是重点 PackageInstaller 的 createSession()内部会通过IPackageInstaller与PackageInstallerService进行进程间通信,最终调用的是PackageInstallerService的createSession方法来创建并返回mSessionId 。

InstallInstalling.onResume方法中,调用onPostExecute()方法,将APK的信息通过IO流的形式写入到PackageInstaller.Session中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
protected void onResume() {
super.onResume();

// This is the first onResume in a single life of the activity
if (mInstallingTask == null) {
PackageInstaller installer = getPackageManager().getPackageInstaller();
PackageInstaller.SessionInfo sessionInfo = installer.getSessionInfo(mSessionId);

if (sessionInfo != null && !sessionInfo.isActive()) {
// 在AsyncTask中将APK以流的方式提交到session中然后会调用PackageInstaller.Session.commit()
// 最终会通过AIDL 调到PackageInstallerSession.commit()中
mInstallingTask = new InstallingAsyncTask();
mInstallingTask.execute();
} else {
// we will receive a broadcast when the install is finished
mCancelButton.setEnabled(false);
setFinishOnTouchOutside(false);
}
}
}
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
private final class InstallingAsyncTask extends AsyncTask<Void, Void,
PackageInstaller.Session> {
volatile boolean isDone;

@Override
protected PackageInstaller.Session doInBackground(Void... params) {
PackageInstaller.Session session;
try {
session = getPackageManager().getPackageInstaller().openSession(mSessionId);
} catch (IOException e) {
return null;
}

session.setStagingProgress(0);
// 第一步: doInBackground()会根据包(APK)的Uri,将APK的信息通过IO流的形式写入到PackageInstaller.Session中
try {
File file = new File(mPackageURI.getPath());

try (InputStream in = new FileInputStream(file)) {
long sizeBytes = file.length();
try (OutputStream out = session
.openWrite("PackageInstaller", 0, sizeBytes)) {
byte[] buffer = new byte[4096];
while (true) {
int numRead = in.read(buffer);

if (numRead == -1) {
session.fsync(out);
break;
}

if (isCancelled()) {
session.close();
break;
}
//将APK的信息通过IO流的形式写入到PackageInstaller.Session中
out.write(buffer, 0, numRead);
if (sizeBytes > 0) {
float fraction = ((float) numRead / (float) sizeBytes);
session.addProgress(fraction);
}
}
}
}

return session;
} catch (IOException | SecurityException e) {
Log.e(LOG_TAG, "Could not write package", e);

session.close();

return null;
} finally {
synchronized (this) {
isDone = true;
notifyAll();
}
}
}

@Override
protected void onPostExecute(PackageInstaller.Session session) {
if (session != null) {
// 第二步:最后在onPostExecute()中 调用PackageInstaller.Session的commit方法,进行安装
Intent broadcastIntent = new Intent(BROADCAST_ACTION);
broadcastIntent.setPackage(
getPackageManager().getPermissionControllerPackageName());
broadcastIntent.putExtra(EventResultPersister.EXTRA_ID, mInstallId);

PendingIntent pendingIntent = PendingIntent.getBroadcast(
InstallInstalling.this,
mInstallId,
broadcastIntent,
PendingIntent.FLAG_UPDATE_CURRENT);
// 提交意图
// 调用PackageInstaller.Session的commit方法,进行安装
session.commit(pendingIntent.getIntentSender());
mCancelButton.setEnabled(false);
setFinishOnTouchOutside(false);
} else {
getPackageManager().getPackageInstaller().abandonSession(mSessionId);

if (!isCancelled()) {
launchFailure(PackageManager.INSTALL_FAILED_INVALID_APK, null);
}
}
}
}
1
2
3
4
5
6
7
8
9
10
// frameworks/base/core/java/android/content/pm/PackageInstaller.java
public void commit(@NonNull IntentSender statusReceiver) {
try {
// mSession的类型为IPackageInstallerSession,这说明要通过IPackageInstallerSession来进行进程间的通信,最终会调用PackageInstallerSession的commit方法,这样代码逻辑就到了Java框架层的。
// 调用IPackageInstallerSession的commit方法, 跨进程调用到PackageInstallerSession.commit()
mSession.commit(statusReceiver, false);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
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
// frameworks/base/services/core/java/com/android/server/pm/PackageInstallerSession.java
public void commit(@NonNull IntentSender statusReceiver, boolean forTransfer) {
if (mIsPerfLockAcquired && mPerfBoostInstall != null) {
mPerfBoostInstall.perfLockRelease();
mIsPerfLockAcquired = false;
}
if (hasParentSessionId()) {
throw new IllegalStateException(
"Session " + sessionId + " is a child of multi-package session "
+ mParentSessionId + " and may not be committed directly.");
}
// markAsCommitted检测session是否传输结束,传输结束了将包进行封存,不让修改了。
if (!markAsCommitted(statusReceiver, forTransfer)) {
return;
}
if (isMultiPackage()) {
final SparseIntArray remainingSessions = mChildSessionIds.clone();
final IntentSender childIntentSender =
new ChildStatusIntentReceiver(remainingSessions, statusReceiver)
.getIntentSender();
RuntimeException commitException = null;
boolean commitFailed = false;
for (int i = mChildSessionIds.size() - 1; i >= 0; --i) {
final int childSessionId = mChildSessionIds.keyAt(i);
try {
// commit all children, regardless if any of them fail; we'll throw/return
// as appropriate once all children have been processed
if (!mSessionProvider.getSession(childSessionId)
.markAsCommitted(childIntentSender, forTransfer)) {
commitFailed = true;
}
} catch (RuntimeException e) {
commitException = e;
}
}
if (commitException != null) {
throw commitException;
}
if (commitFailed) {
return;
}
}
// 发送MSG_COMMIT消息,处理此次commit的session
mHandler.obtainMessage(MSG_COMMIT).sendToTarget();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
 switch (msg.what) {
case MSG_COMMIT:
handleCommit(); // 处理commit
break;

private void handleCommit() {
......

// For a multiPackage session, read the child sessions
// outside of the lock, because reading the child
// sessions with the lock held could lead to deadlock
// (b/123391593).
List<PackageInstallerSession> childSessions = getChildSessions();

try {
synchronized (mLock) {
//最终调用installStage(),进入PKMS
commitNonStagedLocked(childSessions);
}
} catch (PackageManagerException e) {
......
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
// frameworks/base/services/core/java/com/android/server/pm/PackageInstallerSession.java
private void commitNonStagedLocked(List<PackageInstallerSession> childSessions)
throws PackageManagerException {
final PackageManagerService.ActiveInstallSession committingSession =
makeSessionActiveLocked();
if (committingSession == null) {
return;
}
......
// 提交session到PKMS中
mPm.installStage(committingSession);
}
}

通过跨进程进入到PKMS中,命令行安装也会调用到这里来,处理INIT_COPY消息。

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
// frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
void installStage(ActiveInstallSession activeInstallSession) {
......
// 创建了类型为INIT_COPY的消息
final Message msg = mHandler.obtainMessage(INIT_COPY);
// 创建InstallParams,它对应于包的安装数据
final InstallParams params = new InstallParams(activeInstallSession);
params.setTraceMethod("installStage").setTraceCookie(System.identityHashCode(params));
msg.obj = params;

......
// 将InstallParams通过消息发送出去。
mHandler.sendMessage(msg);
}

void doHandleMessage(Message msg) {
switch (msg.what) {
case INIT_COPY: {
HandlerParams params = (HandlerParams) msg.obj;
if (params != null) {
......
// HandlerParams.startCopy方法,完成apk拷贝工作
params.startCopy();
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
break;
}
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
// frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
// HandlerParams是PackageManagerService内部抽象类,具体实现类是MultiPackageInstallParams
private abstract class HandlerParams {
/** User handle for the user requesting the information or installation. */
......
final void startCopy() {
if (DEBUG_INSTALL) Slog.i(TAG, "startCopy " + mUser + ": " + this);
handleStartCopy(); // 开始拷贝
handleReturnCode(); // 处理拷贝结果
}

abstract void handleStartCopy();
abstract void handleReturnCode();
}

class MultiPackageInstallParams extends HandlerParams {

private int mRet = INSTALL_SUCCEEDED;
@NonNull
private final ArrayList<InstallParams> mChildParams;
@NonNull
private final Map<InstallArgs, Integer> mCurrentState;

@Override
void handleStartCopy() {
for (InstallParams params : mChildParams) {
// 调用InstallParams来调用远程方法以获取包信息并安装位置值。
// 如果需要,基于默认策略覆盖安装位置,然后基于安装位置创建安装参数。
params.handleStartCopy();
if (params.mRet != INSTALL_SUCCEEDED) {
mRet = params.mRet;
}
}
}

@Override
void handleReturnCode() {
for (InstallParams params : mChildParams) {
// 找到安装的位置之后,完成拷贝
params.handleReturnCode();
if (params.mRet != INSTALL_SUCCEEDED) {
mRet = params.mRet;
}
}
}
}
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
// frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java 内部类
class InstallParams extends HandlerParams {

public void handleStartCopy() {
// 读APK包,然后解析apk部分信息
pkgLite = PackageManagerServiceUtils.getMinimalPackageInfo(mContext,
origin.resolvedPath, installFlags, packageAbiOverride);

...... // 各种标志位判断

// Override with defaults if needed.
// 获取推荐的安装位置
loc = installLocationPolicy(pkgLite);
if (loc == PackageHelper.RECOMMEND_FAILED_VERSION_DOWNGRADE) {
ret = PackageManager.INSTALL_FAILED_VERSION_DOWNGRADE;
......
}
}

// 创建安装参数
final InstallArgs args = createInstallArgs(this);
mVerificationCompleted = true;
mEnableRollbackCompleted = true;
mArgs = args; // 此处注意赋值给全局变量mArgs,待会儿处理返回参数方法会用到这个参数

...... // 根据apk结果,设置返回参数,到时候处理返回结果会用到这个参数
mRet = ret;
}

void handleReturnCode() {
if (mVerificationCompleted && mEnableRollbackCompleted) {
......
if (mRet == PackageManager.INSTALL_SUCCEEDED) {
mRet = mArgs.copyApk(); // 拷贝apk
}
processPendingInstall(mArgs, mRet); // 处理拷贝结果
}
}
}

此处我们可以看到涉及到APK安装最核心的几个步骤:

  • 1.根据策略找到安装位置
  • 2.拷贝apk到指定位子
  • 3.处理拷贝结果,主要是分析安装状态,扫描apk包,验证apk包,提交和更新系统状态。

上面在handleStartCopy()方法中找到了安装的推荐位置。下面我们来看看apk拷贝过程apk验证过程

4.3.1 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
// frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java 内部类
class FileInstallArgs extends InstallArgs {

int copyApk() {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "copyApk");
try {
return doCopyApk();
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
}

private int doCopyApk() {
......
// 通过读流的方式拷贝package到目标位置,即/data/app
int ret = PackageManagerServiceUtils.copyPackage(
origin.file.getAbsolutePath(), codeFile);
if (ret != PackageManager.INSTALL_SUCCEEDED) {
Slog.e(TAG, "Failed to copy package");
return ret;
}
......
}
}

4.3.2 处理拷贝结果

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
// processPendingInstall -> processInstallRequestsAsync -> installPackagesTracedLI -> installPackagesLI
private void installPackagesLI(List<InstallRequest> requests) {
......
// 准备阶段:分析安装结果,解析包,并且做一些包验证相关的初始化操作
prepareResult = preparePackageLI(request.args, request.installResult);
} catch (PrepareFailure prepareFailure) {
......
// 扫描阶段:根据准备阶段收集的上下文查询已解析的包
final List<ScanResult> scanResults = scanPackageTracedLI(
prepareResult.packageToScan, prepareResult.parseFlags,
prepareResult.scanFlags, System.currentTimeMillis(),
request.args.user);
......
// 协调阶段:验证扫描包的上下文和系统的状态,确保安装成功
reconciledPackages = reconcilePackagesLocked(
reconcileRequest, mSettings.mKeySetManagerService);
......
// 提交结果阶段:提交所有扫描的包并更新系统状态。这是安装流程中唯一可以修改系统状态的地方,在此阶段之前必须确定所有可预测的错误。
commitPackagesLocked(commitRequest);
success = true;
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
}
// 成功安装后,在提交完成并释放包锁.
executePostCommitSteps(commitRequest);
}
......
}

executePostCommitSteps 安装APK,并为新的代码路径准备应用程序配置文件,并再次检查是否需要dex优化。

如果是直接安装新包,会为新的代码路径准备应用程序配置文件。
如果是替换安装:其主要过程为更新设置,清除原有的某些APP数据,重新生成相关的app数据目录等步骤,同时要区分系统应用替换和非系统应用替换。而安装新包:则直接更新设置,生成APP数据即可。

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
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;
//1)进行安装
prepareAppDataAfterInstallLIF(pkg);
//2)如果需要替换安装,则需要清楚原有的APP数据
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.
//3)为新的代码路径准备应用程序配置文件。这需要在调用dexopt之前完成,以便任何安装时配置文件都可以用于优化。
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.
//4)执行dex优化。只有不是instant app和debug app才做dex优化。
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);
// 执行dex优化
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
BackgroundDexOptService.notifyPackageChanged(packageName);
}
}
1
2
3
4
// 通过一系列的调用,最终会调用到[Installer.java] createAppData()进行安装,交给installed进程进行APK的安装
调用栈如下:
prepareAppDataAfterInstallLIF() -> prepareAppDataLIF() -> prepareAppDataLeafLIF() -> [Installer.java]
createAppData()
1
2
3
4
5
6
7
8
9
10
11
private void prepareAppDataAfterInstallLIF(PackageParser.Package pkg) {
......
UserManagerInternal umInternal = getUserManagerInternal();
for (UserInfo user : um.getUsers(false /* excludeDying */)) {
......
if (ps.getInstalled(user.id)) {
// TODO: when user data is locked, mark that we're still dirty
prepareAppDataLIF(pkg, user.id, flags);
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
// 验证目录是否存在,以及所有已安装应用的所有权和标签是否正确。如果所有权不匹配,将尝试通过擦除数据恢复系统应用程序;第三方应用程序数据保持不变。
private void prepareAppDataLIF(PackageParser.Package pkg, int userId, int flags) {
if (pkg == null) {
Slog.wtf(TAG, "Package was null!", new Throwable());
return;
}
prepareAppDataLeafLIF(pkg, userId, flags);
final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
for (int i = 0; i < childCount; i++) {
prepareAppDataLeafLIF(pkg.childPackages.get(i), userId, flags);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
private void prepareAppDataLeafLIF(PackageParser.Package pkg, int userId, int flags) {

......
try {
// 调用Installd守护进程的入口
ceDataInode = mInstaller.createAppData(volumeUuid, packageName, userId, flags,
appId, seInfo, app.targetSdkVersion);
} catch (InstallerException e) {
......
}
......
// 创建native库符号链接
prepareAppDataContentsLeafLIF(pkg, userId, flags);
}

Installer.createAppData 收尾工作,安装完成后,更新设置,更新安装锁等:

1
2
3
4
5
6
7
8
9
10
11
// frameworks/base/services/core/java/com/android/server/pm/Installer.java
public long createAppData(String uuid, String packageName, int userId, int flags, int appId,
String seInfo, int targetSdkVersion) throws InstallerException {
if (!checkBeforeRemote()) return -1;
try {
return mInstalld.createAppData(uuid, packageName, userId, flags, appId, seInfo,
targetSdkVersion);
} catch (Exception e) {
throw InstallerException.from(e);
}
}

4.3.3 APK安装小结

安装原理.png

5 Dex优化

在SystemServer启动引导服务的时候,如果不是核心服务应用,就会查看应用是否需要dex优化。

如果是系统更新,会将InstallerD优化后的dex文件拷贝到ab分区的对应目录。

5.1 拷贝包到AB分区对应目录

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// frameworks/base/services/java/com/android/server/SystemServer.java
private void startBootstrapServices() {
......
if (!mOnlyCore) {
boolean disableOtaDexopt = SystemProperties.getBoolean("config.disable_otadexopt",
false);
if (!disableOtaDexopt) {
traceBeginAndSlog("StartOtaDexOptService");
try {
Watchdog.getInstance().pauseWatchingCurrentThread("moveab");
// OTADexOpt(空中下载dex并优化,用于OTA升级)使能时,启动OTA升级服务
OtaDexoptService.main(mSystemContext, mPackageManagerService);
} catch (Throwable e) {
reportWtf("starting OtaDexOptService", e);
} finally {
Watchdog.getInstance().resumeWatchingCurrentThread("moveab");
traceEnd();
}
}
}
......
}
1
2
3
4
5
6
7
8
9
10
11
12
// frameworks/base/services/core/java/com/android/server/pm/OtaDexoptService.java
public static OtaDexoptService main(Context context,PackageManagerService packageManagerService) {
// 构建OtaDexoptService并且加入到SM中
OtaDexoptService ota = new OtaDexoptService(context, packageManagerService);
ServiceManager.addService("otadexopt", ota);

// Now it's time to check whether we need to move any A/B artifacts.
// 检查是否需要优化
ota.moveAbArtifacts(packageManagerService.mInstaller);

return ota;
}
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
private void moveAbArtifacts(Installer installer) {
if (mDexoptCommands != null) {
throw new IllegalStateException("Should not be ota-dexopting when trying to move.");
}

// 如果没有升级,直接跳过
if (!mPackageManagerService.isUpgrade()) {
Slog.d(TAG, "No upgrade, skipping A/B artifacts check.");
return;
}

// Look into all packages.
Collection<PackageParser.Package> pkgs = mPackageManagerService.getPackages();
int packagePaths = 0;
int pathsSuccessful = 0;
for (PackageParser.Package pkg : pkgs) {
if (pkg == null) {
continue;
}

// Does the package have code? If not, there won't be any artifacts.
// 如果apk只是资源文件,直接跳过
if (!PackageDexOptimizer.canOptimizePackage(pkg)) {
continue;
}
if (pkg.codePath == null) {
Slog.w(TAG, "Package " + pkg + " can be optimized but has null codePath");
continue;
}

// If the path is in /system, /vendor or /product, ignore. It will have been
// ota-dexopted into /data/ota and moved into the dalvik-cache already.
// 如果是/system、/vendor、/product目录下的应用不用做优化,因为已经在系统预编译的时候,编译到/data/dalvik-cache中了。
if (pkg.codePath.startsWith("/system") || pkg.codePath.startsWith("/vendor")
|| pkg.codePath.startsWith("/product")) {
continue;
}

final String[] instructionSets = getAppDexInstructionSets(pkg.applicationInfo);
// 获取代码的目录
final List<String> paths = pkg.getAllCodePathsExcludingResourceOnly();
final String[] dexCodeInstructionSets = getDexCodeInstructionSets(instructionSets);
for (String dexCodeInstructionSet : dexCodeInstructionSets) {
for (String path : paths) {
String oatDir = PackageDexOptimizer.getOatDir(new File(pkg.codePath)).
getAbsolutePath();

// TODO: Check first whether there is an artifact, to save the roundtrip time.

packagePaths++;
try {
// 将代码的目录转移到oatDir中。
installer.moveAb(path, dexCodeInstructionSet, oatDir);
pathsSuccessful++;
} catch (InstallerException e) {
}
}
}
}
Slog.i(TAG, "Moved " + pathsSuccessful + "/" + packagePaths);
}

5.2 dex优化

1
2
3
4
5
6
7
8
9
10
// startOtherServices()中
if (!mOnlyCore) {
traceBeginAndSlog("UpdatePackagesIfNeeded");
try {
mPackageManagerService.updatePackagesIfNeeded();
} catch (Throwable e) {
reportWtf("update packages", e);
}
traceEnd();
}

PKMS对APK进行dex优化,主要分为两部:

  • 将apk按照重要性进行排序
  • 调用InstallD执行dex优化
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
// frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
@Override
public void updatePackagesIfNeeded() {
enforceSystemOrRoot("Only the system can request package update");

// We need to re-extract after an OTA.
// 是否需要重新提取dex
boolean causeUpgrade = isUpgrade();

// First boot or factory reset.
// Note: we also handle devices that are upgrading to N right now as if it is their
// first boot, as they do not have profile data.
// 如果是第一次启动或者恢复出厂都会重新进行dex优化
boolean causeFirstBoot = isFirstBoot() || mIsPreNUpgrade;

// We need to re-extract after a pruned cache, as AoT-ed files will be out of date.
// 如果清空缓存之后也要重新提取dex
boolean causePrunedCache = VMRuntime.didPruneDalvikCache();
// 如果不是以上三个原因所致,直接返回,不做dex优化
if (!causeUpgrade && !causeFirstBoot && !causePrunedCache) {
return;
}

List<PackageParser.Package> pkgs;
synchronized (mPackages) {
// 按重要性对应用程序进行排序,以便进行dexopt排序。如果设备空间不足,重要的应用程序将获得更高的优先级。()
pkgs = PackageManagerServiceUtils.getPackagesForDexopt(mPackages.values(), this);
}

final long startTime = System.nanoTime();
final int[] stats = performDexOptUpgrade(pkgs, mIsPreNUpgrade /* showDialog */,
causeFirstBoot ? REASON_FIRST_BOOT : REASON_BOOT,
false /* bootComplete */);

final int elapsedTimeSeconds =
(int) TimeUnit.NANOSECONDS.toSeconds(System.nanoTime() - startTime);

MetricsLogger.histogram(mContext, "opt_dialog_num_dexopted", stats[0]);
MetricsLogger.histogram(mContext, "opt_dialog_num_skipped", stats[1]);
MetricsLogger.histogram(mContext, "opt_dialog_num_failed", stats[2]);
MetricsLogger.histogram(mContext, "opt_dialog_num_total", getOptimizablePackages().size());
MetricsLogger.histogram(mContext, "opt_dialog_time_s", elapsedTimeSeconds);
}
5.2.1 获取排序好的应用列表

getPackagesForDexopt()方法会拿到根据优先级排序好的应用列表,大的优先级如下:

  • AndroidManifest中配置了coreapp标签优先级 > system app >其他app

  • 在同一级别内部排序是按照LRU原则来排序的,按照最近使用过的app排在前列。

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
// frameworks/base/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
public static List<PackageParser.Package> getPackagesForDexopt(
Collection<PackageParser.Package> packages,
PackageManagerService packageManagerService) {
ArrayList<PackageParser.Package> remainingPkgs = new ArrayList<>(packages);
LinkedList<PackageParser.Package> result = new LinkedList<>();
ArrayList<PackageParser.Package> sortTemp = new ArrayList<>(remainingPkgs.size());

// Give priority to core apps.
// 对core app进行排序
applyPackageFilter((pkg) -> pkg.coreApp, result, remainingPkgs, sortTemp,
packageManagerService);

// Give priority to system apps that listen for pre boot complete.
// 对system app进行排序
Intent intent = new Intent(Intent.ACTION_PRE_BOOT_COMPLETED);
final ArraySet<String> pkgNames = getPackageNamesForIntent(intent, UserHandle.USER_SYSTEM);
applyPackageFilter((pkg) -> pkgNames.contains(pkg.packageName), result, remainingPkgs,
sortTemp, packageManagerService);

// Give priority to apps used by other apps.
// 对其他app进行排序
DexManager dexManager = packageManagerService.getDexManager();
applyPackageFilter((pkg) ->
dexManager.getPackageUseInfoOrDefault(pkg.packageName)
.isAnyCodePathUsedByOtherApps(),
result, remainingPkgs, sortTemp, packageManagerService);

// Filter out packages that aren't recently used, add all remaining apps.
// TODO: add a property to control this?
// 将列表中最近没有使用的应用移除,添加常驻app
Predicate<PackageParser.Package> remainingPredicate;
if (!remainingPkgs.isEmpty() && packageManagerService.isHistoricalPackageUsageAvailable()) {
if (DEBUG_DEXOPT) {
Log.i(TAG, "Looking at historical package use");
}
// Get the package that was used last.
PackageParser.Package lastUsed = Collections.max(remainingPkgs, (pkg1, pkg2) ->
Long.compare(pkg1.getLatestForegroundPackageUseTimeInMills(),
pkg2.getLatestForegroundPackageUseTimeInMills()));
if (DEBUG_DEXOPT) {
Log.i(TAG, "Taking package " + lastUsed.packageName + " as reference in time use");
}
long estimatedPreviousSystemUseTime =
lastUsed.getLatestForegroundPackageUseTimeInMills();
// Be defensive if for some reason package usage has bogus data.
if (estimatedPreviousSystemUseTime != 0) {
final long cutoffTime = estimatedPreviousSystemUseTime - SEVEN_DAYS_IN_MILLISECONDS;
remainingPredicate =
(pkg) -> pkg.getLatestForegroundPackageUseTimeInMills() >= cutoffTime;
} else {
// No meaningful historical info. Take all.
remainingPredicate = (pkg) -> true;
}
sortPackagesByUsageDate(remainingPkgs, packageManagerService);
} else {
// No historical info. Take all.
remainingPredicate = (pkg) -> true;
}
applyPackageFilter(remainingPredicate, result, remainingPkgs, sortTemp,
packageManagerService);

if (DEBUG_DEXOPT) {
Log.i(TAG, "Packages to be dexopted: " + packagesToString(result));
Log.i(TAG, "Packages skipped from dexopt: " + packagesToString(remainingPkgs));
}

return result;
}
5.2.2 执行优化

performDexOptUpgrade() 方法中对传入的需要优化的apk列表进行dex优化,然后返回优化过程中的统计数据结果。

统计结果包含:优化的apk数,跳过的apk数,优化失败的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
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
private int[] performDexOptUpgrade(List<PackageParser.Package> pkgs, boolean showDialog,
final int compilationReason, boolean bootComplete) {
......

// 遍历每一个apk
for (PackageParser.Package pkg : pkgs) {
numberOfPackagesVisited++;

boolean useProfileForDexopt = false;

if ((isFirstBoot() || isUpgrade()) && isSystemApp(pkg)) {
// Copy over initial preopt profiles since we won't get any JIT samples for methods
// that are already compiled.
// 拷贝预编译配置,因为不会对已经编译过的代码进行JIT采样
File profileFile = new File(getPrebuildProfilePath(pkg));
// Copy profile if it exists.
if (profileFile.exists()) {
try {
// We could also do this lazily before calling dexopt in
// PackageDexOptimizer to prevent this happening on first boot. The issue
// is that we don't have a good way to say "do this only once".
// 拷贝配置文件到InstallerD
if (!mInstaller.copySystemProfile(profileFile.getAbsolutePath(),
pkg.applicationInfo.uid, pkg.packageName,
ArtManager.getProfileName(null))) {
Log.e(TAG, "Installer failed to copy system profile!");
} else {
......
} else {
PackageSetting disabledPs = mSettings.getDisabledSystemPkgLPr(pkg.packageName);
// Handle compressed APKs in this path. Only do this for stubs with profiles to
// minimize the number off apps being speed-profile compiled during first boot.
// The other paths will not change the filter.
// 解压apk将配置文件拷贝到installD
if (disabledPs != null && disabledPs.pkg.isStub) {
.....
}
}
}

// 如果apk没有代码不进行优化
if (!PackageDexOptimizer.canOptimizePackage(pkg)) {
....
continue;
}
......
// 拼接优化参数执行dex优化
int primaryDexOptStaus = performDexOptTraced(new DexoptOptions(
pkg.packageName,
pkgCompilationReason,
dexoptFlags));

.....
}

return new int[] { numberOfPackagesOptimized, numberOfPackagesSkipped,
numberOfPackagesFailed };
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
private int performDexOptTraced(DexoptOptions options) {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "dexopt");
try {
return performDexOptInternal(options); // 透传调用
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
}

// Run dexopt on a given package. Returns true if dexopt did not fail, i.e.
// if the package can now be considered up to date for the given filter.
private int performDexOptInternal(DexoptOptions options) {
......
try {
synchronized (mInstallLock) {
return performDexOptInternalWithDependenciesLI(p, options);
}
} finally {
Binder.restoreCallingIdentity(callingId);
}
}
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
private int performDexOptInternalWithDependenciesLI(PackageParser.Package p,
DexoptOptions options) {
// 选择优化器
PackageDexOptimizer pdo = options.isForce()
? new PackageDexOptimizer.ForcedUpdatePackageDexOptimizer(mPackageDexOptimizer)
: mPackageDexOptimizer;

// 首先优化所有依赖库
Collection<PackageParser.Package> deps = findSharedNonSystemLibraries(p);
final String[] instructionSets = getAppDexInstructionSets(p.applicationInfo);
if (!deps.isEmpty()) {
DexoptOptions libraryOptions = new DexoptOptions(options.getPackageName(),
options.getCompilationReason(), options.getCompilerFilter(),
options.getSplitName(),
options.getFlags() | DexoptOptions.DEXOPT_AS_SHARED_LIBRARY);
for (PackageParser.Package depPackage : deps) {
// TODO: Analyze and investigate if we (should) profile libraries.
pdo.performDexOpt(depPackage, null /* sharedLibraries */, instructionSets,
getOrCreateCompilerPackageStats(depPackage),
mDexManager.getPackageUseInfoOrDefault(depPackage.packageName), libraryOptions);
}
}
// 优化dex
return pdo.performDexOpt(p, p.usesLibraryFiles, instructionSets,
getOrCreateCompilerPackageStats(p),
mDexManager.getPackageUseInfoOrDefault(p.packageName), options);
}
1
2
3
4
5
6
7
8
9
10
11
12
// frameworks/base/services/core/java/com/android/server/pm/PackageDexOptimizer.java
int performDexOpt(PackageParser.Package pkg, String[] sharedLibraries,
String[] instructionSets, CompilerStats.PackageStats packageStats,
PackageDexUsage.PackageUseInfo packageUseInfo, DexoptOptions options) {
.....
return performDexOptLI(pkg, sharedLibraries, instructionSets,
packageStats, packageUseInfo, options); // 透传调用
} finally {
releaseWakeLockLI(acquireTime);
}
}
}
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 int performDexOptLI(PackageParser.Package pkg, String[] sharedLibraries,
String[] targetInstructionSets, CompilerStats.PackageStats packageStats,
PackageDexUsage.PackageUseInfo packageUseInfo, DexoptOptions options) {
...... // 以上获取各种路径,classloader

int result = DEX_OPT_SKIPPED;
for (int i = 0; i < paths.size(); i++) {
......

// Append shared libraries with split dependencies for this split.
// 获取共享库路径
String path = paths.get(i);
if (options.getSplitName() != null) {
// We are asked to compile only a specific split. Check that the current path is
// what we are looking for.
if (!options.getSplitName().equals(new File(path).getName())) {
continue;
}
}

.....
for (String dexCodeIsa : dexCodeInstructionSets) {
// 对给定路径的dex进行优化
int newResult = dexOptPath(pkg, path, dexCodeIsa, compilerFilter,
profileUpdated, classLoaderContexts[i], dexoptFlags, sharedGid,
packageStats, options.isDowngrade(), profileName, dexMetadataPath,
options.getCompilationReason());
// The end result is:
// - FAILED if any path failed,
// - PERFORMED if at least one path needed compilation,
// - SKIPPED when all paths are up to date
if ((result != DEX_OPT_FAILED) && (newResult != DEX_OPT_SKIPPED)) {
result = newResult;
}
}
}
return result;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
private int dexOptPath(PackageParser.Package pkg, String path, String isa,
String compilerFilter, boolean profileUpdated, String classLoaderContext,
int dexoptFlags, int uid, CompilerStats.PackageStats packageStats, boolean downgrade,
String profileName, String dexMetadataPath, int compilationReason) {
....

// TODO: Consider adding 2 different APIs for primary and secondary dexopt.
// installd only uses downgrade flag for secondary dex files and ignores it for
// primary dex files.
// 调用到mInstalld.dexopt(),由InstallD守护进程对执行路径下的dex进行优化
mInstaller.dexopt(path, uid, pkg.packageName, isa, dexoptNeeded, oatDir, dexoptFlags,
compilerFilter, pkg.volumeUuid, classLoaderContext, pkg.applicationInfo.seInfo,
false /* downgrade*/, pkg.applicationInfo.targetSdkVersion,
profileName, dexMetadataPath,
getAugmentedReasonName(compilationReason, dexMetadataPath != null));

......
}

在installD守护进程中,最终会调到dexopt的dexopt()。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// frameworks/native/cmds/installd/InstalldNativeService.cpp
binder::Status InstalldNativeService::dexopt(const std::string& apkPath, int32_t uid,
const std::unique_ptr<std::string>& packageName, const std::string& instructionSet,
int32_t dexoptNeeded, const std::unique_ptr<std::string>& outputPath, int32_t dexFlags,
const std::string& compilerFilter, const std::unique_ptr<std::string>& uuid,
const std::unique_ptr<std::string>& classLoaderContext,
const std::unique_ptr<std::string>& seInfo, bool downgrade, int32_t targetSdkVersion,
const std::unique_ptr<std::string>& profileName,
const std::unique_ptr<std::string>& dexMetadataPath,
const std::unique_ptr<std::string>& compilationReason) {
.....
// 以上内容完成参数转换
int res = android::installd::dexopt(apk_path, uid, pkgname, instruction_set, dexoptNeeded,
oat_dir, dexFlags, compiler_filter, volume_uuid, class_loader_context, se_info,
downgrade, targetSdkVersion, profile_name, dm_path, compilation_reason, &error_msg);
return res ? error(res, error_msg) : ok();
}

下面就真正开始dex优化了!!!!

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
// frameworks/native/cmds/installd/dexopt.cpp
int dexopt(const char* dex_path, uid_t uid, const char* pkgname, const char* instruction_set,
int dexopt_needed, const char* oat_dir, int dexopt_flags, const char* compiler_filter,
const char* volume_uuid, const char* class_loader_context, const char* se_info,
bool downgrade, int target_sdk_version, const char* profile_name,
const char* dex_metadata_path, const char* compilation_reason, std::string* error_msg) {
...... // 各种参数校验

// Check if we're dealing with a secondary dex file and if we need to compile it.
// 检查我们是否正在处理一个辅助dex文件,以及是否需要编译它。
std::string oat_dir_str;
if (is_secondary_dex) {
if (process_secondary_dex_dexopt(dex_path, pkgname, dexopt_flags, volume_uuid, uid,
instruction_set, compiler_filter, &is_public, &dexopt_needed, &oat_dir_str,
downgrade, class_loader_context, error_msg)) {
......

// Open the input file.
// 读入待优化的dex文件
unique_fd input_fd(open(dex_path, O_RDONLY, 0));
......

// Create the output OAT file.
char out_oat_path[PKG_PATH_MAX];
// 创建输出优化后的dex文件
Dex2oatFileWrapper out_oat_fd = open_oat_out_file(dex_path, oat_dir, is_public, uid,
instruction_set, is_secondary_dex, out_oat_path);
......

// Open vdex files.
Dex2oatFileWrapper in_vdex_fd;
Dex2oatFileWrapper out_vdex_fd;
// 根据vdex条件打开vdex文件,条件:
// 1.如果读入的vdex文件和写入的vden文件是一样的,就不更新
// 2.如果bootimage变化了,才读入vdex,对于正在运行的进程,不进行vdex优化
if (!open_vdex_files_for_dex2oat(dex_path, out_oat_path, dexopt_needed, instruction_set,
is_public, uid, is_secondary_dex, profile_guided, &in_vdex_fd, &out_vdex_fd)) {
*error_msg = "Could not open vdex files.";
return -1;
}

.......

// Create a swap file if necessary.
unique_fd swap_fd = maybe_open_dexopt_swap_file(out_oat_path);

// Create the app image file if needed.
Dex2oatFileWrapper image_fd = maybe_open_app_image(
out_oat_path, generate_app_image, is_public, uid, is_secondary_dex);

// Open the reference profile if needed.
Dex2oatFileWrapper reference_profile_fd = maybe_open_reference_profile(
pkgname, dex_path, profile_name, profile_guided, is_public, uid, is_secondary_dex);

......

LOG(VERBOSE) << "DexInv: --- BEGIN '" << dex_path << "' ---";

pid_t pid = fork();
if (pid == 0) {
/* child -- drop privileges before continuing */
drop_capabilities(uid);

SetDex2OatScheduling(boot_complete);
if (flock(out_oat_fd.get(), LOCK_EX | LOCK_NB) != 0) {
PLOG(ERROR) << "flock(" << out_oat_path << ") failed";
_exit(DexoptReturnCodes::kFlock);
}
// 在子进程中进行优化
run_dex2oat(input_fd.get(),
out_oat_fd.get(),
in_vdex_fd.get(),
out_vdex_fd.get(),
image_fd.get(),
dex_path,
out_oat_path,
swap_fd.get(),
instruction_set,
compiler_filter,
debuggable,
boot_complete,
background_job_compile,
reference_profile_fd.get(),
class_loader_context,
target_sdk_version,
enable_hidden_api_checks,
generate_compact_dex,
dex_metadata_fd.get(),
compilation_reason);
} else {
int res = wait_child(pid);
if (res == 0) {
LOG(VERBOSE) << "DexInv: --- END '" << dex_path << "' (success) ---";
} else {
LOG(VERBOSE) << "DexInv: --- END '" << dex_path << "' --- status=0x"
<< std::hex << std::setw(4) << res << ", process failed";
*error_msg = format_dexopt_error(res, dex_path);
return res;
}
}

update_out_oat_access_times(dex_path, out_oat_path);

// We've been successful, don't delete output.
out_oat_fd.SetCleanup(false);
out_vdex_fd.SetCleanup(false);
image_fd.SetCleanup(false);
reference_profile_fd.SetCleanup(false);

return 0;
}
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
[[ noreturn ]]
static void run_dex2oat(int zip_fd, int oat_fd, int input_vdex_fd, int output_vdex_fd, int image_fd,
const char* input_file_name, const char* output_file_name, int swap_fd,
const char* instruction_set, const char* compiler_filter,
bool debuggable, bool post_bootcomplete, bool background_job_compile, int profile_fd,
const char* class_loader_context, int target_sdk_version, bool enable_hidden_api_checks,
bool generate_compact_dex, int dex_metadata_fd, const char* compilation_reason) {
static const unsigned int MAX_INSTRUCTION_SET_LEN = 7;

......

// If the runtime was requested to use libartd.so, we'll run dex2oatd, otherwise dex2oat.
const char* dex2oat_bin = "/system/bin/dex2oat";
constexpr const char* kDex2oatDebugPath = "/system/bin/dex2oatd";
// Do not use dex2oatd for release candidates (give dex2oat more soak time).
bool is_release = android::base::GetProperty("ro.build.version.codename", "") == "REL";
if (is_debug_runtime() || (background_job_compile && is_debuggable_build() && !is_release)) {
if (access(kDex2oatDebugPath, X_OK) == 0) {
dex2oat_bin = kDex2oatDebugPath;
}
}
...... // 装配各种参数

// 调用dex2oat 可执行文件进行优化
execv(dex2oat_bin, (char * const *)argv);
PLOG(ERROR) << "execv(" << dex2oat_bin << ") failed";
exit(DexoptReturnCodes::kDex2oatExec);
}

可以看到完成dex优化主要是调用dex2oat工具,配合各种参数完成的dex优化。具体配置的参数函数,此处就不深入了,再深入等需要做相关事情在具体分析。

6 磁盘维护

1
2
3
4
5
6
7
8
9
private void startOtherServices() {
traceBeginAndSlog("PerformFstrimIfNeeded");
try {
mPackageManagerService.performFstrimIfNeeded();
} catch (Throwable e) {
reportWtf("performing fstrim", e);
}
traceEnd();
}
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
public void performFstrimIfNeeded() {
enforceSystemOrRoot("Only the system can request fstrim");

// Before everything else, see whether we need to fstrim.
try {
IStorageManager sm = PackageHelper.getStorageManager();
if (sm != null) {
boolean doTrim = false;
final long interval = android.provider.Settings.Global.getLong(
mContext.getContentResolver(),
android.provider.Settings.Global.FSTRIM_MANDATORY_INTERVAL,
DEFAULT_MANDATORY_FSTRIM_INTERVAL);
// 判断裁剪内存时间是否超过阈值
if (interval > 0) {
final long timeSinceLast = System.currentTimeMillis() - sm.lastMaintenance();
if (timeSinceLast > interval) {
doTrim = true;
Slog.w(TAG, "No disk maintenance in " + timeSinceLast
+ "; running immediately");
}
}
if (doTrim) {
final boolean dexOptDialogShown;
synchronized (mPackages) {
dexOptDialogShown = mDexOptDialogShown;
}
if (!isFirstBoot() && dexOptDialogShown) {
try {
ActivityManager.getService().showBootMessage(
mContext.getResources().getString(
R.string.android_upgrading_fstrim), true);
} catch (RemoteException e) {
}
}
// 开始裁剪
sm.runMaintenance();
}
} else {
Slog.e(TAG, "storageManager service unavailable!");
}
} catch (RemoteException e) {
// Can't happen; StorageManagerService is local
}
}
1
2
3
4
5
6
7
8
9
// frameworks/base/services/core/java/com/android/server/StorageManagerService.java
public void runMaintenance() {
enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
runIdleMaintenance(null);
}

void runIdleMaintenance(Runnable callback) {
mHandler.sendMessage(mHandler.obtainMessage(H_FSTRIM, callback));
}

然后找H_FSTRIM这个消息,就可以找到裁剪内存的消息了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class StorageManagerServiceHandler extends Handler {

@Override
public void handleMessage(Message msg) {
switch (msg.what) {
......
case H_FSTRIM: {
Slog.i(TAG, "Running fstrim idle maintenance");

// Remember when we kicked it off
try {
mLastMaintenance = System.currentTimeMillis();
mLastMaintenanceFile.setLastModified(mLastMaintenance);
} catch (Exception e) {
Slog.e(TAG, "Unable to record last fstrim!");
}

// TODO: Reintroduce shouldBenchmark() test
fstrim(0, null);

......
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// frameworks/base/services/core/java/com/android/server/StorageManagerService.java
public void fstrim(int flags, IVoldTaskListener listener) {
enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);

try {
// 调用到vold进程,回收已挂载的文件系统未使用的块
mVold.fstrim(flags, new IVoldTaskListener.Stub() {
@Override
public void onStatus(int status, PersistableBundle extras) {
dispatchOnStatus(listener, status, extras);
.....
}

@Override
public void onFinished(int status, PersistableBundle extras) {
dispatchOnFinished(listener, status, extras);
......
}
});
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
}

7 PKMS之权限扫描

7.1 赋予默认权限

PackageManagerService中执行systemReady()后,需求对/system/etc/permissions中的各种xml进行扫描,进行相应的权限存储,让以后可以使用。

1
2
3
4
5
private void startOtherServices() {
traceBeginAndSlog("MakePackageManagerServiceReady");
mPackageManagerService.systemReady();
traceEnd();
}
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
public void systemReady() {
......
// 获取各种配置
sUserManager.systemReady();
// If we upgraded grant all default permissions before kicking off.
// 设置默认权限
for (int userId : grantPermissionsUserIds) {
mDefaultPermissionPolicy.grantDefaultPermissions(userId);
}

// Now that we've scanned all packages, and granted any default
// permissions, ensure permissions are updated. Beware of dragons if you
// try optimizing this.
synchronized (mPackages) {
// 扫描所有包,确认所有应用更新了默认权限
mPermissionManager.updateAllPermissions(
StorageManager.UUID_PRIVATE_INTERNAL, false, mPackages.values(),
mPermissionCallback);
}

// Kick off any messages waiting for system ready
// 启动所有等待系统就绪的消息
if (mPostSystemReadyMessages != null) {
for (Message msg : mPostSystemReadyMessages) {
msg.sendToTarget();
}
mPostSystemReadyMessages = null;
}

// Watch for external volumes that come and go over time
final StorageManager storage = mContext.getSystemService(StorageManager.class);
storage.registerListener(mStorageListener);

mInstallerService.systemReady();
mDexManager.systemReady();
mPackageDexOptimizer.systemReady();

StorageManagerInternal StorageManagerInternal = LocalServices.getService(
StorageManagerInternal.class);
// 监控外部存储监控
StorageManagerInternal.addExternalStoragePolicy(
new StorageManagerInternal.ExternalStorageMountPolicy() {
@Override
public int getMountMode(int uid, String packageName) {
if (Process.isIsolated(uid)) {
return Zygote.MOUNT_EXTERNAL_NONE;
}
if (checkUidPermission(READ_EXTERNAL_STORAGE, uid) == PERMISSION_DENIED) {
return Zygote.MOUNT_EXTERNAL_DEFAULT;
}
if (checkUidPermission(WRITE_EXTERNAL_STORAGE, uid) == PERMISSION_DENIED) {
return Zygote.MOUNT_EXTERNAL_READ;
}
return Zygote.MOUNT_EXTERNAL_WRITE;
}

@Override
public boolean hasExternalStorage(int uid, String packageName) {
return true;
}
});

// Now that we're mostly running, clean up stale users and apps
sUserManager.reconcileUsers(StorageManager.UUID_PRIVATE_INTERNAL);
reconcileApps(StorageManager.UUID_PRIVATE_INTERNAL);
// 通知PermissionManger系统启动完毕。
mPermissionManager.systemReady();

if (mInstantAppResolverConnection != null) {
mContext.registerReceiver(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
mInstantAppResolverConnection.optimisticBind();
mContext.unregisterReceiver(this);
}
}, new IntentFilter(Intent.ACTION_BOOT_COMPLETED));
}
}

从上面代码可以看到PackageManagerService被调用systemready()之后,会调用mPermissionManager.updateAllPermissions()方法更新所有应用的默认权限。而默认权限的读入,是在pkms构造方法中调用SystemConfig单例构造方法读取默认权限配置文件读到的。

1
2
3
4
5
6
7
8
9
10
11
12
// frameworks/base/core/java/com/android/server/SystemConfig.java
SystemConfig() {
// Read configuration from system
readPermissions(Environment.buildPath(
Environment.getRootDirectory(), "etc", "sysconfig"), ALLOW_ALL);

// Read configuration from the old permissions dir
readPermissions(Environment.buildPath(
Environment.getRootDirectory(), "etc", "permissions"), ALLOW_ALL);

...... //下面是读取vendor,oem,odm,product目录下的权限配置文件
}

然后回到pmks中调用到mPermissionManager.updateAllPermissions()根据读入的默认权限更新应用的权限。

1
2
3
4
5
6
7
// frameworks/base/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
private void updateAllPermissions(String volumeUuid, boolean sdkUpdated,
Collection<PackageParser.Package> allPackages, PermissionCallback callback) {
final int flags = UPDATE_PERMISSIONS_ALL |
(sdkUpdated ? UPDATE_PERMISSIONS_REPLACE_PKG | UPDATE_PERMISSIONS_REPLACE_ALL : 0);
updatePermissions(null, null, volumeUuid, flags, allPackages, callback);
}
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
private void updatePermissions(String changingPkgName, PackageParser.Package changingPkg,
String replaceVolumeUuid, int flags, Collection<PackageParser.Package> allPackages,
PermissionCallback callback) {
// 更新权限树
flags = updatePermissionTrees(changingPkgName, changingPkg, flags);

// Make sure all dynamic permissions have been assigned to a package,
// and make sure there are no dangling permissions.
// 更新所有应用的动态权限,确保没有摇摆权限没有赋值给应用
flags = updatePermissions(changingPkgName, changingPkg, flags);

Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "grantPermissions");
// Now update the permissions for all packages, in particular
// replace the granted permissions of the system packages.
// 逐个跟新权限,尤其是给系统应用赋权
if ((flags & UPDATE_PERMISSIONS_ALL) != 0) {
for (PackageParser.Package pkg : allPackages) {
if (pkg != changingPkg) {
// Only replace for packages on requested volume
final String volumeUuid = getVolumeUuidForPackage(pkg);
final boolean replace = ((flags & UPDATE_PERMISSIONS_REPLACE_ALL) != 0)
&& Objects.equals(replaceVolumeUuid, volumeUuid);
// 如果uuid不一样,就更新改应用权限
grantPermissions(pkg, replace, changingPkgName, callback);
}
}
}

if (changingPkg != null) {
// Only replace for packages on requested volume
final String volumeUuid = getVolumeUuidForPackage(changingPkg);
final boolean replace = ((flags & UPDATE_PERMISSIONS_REPLACE_PKG) != 0)
&& Objects.equals(replaceVolumeUuid, volumeUuid);
grantPermissions(changingPkg, replace, changingPkgName, callback);
}
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}

至此,PKMS启动之后的所有工作就做完了,给所有应用赋予了默认权限!

7.2 解读权限配置文件

在4.1.1小节pkms启动构造方法中,SystemConfig.getInstance()中会读取系统中的默认权限。例如system/etc/permissions, /vendor/etc/permissions下权限等。

1
2
3
4
5
// system/etc/permissions/android.hardware.ethernet.xml
<?xml version="1.0" encoding="utf-8"?>
<permissions>
<feature name="android.hardware.ethernet" />
</permissions>

让我们来简单的看下/system/etc/permissions/platform.xml的内容。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?xml version="1.0" encoding="utf-8"?>
<permissions>
<permission name="android.permission.BLUETOOTH_ADMIN" >
<group gid="net_bt_admin" />
</permission>

<assign-permission name="android.permission.MODIFY_AUDIO_SETTINGS" uid="media" />
<assign-permission name="android.permission.ACCESS_SURFACE_FLINGER" uid="media" />
<assign-permission name="android.permission.WAKE_LOCK" uid="media" />
<assign-permission name="android.permission.UPDATE_DEVICE_STATS" uid="media" />

<split-permission name="android.permission.ACCESS_FINE_LOCATION">
<new-permission name="android.permission.ACCESS_COARSE_LOCATION" />
</split-permission>

<library name="android.test.base" file="/system/framework/android.test.base.jar" />
</permissions>

以上platform.xml中出现的标签种类则较为多样,它们的含义分别是:

:根据name获取gid

标签:把属性name所描述的权限赋予给标签中属性gid所表示的用户组,一个权限
可以有一个或多个group对象,当一个APK授权于这个这个权限时,它同时属于这几个组

标签:把属性name所描述的权限赋予给uid属性所表示的用户

标签:一个权限可以扩展出一个新的权限

标签:除framework中动态库以外的,所有系统会自动加载的动态库

标签:硬件支持的一些feature

标签:oem厂商自己定义的一些权限

标签:来自system、vendor、product、system_ext的privapp权限分别存
储,这是防止供应商分区中的xml授权于系统分区中的私有应用权限

最后将上面xml解析出来的数据做如下存储:

标签gid属性的值会存放在mGlobalGids数组中;

标签,解析得到的值会存放在mPermissions集合中;

标签解析得到的值会存放在mSystemPermissions中;

存储在mSplitPermissions

标签解析得到的值会存放在mSharedLibraries中;

存储在mAvaliableFeatures

存储在mOemPermissions

会根据不同的存储路径,分别存储在mVendorPrivAppPermissions、mProductPrivAppPermissions、 mSystemExtPrivAppPermissions、mPrivAppPermissions

总结:权限扫描,扫描/system/etc/permissions中的xml,存入相应的结构体中,供之后权限管理使用

8 Apk安装

8.1 有界面安装

由于我使用的华为手机,华为对PackageInstaller应用有定制过,所以和原生的PackageInstaller界面和显示内容有一点点区别,但是流程几乎100%一样。可以参考该界面理解PackageInstaller界面安装应用的流程。

有界面安装apk过程.png

如果是有界面的安装方式相信大家平时接触的都比较多了吧,比如从网络上下载一个apk之后就会弹出安装界面,那就是有界面安装方式。 首先我们要知道有界面安装方式的那个界面是从哪里来的,还有就是如何启动那个安装界面的。那个界面其实就是InstallStart类,这是packages/app/PackageInstaller应用中的主界面,我们可以看一下该应用的Manifest文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<activity android:name=".InstallStart"
android:exported="true"
android:excludeFromRecents="true">
<intent-filter android:priority="1">
<action android:name="android.intent.action.VIEW" />
<action android:name="android.intent.action.INSTALL_PACKAGE" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="file" />
<data android:scheme="content" />
<data android:mimeType="application/vnd.android.package-archive" />
</intent-filter>
<intent-filter android:priority="1">
<action android:name="android.intent.action.INSTALL_PACKAGE" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="file" />
<data android:scheme="package" />
<data android:scheme="content" />
</intent-filter>
<intent-filter android:priority="1">
<action android:name="android.content.pm.action.CONFIRM_PERMISSIONS" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>

InstallStart主要选择哪个Activity是安装过程中的第一个可见Activity,并将意图转发给它

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
protected void onCreate(@Nullable Bundle savedInstanceState) {
......

final boolean isSessionInstall =
PackageInstaller.ACTION_CONFIRM_INSTALL.equals(intent.getAction());

// If the activity was started via a PackageInstaller session, we retrieve the calling package from that session
// 如果这个Activity是通过PackageInstaller会话启动的,我们将从该会话检索调用包
final int sessionId = (isSessionInstall
? intent.getIntExtra(PackageInstaller.EXTRA_SESSION_ID, -1)
: -1);
if (callingPackage == null && sessionId != -1) {
PackageInstaller packageInstaller = getPackageManager().getPackageInstaller();
PackageInstaller.SessionInfo sessionInfo = packageInstaller.getSessionInfo(sessionId);
callingPackage = (sessionInfo != null) ? sessionInfo.getInstallerPackageName() : null;
}
// 查看调用者身份,如果是未知身份警告用户
final ApplicationInfo sourceInfo = getSourceInfo(callingPackage);
final int originatingUid = getOriginatingUid(sourceInfo);
boolean isTrustedSource = false;
if (sourceInfo != null
&& (sourceInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0) {
isTrustedSource = intent.getBooleanExtra(Intent.EXTRA_NOT_UNKNOWN_SOURCE, false);
}

if (!isTrustedSource && originatingUid != PackageInstaller.SessionParams.UID_UNKNOWN) {
final int targetSdkVersion = getMaxTargetSdkVersionForUid(this, originatingUid);
if (targetSdkVersion < 0) {
Log.w(LOG_TAG, "Cannot get target sdk version for uid " + originatingUid);
// Invalid originating uid supplied. Abort install.
mAbortInstall = true;
} else if (targetSdkVersion >= Build.VERSION_CODES.O && !declaresAppOpPermission(
originatingUid, Manifest.permission.REQUEST_INSTALL_PACKAGES)) {
// 此if语句中判断调用者是否有安装权限,如果没有的话,直接放弃安装
Log.e(LOG_TAG, "Requesting uid " + originatingUid + " needs to declare permission "+ Manifest.permission.REQUEST_INSTALL_PACKAGES);
mAbortInstall = true;
}
}
if (mAbortInstall) {
setResult(RESULT_CANCELED);
finish();
return;
}

Intent nextActivity = new Intent(intent);
nextActivity.setFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);

......

if (isSessionInstall) {
// 设置安装界面
nextActivity.setClass(this, PackageInstallerActivity.class);
} else {
Uri packageUri = intent.getData();

if (packageUri != null && packageUri.getScheme().equals(
ContentResolver.SCHEME_CONTENT)) {
// [IMPORTANT] This path is deprecated, but should still work. Only necessary
// features should be added.
// Copy file to prevent it from being changed underneath this process
nextActivity.setClass(this, InstallStaging.class);
} else if (packageUri != null && packageUri.getScheme().equals(
PackageInstallerActivity.SCHEME_PACKAGE)) {
nextActivity.setClass(this, PackageInstallerActivity.class);
} else {
Intent result = new Intent();
result.putExtra(Intent.EXTRA_INSTALL_RESULT,
PackageManager.INSTALL_FAILED_INVALID_URI);
setResult(RESULT_FIRST_USER, result);

nextActivity = null;
}
}

if (nextActivity != null) {
// 启动安装界面
startActivity(nextActivity);
}
// 结束自己。
finish();
}

InstallStart主要做了身份识别,权限校验,为安全安装做了必要的准备,随后调用到PackageInstallerActivity界面,正式开始安装。

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
protected void onCreate(Bundle icicle) {
super.onCreate(icicle);
mPm = getPackageManager();
mIpm = AppGlobals.getPackageManager();
// 获取权限相关的信息
mAppOpsManager = (AppOpsManager) getSystemService(Context.APP_OPS_SERVICE);
mInstaller = mPm.getPackageInstaller();
mUserManager = (UserManager) getSystemService(Context.USER_SERVICE);

final Intent intent = getIntent();

mCallingPackage = intent.getStringExtra(EXTRA_CALLING_PACKAGE);
mSourceInfo = intent.getParcelableExtra(EXTRA_ORIGINAL_SOURCE_INFO);
mOriginatingUid = intent.getIntExtra(Intent.EXTRA_ORIGINATING_UID,
PackageInstaller.SessionParams.UID_UNKNOWN);
mOriginatingPackage = (mOriginatingUid != PackageInstaller.SessionParams.UID_UNKNOWN)
? getPackageNameForUid(mOriginatingUid) : null;


final Uri packageUri;

if (PackageInstaller.ACTION_CONFIRM_PERMISSIONS.equals(intent.getAction())) {
// 开始是空的,sessionId == -1
final int sessionId = intent.getIntExtra(PackageInstaller.EXTRA_SESSION_ID, -1);
final PackageInstaller.SessionInfo info = mInstaller.getSessionInfo(sessionId);
if (info == null || !info.sealed || info.resolvedBaseCodePath == null) {
Log.w(TAG, "Session " + mSessionId + " in funky state; ignoring");
finish();
return;
}

mSessionId = sessionId;
packageUri = Uri.fromFile(new File(info.resolvedBaseCodePath));
mOriginatingURI = null;
mReferrerURI = null;
} else {
mSessionId = -1;
packageUri = intent.getData();
mOriginatingURI = intent.getParcelableExtra(Intent.EXTRA_ORIGINATING_URI);
mReferrerURI = intent.getParcelableExtra(Intent.EXTRA_REFERRER);
}

.....

// load dummy layout with OK button disabled until we override this layout in
// startInstallConfirm
// 绑定确定安装或者取消按钮
bindUi(R.layout.install_confirm, false);
// 此方法用于检查是否运行安装,如果运行就初始化安装流程。
checkIfAllowedAndInitiateInstall();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
private void checkIfAllowedAndInitiateInstall() {
if (mAllowUnknownSources || !isInstallRequestFromUnknownSource(getIntent())) {
// 如果临时运行安装,就走这里
initiateInstall();
return;
}
// If the admin prohibits it, just show error and exit.
// 如果不允许安装,走下面
if (isUnknownSourcesDisallowed()) {
if ((mUserManager.getUserRestrictionSource(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES,
Process.myUserHandle()) & UserManager.RESTRICTION_SOURCE_SYSTEM) != 0) {
// Someone set user restriction via UserManager#setUserRestriction. We don't want to
// break apps that might already be doing this
showDialogInner(DLG_UNKNOWN_SOURCES_RESTRICTED_FOR_USER);
return;
} else {
startActivity(new Intent(Settings.ACTION_SHOW_ADMIN_SUPPORT_DETAILS));
finish();
}
} else {
handleUnknownSources();
}
}
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
// 此方法主要检查要安装的包是否已经被安装
private void initiateInstall() {
String pkgName = mPkgInfo.packageName;
// Check if there is already a package on the device with this name
// but it has been renamed to something else.
// 校验设备上是否已经有该包
String[] oldName = mPm.canonicalToCurrentPackageNames(new String[] { pkgName });
if (oldName != null && oldName.length > 0 && oldName[0] != null) {
pkgName = oldName[0];
mPkgInfo.packageName = pkgName;
mPkgInfo.applicationInfo.packageName = pkgName;
}
// Check if package is already installed. display confirmation dialog if replacing pkg
// 确认该包是否已经安装,弹出对话框让用户确认是否安装
try {
// This is a little convoluted because we want to get all uninstalled
// apps, but this may include apps with just data, and if it is just
// data we still want to count it as "installed".
mAppInfo = mPm.getApplicationInfo(pkgName,
PackageManager.MATCH_UNINSTALLED_PACKAGES);
if ((mAppInfo.flags&ApplicationInfo.FLAG_INSTALLED) == 0) {
mAppInfo = null;
}
} catch (NameNotFoundException e) {
mAppInfo = null;
}
// 在该方法中显示app申请的权限,并且绑定ui供用户选择是否安装。
startInstallConfirm();
}
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
private void startInstallConfirm() {
// We might need to show permissions, load layout with permissions
// 绑定确认取消按钮,供用户选择
if (mAppInfo != null) {
bindUi(R.layout.install_confirm_perm_update, true);
} else {
bindUi(R.layout.install_confirm_perm, true);
}

((TextView) findViewById(R.id.install_confirm_question))
.setText(R.string.install_confirm_question);
TabHost tabHost = (TabHost)findViewById(android.R.id.tabhost);
tabHost.setup();
// 用viewpager显示权限。
ViewPager viewPager = (ViewPager)findViewById(R.id.pager);
TabsAdapter adapter = new TabsAdapter(this, tabHost, viewPager);
// If the app supports runtime permissions the new permissions will
// be requested at runtime, hence we do not show them at install.
boolean supportsRuntimePermissions = mPkgInfo.applicationInfo.targetSdkVersion
>= Build.VERSION_CODES.M;
boolean permVisible = false;
mScrollView = null;
mOkCanInstall = false;
int msg = 0;

AppSecurityPermissions perms = new AppSecurityPermissions(this, mPkgInfo);
final int N = perms.getPermissionCount(AppSecurityPermissions.WHICH_ALL);
......
// 以下是显示应用申请的各种权限
}

此时,PackageInstallerActivity界面就已经跳转到权限显示,用户如果选择安装,那么就开始正式安装了。

接下来就可以和前面讲过的PKMS应用安装衔接起来了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public void onClick(View v) {
if (v == mOk) {
if (mOk.isEnabled()) {
if (mOkCanInstall || mScrollView == null) {
if (mSessionId != -1) {
mInstaller.setPermissionsResult(mSessionId, true);
finish();
} else {
// 开始安装
startInstall();
}
} else {
mScrollView.pageScroll(View.FOCUS_DOWN);
}
}
} else if (v == mCancel) {
// Cancel and finish
setResult(RESULT_CANCELED);
if (mSessionId != -1) {
mInstaller.setPermissionsResult(mSessionId, false);
}
finish();
}
}

startInstall即可衔接4.3节叙述到的应用安装环节,开始安装应用了。

8.2 无界面安装

此处叙述的无界面安装是使用命令行,静默安装的环境在上面小节有叙述到,因此该小节主要叙述使用命令行安装的流程是怎样的。

安装应用的命令:

1
2
3
4
# 使用adb安装
adb install xxxx
# 在车机里面安装
pm install -r /mnt/udisk/xxx.apk

命令行安装流程.png

我们都知道,adb install有很多的参数,但是我们今天就分析最简单的adb install qq.apk,adb是一个命令 而install是其参数,这里我们直接进入处理install的代码逻辑
(system/core/adb/commandline.c)

1
2
3
4
5
6
7
8
int adb_commandline(int argc, char **argv) {
   //......
   if (!strcmp(argv[0], "install")) {        
    if (argc < 2) return usage();        
    //调用install_app函数进行处理
       return install_app(ttype, serial, argc, argv);  
   }
}
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
int install_app(transport_type transport, char* serial, int argc, char** argv) {
   //手机内部存储路径
   static const char *const DATA_DEST = "/data/local/tmp/%s";    //SD卡路径
   static const char *const SD_DEST = "/sdcard/tmp/%s";    
const char* where = DATA_DEST;
   for (i = 1; i < argc; i++) {        //表示安装在SD卡上
       if (!strcmp(argv[i], "-s")) {            
where = SD_DEST;
    }  
}
   char* apk_file = argv[last_apk];    //安装路径
   char apk_dest[PATH_MAX];
   snprintf(apk_dest, sizeof apk_dest, where, get_basename(apk_file));    
//调用do_sync_push将apk文件push到手机中
   int err = do_sync_push(apk_file, apk_dest, 0 /* no show progress */);    
if (err) {
       goto cleanup_apk;  
} else {
       argv[last_apk] = apk_dest; /* destination name, not source location */  }
   //调用shell pm命令去安装
   pm_command(transport, serial, argc, argv); cleanup_apk:
   //在手机中执行shell rm来删除刚刚推入的apk文件    
delete_file(transport, serial, apk_dest);    
return err;
}

这个方法主要的功能就是找到apk安装的路径,然后执行pm命令去安装,并在最终通过rm命令将apk进 行删除,我们在来看一下pm_command函数的功能吧。

1
2
3
4
5
6
7
8
9
10
11
12
static int pm_command(transport_type transport, char* serial, int argc, char** argv) {
char buf[4096];
   //通过pm命令去执行安装操作
   snprintf(buf, sizeof(buf), "shell:pm");    
while(argc-- > 0) {
       char *quoted = escape_arg(*argv++);        
strncat(buf, " ", sizeof(buf) - 1);        
strncat(buf, quoted, sizeof(buf) - 1);        
free(quoted);
  }
   send_shellcommand(transport, serial, buf);    return 0;
}

那什么是pm呢?其实pm只是一个脚本,其源码所在路径(frameworks/base/cmds/pm/pm)。

1
2
3
4
5
# Script to start "pm" on the device, which has a very rudimentary shell.
#
base=/system
export CLASSPATH=$base/framework/pm.jar
exec app_process $base/bin com.android.commands.pm.Pm "$@"

可以发现其执行的是pm.jar包的main函数,我们进入Pm.java类。

1
2
3
4
5
6
7
8
9
10
11
12
13
public static void main(String[] args) {        
int exitCode = 1;
    try {
       exitCode = new Pm().run(args);      
} catch (Exception e) {
       Log.e(TAG, "Error", e);
       System.err.println("Error: " + e);            
if (e instanceof RemoteException) {
          System.err.println(PM_NOT_RUNNING_ERR);      
}
   }
   System.exit(exitCode);  
}

这里直接创建了Pm对象并调用其run方法,我们进入其run方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public int run(String[] args) throws IOException, RemoteException {
//这里获得PKMS的代理对象
   mUm = IUserManager.Stub.asInterface(ServiceManager.getService("user"));    
   mPm = IPackageManager.Stub.asInterface(ServiceManager.getService("package"));    
if (mPm == null) {
       System.err.println(PM_NOT_RUNNING_ERR);        
return 1;
}
//处理install参数,还有很多其他参数
mInstaller = mPm.getPackageInstaller();    
   if ("install".equals(op)) {        
return runInstall();  
}
}

可以发现这里又将安装的操作交给了runInstall这个方法,我们再次进入该方法。

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
private int runInstall() {
//处理很多的参数命令
   while ((opt=nextOption()) != null) {        
       if (opt.equals("-l")) {
          installFlags |= PackageManager.INSTALL_FORWARD_LOCK;          
} else if (opt.equals("-r")) {
          installFlags |= PackageManager.INSTALL_REPLACE_EXISTING;          
} else if (opt.equals("-i")) {
          installerPackageName = nextOptionData();                
if (installerPackageName == null) {
               System.err.println("Error: no value specified for -i");                    
return 1;
        }
       } else if (opt.equals("-t")) {
          installFlags |= PackageManager.INSTALL_ALLOW_TEST;          
} else if (opt.equals("-s")) {
          // Override if -s option is specified.
          installFlags |= PackageManager.INSTALL_EXTERNAL;          
} else if (opt.equals("-f")) {
           // Override if -s option is specified.
           installFlags |= PackageManager.INSTALL_INTERNAL;      
}
           //......  
}
   //多用户手机时将所有用户都安装
   if (userId == UserHandle.USER_ALL) {      
userId = UserHandle.USER_OWNER;
      installFlags |= PackageManager.INSTALL_ALL_USERS;  
}
   //监听安装结果
//调用PKMS的installPackageAsUser方法进行安装操作
   LocalPackageInstallObserver obs = new LocalPackageInstallObserver();    
   mPm.installPackageAsUser(apkFilePath, obs.getBinder(), installFlags,installerPackageName, verificationParams, abi, userId);
   synchronized (obs) {
       while (!obs.finished) {            
obs.wait();
   }
   //当安装成功后打印Success
if (obs.result == PackageManager.INSTALL_SUCCEEDED) {            
System.out.println("Success");
      return 0;      
} else {
       System.err.println("Failure ["+ installFailureToString(obs)+ "]");
       return 1;    
}
}

以上就是runInstall方法的主要内容,首先根据安装参数来设置installFlags属性值,然后创建 LocalPackageInstallObserver对象来监听安装结果,最后调用PKMS对象的installPackageAsUser来执 行安装操作,当然最后无论安装成功还是失败都需返回一个结果以供PC的命令行进行展示,接下来我们 将进入PKMS的installPackageAsUser方法。

1
2
3
4
5
6
7
8
9
// originPath表示apk路径,observer是LocalPackageInstallObserver对象,用于监听apk安装结果,installFlags是安装参数
public void installPackageAsUser(String originPath, IPackageInstallObserver2 observer,int installFlags,...) {
    //......
    //将操作通过发送Handler来处理
    final Message msg = mHandler.obtainMessage(INIT_COPY);
    //注意这里创建了InstallParams对象并将其传递给msg.obj对象,后面我们会详细分析这个对象    
msg.obj = new InstallParams(origin, observer, installFlags,installerPackageName, verificationParams, user, packageAbiOverride);
    mHandler.sendMessage(msg);
}

可以看到installPackageAsUser方法还是蛮简单的,只是创建一个Message对象,然后通过Handler来 发送INIT_COPY的消息,不过这里大家要注意参数的传递,我们进入Handler的处理消息的代码。

看着INIT_COPY消息,就可以联想到4.3节讲到的安装过程。开始拷贝apk文件了。此处查看4.3节的安装流程即可完成安装,为了方便跟流程,我直接上流程图,不上代码了。此篇回顾PKMS blog着实有点长。

PKMS中安装流程

命令行安装.png

在PKMS构造函数中解析所需要的文件目录:

解析所需要的文件目录.png

安装原理:

安装原理.png