Skytoby

PackageManagerService启动流程分析

PackageManagerService启动流程分析

基于Android10.0,分析PackageManagerService启动

一、PakageManagerService概述

1.1 作用

PakageManagerService(简称PKMS),是Android核心服务之一,管理着所有package相关的工作。

如:安装、卸载应用

​ 查询、增加、删除permission相关信息

​ 查询Application相关信息

​ 查询已安装应用

​ 清除用户数据,缓存

1.2 PKMS类关系

PKMS是通过Binder进行通信。IPackageManager.aidl通过工具生成Binder的服务端IPackageManager.Stub和

客户端IPackageManager.Stub.Proxy,编译后生成的路径在 out/target/common 目录下。

Binder服务端:PackageManagerService继承于IPackageManager.Stub

Binder客户端:ApplicationPackageManager(简称APM)的成员变量mPM继承于IPackageManager.Stub.Proxy;

​ APM继承于PakageManager对象

1.3 PKMS类成员

PKMS类共有二万多行,这里就简单介绍一下其中重要的类和成员变量。

重要成员支持类

PackageParser

这个类主要用于解析APK,解析AndroidManifest.xml文件得到package的所有信息,PackageParser.Package用于存储得到的信息。

Settings

这个类表示它服务处理设置和读取包的各种状态,是动态的,比如shareUser,permission,signature,userid等相关信息。安装包就是从安装的package中抽取信息更新Settings中的内容,特别是shareUser和origPackge。为了加速启动,Setting内容会写入data/system/pakcages.xml、packages-backup.xml和packages.list,下次启动时会直接载入。

Installer

这个类是协助安装的过程,操作基本上是在cpp里面,真正的工作是由installd执行,installd通过Native Binder实现。

类成员

//代表系统已经安装的package

final ArrayMap<String, PackageParser.Package> mPackages

//被升级过的应用列表

final private ArrayMap<String, File> mExpectingBetter

//保存PackageManager动态设置信息

final Settings mSettings;

1.4 PKMS启动流程

SystemServer启动过程中涉及的PKMS如下:

主要在下面的两个方法中

1
2
3
4
5
6
private voi run() {
...
startBootstrapServices();
startOtherServices();
...
}

startBootstrapServices方法相关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
25
26
27
28
29
30
31
32
33
34
35
36
/**
* Starts the small tangle of critical services that are needed to get
* the system off the ground. These services have complex mutual dependencies
* which is why we initialize them all in one place here. Unless your service
* is also entwined in these dependencies, it should be initialized in one of
* the other functions.
*/
private void startBootstrapServices() {

//启动installer服务,PKMS相关任务的执行者
// Wait for installd to finish starting up so that it has a chance to
// create critical directories such as /data/user with the appropriate
// permissions. We need this to complete before we initialize other services.
Installer installer = mSystemServiceManager.startService(Installer.class);
....
//加密状态仅仅解析核心应用
// Only run "core" apps if we're encrypting the device.
String cryptState = SystemProperties.get("vold.decrypt");
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;
}
....
//启动PackagemanagerService服务
traceBeginAndSlog("StartPackageManagerService");
mPackageManagerService = PackageManagerService.main(mSystemContext, installer,
mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);
//是否是开机后第一次启动
mFirstBoot = mPackageManagerService.isFirstBoot();
//获取包管理
mPackageManager = mSystemContext.getPackageManager();

}

上面最重要的是PKMS.mian()操作,主要是创建PKMS服务,并注册到ServiceManager中。

startOtherServices方法中相关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
25
26
27
28
29
30
31
32
/**
* Starts a miscellaneous grab bag of stuff that has yet to be refactored
* and organized.
*/
private void startOtherServices() {
//非加密状态
if (!mOnlyCore) {
traceBeginAndSlog("UpdatePackagesIfNeeded");
try {
//dexopt是android上Java字节码的一种优化技术,可提高运行效率
//对应用dexopt的顺序进行排序,并执行dexopt操作
mPackageManagerService.updatePackagesIfNeeded();
} catch (Throwable e) {
reportWtf("update packages", e);
}
traceEnd();
}
traceBeginAndSlog("PerformFstrimIfNeeded");
try {
//当3天未执行fstrim时,则执行fstrim操作
mPackageManagerService.performFstrimIfNeeded();
} catch (Throwable e) {
reportWtf("performing fstrim", e);
}
//通知系统进入就绪状态
mPackageManagerService.systemReady();
...
//等待所有应用准备好,主要是等待应用处理的线程结束
// Wait for all packages to be prepared
mPackageManagerService.waitForAppDataPrepared();
...
}

在SystemServer启动过程中,PKMS最主要的操作如下:

  • PKMS.main()
  • PKMS.updatePackagesIfNeeded()
  • PKMS.systemReady()

二、PKMS.main

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public static PackageManagerService main(Context context, Installer installer,
boolean factoryTest, boolean onlyCore) {
// Self-check for initial settings.
PackageManagerServiceCompilerMapping.checkProperties();

PackageManagerService m = new PackageManagerService(context, installer,
factoryTest, onlyCore);
m.enableSystemUserPackages();
//讲PKMS注册到ServiceManager中
ServiceManager.addService("package", m);
final PackageManagerNative pmn = m.new PackageManagerNative();
ServiceManager.addService("package_native", pmn);
return m;
}

main方法主要功能是创建PKMS对象,创建PKMS对象的执行时间比较长,在其构造函数做了很多的“重力活”,这也是Android启动慢的原因之一。构造函数的主要功能是扫描Android系统中目标文件夹中的APK,从而建立合适的数据结构来管理诸如:Package信息,四大组件、权限等各种信息。PKMS工作流程相对简单,复杂的是其中用于保存各种信息的数据结构以及它们之间的关系。PKMS构造函数主要分为五个阶段,每个阶段都会输出日志到EventLog,除了阶段1的开始部分代码,后面的代码都同时持有同步锁mPackage、mInstallLock。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public PackageManagerService(Context context, Installer installer,
boolean factoryTest, boolean onlyCore) {

阶段1:BOOT_PROGRESS_PMS_START
synchronized (mInstallLock) {
synchronized (mPackages) {
...
阶段2:BOOT_PROGRESS_PMS_SYSTEM_SCAN_START
阶段3:BOOT_PROGRESS_PMS_DATA_SCAN_START
阶段4:BOOT_PROGRESS_PMS_SCAN_END
阶段5:BOOT_PROGRESS_PMS_READY
...
}
}
// 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.
mInstaller.setWarnIfHeld(mPackages);
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}

2.1 PMS_START

主要的工作如下:

  • 创建Settings对象;
  • 将8类shareUserId到mSettings;
  • 初始化SystemConfig;
  • 创建名为“PackageManager”的handler线程mHandlerThread;
  • 创建UserManagerService、PermissionManagerService服务;
  • 通过解析目录中的xmL文件构造共享mSharedLibraries;
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
LockGuard.installLock(mPackages, LockGuard.INDEX_PACKAGES);
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "create package manager");
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_START,
SystemClock.uptimeMillis());

if (mSdkVersion <= 0) {
Slog.w(TAG, "**** ro.build.version.sdk not set!");
}

mContext = context;
//运行在非工厂模式
mFactoryTest = factoryTest;
//标记是否加载核心服务
mOnlyCore = onlyCore;
//显示屏幕相关,如分辨率、屏幕尺寸
mMetrics = new DisplayMetrics();
//安装器,和本地守护进程installed交互,通信方式为socket
mInstaller = installer;

// Create sub-components that provide services / data. Order here is important.
synchronized (mInstallLock) {
synchronized (mPackages) {
//只用于系统内部的packagemanager
// 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);
//权限管理服务
mPermissionManager = PermissionManagerService.create(context,
new DefaultPermissionGrantedCallback() {
@Override
public void onDefaultRuntimePermissionsGranted(int userId) {
synchronized(mPackages) {
mSettings.onDefaultRuntimePermissionsGrantedLPr(userId);
}
}
}, mPackages /*externalLock*/);
mDefaultPermissionPolicy = mPermissionManager.getDefaultPermissionGrantPolicy();
//该类用于存储系统运行过程中的一些设置
mSettings = new Settings(mPermissionManager.getPermissionSettings(), mPackages);
}
}

//添加八种sharedUserId到mSettings
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);
//该值和调试相关,一般不设置该属性,separateProcesses在扫描文件目录中用到
String separateProcesses = SystemProperties.get("debug.separate_processes");
if (separateProcesses != null && separateProcesses.length() > 0) {
if ("*".equals(separateProcesses)) {
mDefParseFlags = PackageParser.PARSE_IGNORE_PROCESSES;
mSeparateProcesses = null;
Slog.w(TAG, "Running with debug.separate_processes: * (ALL)");
} else {
mDefParseFlags = 0;
mSeparateProcesses = separateProcesses.split(",");
Slog.w(TAG, "Running with debug.separate_processes: "
+ separateProcesses);
}
} else {
mDefParseFlags = 0;
mSeparateProcesses = null;
}
//dexopt相关对象初始化
mPackageDexOptimizer = new PackageDexOptimizer(installer, mInstallLock, context,
"*dexopt*");
DexManager.Listener dexManagerListener = DexLogger.getListener(this,
installer, mInstallLock);
mDexManager = new DexManager(mContext, this, mPackageDexOptimizer, installer, mInstallLock,
dexManagerListener);
mArtManagerService = new ArtManagerService(mContext, this, installer, mInstallLock);
mMoveCallbacks = new MoveCallbacks(FgThread.get().getLooper());

mOnPermissionChangeListeners = new OnPermissionChangeListeners(
FgThread.get().getLooper());
//获取当前设置的显示信息
getDefaultDisplayMetrics(context, mMetrics);
//通过SystemConfig读取系统的feature、permission等配置
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "get system config");
SystemConfig systemConfig = SystemConfig.getInstance();
mAvailableFeatures = systemConfig.getAvailableFeatures();
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);

mProtectedPackages = new ProtectedPackages(mContext);

synchronized (mInstallLock) {
// writer
synchronized (mPackages) {
//创建handler线程,主要工作是程序安装和卸载等
mHandlerThread = new ServiceThread(TAG,
Process.THREAD_PRIORITY_BACKGROUND, true /*allowIo*/);
mHandlerThread.start();
mHandler = new PackageHandler(mHandlerThread.getLooper());
mProcessLoggingHandler = new ProcessLoggingHandler();
//将mHandler加入到Watchdog中,安装应用可能会有大量的I/O操作会比较耗时
//因此这里的watchdog设置为10min,一般为60s或者30s
Watchdog.getInstance().addThread(mHandler, WATCHDOG_TIMEOUT);
mInstantAppRegistry = new InstantAppRegistry(this);

//通过systemconfig获取系统中的共享库列表
ArrayMap<String, String> libConfig = systemConfig.getSharedLibraries();
final int builtInLibCount = libConfig.size();
for (int i = 0; i < builtInLibCount; i++) {
String name = libConfig.keyAt(i);
String path = libConfig.valueAt(i);
addSharedLibraryLPw(path, null, null, name, SharedLibraryInfo.VERSION_UNDEFINED,
SharedLibraryInfo.TYPE_BUILTIN, PLATFORM_PACKAGE_NAME, 0);
}
// Builtin libraries cannot encode their dependency where they are
// defined, so fix that now.
setupBuiltinSharedLibraryDependenciesLocked();

//打开SELinux的policy文件,/etc/selinux/plat_mac_permissions.xml
SELinuxMMAC.readInstallPolicy();

//将framework-res.apk添加到AssetManager
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "loadFallbacks");
FallbackCategoryProvider.loadFallbacks();
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);

//读取package.xml的内容,解析后插到mSettings的mPackages等变量中
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "read user settings");
mFirstBoot = !mSettings.readLPw(sUserManager.getUsers(false));
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);

