[toc]
基于 Android 7.1.1 源码分析 PackageManagerService 的架构和逻辑实现,本文是作者原创,转载请说明出处!
0 综述
system 分区和 data 分区的扫描过程到这里就结束了,下面我们来分析下:
1 | ... ... ... ...// 第四阶段 |
下面我们来分析下这个过程!
1 PackageMS.updatePermissionsLPw - 更新权限信息
updatePermissionsLPw 方法用于更新应用的权限信息,首先我们来看看 updateFlags!
1 | int updateFlags = UPDATE_PERMISSIONS_ALL; // 表示更新所有的权限信息; |
updatePermissionsLPw 的逻辑如下,这里的 changingPkg 和 pkgInfo 均为 null;
replaceVolumeUuid 的值为:StorageManager.UUID_PRIVATE_INTERNAL,表示的是安装位置,这里传入的值表示内置存储;
(这里简单的说一下参数的意思:String changingPkg 指定了权限发生变化的包名,PackageParser.Package pkgInfo 表示的是 changingPkg 对应的应用的信息)
1 | private void updatePermissionsLPw(String changingPkg, |
由于这里的 changingPkg 和 pkgInfo 均为 null,所以不仅移除了无效的权限和权限树,而且更新了系统中所有应用的权限信息!
这里涉及到了 flags 标志位,可以取以下值:
1 | static final int UPDATE_PERMISSIONS_ALL = 1<<0; // 更新所有应用的权限信息; |
下面的分析过程中会遇到:
我们继续分析!
1.1 PackageMS.findPermissionTreeLP
找到权限名所属的权限树!1
2
3
4
5
6
7
8
9
10private BasePermission findPermissionTreeLP(String permName) {
for(BasePermission bp : mSettings.mPermissionTrees.values()) {
if (permName.startsWith(bp.name) &&
permName.length() > bp.name.length() &&
permName.charAt(bp.name.length()) == '.') {
return bp;
}
}
return null;
}
1.2 PackageMS.grantPermissionsLPw
在更新过权限后,会再次授予应用权限,因为可能有些权限已经失效并且被移除!
Android 系统有两种类型的权限:安装和运行时,dangerous 属于运行时权限,normal 和 signiture 属于安装时权限。
正常和签名保护级别的权限是安装时权限。 而危险级别的权限是运行时权限!
如果应用的目标 SDK 为 Lollipop MR1 或更早版本,则运行时权限默认按照安装时权限处理。根据上面的代码跟踪
这里的 replace 为 true,由于我们是更新所有的 pacakge,所以 pkg 和 packageOfInterest 均为 null,参数 pkg 是需要更新权限授予信息的应用!
1 | private void grantPermissionsLPw(PackageParser.Package pkg, boolean replace, |
1.2.1 PackageMS.revokeUnusedSharedUserPermissionsLPw
撤销不再使用的共享用户权限;
参数 SharedUserSetting su 表示的是共享 uid 的信息对象!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
63private int[] revokeUnusedSharedUserPermissionsLPw(SharedUserSetting su, int[] allUserIds) {
//【1】收集该 shared user 下的所有被请求的权限!
ArraySet<String> usedPermissions = new ArraySet<>();
final int packageCount = su.packages.size();
for (int i = 0; i < packageCount; i++) {
PackageSetting ps = su.packages.valueAt(i);
if (ps.pkg == null) {
continue;
}
final int requestedPermCount = ps.pkg.requestedPermissions.size();
for (int j = 0; j < requestedPermCount; j++) {
String permission = ps.pkg.requestedPermissions.get(j);
BasePermission bp = mSettings.mPermissions.get(permission);
if (bp != null) {
usedPermissions.add(permission);
}
}
}
//【2】获得该 shared user 的权限管理对象!!
PermissionsState permissionsState = su.getPermissionsState();
//【3】撤销那些本次不再申请,但是之前申请了的安装时权限!!
List<PermissionState> installPermStates = permissionsState.getInstallPermissionStates();
final int installPermCount = installPermStates.size();
for (int i = installPermCount - 1; i >= 0; i--) {
PermissionState permissionState = installPermStates.get(i);
if (!usedPermissions.contains(permissionState.getName())) {
BasePermission bp = mSettings.mPermissions.get(permissionState.getName());
if (bp != null) {
//【3.1】撤销权限,移除所有标志位;
permissionsState.revokeInstallPermission(bp);
permissionsState.updatePermissionFlags(bp, UserHandle.USER_ALL,
PackageManager.MASK_PERMISSION_FLAGS, 0);
}
}
}
int[] runtimePermissionChangedUserIds = EmptyArray.INT;
//【4】撤销那些本次不再申请,但是之前申请了的运行时权限!!
for (int userId : allUserIds) {
List<PermissionState> runtimePermStates = permissionsState
.getRuntimePermissionStates(userId);
final int runtimePermCount = runtimePermStates.size();
for (int i = runtimePermCount - 1; i >= 0; i--) {
PermissionState permissionState = runtimePermStates.get(i);
if (!usedPermissions.contains(permissionState.getName())) {
BasePermission bp = mSettings.mPermissions.get(permissionState.getName());
if (bp != null) {
//【4.1】撤销权限,移除所有标志位;
permissionsState.revokeRuntimePermission(bp, userId);
permissionsState.updatePermissionFlags(bp, userId,
PackageManager.MASK_PERMISSION_FLAGS, 0);
//【4.2】返回该运行时权限所在的 userId;
runtimePermissionChangedUserIds = ArrayUtils.appendInt(
runtimePermissionChangedUserIds, userId);
}
}
}
}
//【5】返回该运行时权限所在的 userId;
return runtimePermissionChangedUserIds;
}
runtimePermissionChangedUserIds 用于持久化运行时数据库;
###1.2.2 PackageMS.grantSignaturePermission
grantSignaturePermission 方法用于判断签名是否能校验通过,我们在这里先忽略掉签名校验的过程,假设要么校验成功,要么校验失败!
1 | private boolean grantSignaturePermission(String perm, PackageParser.Package pkg, |
可以看到,这里对 Signature 类型的权限做了详细的处理!
2 Settings.applyDefaultPreferredAppsLPw - 默认应用设置
该方法用于设置默认应用!
1 | void applyDefaultPreferredAppsLPw(PackageManagerService service, int userId) { |
3 PMS.reconcileAppsDataLI - 准备数据目录
reconcileAppsDataLI 方法用于调整所有应用的数据,该方法会清楚那些被卸载或者重新安装到其他分区上的应用的已有数据,同时也会校验应用对应的数据目录是否存在,不存在的话,会创建对应的目录!
StorageManager.isFileEncryptedNativeOrEmulated() 方法用于判断系统是否运行在文件加密模式,如果是文件加密模式的话,storageFlags 只有 StorageManager.FLAG_STORAGE_DE;
1 | if (StorageManager.isFileEncryptedNativeOrEmulated()) { |
下面我们来看看 reconcileAppsDataLI 方法: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
79private void reconcileAppsDataLI(String volumeUuid, int userId, int flags) {
Slog.v(TAG, "reconcileAppsData for " + volumeUuid + " u" + userId + " 0x"
+ Integer.toHexString(flags));
// cdDir 文件对应的目录是:/data/user/<userId>,在默认用户下是 /data/user/0
// deDir 文件对应的目录是:/data/user_de/<userId>,在默认用户下是 /data/user_de/0
final File ceDir = Environment.getDataUserCeDirectory(volumeUuid, userId);
final File deDir = Environment.getDataUserDeDirectory(volumeUuid, userId);
//【1】系统运行在文件加密模式下,是不会就进入这里的,正常情况会进入这里;
if ((flags & StorageManager.FLAG_STORAGE_CE) != 0) {
if (StorageManager.isFileEncryptedNativeOrEmulated()
&& !StorageManager.isUserKeyUnlocked(userId)) { // 再次校验是否处于文件加密模式下!
throw new RuntimeException(
"Yikes, someone asked us to reconcile CE storage while " + userId
+ " was still locked; this would have caused massive data loss!");
}
//【1.1】遍历 /data/user/0 目录,处理该目录下的每个文件!
final File[] files = FileUtils.listFilesOrEmpty(ceDir);
for (File file : files) {
final String packageName = file.getName();
try {
//【1.2】校验所有已经安装的应用的数据
assertPackageKnownAndInstalled(volumeUuid, packageName, userId);
} catch (PackageManagerException e) {
logCriticalInfo(Log.WARN, "Destroying " + file + " due to: " + e);
try {
// 通过 installd 删除该 package 的旧数据!
mInstaller.destroyAppData(volumeUuid, packageName, userId,
StorageManager.FLAG_STORAGE_CE, 0);
} catch (InstallerException e2) {
logCriticalInfo(Log.WARN, "Failed to destroy: " + e2);
}
}
}
}
//【2】遍历 /data/user_de/0 目录,处理该目录下的每个文件!
if ((flags & StorageManager.FLAG_STORAGE_DE) != 0) {
final File[] files = FileUtils.listFilesOrEmpty(deDir);
for (File file : files) {
final String packageName = file.getName();
try {
assertPackageKnownAndInstalled(volumeUuid, packageName, userId);
} catch (PackageManagerException e) {
logCriticalInfo(Log.WARN, "Destroying " + file + " due to: " + e);
try {
// 通过 installd 删除该 package 的旧数据!
mInstaller.destroyAppData(volumeUuid, packageName, userId,
StorageManager.FLAG_STORAGE_DE, 0);
} catch (InstallerException e2) {
logCriticalInfo(Log.WARN, "Failed to destroy: " + e2);
}
}
}
}
//【3】确定系统中所有应用都有对应的 data 目录!
final List<PackageSetting> packages;
synchronized (mPackages) {
packages = mSettings.getVolumePackagesLPr(volumeUuid);
}
int preparedCount = 0;
for (PackageSetting ps : packages) {
final String packageName = ps.name;
if (ps.pkg == null) {
Slog.w(TAG, "Odd, missing scanned package " + packageName);
continue;
}
//【3.1】如果 package 已经安装了,那么就会调用 prepareAppDataLIF 方法,准备数据目录!
if (ps.getInstalled(userId)) {
prepareAppDataLIF(ps.pkg, userId, flags);
if (maybeMigrateAppDataLIF(ps.pkg, userId)) {
prepareAppDataLIF(ps.pkg, userId, flags);
}
preparedCount++;
}
}
Slog.v(TAG, "reconcileAppsData finished " + preparedCount + " packages");
}
这里想说下 /data/user/0 和 /data/user_de/0,其实它们是 /data/data 目录的 link 名称,本质上指向了一个目录!
这个过程如下:
- 校验所有已经安装的应用,删除那些异常情况下的应用的数据,如果应用改了包名等等的情况,删除之前的数据;
- 为没有数据目录的应用创建目录;
这个过程首先处理了 rename package 的情况,对于 rename package 的情况,重命名之前的数据是不可用的,所以这里会使用 assertPackageKnownAndInstalled 方法来进行处理!
1 | private void assertPackageKnownAndInstalled(String volumeUuid, String packageName, int userId) |
如果查不到安装数据,或者 volumeUuid 不匹配,或者该应用在当前设备用户 id 下不存在了,那就会抛出异常,然后 pms 会删除掉之前的数据!
normalizePackageNameLPr 会根据传入的 packageName,在 mRenamedPackages 找到重命名前的 oldName,如果该 package 之前重命名过,那么其一定会有 old name;
1 | private String normalizePackageNameLPr(String packageName) { |
方法逻辑很简单!
3.1 PMS.prepareAppDataLIF
prepareAppDataLIF 方法为应用准备数据目录!
1 | private void prepareAppDataLIF(PackageParser.Package pkg, int userId, int flags) { |
3.2 PMS.prepareAppDataLeafLIF
prepareAppDataLeafLIF 方法会继续处理数据目录操作:
1 | private void prepareAppDataLeafLIF(PackageParser.Package pkg, int userId, int flags) { |
3.3 PMS.prepareAppDataContentsLeafLIF
1 | private void prepareAppDataContentsLeafLIF(PackageParser.Package pkg, int userId, int flags) { |
可以看到,PMS 对于应用的数据目录的一系列操作,都是通过 installd 来实现的,因为 pms 本身没有 selinux 权限,所以他必须将权限交给一个特权进程,也就是 installd 来做!
4 PackageManagerService.clearAppDataLIF
清楚缓存数据的前提是:ps.volumeUuid == StorageManager.UUID_PRIVATE_INTERNAL
参数传递:flags 为 StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE | Installer.FLAG_CLEAR_CODE_CACHE_ONLY1
2
3
4
5
6
7
8
9
10
11private void clearAppDataLIF(PackageParser.Package pkg, int userId, int flags) {
if (pkg == null) {
Slog.wtf(TAG, "Package was null!", new Throwable());
return;
}
clearAppDataLeafLIF(pkg, userId, flags);
final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
for (int i = 0; i < childCount; i++) {
clearAppDataLeafLIF(pkg.childPackages.get(i), userId, flags);
}
}
继续调用:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16private void clearAppDataLeafLIF(PackageParser.Package pkg, int userId, int flags) {
final PackageSetting ps;
synchronized (mPackages) {
ps = mSettings.mPackages.get(pkg.packageName);
}
for (int realUserId : resolveUserIds(userId)) {
final long ceDataInode = (ps != null) ? ps.getCeDataInode(realUserId) : 0;
try {
mInstaller.clearAppData(pkg.volumeUuid, pkg.packageName, realUserId, flags,
ceDataInode);
} catch (InstallerException e) {
Slog.w(TAG, String.valueOf(e));
}
}
}
仍然是调用 mInstaller 来对用户的应用数据进行操作!
5 Settings.writeLPr - 持久化最新数据
将解析到的安装数据写回到 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
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
165void writeLPr() {
Debug.startMethodTracing("/data/system/packageprof", 8 * 1024 * 1024);
//【1】下面会先将最新的数据写入到 packages-backup.xml 文件中!
if (mSettingsFilename.exists()) {
if (!mBackupSettingsFilename.exists()) {
if (!mSettingsFilename.renameTo(mBackupSettingsFilename)) {
Slog.wtf(PackageManagerService.TAG,
"Unable to backup package manager settings, "
+ " current changes will be lost at reboot");
return;
}
} else {
mSettingsFilename.delete();
Slog.w(PackageManagerService.TAG, "Preserving older settings backup");
}
}
mPastSignatures.clear();
try {
FileOutputStream fstr = new FileOutputStream(mSettingsFilename);
BufferedOutputStream str = new BufferedOutputStream(fstr);
//XmlSerializer serializer = XmlUtils.serializerInstance();
XmlSerializer serializer = new FastXmlSerializer();
serializer.setOutput(str, StandardCharsets.UTF_8.name());
serializer.startDocument(null, true);
serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
serializer.startTag(null, "packages"); //【2】写入 "packages"!
for (int i = 0; i < mVersion.size(); i++) { //【3】写入 "version"
final String volumeUuid = mVersion.keyAt(i);
final VersionInfo ver = mVersion.valueAt(i);
serializer.startTag(null, TAG_VERSION);
XmlUtils.writeStringAttribute(serializer, ATTR_VOLUME_UUID, volumeUuid);
XmlUtils.writeIntAttribute(serializer, ATTR_SDK_VERSION, ver.sdkVersion);
XmlUtils.writeIntAttribute(serializer, ATTR_DATABASE_VERSION, ver.databaseVersion);
XmlUtils.writeStringAttribute(serializer, ATTR_FINGERPRINT, ver.fingerprint);
serializer.endTag(null, TAG_VERSION);
}
if (mVerifierDeviceIdentity != null) { //【4】写入 "verifier"
serializer.startTag(null, "verifier");
serializer.attribute(null, "device", mVerifierDeviceIdentity.toString());
serializer.endTag(null, "verifier");
}
if (mReadExternalStorageEnforced != null) {
serializer.startTag(null, TAG_READ_EXTERNAL_STORAGE);
serializer.attribute(
null, ATTR_ENFORCEMENT, mReadExternalStorageEnforced ? "1" : "0");
serializer.endTag(null, TAG_READ_EXTERNAL_STORAGE);
}
serializer.startTag(null, "permission-trees"); //【4.1】写入 "permission-trees"
for (BasePermission bp : mPermissionTrees.values()) {
writePermissionLPr(serializer, bp);
}
serializer.endTag(null, "permission-trees");
serializer.startTag(null, "permissions"); //【4.1】写入 "permissions"
for (BasePermission bp : mPermissions.values()) {
writePermissionLPr(serializer, bp);
}
serializer.endTag(null, "permissions");
for (final PackageSetting pkg : mPackages.values()) { // 写入 "package"
writePackageLPr(serializer, pkg);
}
for (final PackageSetting pkg : mDisabledSysPackages.values()) { // 写入 "updated-package"
writeDisabledSysPackageLPr(serializer, pkg);
}
for (final SharedUserSetting usr : mSharedUsers.values()) { // 写入 "shared-user"
serializer.startTag(null, "shared-user");
serializer.attribute(null, ATTR_NAME, usr.name);
serializer.attribute(null, "userId",
Integer.toString(usr.userId));
usr.signatures.writeXml(serializer, "sigs", mPastSignatures);
// 写入 shared-user 的安装时权限!
writePermissionsLPr(serializer, usr.getPermissionsState()
.getInstallPermissionStates());
serializer.endTag(null, "shared-user");
}
if (mPackagesToBeCleaned.size() > 0) { // 写入 "cleaning-package"
for (PackageCleanItem item : mPackagesToBeCleaned) {
final String userStr = Integer.toString(item.userId);
serializer.startTag(null, "cleaning-package");
serializer.attribute(null, ATTR_NAME, item.packageName);
serializer.attribute(null, ATTR_CODE, item.andCode ? "true" : "false");
serializer.attribute(null, ATTR_USER, userStr);
serializer.endTag(null, "cleaning-package");
}
}
if (mRenamedPackages.size() > 0) { // 写入 "renamed-package"
for (Map.Entry<String, String> e : mRenamedPackages.entrySet()) {
serializer.startTag(null, "renamed-package");
serializer.attribute(null, "new", e.getKey());
serializer.attribute(null, "old", e.getValue());
serializer.endTag(null, "renamed-package");
}
}
final int numIVIs = mRestoredIntentFilterVerifications.size();
if (numIVIs > 0) {
if (DEBUG_DOMAIN_VERIFICATION) {
Slog.i(TAG, "Writing restored-ivi entries to packages.xml");
}
serializer.startTag(null, "restored-ivi");
for (int i = 0; i < numIVIs; i++) {
IntentFilterVerificationInfo ivi = mRestoredIntentFilterVerifications.valueAt(i);
writeDomainVerificationsLPr(serializer, ivi);
}
serializer.endTag(null, "restored-ivi");
} else {
if (DEBUG_DOMAIN_VERIFICATION) {
Slog.i(TAG, " no restored IVI entries to write");
}
}
mKeySetManagerService.writeKeySetManagerServiceLPr(serializer);
serializer.endTag(null, "packages"); // 结束 packages-backup.xml 文件的写入!
serializer.endDocument();
str.flush();
FileUtils.sync(fstr);
str.close();
// New settings successfully written, old ones are no longer
// needed.
mBackupSettingsFilename.delete();
FileUtils.setPermissions(mSettingsFilename.toString(),
FileUtils.S_IRUSR|FileUtils.S_IWUSR
|FileUtils.S_IRGRP|FileUtils.S_IWGRP,
-1, -1);
writeKernelMappingLPr();
writePackageListLPr(); //【4.4】写入 packageslist 文件!
writeAllUsersPackageRestrictionsLPr(); //【4.5】写入偏好设置信息;
writeAllRuntimePermissionsLPr(); //【4.6】写入运行时权限授予信息!
return;
} catch(XmlPullParserException e) {
Slog.wtf(PackageManagerService.TAG, "Unable to write package manager settings, "
+ "current changes will be lost at reboot", e);
} catch(java.io.IOException e) {
Slog.wtf(PackageManagerService.TAG, "Unable to write package manager settings, "
+ "current changes will be lost at reboot", e);
}
// Clean up partially written files
if (mSettingsFilename.exists()) {
if (!mSettingsFilename.delete()) {
Slog.wtf(PackageManagerService.TAG, "Failed to clean up mangled file: "
+ mSettingsFilename);
}
}
//Debug.stopMethodTracing();
}
5.1 Settings.writePermissionLPr - 保存 “permission-trees” / “permission”
1 | void writePermissionLPr(XmlSerializer serializer, BasePermission bp) |
权限树以 <permission-trees> </permission-trees>
开始和结束,权限树以 <permissions> </permissions>
开始和结束!
5.2 Settings.writePackageLPr - 保存 “package”
1 |
|
应用包信息以 <package> </package>
开始和结束,不多说了!
5.3 Settings.writeDisabledSysPackageLPr - 保存 “updated-package”
1 |
|
被更新过的应用的信息以 <updated-package> </updated-package>
开始和结束,不多说了!
5.4 Settings.writePackageListLPr - 写入 “packages.list”
1 | void writePackageListLPr() { |
最后,调用的是 writePackageListLPr 一参数方法:
1 | void writePackageListLPr(int creatingUserId) { |
我们可以看到,在 packages.list 文件中,存储的格式为:1
pkgName userId debugFlag dataPath seinfo gids
大家可以去看那个文件内容!!
5.5 Settings.writeAllUsersPackageRestrictionsLPr - 保存偏好设置
接下来,写入最新的偏好设置!1
2
3
4
5
6
7
8void writeAllUsersPackageRestrictionsLPr() {
List<UserInfo> users = getAllUsers();
if (users == null) return;
for (UserInfo user : users) {
writePackageRestrictionsLPr(user.id);
}
}
接着,调用 writePackageRestrictionsLPr 方法!这个方法我们前面分析过,这里不处理!
5.6 Settings.writeAllRuntimePermissionsLPr - 保存运行时权限授予信息
接下来,写入最新的运行时权限授予信息!1
2
3
4
5
6void writeAllRuntimePermissionsLPr() {
for (int userId : UserManagerService.getInstance().getUserIds()) {
//【5.6.1】对每一个设备用户,保存其运行时权限授予信息!
mRuntimePermissionsPersistence.writePermissionsForUserAsyncLPr(userId);
}
}
5.6.1 RuntimePermissionsPersistence.writePermissionsForUserAsyncLPr
1 | public void writePermissionsForUserAsyncLPr(int userId) { |
就是发送消息给 MyHandler:
5.6.2 RuntimePermissionsPersistence.MyHandler.handleMessage
1 | private final class MyHandler extends Handler { |
5.6.3 RuntimePermissionsPersistence.writePermissionsSync
writePermissionsSync 会将上一次运行时权限的授予情况保存到文件中!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
137private void writePermissionsSync(int userId) {
AtomicFile destination = new AtomicFile(getUserRuntimePermissionsFile(userId));
//【1】用于保存 package 和 SharedUser 运行时权限!
ArrayMap<String, List<PermissionState>> permissionsForPackage = new ArrayMap<>();
ArrayMap<String, List<PermissionState>> permissionsForSharedUser = new ArrayMap<>();
synchronized (mLock) {
mWriteScheduled.delete(userId);
//【2】收集 package 运行时权限,保存到 permissionsForPackage!
final int packageCount = mPackages.size();
for (int i = 0; i < packageCount; i++) {
String packageName = mPackages.keyAt(i);
PackageSetting packageSetting = mPackages.valueAt(i);
if (packageSetting.sharedUser == null) {
PermissionsState permissionsState = packageSetting.getPermissionsState();
List<PermissionState> permissionsStates = permissionsState
.getRuntimePermissionStates(userId);
if (!permissionsStates.isEmpty()) {
permissionsForPackage.put(packageName, permissionsStates);
}
}
}
//【3】收集 SharedUser 运行时权限,保存到 permissionsForSharedUser!
final int sharedUserCount = mSharedUsers.size();
for (int i = 0; i < sharedUserCount; i++) {
String sharedUserName = mSharedUsers.keyAt(i);
SharedUserSetting sharedUser = mSharedUsers.valueAt(i);
PermissionsState permissionsState = sharedUser.getPermissionsState();
List<PermissionState> permissionsStates = permissionsState
.getRuntimePermissionStates(userId);
if (!permissionsStates.isEmpty()) {
permissionsForSharedUser.put(sharedUserName, permissionsStates);
}
}
}
FileOutputStream out = null;
try {
out = destination.startWrite();
XmlSerializer serializer = Xml.newSerializer();
serializer.setOutput(out, StandardCharsets.UTF_8.name());
serializer.setFeature(
"http://xmlpull.org/v1/doc/features.html#indent-output", true);
serializer.startDocument(null, true);
serializer.startTag(null, TAG_RUNTIME_PERMISSIONS); // 根标签 runtime-permissions!
String fingerprint = mFingerprints.get(userId);
if (fingerprint != null) {
serializer.attribute(null, ATTR_FINGERPRINT, fingerprint); // 属性 fingerprint!
}
// 写入 package 运行时权限!
final int packageCount = permissionsForPackage.size();
for (int i = 0; i < packageCount; i++) {
String packageName = permissionsForPackage.keyAt(i);
List<PermissionState> permissionStates = permissionsForPackage.valueAt(i);
serializer.startTag(null, TAG_PACKAGE); // pkg 标签
serializer.attribute(null, ATTR_NAME, packageName); // name 属性!
//【4.6.3.1】写入运行时权限信息
writePermissions(serializer, permissionStates);
serializer.endTag(null, TAG_PACKAGE);
}
// 写入 SharedUser 运行时权限!
final int sharedUserCount = permissionsForSharedUser.size();
for (int i = 0; i < sharedUserCount; i++) {
String packageName = permissionsForSharedUser.keyAt(i);
List<PermissionState> permissionStates = permissionsForSharedUser.valueAt(i);
serializer.startTag(null, TAG_SHARED_USER); // shared-user 标签;
serializer.attribute(null, ATTR_NAME, packageName); // name 属性;
//【4.6.3.1】写入运行时权限信息;
writePermissions(serializer, permissionStates);
serializer.endTag(null, TAG_SHARED_USER);
}
serializer.endTag(null, TAG_RUNTIME_PERMISSIONS);
// Now any restored permission grants that are waiting for the apps
// in question to be installed. These are stored as per-package
// TAG_RESTORED_RUNTIME_PERMISSIONS blocks, each containing some
// number of individual permission grant entities.
if (mRestoredUserGrants.get(userId) != null) {
ArrayMap<String, ArraySet<RestoredPermissionGrant>> restoredGrants =
mRestoredUserGrants.get(userId);
if (restoredGrants != null) {
final int pkgCount = restoredGrants.size();
for (int i = 0; i < pkgCount; i++) {
final ArraySet<RestoredPermissionGrant> pkgGrants =
restoredGrants.valueAt(i);
if (pkgGrants != null && pkgGrants.size() > 0) {
final String pkgName = restoredGrants.keyAt(i);
serializer.startTag(null, TAG_RESTORED_RUNTIME_PERMISSIONS); // restored-perms 标签;
serializer.attribute(null, ATTR_PACKAGE_NAME, pkgName); // packageName 属性;
final int N = pkgGrants.size();
for (int z = 0; z < N; z++) {
RestoredPermissionGrant g = pkgGrants.valueAt(z);
serializer.startTag(null, TAG_PERMISSION_ENTRY); // perm 标签;
serializer.attribute(null, ATTR_NAME, g.permissionName); // name 属性;
if (g.granted) {
serializer.attribute(null, ATTR_GRANTED, "true"); // granted 属性
}
if ((g.grantBits&FLAG_PERMISSION_USER_SET) != 0) { // set 属性
serializer.attribute(null, ATTR_USER_SET, "true");
}
if ((g.grantBits&FLAG_PERMISSION_USER_FIXED) != 0) { // fixed 属性
serializer.attribute(null, ATTR_USER_FIXED, "true");
}
if ((g.grantBits&FLAG_PERMISSION_REVOKE_ON_UPGRADE) != 0) { // rou 属性
serializer.attribute(null, ATTR_REVOKE_ON_UPGRADE, "true");
}
serializer.endTag(null, TAG_PERMISSION_ENTRY);
}
serializer.endTag(null, TAG_RESTORED_RUNTIME_PERMISSIONS);
}
}
}
}
serializer.endDocument();
destination.finishWrite(out);
if (Build.FINGERPRINT.equals(fingerprint)) { // 如果
mDefaultPermissionsGranted.put(userId, true);
}
// Any error while writing is fatal.
} catch (Throwable t) {
Slog.wtf(PackageManagerService.TAG,
"Failed to write settings, restoring backup", t);
destination.failWrite(out);
} finally {
IoUtils.closeQuietly(out);
}
}
5.6.3.1 RuntimePermissionsPersistence.writePermissions
1 | private void writePermissions(XmlSerializer serializer, |
这里就不多说了!