//清理代码路径不存在的异常package
// 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);
}
}
//PKMS是否首次启动
if (!mOnlyCore && mFirstBoot) {
//copy定时,等100s #platform/system/extras/cppreopt/
requestCopyPreoptedFiles();
}
//代替缺省的ResolverActivity #ResolverActivity
String customResolverActivity = Resources.getSystem().getString(
R.string.config_customResolverActivity);
if (TextUtils.isEmpty(customResolverActivity)) {
customResolverActivity = null;
} else {
mCustomResolverComponentName = ComponentName.unflattenFromString(
customResolverActivity);
}

2.1.1 new Settings

Setting构造函数主要工作是创建系统文件夹和一些包管理的文件。

packages.xml、packages-backup.xml是一组,用于描述系统所安装的Package信息,其中packages-backup.xml是packages.xml的备份

packages.list用于描述系统中存在的所有非系统自带的apk信息以及UID大于10000的apk。当APK有变化时,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
25
26
Settings(File dataDir, PermissionSettings permission, Object lock) {
mLock = lock;
mPermissions = permission;
//创建mRuntimePermissionsPersistence,是Setting内部类
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);
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");
}

2.1.2 addSharedUserLPw

该方法将shareUserId name和一个int类型的UID对应起来。UID的定义在Process.java中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
SharedUserSetting addSharedUserLPw(String name, int uid, int pkgFlags, int pkgPrivateFlags) {
//获取SharedUserSetting对象
SharedUserSetting s = mSharedUsers.get(name);
if (s != null) {
if (s.userId == uid) {
return s;
}
PackageManagerService.reportSettingsProblem(Log.ERROR,
"Adding duplicate shared user, keeping first: " + name);
return null;
}
//没有在mSharedUsers找到则新建,并保存起来
s = new SharedUserSetting(name, pkgFlags, pkgPrivateFlags);
s.userId = uid;
if (addUserIdLPw(uid, s, name)) {
mSharedUsers.put(name, s);
return s;
}
return null;
}

UID、GID

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
/**
* Defines the root UID.
*/
public static final int ROOT_UID = 0;

/**
* Defines the UID/GID under which system code runs.
*/
public static final int SYSTEM_UID = 1000;

/**
* Defines the UID/GID under which the telephony code runs.
*/
public static final int PHONE_UID = 1001;

/**
* Defines the UID/GID for the user shell.
*/
public static final int SHELL_UID = 2000;

/**
* Defines the UID/GID for the log group.
* @hide
*/
@UnsupportedAppUsage
public static final int LOG_UID = 1007;

/**
* Defines the UID/GID for the WIFI supplicant process.
* @hide
*/
@UnsupportedAppUsage
public static final int WIFI_UID = 1010;
...

//第一个应用package的起始UID为10000
/**
* Defines the start of a range of UIDs (and GIDs), going from this
* number to {@link #LAST_APPLICATION_UID} that are reserved for assigning
* to applications.
*/
public static final int FIRST_APPLICATION_UID = 10000;
//最后一个应用package的UID为19999
/**
* Last of application-specific UIDs starting at
* {@link #FIRST_APPLICATION_UID}.
*/
public static final int LAST_APPLICATION_UID = 19999;

Setting模块的AndroidManifest.xml里面,如下所示:

1
2
3
4
5
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
package="com.android.settings"
coreApp="true"
android:sharedUserId="android.uid.system">

在xml里面android:sharedUserId属性设置为”android.uid.system”。sharedUserId这个属性主要有两个作用:

1.两个或者多个声明了同一种sharedUserId的应用可以共享彼此的数据

2.通过声明特定sharedUserId,该应用所在进程将赋予指定的UID。如Setting声明了system的uid,则就可以共享system用户所对应的权限。

除了了xml了声明sharedUserId外,应用编译的时候还必须使用对应的证书进行签名。如Setting需要platform的签名。

PID、UID的区别

PID是进程的身份识别,程序一旦运行,就会给应用分配唯一的PID。一个应用可能包含多个进程,每个进程有唯一的一个PID。进程终止后PID被系统回收,再次打开应用,会分配一个PID(新进程的PID一般比之前的号大)。

调用adb shell ps可以查看系统运行的进程。

UID是用户ID。UID在linux中就是用户ID,表明哪个用户运行了这个程序,主要用于权限的管理。而Android为单用户系统,这时候UID被赋予了新的使命,数据共享,为了实现数据共享,android为每个应用都分配了不同的uid,不像传统的linux,每个用户相同就为之分配相同的UID。

GID时用户组ID。对于普通的应用程序来说GID等于UID,由于每个应用程序的UID和GID不相同,所以不管是native还是java层都能够达到保护私有数据的作用。

adb shell cat /proc/PID号/status

2.1.3 SystemConfig.getInstance

SystemConfig构造函数中主要通过readPermissions函数将对应目录下的xml文件中定义的各个节点读取出来保存到SystemConfig成员变量中。在终端的/system/etc/permissions目录下可以看到很多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
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);

// Vendors are only allowed to customze libs, features and privapp permissions
int vendorPermissionFlag = ALLOW_LIBS | ALLOW_FEATURES | ALLOW_PRIVAPP_PERMISSIONS;
if (Build.VERSION.FIRST_SDK_INT <= Build.VERSION_CODES.O_MR1) {
// For backward compatibility
vendorPermissionFlag |= (ALLOW_PERMISSIONS | ALLOW_APP_CONFIGS);
}
readPermissions(Environment.buildPath(
Environment.getVendorDirectory(), "etc", "sysconfig"), vendorPermissionFlag);
readPermissions(Environment.buildPath(
Environment.getVendorDirectory(), "etc", "permissions"), vendorPermissionFlag);

// Allow ODM to customize system configs as much as Vendor, because /odm is another
// vendor partition other than /vendor.
int odmPermissionFlag = vendorPermissionFlag;
readPermissions(Environment.buildPath(
Environment.getOdmDirectory(), "etc", "sysconfig"), odmPermissionFlag);
readPermissions(Environment.buildPath(
Environment.getOdmDirectory(), "etc", "permissions"), odmPermissionFlag);

String skuProperty = SystemProperties.get(SKU_PROPERTY, "");
if (!skuProperty.isEmpty()) {
String skuDir = "sku_" + skuProperty;

readPermissions(Environment.buildPath(
Environment.getOdmDirectory(), "etc", "sysconfig", skuDir), odmPermissionFlag);
readPermissions(Environment.buildPath(
Environment.getOdmDirectory(), "etc", "permissions", skuDir),
odmPermissionFlag);
}

// Allow OEM to customize features and OEM permissions
int oemPermissionFlag = ALLOW_FEATURES | ALLOW_OEM_PERMISSIONS;
readPermissions(Environment.buildPath(
Environment.getOemDirectory(), "etc", "sysconfig"), oemPermissionFlag);
readPermissions(Environment.buildPath(
Environment.getOemDirectory(), "etc", "permissions"), oemPermissionFlag);

// Allow Product to customize all system configs
readPermissions(Environment.buildPath(
Environment.getProductDirectory(), "etc", "sysconfig"), ALLOW_ALL);
readPermissions(Environment.buildPath(
Environment.getProductDirectory(), "etc", "permissions"), ALLOW_ALL);
}

如下是终端的/system/etc/permissions目录的xml配置文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
HWSTF:/system/etc/permissions $ ls -all
total 300
drwxr-xr-x 2 root root 4096 2018-08-08 00:01:00.000000000 +0800 .
drwxr-xr-x 26 root root 4096 2018-08-08 00:01:00.000000000 +0800 ..
-rw-r--r-- 1 root root 1515 2018-08-08 00:01:00.000000000 +0800 HiViewTunnel-core.xml
-rw-r--r-- 1 root root 830 2018-08-08 00:01:00.000000000 +0800 android.hardware.bluetooth_le.xml
-rw-r--r-- 1 root root 927 2018-08-08 00:01:00.000000000 +0800 android.hardware.faketouch.xml
-rw-r--r-- 1 root root 834 2018-08-08 00:01:00.000000000 +0800 android.hardware.fingerprint.xml
-rw-r--r-- 1 root root 942 2018-08-08 00:01:00.000000000 +0800 android.hardware.location.gps.xml
-rw-r--r-- 1 root root 949 2018-08-08 00:01:00.000000000 +0800 android.hardware.location.xml
-rw-r--r-- 1 root root 888 2018-08-08 00:01:00.000000000 +0800 android.hardware.nfc.hce.xml
-rw-r--r-- 1 root root 891 2018-08-08 00:01:00.000000000 +0800 android.hardware.nfc.hcef.xml
-rw-r--r-- 1 root root 921 2018-08-08 00:01:00.000000000 +0800 android.hardware.nfc.xml
-rw-r--r-- 1 root root 870 2018-08-08 00:01:00.000000000 +0800 android.hardware.opengles.aep.xml
-rw-r--r-- 1 root root 824 2018-08-08 00:01:00.000000000 +0800
...

这些配置文件都是编译时从framework指定位置拷贝过来的(framework/native/data/etc),下面是platform.xml里面的部分

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<permissions>

<permission name="android.permission.BLUETOOTH_ADMIN" >
<group gid="net_bt_admin" />
</permission>
<permission name="android.permission.READ_EXTERNAL_STORAGE" />
<assign-permission name="android.permission.MODIFY_AUDIO_SETTINGS" uid="media" />
<library name="org.apache.http.legacy"
file="/system/framework/org.apache.http.legacy.boot.jar" />
<allow-in-power-save package="com.android.providers.downloads" />
<!-- These are the packages that shouldn't run as system user -->
<system-user-blacklisted-app package="com.android.wallpaper.livepicker" />
<allow-in-data-usage-save package="com.dti.att" />
<feature name="android.hardware.vulkan.level" version="0" />
...
</permissions>

readPermissions方法内部调用readPermissionsFromXml方法来解析xml里面的各个节点,其中xml涉及到的标签内容有permission、assign-permission、library、feature等,这些标签的内容解析出来保存到SystemConfig的对应数据结构的全局变量中,以便管理查询。

feature用来描述设备是否支持硬件特性;

library用于指定系统库,当应用程序运行时,系统会为进程加载一些必须的库;

assign-permission将system中描述的permission与uid关联;

permission将permission和gid关联。

2.1.4 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
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
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
boolean readLPw(@NonNull List<UserInfo> users) {
FileInputStream str = null;
//备份的文件是否存在
if (mBackupSettingsFilename.exists()) {
try {
//data/system/packages_backup.xml
str = new FileInputStream(mBackupSettingsFilename);
mReadMessages.append("Reading from backup settings file/n");
PackageManagerService.reportSettingsProblem(Log.INFO,
"Need to read from backup settings file");
if (mSettingsFilename.exists()) {
// If both the backup and settings file exist, we
// ignore the settings since it might have been
// corrupted.
Slog.w(PackageManagerService.TAG, "Cleaning up settings file "
+ mSettingsFilename);
mSettingsFilename.delete();
}
} catch (java.io.IOException e) {
// We'll try for the normal settings file.
}
}

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

try {
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;
}
// data/system/packages.xml
str = new FileInputStream(mSettingsFilename);
}
XmlPullParser parser = Xml.newPullParser();
parser.setInput(str, StandardCharsets.UTF_8.name());

int type;
while ((type = parser.next()) != XmlPullParser.START_TAG
&& type != XmlPullParser.END_DOCUMENT) {
;
}

if (type != XmlPullParser.START_TAG) {
mReadMessages.append("No start tag found in settings file/n");
PackageManagerService.reportSettingsProblem(Log.WARN,
"No start tag found in package manager settings");
Slog.wtf(PackageManagerService.TAG,
"No start tag found in package manager settings");
return false;
}

int outerDepth = parser.getDepth();
//解析xml文件
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
&& (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
continue;
}

String tagName = parser.getName();
if (tagName.equals("package")) {
readPackageLPw(parser);
} else if (tagName.equals("permissions")) {
mPermissions.readPermissions(parser);
} else if (tagName.equals("permission-trees")) {
mPermissions.readPermissionTrees(parser);
} else if (tagName.equals("shared-user")) {
readSharedUserLPw(parser);
} else if (tagName.equals("preferred-packages")) {
// no longer used.
} else if (tagName.equals("preferred-activities")) {
// Upgrading from old single-user implementation;
// these are the preferred activities for user 0.
readPreferredActivitiesLPw(parser, 0);
} else if (tagName.equals(TAG_PERSISTENT_PREFERRED_ACTIVITIES)) {
// TODO: check whether this is okay! as it is very
// similar to how preferred-activities are treated
readPersistentPreferredActivitiesLPw(parser, 0);
} else if (tagName.equals(TAG_CROSS_PROFILE_INTENT_FILTERS)) {
// TODO: check whether this is okay! as it is very
// similar to how preferred-activities are treated
readCrossProfileIntentFiltersLPw(parser, 0);
} else if (tagName.equals(TAG_DEFAULT_BROWSER)) {
readDefaultAppsLPw(parser, 0);
} else if (tagName.equals("updated-package")) {
readDisabledSysPackageLPw(parser);
} else if (tagName.equals("cleaning-package")) {
String name = parser.getAttributeValue(null, ATTR_NAME);
String userStr = parser.getAttributeValue(null, ATTR_USER);
String codeStr = parser.getAttributeValue(null, ATTR_CODE);
if (name != null) {
int userId = UserHandle.USER_SYSTEM;
boolean andCode = true;
try {
if (userStr != null) {
userId = Integer.parseInt(userStr);
}
} catch (NumberFormatException e) {
}
if (codeStr != null) {
andCode = Boolean.parseBoolean(codeStr);
}
addPackageToCleanLPw(new PackageCleanItem(userId, name, andCode));
}
} else if (tagName.equals("renamed-package")) {
String nname = parser.getAttributeValue(null, "new");
String oname = parser.getAttributeValue(null, "old");
if (nname != null && oname != null) {
mRenamedPackages.put(nname, oname);
}
} else if (tagName.equals("restored-ivi")) {
readRestoredIntentFilterVerifications(parser);
} else if (tagName.equals("last-platform-version")) {
// Upgrade from older XML schema
final VersionInfo internal = findOrCreateVersion(
StorageManager.UUID_PRIVATE_INTERNAL);
final VersionInfo external = findOrCreateVersion(
StorageManager.UUID_PRIMARY_PHYSICAL);

internal.sdkVersion = XmlUtils.readIntAttribute(parser, "internal", 0);
external.sdkVersion = XmlUtils.readIntAttribute(parser, "external", 0);
internal.fingerprint = external.fingerprint =
XmlUtils.readStringAttribute(parser, "fingerprint");

} else if (tagName.equals("database-version")) {
// Upgrade from older XML schema
final VersionInfo internal = findOrCreateVersion(
StorageManager.UUID_PRIVATE_INTERNAL);
final VersionInfo external = findOrCreateVersion(
StorageManager.UUID_PRIMARY_PHYSICAL);

internal.databaseVersion = XmlUtils.readIntAttribute(parser, "internal", 0);
external.databaseVersion = XmlUtils.readIntAttribute(parser, "external", 0);

} else if (tagName.equals("verifier")) {
final String deviceIdentity = parser.getAttributeValue(null, "device");
try {
mVerifierDeviceIdentity = VerifierDeviceIdentity.parse(deviceIdentity);
} catch (IllegalArgumentException e) {
Slog.w(PackageManagerService.TAG, "Discard invalid verifier device id: "
+ e.getMessage());
}
} else if (TAG_READ_EXTERNAL_STORAGE.equals(tagName)) {
final String enforcement = parser.getAttributeValue(null, ATTR_ENFORCEMENT);
mReadExternalStorageEnforced =
"1".equals(enforcement) ? Boolean.TRUE : Boolean.FALSE;
} else if (tagName.equals("keyset-settings")) {
mKeySetManagerService.readKeySetsLPw(parser, mKeySetRefs);
} else if (TAG_VERSION.equals(tagName)) {
final String volumeUuid = XmlUtils.readStringAttribute(parser,
ATTR_VOLUME_UUID);
final VersionInfo ver = findOrCreateVersion(volumeUuid);
ver.sdkVersion = XmlUtils.readIntAttribute(parser, ATTR_SDK_VERSION);
ver.databaseVersion = XmlUtils.readIntAttribute(parser, ATTR_DATABASE_VERSION);
ver.fingerprint = XmlUtils.readStringAttribute(parser, ATTR_FINGERPRINT);
} else {
Slog.w(PackageManagerService.TAG, "Unknown element under <packages>: "
+ parser.getName());
XmlUtils.skipCurrentTag(parser);
}
}

str.close();

} catch (XmlPullParserException e) {
mReadMessages.append("Error reading: " + e.toString());
PackageManagerService.reportSettingsProblem(Log.ERROR, "Error reading settings: " + e);
Slog.wtf(PackageManagerService.TAG, "Error reading package manager settings", e);

} catch (java.io.IOException e) {
mReadMessages.append("Error reading: " + e.toString());
PackageManagerService.reportSettingsProblem(Log.ERROR, "Error reading settings: " + e);
Slog.wtf(PackageManagerService.TAG, "Error reading package manager settings", e);
}
//这里解析xml结束

//如果build的版本不匹配,删除用户运行时权限
// If the build is setup to drop runtime permissions
// on update drop the files before loading them.
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);
}
}
}

//没有处理的具有sharedUserID的package需要添加
final int N = mPendingPackages.size();

for (int i = 0; i < N; i++) {
final PackageSetting p = mPendingPackages.get(i);
final int sharedUserId = p.getSharedUserId();
final Object idObj = getUserIdLPr(sharedUserId);
if (idObj instanceof SharedUserSetting) {
final SharedUserSetting sharedUser = (SharedUserSetting) idObj;
p.sharedUser = sharedUser;
p.appId = sharedUser.userId;
addPackageSettingLPw(p, sharedUser);
} else if (idObj != null) {
String msg = "Bad package setting: package " + p.name + " has shared uid "
+ sharedUserId + " that is not a shared uid/n";
mReadMessages.append(msg);
PackageManagerService.reportSettingsProblem(Log.ERROR, msg);
} else {
String msg = "Bad package setting: package " + p.name + " has shared uid "
+ sharedUserId + " that is not defined/n";
mReadMessages.append(msg);
PackageManagerService.reportSettingsProblem(Log.ERROR, msg);
}
}
mPendingPackages.clear();
//备份的强制停止的包
if (mBackupStoppedPackagesFilename.exists()
|| mStoppedPackagesFilename.exists()) {
// Read old file
readStoppedLPw();
mBackupStoppedPackagesFilename.delete();
mStoppedPackagesFilename.delete();
// Migrate to new file format
writePackageRestrictionsLPr(UserHandle.USER_SYSTEM);
} else {
for (UserInfo user : users) {
readPackageRestrictionsLPr(user.id);
}
}

for (UserInfo user : users) {
mRuntimePermissionsPersistence.readStateForUserSyncLPr(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 = getUserIdLPr(disabledPs.appId);
if (id != null && id instanceof SharedUserSetting) {
disabledPs.sharedUser = (SharedUserSetting) id;
}
}

mReadMessages.append("Read completed successfully: " + mPackages.size() + " packages, "
+ mSharedUsers.size() + " shared uids/n");

writeKernelMappingLPr();

return true;
}

2.2 PMS_SYSTEM_SCAN_START

主要的工作是扫描系统apk。

1
2
3
4
5
6
7
8
9
10
11
12
13
扫描目录
/vendor/overlay
/product/overlay
/system/frameworks
/system/priv-app
/system/app
/vendor/priv-app
/vendor/app
/odm/priv-app
/odm/app
/oem/app
/oem/priv-app
/product/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
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
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
long startTime = SystemClock.uptimeMillis();
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SYSTEM_SCAN_START,
startTime);

final String bootClassPath = System.getenv("BOOTCLASSPATH");
final String systemServerClassPath = System.getenv("SYSTEMSERVERCLASSPATH");

if (bootClassPath == null) {
Slog.w(TAG, "No BOOTCLASSPATH found!");
}

if (systemServerClassPath == null) {
Slog.w(TAG, "No SYSTEMSERVERCLASSPATH found!");
}
//创建framework目录为/system/framework
File frameworkDir = new File(Environment.getRootDirectory(), "framework");

//是否升级
final VersionInfo ver = mSettings.getInternalVersion();
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
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.
mIsPreNUpgrade = mIsUpgrade && ver.sdkVersion < Build.VERSION_CODES.N;

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

//是否需要提升权限
// 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
if (mPromoteSystemApps) {
Iterator<PackageSetting> pkgSettingIter = mSettings.mPackages.values().iterator();
while (pkgSettingIter.hasNext()) {
PackageSetting ps = pkgSettingIter.next();
if (isSystemApp(ps)) {
mExistingSystemPackages.add(ps.name);
}
}
}
//扫描目录解析包信息缓存路径
mCacheDir = preparePackageParserCache(mIsUpgrade);
//定义扫描参数
// Set flag to monitor and not change apk file paths when
// scanning install directories.
int scanFlags = SCAN_BOOTING | SCAN_INITIAL;

if (mIsUpgrade || mFirstBoot) {
scanFlags = scanFlags | SCAN_FIRST_BOOT_OR_UPGRADE;
}

//扫描 /vendor/overlay/ 、 product/overlay目录
// Collect vendor/product 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.
scanDirTracedLI(new File(VENDOR_OVERLAY_DIR),
mDefParseFlags
| PackageParser.PARSE_IS_SYSTEM_DIR,
scanFlags
| SCAN_AS_SYSTEM
| SCAN_AS_VENDOR,
0);
scanDirTracedLI(new File(PRODUCT_OVERLAY_DIR),
mDefParseFlags
| PackageParser.PARSE_IS_SYSTEM_DIR,
scanFlags
| SCAN_AS_SYSTEM
| SCAN_AS_PRODUCT,
0);

mParallelPackageParserCallback.findStaticOverlayPackages();

//扫描 /system/frameworks目录
// Find base frameworks (resource packages without code).
scanDirTracedLI(frameworkDir,
mDefParseFlags
| PackageParser.PARSE_IS_SYSTEM_DIR,
scanFlags
| SCAN_NO_DEX
| SCAN_AS_SYSTEM
| SCAN_AS_PRIVILEGED,
0);

//扫描 /system/priv-app目录
// Collect privileged system packages.
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);

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

//扫描 /vendor/priv-app目录
// Collect privileged vendor packages.
File privilegedVendorAppDir = new File(Environment.getVendorDirectory(), "priv-app");
try {
privilegedVendorAppDir = privilegedVendorAppDir.getCanonicalFile();
} catch (IOException e) {
// failed to look up canonical path, continue with original one
}
scanDirTracedLI(privilegedVendorAppDir,
mDefParseFlags
| PackageParser.PARSE_IS_SYSTEM_DIR,
scanFlags
| SCAN_AS_SYSTEM
| SCAN_AS_VENDOR
| SCAN_AS_PRIVILEGED,
0);

//扫描 /vendor/app目录
// Collect ordinary vendor packages.
File vendorAppDir = new File(Environment.getVendorDirectory(), "app");
try {
vendorAppDir = vendorAppDir.getCanonicalFile();
} catch (IOException e) {
// failed to look up canonical path, continue with original one
}
scanDirTracedLI(vendorAppDir,
mDefParseFlags
| PackageParser.PARSE_IS_SYSTEM_DIR,
scanFlags
| SCAN_AS_SYSTEM
| SCAN_AS_VENDOR,
0);

//扫描 /odm/priv-app目录
// Collect privileged odm packages. /odm is another vendor partition
// other than /vendor.
File privilegedOdmAppDir = new File(Environment.getOdmDirectory(),
"priv-app");
try {
privilegedOdmAppDir = privilegedOdmAppDir.getCanonicalFile();
} catch (IOException e) {
// failed to look up canonical path, continue with original one
}
scanDirTracedLI(privilegedOdmAppDir,
mDefParseFlags
| PackageParser.PARSE_IS_SYSTEM_DIR,
scanFlags
| SCAN_AS_SYSTEM
| SCAN_AS_VENDOR
| SCAN_AS_PRIVILEGED,
0);

//扫描 /odm/app目录
// Collect ordinary odm packages. /odm is another vendor partition
// other than /vendor.
File odmAppDir = new File(Environment.getOdmDirectory(), "app");
try {
odmAppDir = odmAppDir.getCanonicalFile();
} catch (IOException e) {
// failed to look up canonical path, continue with original one
}
scanDirTracedLI(odmAppDir,
mDefParseFlags
| PackageParser.PARSE_IS_SYSTEM_DIR,
scanFlags
| SCAN_AS_SYSTEM
| SCAN_AS_VENDOR,
0);

//扫描 /oem/app目录
// Collect all OEM packages.
final File oemAppDir = new File(Environment.getOemDirectory(), "app");
scanDirTracedLI(oemAppDir,
mDefParseFlags
| PackageParser.PARSE_IS_SYSTEM_DIR,
scanFlags
| SCAN_AS_SYSTEM
| SCAN_AS_OEM,
0);

//扫描 /oem/priv-app目录
// Collected privileged product packages.
File privilegedProductAppDir = new File(Environment.getProductDirectory(), "priv-app");
try {
privilegedProductAppDir = privilegedProductAppDir.getCanonicalFile();
} catch (IOException e) {
// failed to look up canonical path, continue with original one
}
scanDirTracedLI(privilegedProductAppDir,
mDefParseFlags
| PackageParser.PARSE_IS_SYSTEM_DIR,
scanFlags
| SCAN_AS_SYSTEM
| SCAN_AS_PRODUCT
| SCAN_AS_PRIVILEGED,
0);

//扫描 /product/app目录
// Collect ordinary product packages.
File productAppDir = new File(Environment.getProductDirectory(), "app");
try {
productAppDir = productAppDir.getCanonicalFile();
} catch (IOException e) {
// failed to look up canonical path, continue with original one
}
scanDirTracedLI(productAppDir,
mDefParseFlags
| PackageParser.PARSE_IS_SYSTEM_DIR,
scanFlags
| SCAN_AS_SYSTEM
| SCAN_AS_PRODUCT,
0);

//删除不存在的系统包
// 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<>();
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.
*/
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.
*/
if (mSettings.isDisabledSystemPackageLPr(ps.name)) {
logCriticalInfo(Log.WARN,
"Expecting better updated system app for " + ps.name
+ "; removing system app. Last known"
+ " codePath=" + ps.codePathString
+ ", versionCode=" + ps.versionCode
+ "; scanned versionCode=" + scannedPkg.getLongVersionCode());
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) {
possiblyDeletedUpdatedSystemApps.add(ps.name);
}
}
}
}
//删除临时文件
//delete tmp files
deleteTempPackageFiles();

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

//删除不相关包中的所有共享userIDs
// Remove any shared userIDs that have no associated packages
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);
}

2.2.1 PackageParser.Package

Package数据,表示从磁盘上的apk文件解析出来的package,一个包由一个基础的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
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
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
   /**
* Representation of a full package parsed from APK files on disk. A package
* consists of a single base APK, and zero or more split APKs.
*/
public final static class Package implements Parcelable {
//表示包名
@UnsupportedAppUsage
public String packageName;
//表示manifest中声明的包名
// The package name declared in the manifest as the package can be
// renamed, for example static shared libs use synthetic package names.
public String manifestPackageName;
//表示拆包的包名
/** Names of any split APKs, ordered by parsed splitName */
public String[] splitNames;

// TODO: work towards making these paths invariant
//对应一个volume的uid
public String volumeUuid;

/**
* Path where this package was found on disk. For monolithic packages
* this is path to single base APK file; for cluster packages this is
* path to the cluster directory.
*/
//表示代码路径
public String codePath;

/** Path of base APK */
//表示base APK路径
public String baseCodePath;
//表示拆分APK路径
/** Paths of any split APKs, ordered by parsed splitName */
public String[] splitCodePaths;
//表示base APK调整版本号
/** Revision code of base APK */
public int baseRevisionCode;
//表示拆分APK调整版本号
/** Revision codes of any split APKs, ordered by parsed splitName */
public int[] splitRevisionCodes;

//表示拆分APK的标注数组
/** Flags of any split APKs; ordered by parsed splitName */
public int[] splitFlags;

/**
* Private flags of any split APKs; ordered by parsed splitName.
*
* {@hide}
*/
//表示拆分APK的私有标注数组
public int[] splitPrivateFlags;
//表示是否支持硬件加速
public boolean baseHardwareAccelerated;

//对应application对象,对应AndroidManifest里面的<Application>
// For now we only support one application per package.
@UnsupportedAppUsage
public ApplicationInfo applicationInfo = new ApplicationInfo();

//apk安装包中,对应AndroidManifest里面的<Permission>
@UnsupportedAppUsage
public final ArrayList<Permission> permissions = new ArrayList<Permission>(0);
//apk安装包中,对应AndroidManifest里面的<PermissionGroup>
@UnsupportedAppUsage
public final ArrayList<PermissionGroup> permissionGroups = new ArrayList<PermissionGroup>(0);
//apk安装包中,对应AndroidManifest里面的<Activity>
//不是通常说的Activity,而是PackageParse的内部类Activity
@UnsupportedAppUsage
public final ArrayList<Activity> activities = new ArrayList<Activity>(0);

//apk安装包中,对应AndroidManifest里面的<Receiver>
//不是通常说的Activity,而是PackageParse的内部类Activity
@UnsupportedAppUsage
public final ArrayList<Activity> receivers = new ArrayList<Activity>(0);

//apk安装包中,对应AndroidManifest里面的<Provider>
//不是通常说的Provider,而是PackageParse的内部类Provider
@UnsupportedAppUsage
public final ArrayList<Provider> providers = new ArrayList<Provider>(0);

//apk安装包中,对应AndroidManifest里面的<Service>
//不是通常说的Service,而是PackageParse的内部类Service
@UnsupportedAppUsage
public final ArrayList<Service> services = new ArrayList<Service>(0);

//apk安装包中,对应AndroidManifest里面的<Instrumentation>
//不是通常说的Instrumentation,而是内部类Instrumentation
@UnsupportedAppUsage
public final ArrayList<Instrumentation> instrumentation = new ArrayList<Instrumentation>(0);
//apk安装包中请求的权限
@UnsupportedAppUsage
public final ArrayList<String> requestedPermissions = new ArrayList<String>();

//apk安装包中保内广播的action
@UnsupportedAppUsage
public ArrayList<String> protectedBroadcasts;
//父包
public Package parentPackage;
//子包
public ArrayList<Package> childPackages;
//共享库名称
public String staticSharedLibName = null;
//共享库版本
public long staticSharedLibVersion = 0;
//依赖库名称
public ArrayList<String> libraryNames = null;
@UnsupportedAppUsage
//使用库名称
public ArrayList<String> usesLibraries = null;
//使用静态库名称
public ArrayList<String> usesStaticLibraries = null;
//使用静态库版本
public long[] usesStaticLibrariesVersions = null;
public String[][] usesStaticLibrariesCertDigests = null;
//使用其它的库
@UnsupportedAppUsage
public ArrayList<String> usesOptionalLibraries = null;
//使用静态库文件
@UnsupportedAppUsage
public String[] usesLibraryFiles = null;
//使用共享库信息
public ArrayList<SharedLibraryInfo> usesLibraryInfos = null;
//安装包中某个Activity信息的集合 在AndroidManifest里面对应<preferred>标签
public ArrayList<ActivityIntentInfo> preferredActivityFilters = null;
//安装包中 AndroidManifest中对应original-package的集合
public ArrayList<String> mOriginalPackages = null;
//真实包名,通常和mOriginalPackages一起使用
public String mRealPackage = null;
//APK安装包 AndroidManifest中对应adopt-permissions的集合
public ArrayList<String> mAdoptPermissions = null;
//独立的存储应用程序元数据,避免多个不需要的引用
// We store the application meta-data independently to avoid multiple unwanted references
@UnsupportedAppUsage
public Bundle mAppMetaData = null;
//版本号
// The version code declared for this package.
@UnsupportedAppUsage
public int mVersionCode;
//主版本号
// The major version code declared for this package.
public int mVersionCodeMajor;
//长版本号
// Return long containing mVersionCode and mVersionCodeMajor.
public long getLongVersionCode() {
return PackageInfo.composeLongVersionCode(mVersionCodeMajor, mVersionCode);
}
//版本名
// The version name declared for this package.
@UnsupportedAppUsage
public String mVersionName;
//共享用户Id
// The shared user id that this package wants to use.
@UnsupportedAppUsage
public String mSharedUserId;
//共享用户标签
// The shared user label that this package wants to use.
@UnsupportedAppUsage
public int mSharedUserLabel;
//签名
// Signatures that were read from the package.
@UnsupportedAppUsage
@NonNull public SigningDetails mSigningDetails = SigningDetails.UNKNOWN;
//dexopt的位置,以便pkms跟踪执行dexopt的位置
// For use by package manager service for quick lookup of
// preferred up order.
@UnsupportedAppUsage
public int mPreferredOrder = 0;
//最后一次使用package的时间
// For use by package manager to keep track of when a package was last used.
public long[] mLastPackageUsageTimeInMills =
new long[PackageManager.NOTIFY_PACKAGE_USE_REASONS_COUNT];

// // User set enabled state.
// public int mSetEnabled = PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
//
// // Whether the package has been stopped.
// public boolean mSetStopped = false;

//附加数据
// Additional data supplied by callers.
@UnsupportedAppUsage
public Object mExtras;

//硬件配置信息,对应AndroidManifest里面的<users-configuration>标签
// Applications hardware preferences
@UnsupportedAppUsage
public ArrayList<ConfigurationInfo> configPreferences = null;
//特性组信息,对应AndroidManifest里面的<uses-feature>标签
// Applications requested features
@UnsupportedAppUsage
public ArrayList<FeatureInfo> reqFeatures = null;
//特性组信息,对应AndroidManifest里面的<feature-group>标签
// Applications requested feature groups
public ArrayList<FeatureGroupInfo> featureGroups = null;

//安装的属性
@UnsupportedAppUsage
public int installLocation;

//是否是核心
public boolean coreApp;

//是否是全局必要,所有用户都需要的应用程序,无法为用户卸载
/* An app that's required for all users and cannot be uninstalled for a user */
public boolean mRequiredForAllUsers;

//受限账户的验证类型
/* The restricted account authenticator type that is used by this application */
public String mRestrictedAccountType;
//账户的类型
/* The required account type without which this application will not function */
public String mRequiredAccountType;

//对应AndroidManifest里面的<overlay>标签
public String mOverlayTarget;
//overlay类别
public String mOverlayCategory;
//overlay优先等级
public int mOverlayPriority;
//是否是静态overlay
public boolean mOverlayIsStatic;
//编译sdk版本
public int mCompileSdkVersion;
//编译sdk版本名称
public String mCompileSdkVersionCodename;

//下面用来给KeySetManagerService的数据
/**
* Data used to feed the KeySetManagerService
*/
@UnsupportedAppUsage
public ArraySet<String> mUpgradeKeySets; //升级
@UnsupportedAppUsage
public ArrayMap<String, ArraySet<PublicKey>> mKeySetMapping; //公钥

//有abi的话覆盖
/**
* The install time abi override for this package, if any.
*
* TODO: This seems like a horrible place to put the abiOverride because
* this isn't something the packageParser parsers. However, this fits in with
* the rest of the PackageManager where package scanning randomly pushes
* and prods fields out of {@code this.applicationInfo}.
*/
public String cpuAbiOverride;
//是否用32位的abi
/**
* The install time abi override to choose 32bit abi's when multiple abi's
* are present. This is only meaningfull for multiarch applications.
* The use32bitAbi attribute is ignored if cpuAbiOverride is also set.
*/
public boolean use32bitAbi;
//限制升级hash
public byte[] restrictUpdateHash;
//是否对InstantApps可见
/** Set if the app or any of its components are visible to instant applications. */
public boolean visibleToInstantApps;
//是否是备份
/** Whether or not the package is a stub and must be replaced by the full version. */
public boolean isStub;

@UnsupportedAppUsage
public Package(String packageName) {
this.packageName = packageName;
this.manifestPackageName = packageName;
applicationInfo.packageName = packageName;
applicationInfo.uid = -1;
}
...
}

2.2.2 scanDirTracedLI

这个是扫描目录的函数,主要是解析apk中xml的数据,并把相关信息保存到PackageParser.Package中。

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

里面跳转的方法比较多,其主要流程如下:

2.3 PMS_DATA_SCAN_START

主要的工作是扫描data分区的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
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
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
//非加密状态
if (!mOnlyCore) {
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START,
SystemClock.uptimeMillis());

//扫描 /data/app目录
scanDirTracedLI(sAppInstallDir, 0, scanFlags | SCAN_REQUIRE_KNOWN, 0);
//扫描 /data/app-private目录
scanDirTracedLI(sDrmAppPrivateInstallDir, mDefParseFlags
| PackageParser.PARSE_FORWARD_LOCK,
scanFlags | SCAN_REQUIRE_KNOWN, 0);

//放在possiblyDeletedUpdatedSystemApps中的应用是在package.xml标记成待升级的系统应用
//但是文件却不存在了,因此需要检查用户目录下升级文件是否还存在,然后处理
// 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 (String deletedAppName : possiblyDeletedUpdatedSystemApps) {
PackageParser.Package deletedPkg = mPackages.get(deletedAppName);
mSettings.removeDisabledSystemPackageLPw(deletedAppName);
final String msg;
if (deletedPkg == null) {
//用户目录中也没有,在肯定是残留应用,删除操作在后面
// should have found an update, but, we didn't; remove everything
msg = "Updated system package " + deletedAppName
+ " no longer exists; removing its data";
// Actual deletion of code and data will be handled by later
// reconciliation step
} else {
//如果用户空间找到了文件,则说明系统目录下的文件可能被删除了
//因此需要把应用的属性去掉,以普通应用的方式运行
// found an update; revoke system privileges
msg = "Updated system package + " + deletedAppName
+ " no longer exists; revoking system privileges";

// Don't do anything if a stub is removed from the system image. If
// we were to remove the uncompressed version from the /data partition,
// this is where it'd be done.

final PackageSetting deletedPs = mSettings.mPackages.get(deletedAppName);
deletedPkg.applicationInfo.flags &= ~ApplicationInfo.FLAG_SYSTEM;
deletedPs.pkgFlags &= ~ApplicationInfo.FLAG_SYSTEM;
}
logCriticalInfo(Log.WARN, msg);
}

//这个列表的应用是带有升级包的系统应用,前面已经把他们从mPackages列表中清除
//并加入到该列表,最后也对他们扫描处理,但是不会放到mPackages中
/*
* 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.
*/
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;
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)) {
reparseFlags =
mDefParseFlags |
PackageParser.PARSE_IS_SYSTEM_DIR;
rescanFlags =
scanFlags
| SCAN_AS_SYSTEM;
} else if (FileUtils.contains(privilegedVendorAppDir, scanFile)
|| FileUtils.contains(privilegedOdmAppDir, scanFile)) {
reparseFlags =
mDefParseFlags |
PackageParser.PARSE_IS_SYSTEM_DIR;
rescanFlags =
scanFlags
| SCAN_AS_SYSTEM
| SCAN_AS_VENDOR
| SCAN_AS_PRIVILEGED;
} else if (FileUtils.contains(vendorAppDir, scanFile)
|| FileUtils.contains(odmAppDir, scanFile)) {
reparseFlags =
mDefParseFlags |
PackageParser.PARSE_IS_SYSTEM_DIR;
rescanFlags =
scanFlags
| SCAN_AS_SYSTEM
| SCAN_AS_VENDOR;
} else if (FileUtils.contains(oemAppDir, scanFile)) {
reparseFlags =
mDefParseFlags |
PackageParser.PARSE_IS_SYSTEM_DIR;
rescanFlags =
scanFlags
| SCAN_AS_SYSTEM
| SCAN_AS_OEM;
} else if (FileUtils.contains(privilegedProductAppDir, scanFile)) {
reparseFlags =
mDefParseFlags |
PackageParser.PARSE_IS_SYSTEM_DIR;
rescanFlags =
scanFlags
| SCAN_AS_SYSTEM
| SCAN_AS_PRODUCT
| SCAN_AS_PRIVILEGED;
} else if (FileUtils.contains(productAppDir, scanFile)) {
reparseFlags =
mDefParseFlags |
PackageParser.PARSE_IS_SYSTEM_DIR;
rescanFlags =
scanFlags
| SCAN_AS_SYSTEM
| SCAN_AS_PRODUCT;
} else {
Slog.e(TAG, "Ignoring unexpected fallback path " + scanFile);
continue;
}

//把这个应用标记为系统应用,从mSettings.mDisabledSysPackages中删除
//因为在scanDirLi->scanPackageLI中会执行mSettings.disableSystemPakcageLPw
//此时包名的标签只有<update-package>,执行到这部之后变成<package>标签
//在下面的scanPackageTracedLI中会添加一个<update-package>标签
mSettings.enableSystemPackageLPw(packageName);

try {
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.
decompressSystemApplications(stubSystemApps, scanFlags);

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

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列表
mExpectingBetter.clear();

//获取存储管理包名
// Resolve the storage manager.
mStorageManagerPackage = getStorageManagerPackageName();

//获取引导包名
// Resolve protected action filters. Only the setup wizard is allowed to
// have a high priority filter for these actions.
mSetupWizardPackage = getSetupWizardPackageName();
if (mProtectedFilters.size() > 0) {
if (DEBUG_FILTERS && mSetupWizardPackage == null) {
Slog.i(TAG, "No setup wizard;"
+ " All protected intents capped to priority 0");
}
for (ActivityIntentInfo filter : mProtectedFilters) {
if (filter.activity.info.packageName.equals(mSetupWizardPackage)) {
if (DEBUG_FILTERS) {
Slog.i(TAG, "Found setup wizard;"
+ " allow priority " + filter.getPriority() + ";"
+ " package: " + filter.activity.info.packageName
+ " activity: " + filter.activity.className
+ " priority: " + filter.getPriority());
}
// skip setup wizard; allow it to keep the high priority filter
continue;
}
if (DEBUG_FILTERS) {
Slog.i(TAG, "Protected action; cap priority to 0;"
+ " package: " + filter.activity.info.packageName
+ " activity: " + filter.activity.className
+ " origPrio: " + filter.getPriority());
}
filter.setPriority(0);
}
}

mSystemTextClassifierPackage = getSystemTextClassifierPackageName();

mDeferProtectedFilters = false;
mProtectedFilters.clear();

//更新所有应用的动态库路径
// Now that we know all of the shared libraries, update all clients to have
// the correct library paths.
updateAllSharedLibrariesLPw(null);

for (SharedUserSetting setting : mSettings.getAllSharedUsersLPw()) {
//调整更新Abis为共享用户所用
// 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.
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.
setting.fixSeInfoLocked();
}

// Now that we know all the packages we are keeping,
// read and update their last usage times.
mPackageUsage.read(mPackages);
mCompilerStats.read();

2.4 PMS_SCAN_END

主要的工作如下:

  • 更新所有权限;
  • 为系统应用准备空间和数据
  • 将上述信息写回/data/system/packages.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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SCAN_END,
SystemClock.uptimeMillis());
Slog.i(TAG, "Time to scan packages: "
+ ((SystemClock.uptimeMillis()-startTime)/1000f)
+ " seconds");
//如果sdk版本发生变化,则可能permission的定义也发生变化,因此需要重新更新应用权限
// 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.
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;

//如果是第一次启动或者是android M升级后的第一次启动,需要执行一些初始化操作
// 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.
if (!onlyCore && (mPromoteSystemApps || mFirstBoot)) {
for (UserInfo user : sUserManager.getUsers(true)) {
mSettings.applyDefaultPreferredAppsLPw(this, user.id);
applyFactoryDefaultBrowserLPw(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
final int storageFlags;
if (StorageManager.isFileEncryptedNativeOrEmulated()) {
storageFlags = StorageManager.FLAG_STORAGE_DE;
} else {
storageFlags = StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE;
}
List<String> deferPackages = reconcileAppsDataLI(StorageManager.UUID_PRIVATE_INTERNAL,
UserHandle.USER_SYSTEM, storageFlags, true /* migrateAppData */,
true /* onlyCoreApps */);
mPrepareAppDataFuture = SystemServerInitThreadPool.get().submit(() -> {
TimingsTraceLog traceLog = new TimingsTraceLog("SystemServerTimingAsync",
Trace.TRACE_TAG_PACKAGE_MANAGER);
traceLog.traceBegin("AppDataFixup");
try {
mInstaller.fixupAppData(StorageManager.UUID_PRIVATE_INTERNAL,
StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE);
} catch (InstallerException e) {
Slog.w(TAG, "Trouble fixing GIDs", e);
}
traceLog.traceEnd();

traceLog.traceBegin("AppDataPrepare");
if (deferPackages == null || deferPackages.isEmpty()) {
return;
}
int count = 0;
for (String pkgName : deferPackages) {
PackageParser.Package pkg = null;
synchronized (mPackages) {
PackageSetting ps = mSettings.getPackageLPr(pkgName);
if (ps != null && ps.getInstalled(UserHandle.USER_SYSTEM)) {
pkg = ps.pkg;
}
}
if (pkg != null) {
synchronized (mInstallLock) {
prepareAppDataAndMigrateLIF(pkg, UserHandle.USER_SYSTEM, storageFlags,
true /* maybeMigrateAppData */);
}
count++;
}
}
traceLog.traceEnd();
Slog.i(TAG, "Deferred reconcileAppsData finished " + count + " packages");
}, "prepareAppData");

//如果是执行OTA升级后的第一次启动,需要清除cache
// 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).
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,
StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE
| Installer.FLAG_CLEAR_CODE_CACHE_ONLY);
}
}
ver.fingerprint = Build.FINGERPRINT;
}

checkDefaultBrowser();

// clear only after permissions and other defaults have been updated
mExistingSystemPackages.clear();
mPromoteSystemApps = false;

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

//把Settings的内容保存到packages.xml中
// can downgrade to reader
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "write settings");
mSettings.writeLPr();
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);

2.5 PMS_READY

主要工作是创建PackageInstallerService服务。

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
    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;
}
//启动PackageInstallerService服务
mInstallerService = new PackageInstallerService(context, this);
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;
}
//初始化 installer activity
updateInstantAppInstallerLocked(null);

//更新使用的Packages
// 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).
final Map<Integer, List<PackageInfo>> userPackages = new HashMap<>();
final int[] currentUserIds = UserManagerService.getInstance().getUserIds();
for (int userId : currentUserIds) {
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)

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

//mPackages锁被占用,则给出警告提示
// 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.
mInstaller.setWarnIfHeld(mPackages);

Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);

三、PKMS操作

3.1 getPackageManager

在ContextImpl中

/frameworks/base/core/java/android/app/ContextImpl.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Override
public PackageManager getPackageManager() {
if (mPackageManager != null) {
return mPackageManager;
}

IPackageManager pm = ActivityThread.getPackageManager();
if (pm != null) {
// Doesn't matter if we make more than one instance.
return (mPackageManager = new ApplicationPackageManager(this, pm));
}

return null;
}

/frameworks/base/core/java/android/app/ActivityThread.java

1
2
3
4
5
6
7
8
9
10
11
12
@UnsupportedAppUsage
public static IPackageManager getPackageManager() {
if (sPackageManager != null) {
//Slog.v("PackageManager", "returning cur default = " + sPackageManager);
return sPackageManager;
}
IBinder b = ServiceManager.getService("package");
//Slog.v("PackageManager", "default service binder = " + b);
sPackageManager = IPackageManager.Stub.asInterface(b);
//Slog.v("PackageManager", "default service = " + sPackageManager);
return sPackageManager;
}

3.2 updatePackagesIfNeeded

这里主要是对package进行Dexopt

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
@Override
public void updatePackagesIfNeeded() {
enforceSystemOrRoot("Only the system can request package update");

// We need to re-extract after an OTA.
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.
boolean causeFirstBoot = isFirstBoot() || mIsPreNUpgrade;

// We need to re-extract after a pruned cache, as AoT-ed files will be out of date.
boolean causePrunedCache = VMRuntime.didPruneDalvikCache();

if (!causeUpgrade && !causeFirstBoot && !causePrunedCache) {
return;
}

List<PackageParser.Package> pkgs;
synchronized (mPackages) {
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);
}

PackageManagerServiceUtils.getPackagesForDexopt的方法,主要的功能是根据app的重要性,对dexopt的顺序进行排序,重要的app将会首先会执行Dexopt操作,以防止设备空间不足。排序的原则是根据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
// Sort apps by importance for dexopt ordering. Important apps are given
// more priority in case the device runs out of space.
public static List<PackageParser.Package> getPackagesForDexopt(
Collection<PackageParser.Package> packages,
PackageManagerService packageManagerService) {
return getPackagesForDexopt(packages, packageManagerService, DEBUG_DEXOPT);
}

public static List<PackageParser.Package> getPackagesForDexopt(
Collection<PackageParser.Package> packages,
PackageManagerService packageManagerService,
boolean debug) {
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.
applyPackageFilter((pkg) -> pkg.coreApp, result, remainingPkgs, sortTemp,
packageManagerService);

// Give priority to system apps that listen for pre boot complete.
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.
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?
Predicate<PackageParser.Package> remainingPredicate;
if (!remainingPkgs.isEmpty() && packageManagerService.isHistoricalPackageUsageAvailable()) {
if (debug) {
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) {
Log.i(TAG, "Taking package " + lastUsed.packageName + " as reference in time use");
}
//统计app使用的时长
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) {
Log.i(TAG, "Packages to be dexopted: " + packagesToString(result));
Log.i(TAG, "Packages skipped from dexopt: " + packagesToString(remainingPkgs));
}

return result;
}

performDexOptUpgrade方法是对packages执行dexopt操作。首先是创建package的配置文件,配置文件生成后再执行performDexOptTraced的操作,里面最后执行的操作是mInstaller.dexopt方法。

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
/**
* Performs dexopt on the set of packages in {@code packages} and returns an int array
* containing statistics about the invocation. The array consists of three elements,
* which are (in order) {@code numberOfPackagesOptimized}, {@code numberOfPackagesSkipped}
* and {@code numberOfPackagesFailed}.
*/
private int[] performDexOptUpgrade(List<PackageParser.Package> pkgs, boolean showDialog,
final int compilationReason, boolean bootComplete) {

int numberOfPackagesVisited = 0;
int numberOfPackagesOptimized = 0;
int numberOfPackagesSkipped = 0;
int numberOfPackagesFailed = 0;
final int numberOfPackagesToDexopt = pkgs.size();

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.
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".
if (!mInstaller.copySystemProfile(profileFile.getAbsolutePath(),
pkg.applicationInfo.uid, pkg.packageName,
ArtManager.getProfileName(null))) {
Log.e(TAG, "Installer failed to copy system profile!");
} else {
// Disabled as this causes speed-profile compilation during first boot
// even if things are already compiled.
// useProfileForDexopt = true;
}
} catch (Exception e) {
Log.e(TAG, "Failed to copy profile " + profileFile.getAbsolutePath() + " ",
e);
}
} 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.
if (disabledPs != null && disabledPs.pkg.isStub) {
// The package is the stub one, remove the stub suffix to get the normal
// package and APK names.
String systemProfilePath =
getPrebuildProfilePath(disabledPs.pkg).replace(STUB_SUFFIX, "");
profileFile = new File(systemProfilePath);
// If we have a profile for a compressed APK, copy it to the reference
// location.
// Note that copying the profile here will cause it to override the
// reference profile every OTA even though the existing reference profile
// may have more data. We can't copy during decompression since the
// directories are not set up at that point.
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".
if (!mInstaller.copySystemProfile(profileFile.getAbsolutePath(),
pkg.applicationInfo.uid, pkg.packageName,
ArtManager.getProfileName(null))) {
Log.e(TAG, "Failed to copy system profile for stub package!");
} else {
useProfileForDexopt = true;
}
} catch (Exception e) {
Log.e(TAG, "Failed to copy profile " +
profileFile.getAbsolutePath() + " ", e);
}
}
}
}
}

if (!PackageDexOptimizer.canOptimizePackage(pkg)) {
if (DEBUG_DEXOPT) {
Log.i(TAG, "Skipping update of of non-optimizable app " + pkg.packageName);
}
numberOfPackagesSkipped++;
continue;
}

if (DEBUG_DEXOPT) {
Log.i(TAG, "Updating app " + numberOfPackagesVisited + " of " +
numberOfPackagesToDexopt + ": " + pkg.packageName);
}

if (showDialog) {
try {
ActivityManager.getService().showBootMessage(
mContext.getResources().getString(R.string.android_upgrading_apk,
numberOfPackagesVisited, numberOfPackagesToDexopt), true);
} catch (RemoteException e) {
}
synchronized (mPackages) {
mDexOptDialogShown = true;
}
}

int pkgCompilationReason = compilationReason;
if (useProfileForDexopt) {
// Use background dexopt mode to try and use the profile. Note that this does not
// guarantee usage of the profile.
pkgCompilationReason = PackageManagerService.REASON_BACKGROUND_DEXOPT;
}

if (SystemProperties.getBoolean(PRECOMPILE_LAYOUTS, false)) {
mArtManagerService.compileLayouts(pkg);
}

// checkProfiles is false to avoid merging profiles during boot which
// might interfere with background compilation (b/28612421).
// Unfortunately this will also means that "pm.dexopt.boot=speed-profile" will
// behave differently than "pm.dexopt.bg-dexopt=speed-profile" but that's a
// trade-off worth doing to save boot time work.
int dexoptFlags = bootComplete ? DexoptOptions.DEXOPT_BOOT_COMPLETE : 0;
if (compilationReason == REASON_FIRST_BOOT) {
// TODO: This doesn't cover the upgrade case, we should check for this too.
dexoptFlags |= DexoptOptions.DEXOPT_INSTALL_WITH_DEX_METADATA_FILE;
}
//执行dexopt操作
int primaryDexOptStaus = performDexOptTraced(new DexoptOptions(
pkg.packageName,
pkgCompilationReason,
dexoptFlags));

switch (primaryDexOptStaus) {
case PackageDexOptimizer.DEX_OPT_PERFORMED:
numberOfPackagesOptimized++;
break;
case PackageDexOptimizer.DEX_OPT_SKIPPED:
numberOfPackagesSkipped++;
break;
case PackageDexOptimizer.DEX_OPT_FAILED:
numberOfPackagesFailed++;
break;
default:
Log.e(TAG, "Unexpected dexopt return code " + primaryDexOptStaus);
break;
}
}

return new int[] { numberOfPackagesOptimized, numberOfPackagesSkipped,
numberOfPackagesFailed };
}

3.3 performFstrimIfNeeded

这个操作主要是用来清理磁盘碎片,条件是离上一次的清理的时间间隔3天。sm.runMaintenance方法调用的是StorageManagerService中的runMaintenance方法。

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 static final long DEFAULT_MANDATORY_FSTRIM_INTERVAL = 3 * DateUtils.DAY_IN_MILLIS;
@Override
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
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
// Binder entry point for kicking off an immediate fstrim
@Override
public void runMaintenance() {
enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
runIdleMaintenance(null);
}
@Override
public void fstrim(int flags, IVoldTaskListener listener) {
enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);

try {
mVold.fstrim(flags, new IVoldTaskListener.Stub() {
@Override
public void onStatus(int status, PersistableBundle extras) {
dispatchOnStatus(listener, status, extras);

// Ignore trim failures
if (status != 0) return;

final String path = extras.getString("path");
final long bytes = extras.getLong("bytes");
final long time = extras.getLong("time");

final DropBoxManager dropBox = mContext.getSystemService(DropBoxManager.class);
dropBox.addText(TAG_STORAGE_TRIM, scrubPath(path) + " " + bytes + " " + time);

synchronized (mLock) {
final VolumeRecord rec = findRecordForPath(path);
if (rec != null) {
rec.lastTrimMillis = System.currentTimeMillis();
writeSettingsLocked();
}
}
}

@Override
public void onFinished(int status, PersistableBundle extras) {
dispatchOnFinished(listener, status, extras);

// TODO: benchmark when desired
}
});
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
}

3.4 systemReady

系统初始化完成并且PKMS也初始化完成,PKMS需要进行的操作,如通知其他服务执行systemReady操作。

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
@Override
public void systemReady() {
enforceSystemOrRoot("Only the system can claim the system is ready");

mSystemReady = true;
final ContentResolver resolver = mContext.getContentResolver();
ContentObserver co = new ContentObserver(mHandler) {
@Override
public void onChange(boolean selfChange) {
mWebInstantAppsDisabled =
(Global.getInt(resolver, Global.ENABLE_EPHEMERAL_FEATURE, 1) == 0) ||
(Secure.getInt(resolver, Secure.INSTANT_APPS_ENABLED, 1) == 0);
}
};
mContext.getContentResolver().registerContentObserver(android.provider.Settings.Global
.getUriFor(Global.ENABLE_EPHEMERAL_FEATURE),
false, co, UserHandle.USER_SYSTEM);
mContext.getContentResolver().registerContentObserver(android.provider.Settings.Secure
.getUriFor(Secure.INSTANT_APPS_ENABLED), false, co, UserHandle.USER_SYSTEM);
co.onChange(true);

// Disable any carrier apps. We do this very early in boot to prevent the apps from being
// disabled after already being started.
CarrierAppUtils.disableCarrierAppsUntilPrivileged(mContext.getOpPackageName(), this,
mContext.getContentResolver(), UserHandle.USER_SYSTEM);

disableSkuSpecificApps();

// Read the compatibilty setting when the system is ready.
boolean compatibilityModeEnabled = android.provider.Settings.Global.getInt(
mContext.getContentResolver(),
android.provider.Settings.Global.COMPATIBILITY_MODE, 1) == 1;
PackageParser.setCompatibilityModeEnabled(compatibilityModeEnabled);
if (DEBUG_SETTINGS) {
Log.d(TAG, "compatibility mode:" + compatibilityModeEnabled);
}

int[] grantPermissionsUserIds = EMPTY_INT_ARRAY;

synchronized (mPackages) {
// Verify that all of the preferred activity components actually
// exist. It is possible for applications to be updated and at
// that point remove a previously declared activity component that
// had been set as a preferred activity. We try to clean this up
// the next time we encounter that preferred activity, but it is
// possible for the user flow to never be able to return to that
// situation so here we do a sanity check to make sure we haven't
// left any junk around.
ArrayList<PreferredActivity> removed = new ArrayList<PreferredActivity>();
for (int i=0; i<mSettings.mPreferredActivities.size(); i++) {
PreferredIntentResolver pir = mSettings.mPreferredActivities.valueAt(i);
removed.clear();
for (PreferredActivity pa : pir.filterSet()) {
if (mActivities.mActivities.get(pa.mPref.mComponent) == null) {
removed.add(pa);
}
}
if (removed.size() > 0) {
for (int r=0; r<removed.size(); r++) {
PreferredActivity pa = removed.get(r);
Slog.w(TAG, "Removing dangling preferred activity: "
+ pa.mPref.mComponent);
pir.removeFilter(pa);
}
mSettings.writePackageRestrictionsLPr(
mSettings.mPreferredActivities.keyAt(i));
}
}

for (int userId : UserManagerService.getInstance().getUserIds()) {
if (!mSettings.areDefaultRuntimePermissionsGrantedLPr(userId)) {
grantPermissionsUserIds = ArrayUtils.appendInt(
grantPermissionsUserIds, userId);
}
}
}
sUserManager.systemReady();
// If we upgraded grant all default permissions before kicking off.
for (int userId : grantPermissionsUserIds) {
mDefaultPermissionPolicy.grantDefaultPermissions(userId);
}

if (grantPermissionsUserIds == EMPTY_INT_ARRAY) {
// If we did not grant default permissions, we preload from this the
// default permission exceptions lazily to ensure we don't hit the
// disk on a new user creation.
mDefaultPermissionPolicy.scheduleReadDefaultPermissionExceptions();
}

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

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

3.5 waitForAppDataPrepared

该方法主要是等待mPrepareAppDataFuture多线程的任务都处理完成。

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
public void waitForAppDataPrepared() {
if (mPrepareAppDataFuture == null) {
return;
}
ConcurrentUtils.waitForFutureNoInterrupt(mPrepareAppDataFuture, "wait for prepareAppData");
mPrepareAppDataFuture = null;
}

/**
* Waits if necessary for the computation to complete, and then retrieves its result.
* <p>If {@code InterruptedException} occurs, this method will interrupt the current thread
* and throw {@code IllegalStateException}</p>
*
* @param future future to wait for result
* @param description short description of the operation
* @return the computed result
* @throws IllegalStateException if interrupted during wait
* @throws RuntimeException if an error occurs while waiting for {@link Future#get()}
* @see Future#get()
*/
public static <T> T waitForFutureNoInterrupt(Future<T> future, String description) {
try {
return future.get();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new IllegalStateException(description + " interrupted");
} catch (ExecutionException e) {
throw new RuntimeException(description + " failed", e);
}
}

四、PKMS总结

主要介绍了PKMS从SystemServer开始启动的相关流程,并详细介绍了流程相关的重要方法。PKMS初始化按照其代码的日志区分可以分为五个阶段,但从其功能上来说,可以分为三个阶段:

第一阶段:主要是扫描解析XML文件,并将其中的信息保存到特定的数据结构中,为下一阶段工作提供重要的参考信息;

第二阶段:扫描各个目录下的APK,可以看到手机上apk,扫描的工作量就越大,系统启动速度也就越慢; 第三阶段:主要是更新相关信息并启动PackageInstallerService服务。

PKMS构造函数工作任务非常繁重,特别是在扫描apk的时候。如果需要优化该流程以加快启动速度,则这个是一个好的方向。如延时扫描不重要的apk,或者保存Package信息到文件,然后启动时从文件中恢复这些信息以减少APK文件读取并解析xml的工作量。但是一直没有比较满意的方案,原因很多,比如apk之间有着比较多微妙的关系,因此到底延时扫描哪些apk,尚不能确定。还有一种方案是,PKMS可以启动多个线程扫描不同的目录,在android10.0中可以看到在扫描的时候已经启动多线程来扫描。对于PKMS的优化,Google基本上能想到基本上已经优化了,我们也可以思考。

后记

对于这些流程中有一些操作并没有详细的描述,由于篇幅有限将单独介绍。

PKMS相关类分析

installd守护进程

fstrim解析

Android dex,odex,oat,vdex,art文件结构

参考资料

https://blog.csdn.net/thh159/article/details/88289642

https://www.jianshu.com/p/cbf8e73f41ed

https://blog.csdn.net/innost/article/details/47253179

https://blog.csdn.net/xiaosongluo/article/details/52014585

https://blog.csdn.net/u013553529/article/details/61962439

附录

源码路径

1
2
3
4
5
frameworks/base/core/java/android/content/pm/PackageManager.java
frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
frameworks/base/core/java/android/app/ApplicationPackageManager.java
frameworks/base/core/java/android/content/pm/IPackageManager.aidl
frameworks/base/services/java/com/android/server/SystemServer.java

LI、LIF、LPw、LPr的含义

PackageManagerService中方法名中LI、LIF、LPw、LPr的含义

PackageManagerService内部用两个锁,mInstallLock和mPackages。LI、LIF、LPw、LPr中的L,指的是Lock,而后米娜跟的是I和P两个锁,I表示mInstallLock同步锁,P表示mPackages同步锁。LPw、LPr中的w表示writing,r表示reading。LIF中的F表示Frozen.

mInstallLockt同步锁是指安装app的时候,对安装的处理要用synchronized保护起来,用于保护所有对installd的访问,installd通常包含对应用数据的繁重操作。

mPackages同步锁用来保护内存中已经解析的包信息以及其他相关状态。因为争抢mPackage锁的请求很多,只能短时间持有这个锁。

1
2
3
4
5
6
7
8
9
10
11
//这种情况是允许的,因为mPackages处理完成之后,其他对mPackages操作的请求可以处理,不需要等待太久
//由于mInstall的时间很长, synchronized (mPackages)比较快,不会对mInstallLock有很大影响
synchronized (mInstallLock) {
synchronized (mPackages) {
}
}
//不允许,mInstall的时间很长,会导致mPackages锁住的时间变长
synchronized (mPackages) {
synchronized (mInstallLock) {
}
}

@GuardedBy注解,用于标记哪些变量要用同步锁保护起来。

PackageManagerService中的注解

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
/**
* Keep track of all those APKs everywhere.
* <p>
* Internally there are two important locks:
* <ul>
* <li>{@link #mPackages} is used to guard all in-memory parsed package details
* and other related state. It is a fine-grained lock that should only be held
* momentarily, as it's one of the most contended locks in the system.
* <li>{@link #mInstallLock} is used to guard all {@code installd} access, whose
* operations typically involve heavy lifting of application data on disk. Since
* {@code installd} is single-threaded, and it's operations can often be slow,
* this lock should never be acquired while already holding {@link #mPackages}.
* Conversely, it's safe to acquire {@link #mPackages} momentarily while already
* holding {@link #mInstallLock}.
* </ul>
* Many internal methods rely on the caller to hold the appropriate locks, and
* this contract is expressed through method name suffixes:
* <ul>
* <li>fooLI(): the caller must hold {@link #mInstallLock}
* <li>fooLIF(): the caller must hold {@link #mInstallLock} and the package
* being modified must be frozen
* <li>fooLPr(): the caller must hold {@link #mPackages} for reading
* <li>fooLPw(): the caller must hold {@link #mPackages} for writing
* </ul>
* <p>
* Because this class is very central to the platform's security; please run all
* CTS and unit tests whenever making modifications:
*
* <pre>
* $ runtest -c android.content.pm.PackageManagerTests frameworks-core
* $ cts-tradefed run commandAndExit cts -m CtsAppSecurityHostTestCases
* </pre>
*/

A/B(无缝)系统更新

A/B 系统更新(也称为无缝更新)的目标是确保在无线下载 (OTA) 更新期间在磁盘上保留一个可正常启动和使用的系统。采用这种方式可以降低更新之后设备无法启动的可能性,这意味着用户需要将设备送到维修和保修中心进行更换和刷机的情况将会减少。其他某些商业级操作系统(例如 ChromeOS)也成功使用了 A/B 更新机制。

要详细了解 A/B 系统更新,请参见分区选择(槽位)一节。

A/B 系统更新可带来以下好处**

  • OTA 更新可以在系统运行期间进行,而不会打断用户。用户可以在 OTA 期间继续使用其设备。在更新期间,唯一的一次宕机发生在设备重新启动到更新后的磁盘分区时。
  • 更新后,重新启动所用的时间不会超过常规重新启动所用的时间。
  • 如果 OTA 无法应用(例如,因为刷机失败),用户将不会受到影响。用户将继续运行旧的操作系统,并且客户端可以重新尝试进行更新。
  • 如果 OTA 更新已应用但无法启动,设备将重新启动回旧分区,并且仍然可以使用。客户端可以重新尝试进行更新。
  • 任何错误(例如 I/O 错误)都只会影响未使用的分区组,并且用户可以进行重试。由于 I/O 负载被特意控制在较低水平,以免影响用户体验,因此发生此类错误的可能性也会降低。
  • 更新包可以流式传输到 A/B 设备,因此在安装之前不需要先下载更新包。流式更新意味着用户没有必要在 /data/cache 上留出足够的可用空间来存储更新包。
  • 缓存分区不再用于存储 OTA 更新包,因此无需确保缓存分区的大小要足以应对日后的更新。
  • dm-verity 可保证设备将使用未损坏的启动映像。如果设备因 OTA 错误或 dm-verity 问题而无法启动,则可以重新启动到旧映像。(Android 验证启动不需要 A/B 更新。)

关于 A/B 系统更新

进行 A/B 更新时,客户端和系统都需要进行更改。不过,OTA 更新包服务器应该不需要进行更改:更新包仍通过 HTTPS 提供。对于使用 Google OTA 基础架构的设备,系统更改全部是在 AOSP 中进行,并且客户端代码由 Google Play 服务提供。不使用 Google OTA 基础架构的原始设备制造商 (OEM) 将能够重复使用 AOSP 系统代码,但需要自行提供客户端。

如果 OEM 自行提供客户端,客户端需要:

  • 确定何时进行更新。由于 A/B 更新是在后台进行,因此不再需要由用户启动。为了避免干扰用户,建议将更新安排在设备处于闲时维护模式(如夜间)并已连接到 WLAN 网络时进行。不过,客户端可以使用您希望使用的任何启发法。
  • 向 OTA 更新包服务器进行核查,确定是否有可用的更新。这应与您现有的客户端代码大体相同,不过您需要表明相应设备支持 A/B 更新。(Google 的客户端还包含立即检查按钮,以便用户检查是否有最新更新。)
  • 调用 update_engine(使用 HTTPS 网址),以获取更新包(假设有可用的更新包)。update_engine 将在流式传输更新包的同时,在当前未使用的分区上更新原始数据块。
  • 根据 update_engine 结果代码向您的服务器报告安装是成功了还是失败了。如果更新已成功应用,update_engine 将会告知引导加载程序在下次重新启动时启动到新的操作系统。如果新的操作系统无法启动,引导加载程序将会回退到旧的操作系统,因此无需在客户端执行任何操作。如果更新失败,客户端将需要根据详细的错误代码确定何时(以及是否)重试。例如,优秀的客户端能够识别出是一部分(“diff”)OTA 更新包失败,并改为尝试完整的 OTA 更新包。

客户端可能会:

  • 显示通知,以提醒用户重新启动系统。如果您想要实施鼓励用户定期更新的政策,则可以将该通知添加到客户端。如果客户端不提示用户,用户将会在下次重新启动系统时收到更新。(Google 的客户端会有延迟,该延迟可按每次更新进行配置。)
  • 显示通知,以告知用户他们是启动到了新的操作系统版本,还是应启动到新的操作系统版本,但却回退到了旧的操作系统版本。(Google 的客户端通常不会显示此类通知。)

在系统方面,A/B 系统更新会影响以下各项:

  • 分区选择(槽位)、update_engine 守护进程,以及引导加载程序交互(如下所述)
  • 编译过程和 OTA 更新包生成(如实现 A/B 更新中所述)

注意:只有对于新设备,才建议通过 OTA 实现 A/B 系统更新。

分区选择(槽位)

A/B 系统更新使用两组称为槽位(通常是槽位 A 和槽位 B)的分区。系统从“当前”槽位运行,但在正常操作期间,运行中的系统不会访问未使用的槽位中的分区。这种方法通过将未使用的槽位保留为后备槽位,来防范更新出现问题:如果在更新期间或更新刚刚完成后出现错误,系统可以回滚到原来的槽位并继续正常运行。为了实现这一目标,当前槽位使用的任何分区(包括只有一个副本的分区)都不应在 OTA 更新期间进行更新。

每个槽位都有一个“可启动”属性,该属性用于表明相应槽位存储的系统正确无误,设备可从相应槽位启动。系统运行时,当前槽位处于可启动状态,但另一个槽位则可能包含旧版本(仍然正确)的系统、包含更新版本的系统,或包含无效的数据。无论当前槽位是哪一个,都有一个槽位是活动槽位(引导加载程序在下次启动时将使用的槽位,也称为首选槽位)。

此外,每个槽位还都有一个由用户空间设置的“成功”属性,仅当相应槽位处于可启动状态时,该属性才具有相关性。被标记为成功的槽位应该能够自行启动、运行和更新。未被标记为成功的可启动槽位(多次尝试使用它启动之后)应由引导加载程序标记为不可启动,其中包括将活动槽位更改为另一个可启动的槽位(通常是更改为在尝试启动到新的活动槽位之前正在运行的槽位)。关于相应接口的具体详细信息在 boot_control.h 中进行了定义。

更新引擎守护进程

A/B 系统更新过程会使用名为 update_engine 的后台守护进程来使系统做好准备,以启动到更新后的新版本。该守护进程可以执行以下操作:

  • 按照 OTA 更新包的指示,从当前槽位 A/B 分区读取数据,然后将所有数据写入到未使用槽位 A/B 分区。
  • 在预定义的工作流程中调用 boot_control 接口。
  • 按照 OTA 更新包的指示,在将数据写入到所有未使用槽位分区之后,从新分区运行安装后程序。(有关详细信息,请参阅安装后)。

由于 update_engine 守护进程本身不会参与到启动流程中,因此该守护进程在更新期间可执行的操作受限于当前槽位中的 SELinux 政策和功能(在系统启动到新版本之前,此类政策和功能无法更新)。为了维持一个稳定可靠的系统,更新流程不应修改分区表、当前槽位中各个分区的内容,以及无法通过恢复出厂设置擦除的非 A/B 分区的内容。

更新引擎源代码

update_engine 源代码位于 system/update_engine 中。A/B OTA dexopt 文件分开放到了 installd 和一个程序包管理器中:

  • frameworks/native/cmds/installd/ota* 包括安装后脚本、用于 chroot 的二进制文件、负责调用 dex2oat 的已安装克隆、OTA 后 move-artifacts 脚本,以及 move 脚本的 rc 文件。
  • frameworks/base/services/core/java/com/android/server/pm/OtaDexoptService.java(加上 OtaDexoptShellCommand)是负责为应用准备 dex2oat 命令的程序包管理器。

如需实际示例,请参阅 /device/google/marlin/device-common.mk

更新引擎日志

对于 Android 8.x 及更低版本,可在 logcat 及错误报告中找到 update_engine 日志。要使 update_engine 日志可在文件系统中使用,请将以下更改添加到您的细分版本中:

这些更改会将最新的 update_engine 日志的副本保存到 /data/misc/update_engine_log/update_engine.YEAR-TIME。除当前日志以外,最近的五个日志也会保存在 /data/misc/update_engine_log/ 下。拥有日志组 ID 的用户将能够访问相应的文件系统日志。

引导加载程序交互

boot_control HAL 供 update_engine(可能还有其他守护进程)用于指示引导加载程序从何处启动。常见的示例情况及其相关状态包括:

  • 正常情况:系统正在从其当前槽位(槽位 A 或槽位 B)运行。到目前为止尚未应用任何更新。系统的当前槽位是可启动且被标记为成功的活动槽位。
  • 正在更新:系统正在从槽位 B 运行,因此,槽位 B 是可启动且被标记为成功的活动槽位。由于槽位 A 中的内容正在更新,但是尚未完成,因此槽位 A 被标记为不可启动。在此状态下,应继续从槽位 B 重新启动。
  • 已应用更新,正在等待重新启动:系统正在从槽位 B 运行,槽位 B 可启动且被标记为成功,但槽位 A 之前被标记为活动槽位(因此现在被标记为可启动)。槽位 A 尚未被标记为成功,引导加载程序应尝试从槽位 A 启动若干次。
  • 系统已重新启动到新的更新:系统正在首次从槽位 A 运行,槽位 B 仍可启动且被标记为成功,而槽位 A 仅可启动,且仍是活动槽位,但未被标记为成功。在进行一些检查之后,用户空间守护进程 update_verifier 应将槽位 A 标记为成功。

流式更新支持

用户设备并非在 /data 上总是有足够的空间来下载更新包。由于 OEM 和用户都不想浪费 /cache 分区上的空间,因此有些用户会因为设备上没有空间来存储更新包而不进行更新。为了解决这个问题,Android 8.0 中添加了对流式 A/B 更新(下载数据块后直接将数据块写入 B 分区,而无需将数据块存储在 /data 上)的支持。流式 A/B 更新几乎不需要临时存储空间,并且只需要能够存储大约 100KiB 元数据的存储空间即可。

要在 Android 7.1 中实现流式更新,请选择以下补丁程序:

无论是使用 Google 移动服务 (GMS),还是使用任何其他更新客户端,都需要安装这些补丁程序,才能在 Android 7.1 中支持流式传输 A/B 更新包。

A/B 更新过程

当有 OTA 更新包(在代码中称为有效负载)可供下载时,更新流程便开始了。设备中的政策可以根据电池电量、用户活动、充电状态或其他政策来延迟下载和应用有效负载。此外,由于更新是在后台运行,因此用户可能并不知道正在进行更新。所有这些都意味着,更新流程可能随时会由于政策、意外重新启动或用户操作而中断。

OTA 更新包本身所含的元数据可能会指示可进行流式更新,在这种情况下,相应更新包也可采用非流式安装方式。服务器可以利用这些元数据告诉客户端正在进行流式更新,以便客户端正确地将 OTA 移交给 update_engine。如果设备制造商具有自己的服务器和客户端,便可以通过确保以下两项来实现流式更新:确保服务器能够识别出更新是流式更新(或假定所有更新都是流式更新),并确保客户端能够正确调用 update_engine 来进行流式更新。制造商可以根据更新包是流式更新变体这一事实向客户端发送一个标记,以便在进行流式更新时触发向框架端的移交工作。

有可用的有效负载后,更新流程将遵循如下步骤:

步骤 操作
1 通过 markBootSuccessful() 将当前槽位(或“源槽位”)标记为成功(如果尚未标记)。
2 调用函数 setSlotAsUnbootable(),将未使用的槽位(或“目标槽位”)标记为不可启动。当前槽位始终会在更新开始时被标记为成功,以防止引导加载程序回退到未使用的槽位(该槽位中很快将会有无效数据)。如果系统已做好准备,可以开始应用更新,那么即使其他主要组件出现损坏(例如界面陷入崩溃循环),当前槽位也会被标记为成功,因为可以通过推送新软件来解决这些问题。 更新有效负载是不透明的 Blob,其中包含更新到新版本的指示。更新有效负载由以下部分组成:元数据。元数据在更新有效负载中所占的比重相对较小,其中包含一系列用于在目标槽位上生成和验证新版本的操作。例如,某项操作可能会解压缩特定 Blob 并将其写入到目标分区中的特定块,或者从源分区读取数据、应用二进制补丁程序,然后写入到目标分区中的特定块。额外数据。与操作相关的额外数据在更新有效负载中占据了大部分比重,其中包含这些示例中的已压缩 Blob 或二进制补丁程序。
3 下载有效负载元数据。
4 对于元数据中定义的每项操作,都将按顺序发生以下行为:将相关数据(如果有)下载到内存中、应用操作,然后释放关联的内存。
5 对照预期的哈希重新读取并验证所有分区。
6 运行安装后步骤(如果有)。如果在执行任何步骤期间出现错误,则更新失败,系统可能会通过其他有效负载重新尝试更新。如果上述所有步骤均已成功完成,则更新成功,系统会执行最后一个步骤。
7 调用 setActiveBootSlot(),将未使用的槽位标记为活动槽位。将未使用的槽位标记为活动槽位并不意味着它将完成启动。如果引导加载程序(或系统本身)未读取到“成功”状态,则可以将活动槽位切换回来。
8 安装后步骤(如下所述)包括从“新更新”版本中运行仍在旧版本中运行的程序。如果此步骤已在 OTA 更新包中定义,则为强制性步骤,且程序必须返回并显示退出代码 0,否则更新会失败。
9 在系统足够深入地成功启动到新槽位并完成重新启动后检查之后,系统会调用 markBootSuccessful(),将现在的当前槽位(原“目标槽位”)标记为成功。

注意:第 3 步和第 4 步占用了大部分更新时间,因为这两个步骤涉及写入和下载大量数据,并且可能会因政策或重新启动等原因而中断。

安装后

对于定义了安装后步骤的每个分区,update_engine 都会将新分区装载到特定位置,并执行与装载的分区相关的 OTA 中指定的程序。例如,如果安装后程序被定义为相应系统分区中的 usr/bin/postinstall,则系统会将未使用槽位中的这个分区装载到一个固定位置(例如 /postinstall_mount),然后执行 /postinstall_mount/usr/bin/postinstall 命令。

为确保成功执行安装后步骤,旧内核必须能够:

  • 装载新的文件系统格式。文件系统类型不能更改(除非旧内核中支持这么做),包括使用的压缩算法(如果使用 SquashFS 等经过压缩的文件系统)等详细信息。
  • 理解新分区的安装后程序格式。如果使用可执行且可链接格式 (ELF) 的二进制文件,则该文件应该与旧内核兼容(例如,如果架构从 32 位细分版本改为使用 64 位细分版本,则 64 位的新程序应该可以在旧的 32 位内核上运行)。除非加载程序 (ld) 收到使用其他路径或编译静态二进制文件的指令,否则将会从旧系统映像而非新系统映像加载各种库。

例如,您可以使用 shell 脚本作为安装后程序(由旧系统中顶部包含 #! 标记的 shell 二进制文件解析),然后从新环境设置库路径,以便执行更复杂的二进制安装后程序。或者,您可以从专用的较小分区执行安装后步骤,以便主系统分区中的文件系统格式可以得到更新,同时不会产生向后兼容问题或引发 stepping-stone 更新;这样一来,用户便可以从出厂映像直接更新到最新版本。

新的安装后程序将受旧系统中定义的 SELinux 政策限制。因此,安装后步骤适用于在指定设备上执行设计所要求的任务或其他需要尽可能完成的任务(例如,更新支持 A/B 更新的固件或引导加载程序、为新版本准备数据库副本,等等)。安装后步骤不适用于重新启动之前的一次性错误修复(此类修复需要无法预见的权限)。

所选的安装后程序在 postinstall SELinux 环境中运行。新装载的分区中的所有文件都将带有 postinstall_file 标记,无论在重新启动到新系统后它们的属性如何,都是如此。在新系统中对 SELinux 属性进行的更改不会影响安装后步骤。如果安装后程序需要额外的权限,则必须将这些权限添加到安装后环境中。

重新启动后

重新启动后,update_verifier 会触发利用 dm-verity 进行完整性检查。系统会先启动该检查,然后再启动 zygote,以避免 Java 服务进行任何无法撤消且会导致无法进行安全回滚的更改。在此过程中,如果验证启动功能或 dm-verity 检测到任何损坏,引导加载程序和内核还可能会触发重新启动。检查完成后,update_verifier 会将启动标记为成功。

update_verifier 只会读取 /data/ota_package/care_map.txt(在使用 AOSP 代码时,该文件会包含在 A/B OTA 更新包中)中列出的数据块。Java 系统更新客户端(例如 GmsCore)会在重新启动设备前提取 care_map.txt 并设置访问权限,在系统成功启动到新版本后会删除所提取的文件。