[toc]
基于 Android 7.1.1 源码分析 PackageManagerService 的架构和逻辑实现,本文是作者原创,转载请说明出处!
0 综述
最后我们会进入 PMS 初始化的最后阶段:
1 | ... ... ... ...// 第五阶段 |
这个阶段逻辑很简单,我们不多分析!
1 获得一些 PMS 会用到的应用的包名
1.1 PackageMS.getRequiredButNotReallyRequiredVerifierLPr
1 | private String getRequiredButNotReallyRequiredVerifierLPr() { |
1.2 PackageMS.getRequiredInstallerLPr
获得 packageInstaller 的包名!1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18private String getRequiredInstallerLPr() {
final Intent intent = new Intent(Intent.ACTION_INSTALL_PACKAGE);
intent.addCategory(Intent.CATEGORY_DEFAULT);
intent.setDataAndType(Uri.fromFile(new File("foo.apk")), PACKAGE_MIME_TYPE);
final List<ResolveInfo> matches = queryIntentActivitiesInternal(intent, PACKAGE_MIME_TYPE,
MATCH_SYSTEM_ONLY | MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE,
UserHandle.USER_SYSTEM);
if (matches.size() == 1) {
ResolveInfo resolveInfo = matches.get(0);
if (!resolveInfo.activityInfo.applicationInfo.isPrivilegedApp()) {
throw new RuntimeException("The installer must be a privileged app");
}
return matches.get(0).getComponentInfo().packageName;
} else {
throw new RuntimeException("There must be exactly one installer; found " + matches);
}
}
1.3 PackageMS.getRequiredUninstallerLPr
1 | private String getRequiredUninstallerLPr() { |
1.4 PackageMS.getIntentFilterVerifierComponentNameLPr
1 | private ComponentName getIntentFilterVerifierComponentNameLPr() { |
1.5 PackageMS.getRequiredSharedLibraryLPr
1 | /** |
1 | mServicesSystemSharedLibraryPackageName = getRequiredSharedLibraryLPr( |
2 new PackageInstallerService - 创建安装服务对象
创建 PackageInstallerService 服务对象,用于应用的安装,关于安装,这个我们先不关注!
1 | public PackageInstallerService(Context context, PackageManagerService pm) { |
在 PackageInstallerService 有如下的集合,来保存安装事务!1
2
3
4
5
6
7
8
9
10
11// 所有的事务,有效和无效的
"mSessions") (
private final SparseBooleanArray mAllocatedSessions = new SparseBooleanArray();
// 用于保存那些有效的安装事务!
"mSessions") (
private final SparseArray<PackageInstallerSession> mSessions = new SparseArray<>();
// 用于保存那些无效的历史事务!
"mSessions") (
private final SparseArray<PackageInstallerSession> mHistoricalSessions = new SparseArray<>();
在创建 PackageInstallerService 的时候会调用 readSessionsLocked 读取重启之前的所有安装事务!
2.1 new Callback
Callback 本质上也是一个 Handler 对象,其 Looper 对象来自 mInstallThread.getLooper(),用于处理耗时操作:
1 | private static class Callbacks extends Handler { |
Callback 用于处理和 session 相关的消息:1
2
3
4
5private static final int MSG_SESSION_CREATED = 1;
private static final int MSG_SESSION_BADGING_CHANGED = 2;
private static final int MSG_SESSION_ACTIVE_CHANGED = 3;
private static final int MSG_SESSION_PROGRESS_CHANGED = 4;
private static final int MSG_SESSION_FINISHED = 5;
本质上讲,Callback 只是这些消息的中转站,它会将消息发送给注册到其内部的远程回调接口:
1 | private final RemoteCallbackList<IPackageInstallerCallback> |
CallBack 内部提供了注册相关的接口:
1 | public void register(IPackageInstallerCallback callback, int userId) { |
我们来看下,其实如何处理回调的,当有 Session 发生变化后,下面的接口会被触发调用!1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19private void notifySessionCreated(int sessionId, int userId) {
obtainMessage(MSG_SESSION_CREATED, sessionId, userId).sendToTarget();
}
private void notifySessionBadgingChanged(int sessionId, int userId) {
obtainMessage(MSG_SESSION_BADGING_CHANGED, sessionId, userId).sendToTarget();
}
private void notifySessionActiveChanged(int sessionId, int userId, boolean active) {
obtainMessage(MSG_SESSION_ACTIVE_CHANGED, sessionId, userId, active).sendToTarget();
}
private void notifySessionProgressChanged(int sessionId, int userId, float progress) {
obtainMessage(MSG_SESSION_PROGRESS_CHANGED, sessionId, userId, progress).sendToTarget();
}
public void notifySessionFinished(int sessionId, int userId, boolean success) {
obtainMessage(MSG_SESSION_FINISHED, sessionId, userId, success).sendToTarget();
}
这些接口会发送消息,处理仍然是在 CallBack 中:
1 |
|
invokeCallback 方法将 session 变化的消息会转发给所有注册到其内部的远程回调接口!1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21private void invokeCallback(IPackageInstallerCallback callback, Message msg)
throws RemoteException {
final int sessionId = msg.arg1;
switch (msg.what) {
case MSG_SESSION_CREATED:
callback.onSessionCreated(sessionId);
break;
case MSG_SESSION_BADGING_CHANGED:
callback.onSessionBadgingChanged(sessionId);
break;
case MSG_SESSION_ACTIVE_CHANGED:
callback.onSessionActiveChanged(sessionId, (boolean) msg.obj);
break;
case MSG_SESSION_PROGRESS_CHANGED:
callback.onSessionProgressChanged(sessionId, (float) msg.obj);
break;
case MSG_SESSION_FINISHED:
callback.onSessionFinished(sessionId, (boolean) msg.obj);
break;
}
}
2.2 PackageInstallerService.readSessionsLocked[0]
readSessionsLocked 用来读取事务!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
51private void readSessionsLocked() {
if (LOGD) Slog.v(TAG, "readSessionsLocked()");
mSessions.clear();
FileInputStream fis = null;
try {
fis = mSessionsFile.openRead();
final XmlPullParser in = Xml.newPullParser();
in.setInput(fis, StandardCharsets.UTF_8.name());
int type;
while ((type = in.next()) != END_DOCUMENT) {
if (type == START_TAG) {
final String tag = in.getName();
if (TAG_SESSION.equals(tag)) { // session 标签,用户封装指定的安装事务!
//【2.2】读取安装事务,返回 PackageInstallerSession 对象!
final PackageInstallerSession session = readSessionLocked(in);
// 计算事务的有效性!
final long age = System.currentTimeMillis() - session.createdMillis;
final boolean valid;
// 如果大于 MAX_AGE_MILLIS 3 天,那就是无效的,否则是有效的!
if (age >= MAX_AGE_MILLIS) {
Slog.w(TAG, "Abandoning old session first created at "
+ session.createdMillis);
valid = false;
} else {
valid = true;
}
if (valid) {
// 有效的事务
mSessions.put(session.sessionId, session);
} else {
// 无效的事务,用于 debug,比如 dumpsys 等等!
mHistoricalSessions.put(session.sessionId, session);
}
// 所有的事务!
mAllocatedSessions.put(session.sessionId, true);
}
}
}
} catch (FileNotFoundException e) {
// Missing sessions are okay, probably first boot
} catch (IOException | XmlPullParserException e) {
Slog.wtf(TAG, "Failed reading install sessions", e);
} finally {
IoUtils.closeQuietly(fis);
}
}
判断一个事务是否有效的依据是,其实是否是在 3 天时间间隔之前创建的!1
private static final long MAX_AGE_MILLIS = 3 * DateUtils.DAY_IN_MILLIS;
2.2.1 PackageInstallerService.readSessionsLocked[1]
我们看下解析单个事务的具体过程!
1 | private PackageInstallerSession readSessionLocked(XmlPullParser in) throws IOException, |
方法步骤:
- 解析 xml;
- 创建事务对象 PackageInstallerSession;
2.2.1.1 new SessionParams
1 | public SessionParams(int mode) { |
创建了一个 SessionParams,用于封装事务参数!
2.2.1.2 PackageInstallerService.readGrantedRuntimePermissions
readGrantedRuntimePermissions 方法会读取授予的运行时权限!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
29private static String[] readGrantedRuntimePermissions(XmlPullParser in)
throws IOException, XmlPullParserException {
List<String> permissions = null;
final int outerDepth = in.getDepth();
int type;
while ((type = in.next()) != XmlPullParser.END_DOCUMENT
&& (type != XmlPullParser.END_TAG || in.getDepth() > outerDepth)) {
if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
continue;
}
if (TAG_GRANTED_RUNTIME_PERMISSION.equals(in.getName())) { // 读取 granted-runtime-permission 子标签!
String permission = readStringAttribute(in, ATTR_NAME); // 读取 name 属性,即运行时权限名
if (permissions == null) {
permissions = new ArrayList<>();
}
// 将权限名保存到 permissions,并返回!!
permissions.add(permission);
}
}
if (permissions == null) {
return null;
}
String[] permissionsArray = new String[permissions.size()];
permissions.toArray(permissionsArray);
return permissionsArray;
}
方法很简单,这就不多说了!
2.2.1.3 new PackageInstallerSession
创建一个 PackageInstallerSession,参数来自前面的解析!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
55public PackageInstallerSession(PackageInstallerService.InternalCallback callback,
Context context, PackageManagerService pm, Looper looper, int sessionId, int userId,
String installerPackageName, int installerUid, SessionParams params, long createdMillis,
File stageDir, String stageCid, boolean prepared, boolean sealed) {
mCallback = callback; // InternalCallback 对象,用于监听和相应 session 的变化!!
mContext = context;
mPm = pm;
mHandler = new Handler(looper, mHandlerCallback);
this.sessionId = sessionId;
this.userId = userId;
this.installerPackageName = installerPackageName;
this.installerUid = installerUid;
this.params = params;
this.createdMillis = createdMillis;
this.stageDir = stageDir;
this.stageCid = stageCid;
if ((stageDir == null) == (stageCid == null)) {
throw new IllegalArgumentException(
"Exactly one of stageDir or stageCid stage must be set");
}
mPrepared = prepared;
mSealed = sealed;
// Device owners are allowed to silently install packages, so the permission check is
// waived if the installer is the device owner.
DevicePolicyManager dpm = (DevicePolicyManager) mContext.getSystemService(
Context.DEVICE_POLICY_SERVICE);
final boolean isPermissionGranted =
(mPm.checkUidPermission(android.Manifest.permission.INSTALL_PACKAGES, installerUid)
== PackageManager.PERMISSION_GRANTED);
final boolean isInstallerRoot = (installerUid == Process.ROOT_UID); // 安装者是否是 root 级别!
final boolean forcePermissionPrompt =
(params.installFlags & PackageManager.INSTALL_FORCE_PERMISSION_PROMPT) != 0;
mIsInstallerDeviceOwner = (dpm != null) && dpm.isDeviceOwnerAppOnCallingUser(
installerPackageName);
if ((isPermissionGranted
|| isInstallerRoot
|| mIsInstallerDeviceOwner)
&& !forcePermissionPrompt) {
mPermissionsAccepted = true;
} else {
mPermissionsAccepted = false;
}
final long identity = Binder.clearCallingIdentity();
try {
final int uid = mPm.getPackageUid(PackageManagerService.DEFAULT_CONTAINER_PACKAGE,
PackageManager.MATCH_SYSTEM_ONLY, UserHandle.USER_SYSTEM);
defaultContainerGid = UserHandle.getSharedAppGid(uid);
} finally {
Binder.restoreCallingIdentity(identity);
}
}
在创建 PackageInstallerSession 的时候,我们传入了一个 mInternalCallback,他是 PackageInstallerService 的成员变量:
1 | private final InternalCallback mInternalCallback = new InternalCallback(); |
这个接口用于监听和相应 Sessions 的变化,当 Sessions 发生变化后,会通过该接口,将相应的消息抓发给 Callback,Callback 会将消息再次转发给远程回调接口!1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53class InternalCallback {
public void onSessionBadgingChanged(PackageInstallerSession session) {
mCallbacks.notifySessionBadgingChanged(session.sessionId, session.userId);
writeSessionsAsync();
}
public void onSessionActiveChanged(PackageInstallerSession session, boolean active) {
mCallbacks.notifySessionActiveChanged(session.sessionId, session.userId, active);
}
// 安装事务的进度发生变化!
public void onSessionProgressChanged(PackageInstallerSession session, float progress) {
mCallbacks.notifySessionProgressChanged(session.sessionId, session.userId, progress);
}
// 处理事务完成的消息!
public void onSessionFinished(final PackageInstallerSession session, boolean success) {
mCallbacks.notifySessionFinished(session.sessionId, session.userId, success);
mInstallHandler.post(new Runnable() {
public void run() {
synchronized (mSessions) {
// 将已经完成的消息移除 mSessions,加入到 mHistoricalSessions 中!
mSessions.remove(session.sessionId);
mHistoricalSessions.put(session.sessionId, session);
final File appIconFile = buildAppIconFile(session.sessionId);
if (appIconFile.exists()) {
appIconFile.delete();
}
writeSessionsLocked(); // 更新 sessions 变化到本地文件中!
}
}
});
}
public void onSessionPrepared(PackageInstallerSession session) {
// We prepared the destination to write into; we want to persist
// this, but it's not critical enough to block for.
writeSessionsAsync(); // 将 sessions 数据写到本地文件中!
}
public void onSessionSealedBlocking(PackageInstallerSession session) {
// It's very important that we block until we've recorded the
// session as being sealed, since we never want to allow mutation
// after sealing.
synchronized (mSessions) {
writeSessionsLocked();
}
}
}
关于 Session,我们想讲这么多,在分析安装的过程中,我们在深入分析,我们只需要知道,每一个安装任务都会封装成一个 Session 即可!
3 new PackageManagerInternalImpl - 系统进程内部调用
在 pms 的构造器结尾,调用了 LocalServices,将一个 PackageManagerInternalImpl 对象注册到本地服务管理中,这种方式用于系统进程内部服务间的通信,因为不需要使用 Binder 线程,所以效率更高!
1 | //【3】将自身加入本地服务管理中,方便系统自身访问! |
LocalServices 内部保存着一个静态的 ArrayMap 来保存所有注册到其内部的服务:
1 | private static final ArrayMap<Class<?>, Object> sLocalServiceObjects = |
通过其内部的 addService 方法,将系统服务添加进来!1
2
3
4
5
6
7
8public static <T> void addService(Class<T> type, T service) {
synchronized (sLocalServiceObjects) {
if (sLocalServiceObjects.containsKey(type)) {
throw new IllegalStateException("Overriding service registration");
}
sLocalServiceObjects.put(type, service);
}
}
PackageManagerInternalImpl 对象继承了 PackageManagerInternal 并实现了其抽象方法,其内部有多个方案来供其他服务访问 PMS:
3.1 注册系统服务 provider
后续会有其他的系统服务启动,他们会把自身的 provider 注册进入 PMS,后续 PMS 会授予他们权限!
1 | private class PackageManagerInternalImpl extends PackageManagerInternal { |
上面的内容,后面会遇到!
3.2 授予默认权限接口
1 | private class PackageManagerInternalImpl extends PackageManagerInternal { |
以上方法都是在 TelecomLoaderService 服务中调用的!
4 PackageMS.updatePackagesIfNeeded - 执行 Odex 优化
在 SystemServer.startOtherServices 中,会调用 updatePackagesIfNeeded 更新 package!
1 | if (!mOnlyCore) { |
我们去看看 updatePackagesIfNeeded 方法,该方法的主要作用是对应用进行 Odex 优化!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
public void updatePackagesIfNeeded() {
enforceSystemOrRoot("Only the system can request package update");
//【1】是否是通过 OTA 升级的!
boolean causeUpgrade = isUpgrade();
//【2】是否是第一次启动,包括出场第一次开机,factory reset,如果是从 Android N 升级上来的,也看作是第一次启动!
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();
//【1】如果不是上面几种情况,不处理!
if (!causeUpgrade && !causeFirstBoot && !causePrunedCache) {
return;
}
//【4.1】获得要执行 odex 优化的 package!
List<PackageParser.Package> pkgs;
synchronized (mPackages) {
pkgs = PackageManagerServiceUtils.getPackagesForDexopt(mPackages.values(), this);
}
final long startTime = System.nanoTime();
//【4.2】执行 odex 优化!
final int[] stats = performDexOptUpgrade(pkgs, mIsPreNUpgrade /* showDialog */,
getCompilerFilterForReason(causeFirstBoot ? REASON_FIRST_BOOT : REASON_BOOT));
final int elapsedTimeSeconds =
(int) TimeUnit.NANOSECONDS.toSeconds(System.nanoTime() - startTime);
//【4】记录执行结果!
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);
}
整个过程就是收集所有的 Pacakge,然后执行 Odex 优化!
可以看到,只有
4.1 PackageManagerServiceUtils.getPackagesForDexopt
getPackagesForDexopt 会对系统中所有扫描到的 package 进行排序!1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71public static List<PackageParser.Package> getPackagesForDexopt(
Collection<PackageParser.Package> packages,
PackageManagerService packageManagerService) {
//【1】result 用于保存排序后的所有结果,remainingPkgs 用于保存没有排序的 package
// sortTemp 用于缓存排序的结果!
ArrayList<PackageParser.Package> remainingPkgs = new ArrayList<>(packages); // 初始化 remainingPkgs!
LinkedList<PackageParser.Package> result = new LinkedList<>();
ArrayList<PackageParser.Package> sortTemp = new ArrayList<>(remainingPkgs.size());
//【4.1.1】调用 applyPackageFilter 设置优先级,然后排序!
//【4.1.1.1】开始第一阶段排序,收集那些 pkg.coreApp 为 true 的应用,进行排序,然后添加到 result 中!
applyPackageFilter((pkg) -> pkg.coreApp, result, remainingPkgs, sortTemp,
packageManagerService);
//【4.1.1.2】开始第二个阶段排序,条件是是否监听 ACTION_PRE_BOOT_COMPLETED 这个广播!
// 手机监听该广播的 package,进行排序,结果添加到 result 中!
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);
//【4.1.1.3】开始第三个阶段排序,条件是 package 是否被其他应用加载或使用,排序后结果添加到 result 中!
applyPackageFilter((pkg) -> PackageDexOptimizer.isUsedByOtherApps(pkg), result,
remainingPkgs, sortTemp, packageManagerService);
//【2】处理剩余的仍然没有被处理的 Package!
Predicate<PackageParser.Package> remainingPredicate;
if (!remainingPkgs.isEmpty() && packageManagerService.isHistoricalPackageUsageAvailable()) {
if (DEBUG_DEXOPT) {
Log.i(TAG, "Looking at historical package use");
}
//【1】对剩余的 package 进行比较,找到最新使用时间最晚的那个 package!
PackageParser.Package lastUsed = Collections.max(remainingPkgs, (pkg1, pkg2) ->
Long.compare(pkg1.getLatestForegroundPackageUseTimeInMills(),
pkg2.getLatestForegroundPackageUseTimeInMills()));
if (DEBUG_DEXOPT) {
Log.i(TAG, "Taking package " + lastUsed.packageName + " as reference in time use");
}
long estimatedPreviousSystemUseTime =
lastUsed.getLatestForegroundPackageUseTimeInMills();
//【2】确定过滤器
if (estimatedPreviousSystemUseTime != 0) {
//【2.1】剩余 package 的排序条件为:该应用最新使用时间距离安装超过了 7 天!
final long cutoffTime = estimatedPreviousSystemUseTime - SEVEN_DAYS_IN_MILLISECONDS;
remainingPredicate =
(pkg) -> pkg.getLatestForegroundPackageUseTimeInMills() >= cutoffTime;
} else {
//【2.2】剩余 package 的排序条件为 true,即:不过滤,处理剩下的所有 package!
remainingPredicate = (pkg) -> true;
}
// 先对剩余的 package 进行一次时间排序,目的是使用!
sortPackagesByUsageDate(remainingPkgs, packageManagerService);
} else {
//【2.3】剩余 package 的排序条件为 true,即:不过滤,处理剩下的所有 package
remainingPredicate = (pkg) -> true;
}
//【4.1.1.4】最后一次排序,处理剩余的仍然没有被处理的 Package,满足上面条件的 package!!
applyPackageFilter(remainingPredicate, result, remainingPkgs, sortTemp,
packageManagerService);
if (DEBUG_DEXOPT) {
Log.i(TAG, "Packages to be dexopted: " + packagesToString(result));
Log.i(TAG, "Packages skipped from dexopt: " + packagesToString(remainingPkgs));
}
//【3】返回需要做 Odex 的排序过的 Package!
return result;
}
对于 getPackagesForDexopt 方法的分析就到这里!
4.1.1 PackageManagerServiceUtils.applyPackageFilter
applyPackageFilter 方法通过传入的过滤条件,收集满足条件的 package,对其进行排序!1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33private static void applyPackageFilter(Predicate<PackageParser.Package> filter,
Collection<PackageParser.Package> result,
Collection<PackageParser.Package> packages,
@NonNull List<PackageParser.Package> sortTemp,
PackageManagerService packageManagerService) {
//【1】收集那些满足 filter 设定的条件的 package,添加到 sortTemp!
for (PackageParser.Package pkg : packages) {
if (filter.test(pkg)) {
sortTemp.add(pkg);
}
}
//【4.1.1.1】对 sortTemp 中的 package 进行排序!
sortPackagesByUsageDate(sortTemp, packageManagerService);
//【2】从 packages (就是 remainingPkgs)中移除 sortTemp 包含的 pacakge!
packages.removeAll(sortTemp);
//【3】将 sortTemp 中排好序的所有 package,添加到 result 中!
for (PackageParser.Package pkg : sortTemp) {
result.add(pkg);
//【3.1】找到和该 pkg 共享非系统库文件的 package,也添加到 result 中!
// 同时从 packages (就是 remainingPkgs)中也移除这部分 package!
Collection<PackageParser.Package> deps =
packageManagerService.findSharedNonSystemLibraries(pkg);
if (!deps.isEmpty()) {
deps.removeAll(result);
result.addAll(deps);
packages.removeAll(deps);
}
}
sortTemp.clear();
}
过程很简单不多说了!
4.1.1.1 PackageManagerServiceUtils.sortPackagesByUsageDate
该方法的作用是对 package 列表进行排序!1
2
3
4
5
6
7
8
9
10public static void sortPackagesByUsageDate(List<PackageParser.Package> pkgs,
PackageManagerService packageManagerService) {
if (!packageManagerService.isHistoricalPackageUsageAvailable()) {
return;
}
//【1】排序依据是:package 在前台使用是时间!
Collections.sort(pkgs, (pkg1, pkg2) ->
Long.compare(pkg2.getLatestForegroundPackageUseTimeInMills(),
pkg1.getLatestForegroundPackageUseTimeInMills()));
}
4.2 PackageMS.performDexOptUpgrade
performDexOptUpgrade 用于执行 Odex 优化操作!
对于参数 showDialog:传入的是 mIsPreNUpgrade,表示是否是从 N 升级上来的!
对于参数 compilerFilter:传入的是 getCompilerFilterForReason(causeFirstBoot ? REASON_FIRST_BOOT : REASON_BOOT)!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
81private int[] performDexOptUpgrade(List<PackageParser.Package> pkgs, boolean showDialog,
String compilerFilter) {
int numberOfPackagesVisited = 0;
int numberOfPackagesOptimized = 0;
int numberOfPackagesSkipped = 0;
int numberOfPackagesFailed = 0;
final int numberOfPackagesToDexopt = pkgs.size();
//【All】遍历所有要执行 Odex 的所有 Package!
for (PackageParser.Package pkg : pkgs) {
numberOfPackagesVisited++;
//【1】跳过那些不能做 Odex 优化的 Package!
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);
}
//【2】在做 Odex 优化的时候,是否显示界面进行提示!
if (showDialog) {
try {
ActivityManagerNative.getDefault().showBootMessage(
mContext.getResources().getString(R.string.android_upgrading_apk,
numberOfPackagesVisited, numberOfPackagesToDexopt), true);
} catch (RemoteException e) {
}
synchronized (mPackages) {
mDexOptDialogShown = true;
}
}
// If the OTA updates a system app which was previously preopted to a non-preopted state
// the app might end up being verified at runtime. That's because by default the apps
// are verify-profile but for preopted apps there's no profile.
// Do a hacky check to ensure that if we have no profiles (a reasonable indication
// that before the OTA the app was preopted) the app gets compiled with a non-profile
// filter (by default interpret-only).
// Note that at this stage unused apps are already filtered.
//【3】设置执行 Odex 优化的时候的 compilerFilter 类型!
if (isSystemApp(pkg) &&
DexFile.isProfileGuidedCompilerFilter(compilerFilter) &&
!Environment.getReferenceProfile(pkg.packageName).exists()) {
compilerFilter = getNonProfileGuidedCompilerFilter(compilerFilter);
}
// 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.
//【4.2.2】执行 Odex
int dexOptStatus = performDexOptTraced(pkg.packageName,
false /* checkProfiles */,
compilerFilter,
false /* force */);
switch (dexOptStatus) {
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 " + dexOptStatus);
break;
}
}
return new int[] { numberOfPackagesOptimized, numberOfPackagesSkipped,
numberOfPackagesFailed };
}
4.2.1 PackageManagerServiceCompilerMapping.getCompilerFilterForReason
这里调用了 getCompilerFilterForReason,根据执行的原因选择合适的 compileFilter:1
2
3
4public static String getCompilerFilterForReason(int reason) {
//【4.2.1.1】通过 reason 来获得 compileFilter
return getAndCheckValidity(reason);
}
如果是 first boot,则为 REASON_FIRST_BOOT,否则为 REASON_BOOT!
1 | // Compilation reasons. |
对于 reason 的取值如上,其实通过名字,很容易就能看到,每种 reason 的使用类型!
4.2.1.1 PackageManagerServiceCompilerMapping.getAndCheckValidity
检查 reason 对应的有效性!
1 | private static String getAndCheckValidity(int reason) { |
每一个有效的 reason 都会对应一个系统属性名,PackageManagerServiceCompilerMapping 内置了如下的系统属性名关键字:1
2
3
4static final String REASON_STRINGS[] = {
"first-boot", "boot", "install", "bg-dexopt", "ab-ota", "nsys-library", "shared-apk",
"forced-dexopt", "core-app"
};
如果是 REASON_FIRST_BOOT,对应的关键字就是 “first-boot”,其他的以此类推!1
2
3
4
5
6
7private static String getSystemPropertyName(int reason) {
if (reason < 0 || reason >= REASON_STRINGS.length) {
throw new IllegalArgumentException("reason " + reason + " invalid");
}
return "pm.dexopt." + REASON_STRINGS[reason];
}
然后,我们就可以获得系统属性名了,格式为:pm.dexopt.REASON_STRINGS[reason],比如对于 REASON_FIRST_BOOT,对应的系统属性名为 :pm.dexopt.first-boot!
然后我们通过该系统属性名,获得对应的属性 compileFilter!
4.2.2 PackageMS.performDexOptTraced
执行 Odex 优化操作!
1 | private int performDexOptTraced(String packageName, |
继续调用 performDexOptTraced 方法!
4.2.2.1 PackageMS.performDexOptTraced
1 | private int performDexOptInternal(String packageName, |
继续调用 performDexOptInternalWithDependenciesLI
4.2.2.2 PackageMS.performDexOptInternalWithDependenciesLI
根据前面的参数传递:checkProfiles 的值为 false;force 的值为 false:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26private int performDexOptInternalWithDependenciesLI(PackageParser.Package p,
boolean checkProfiles, String targetCompilerFilter,
boolean force) {
//【1】根据参数 force 的值,选择不同的 PackageDexOptimizer,绝大多数情况下,选择的是
// PackageDexOptimizer!
PackageDexOptimizer pdo = force
? new PackageDexOptimizer.ForcedUpdatePackageDexOptimizer(mPackageDexOptimizer)
: mPackageDexOptimizer;
//【2】先对该 package 所依赖的共享库所属 pacakge 进行 Odex 优化!
Collection<PackageParser.Package> deps = findSharedNonSystemLibraries(p);
final String[] instructionSets = getAppDexInstructionSets(p.applicationInfo);
if (!deps.isEmpty()) {
for (PackageParser.Package depPackage : deps) {
// TODO: Analyze and investigate if we (should) profile libraries.
// Currently this will do a full compilation of the library by default.
pdo.performDexOpt(depPackage, null /* sharedLibraries */, instructionSets,
false /* checkProfiles */,
getCompilerFilterForReason(REASON_NON_SYSTEM_LIBRARY),
getOrCreateCompilerPackageStats(depPackage));
}
}
//【4.2.2.3】对该 package 进行 Odex 优化!
return pdo.performDexOpt(p, p.usesLibraryFiles, instructionSets, checkProfiles,
targetCompilerFilter, getOrCreateCompilerPackageStats(p));
}
如果 force 的值为 false,那么选择的是 mPackageDexOptimizer,mPackageDexOptimizer 我们都知道,在 PackageManagerService 的初始化的时候,会创建对应的 PackageDexOptimizer 对象!
绝大数情况,force 都是 false;为 true 的情况很少使用,主要用于 cmd test!
当然,最终调用了:1
PackageDexOptimizer.performDexOpt
performDexOpt 方法进行 Odex 优化!
4.2.2.3 PackageDexOptimizer.performDexOpt
1 | int performDexOpt(PackageParser.Package pkg, String[] sharedLibraries, |
4.2.2.3.1 PackageDexOptimizer.performDexOptLI
performDexOptLI 是执行 Odex 的重要方法: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
142private int performDexOptLI(PackageParser.Package pkg, String[] sharedLibraries,
String[] targetInstructionSets, boolean checkProfiles, String targetCompilerFilter,
CompilerStats.PackageStats packageStats) {
final String[] instructionSets = targetInstructionSets != null ?
targetInstructionSets : getAppDexInstructionSets(pkg.applicationInfo);
//【1】如果该 package 没有 ApplicationInfo.FLAG_HAS_CODE 该标志,
// 就不能执行 Odex 优化,返回 DEX_OPT_SKIPPED!
if (!canOptimizePackage(pkg)) {
return DEX_OPT_SKIPPED;
}
//【2】获得该应用的 apk 文件所在路径!
final List<String> paths = pkg.getAllCodePathsExcludingResourceOnly();
final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);
//【3】如果该应用被其他的应用使用,不能用 profile-guided
boolean isProfileGuidedFilter = DexFile.isProfileGuidedCompilerFilter(targetCompilerFilter);
if (isProfileGuidedFilter && isUsedByOtherApps(pkg)) {
checkProfiles = false;
targetCompilerFilter = getNonProfileGuidedCompilerFilter(targetCompilerFilter);
if (DexFile.isProfileGuidedCompilerFilter(targetCompilerFilter)) {
throw new IllegalStateException(targetCompilerFilter);
}
isProfileGuidedFilter = false;
}
// If we're asked to take profile updates into account, check now.
boolean newProfile = false;
if (checkProfiles && isProfileGuidedFilter) {
// Merge profiles, see if we need to do anything.
try {
newProfile = mInstaller.mergeProfiles(sharedGid, pkg.packageName);
} catch (InstallerException e) {
Slog.w(TAG, "Failed to merge profiles", e);
}
}
final boolean vmSafeMode = (pkg.applicationInfo.flags & ApplicationInfo.FLAG_VM_SAFE_MODE) != 0;
final boolean debuggable = (pkg.applicationInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
boolean performedDexOpt = false;
boolean successfulDexOpt = true;
//【5】处理所有指令集下的 Odex 优化!
final String[] dexCodeInstructionSets = getDexCodeInstructionSets(instructionSets);
for (String dexCodeInstructionSet : dexCodeInstructionSets) {
for (String path : paths) {
int dexoptNeeded;
try {
//【5.1】判断是否有必要做 Odex 优化,结果保存到 dexoptNeeded!
dexoptNeeded = DexFile.getDexOptNeeded(path,
dexCodeInstructionSet, targetCompilerFilter, newProfile);
} catch (IOException ioe) {
Slog.w(TAG, "IOException reading apk: " + path, ioe);
return DEX_OPT_FAILED;
}
dexoptNeeded = adjustDexoptNeeded(dexoptNeeded); // 返回自身!
if (PackageManagerService.DEBUG_DEXOPT) {
Log.i(TAG, "DexoptNeeded for " + path + "@" + targetCompilerFilter + " is " +
dexoptNeeded);
}
final String dexoptType;
String oatDir = null;
//【5.2】处理 dexoptNeeded 结果!
switch (dexoptNeeded) {
case DexFile.NO_DEXOPT_NEEDED:
// 如果是 NO_DEXOPT_NEEDED,不需要优化,跳过;
continue;
case DexFile.DEX2OAT_NEEDED:
// 如果是 DEX2OAT_NEEDED,需要优化,类型为 dex2oat!
//【4.2.2.3.1.1】并创建 oat 目标目录!
dexoptType = "dex2oat";
oatDir = createOatDirIfSupported(pkg, dexCodeInstructionSet);
break;
case DexFile.PATCHOAT_NEEDED:
// 如果是 PATCHOAT_NEEDED,需要优化,类型为 patchoat!
dexoptType = "patchoat";
break;
case DexFile.SELF_PATCHOAT_NEEDED:
// 如果是 SELF_PATCHOAT_NEEDED,需要优化,类型为 self patchoat!
dexoptType = "self patchoat";
break;
default:
throw new IllegalStateException("Invalid dexopt:" + dexoptNeeded);
}
String sharedLibrariesPath = null;
if (sharedLibraries != null && sharedLibraries.length != 0) {
StringBuilder sb = new StringBuilder();
for (String lib : sharedLibraries) {
if (sb.length() != 0) {
sb.append(":");
}
sb.append(lib);
}
sharedLibrariesPath = sb.toString();
}
Log.i(TAG, "Running dexopt (" + dexoptType + ") on: " + path + " pkg="
+ pkg.applicationInfo.packageName + " isa=" + dexCodeInstructionSet
+ " vmSafeMode=" + vmSafeMode + " debuggable=" + debuggable
+ " target-filter=" + targetCompilerFilter + " oatDir = " + oatDir
+ " sharedLibraries=" + sharedLibrariesPath);
// Profile guide compiled oat files should not be public.
final boolean isPublic = !pkg.isForwardLocked() && !isProfileGuidedFilter;
final int profileFlag = isProfileGuidedFilter ? DEXOPT_PROFILE_GUIDED : 0;
final int dexFlags = adjustDexoptFlags(
( isPublic ? DEXOPT_PUBLIC : 0)
| (vmSafeMode ? DEXOPT_SAFEMODE : 0)
| (debuggable ? DEXOPT_DEBUGGABLE : 0)
| profileFlag
| DEXOPT_BOOTCOMPLETE);
try {
long startTime = System.currentTimeMillis();
//【5.3】执行 Odex 优化!
mInstaller.dexopt(path, sharedGid, pkg.packageName, dexCodeInstructionSet,
dexoptNeeded, oatDir, dexFlags, targetCompilerFilter, pkg.volumeUuid,
sharedLibrariesPath);
performedDexOpt = true;
if (packageStats != null) {
long endTime = System.currentTimeMillis();
packageStats.setCompileTime(path, (int)(endTime - startTime));
}
} catch (InstallerException e) {
Slog.w(TAG, "Failed to dexopt", e);
successfulDexOpt = false; // 如果有异常,successfulDexOpt 为 false!
}
}
}
//【6】处理 Odex 优化结果,如果 successfulDexOpt 为 true,说明执行 Odex 的过程中没有发生错误!
// 然后还要处理 performedDexOpt,如果为 true,表示 Odex 优化成功,返回 DEX_OPT_PERFORMED!
// 否则,直接返回 DEX_OPT_SKIPPED 表示无需 Odex 优化,直接跳过!
if (successfulDexOpt) {
return performedDexOpt ? DEX_OPT_PERFORMED : DEX_OPT_SKIPPED;
} else {
return DEX_OPT_FAILED;
}
}
整个流程很清晰,不多说!
4.2.2.3.1.1 PackageDexOptimizer.createOatDirIfSupported
createOatDirIfSupported 方法用于创建 oat 目录!1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
private String createOatDirIfSupported(PackageParser.Package pkg, String dexInstructionSet) {
//【1】如果应用不能有 oat 文件,返回 null!
if (!pkg.canHaveOatDir()) {
return null;
}
File codePath = new File(pkg.codePath);
if (codePath.isDirectory()) {
//【2】创建 oat 目录!
File oatDir = getOatDir(codePath);
try {
// 这里的 oatDir 为 /data/app/<packageName>/oat
// 而 dexInstructionSet 为 arm/arm64
mInstaller.createOatDir(oatDir.getAbsolutePath(), dexInstructionSet);
} catch (InstallerException e) {
Slog.w(TAG, "Failed to create oat dir", e);
return null;
}
return oatDir.getAbsolutePath();
}
return null;
}
PackageParser.Package.canHaveOatDir 方法用于判断该应用是否能够有 oat 目录!1
2
3
4
5
6
7public boolean canHaveOatDir() {
// 要能有 oat 目录,必须要满足 2 个条件;
// 1、不是 system app,或者是被更新过的 system app;
// 2、同时不能是 forward-locked app,并且不能被安装在 external 上!
return (!isSystemApp() || isUpdatedSystemApp())
&& !isForwardLocked() && !applicationInfo.isExternalAsec();
}
5 PackageMS.systemReady - 进入最终阶段
在 SystemServer.startOtherServices 中,最后,会调用 systemReady 方法,进入 PackageManagerService 启动的最终阶段!1
2
3
4
5
6Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "MakePackageManagerServiceReady");
try {
mPackageManagerService.systemReady();
} catch (Throwable e) {
reportWtf("making Package Manager Service ready", e);
}
当系统准备完成后,会调用到 PackageManagerService 的 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
public void systemReady() {
mSystemReady = 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);
// 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);
}
//【1】该集合表示需要默认授予运行时权限的 userId!
int[] grantPermissionsUserIds = EMPTY_INT_ARRAY;
synchronized (mPackages) {
//【1】移除那些已经不存在的 preferred activity
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);
}
}
// 移除这些不存在的 preferred activity 在系统中的关联!
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));
}
}
// 返回需要授予默认权限的 userId 集合!,其实就是访问 mDefaultPermissionsGranted 在指定的 userId 下的值
// 如果指定 userId 返回 false,表示发生了系统升级,那么我们会执行默认运行时权限授予!!
for (int userId : UserManagerService.getInstance().getUserIds()) {
if (!mSettings.areDefaultRuntimePermissionsGrantedLPr(userId)) {
grantPermissionsUserIds = ArrayUtils.appendInt(
grantPermissionsUserIds, userId);
}
}
}
// 通知 userManager 系统准备完毕!
sUserManager.systemReady();
//【5.1】执行默认授予运行时权限的操作!
for (int userId : grantPermissionsUserIds) {
mDefaultPermissionPolicy.grantDefaultPermissions(userId);
}
// 如果没有默认授予运行时权限给指定的 userId,那么我们会直接读取 default-permissions 目录中的文件
// 初始化 mGrantExceptions,和上面的过程类似,不关注!
if (grantPermissionsUserIds == EMPTY_INT_ARRAY) {
// 该方法会发送 MSG_READ_DEFAULT_PERMISSION_EXCEPTIONS 消息给内部的 Handler
// 然后会调用:readDefaultPermissionExceptionsLPw 方法!
mDefaultPermissionPolicy.scheduleReadDefaultPermissionExceptions();
}
// 处理 mPostSystemReadyMessages 中的 START_CLEANING_PACKAGE 消息,这些消息是在 delete/remove package
// 的时候添加进来的!!
if (mPostSystemReadyMessages != null) {
for (Message msg : mPostSystemReadyMessages) {
msg.sendToTarget();
}
mPostSystemReadyMessages = null;
}
// 注册存储监听器,持续监听存储变化!
final StorageManager storage = mContext.getSystemService(StorageManager.class);
storage.registerListener(mStorageListener);
// 通知 PackageInstallerService 和 PackageDexOptimizer 系统准备完成!
// PackageDexOptimizer 是用于执行 odex 优化的,后续我们会看到!
mInstallerService.systemReady();
mPackageDexOptimizer.systemReady();
MountServiceInternal mountServiceInternal = LocalServices.getService(
MountServiceInternal.class);
mountServiceInternal.addExternalStoragePolicy(
new MountServiceInternal.ExternalStorageMountPolicy() {
public int getMountMode(int uid, String packageName) {
if (Process.isIsolated(uid)) {
return Zygote.MOUNT_EXTERNAL_NONE;
}
if (checkUidPermission(WRITE_MEDIA_STORAGE, uid) == PERMISSION_GRANTED) {
return Zygote.MOUNT_EXTERNAL_DEFAULT;
}
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;
}
public boolean hasExternalStorage(int uid, String packageName) {
return true;
}
});
//【5.2】清楚哪些无效不用的用户和应用!
reconcileUsers(StorageManager.UUID_PRIVATE_INTERNAL);
reconcileApps(StorageManager.UUID_PRIVATE_INTERNAL);
}
5.1 DefaultPermissionGrantPolicy.grantDefaultPermissions - 默认运行时权限授予
前面有讲过 DefaultPermissionGrantPolicy 用来处理默认授予系统应用相应的运行时权限的!1
2
3
4
5
6
7
8public void grantDefaultPermissions(int userId) {
//【5.1.1】默认授予系统组件和 pri app 相应的运行时权限!
grantPermissionsToSysComponentsAndPrivApps(userId);
//【5.1.2】默认授予系统中的一些重要应用包相应的运行时权限!
grantDefaultSystemHandlerPermissions(userId);
//【5.1.3】处理之前授予异常的情况!
grantDefaultPermissionExceptions(userId);
}
我们来一个一个分析!
下面分析过程中,我们把 DefaultPermissionGrantPolicy 简称为 DPGrantPolicy
5.1.1 DPGrantPolicy.grantPermissionsToSysComponentsAndPrivApps
授予系统组件和私有应用默认权限!
1 | private void grantPermissionsToSysComponentsAndPrivApps(int userId) { |
直接授予权限即可!
5.1.1.1 DPGrantPolicy.isSysComponentOrPersistentPlatformSignedPrivAppLPr
1 | private boolean isSysComponentOrPersistentPlatformSignedPrivAppLPr(PackageParser.Package pkg) { |
上面的逻辑就不多说了!
5.1.1.2 DPGrantPolicy.doesPackageSupportRuntimePermissions
判断该 package 是否支持运行时权限!1
2
3private static boolean doesPackageSupportRuntimePermissions(PackageParser.Package pkg) {
return pkg.applicationInfo.targetSdkVersion > Build.VERSION_CODES.LOLLIPOP_MR1;
}
即:如果目标 sdk 大于 Android5.1,那就是支持,返回 true!
5.1.2 DPGrantPolicy.grantDefaultSystemHandlerPermissions
1 | private void grantDefaultSystemHandlerPermissions(int userId) { |
我们可以看到,这个阶段 DefaultPermissionGrantPolicy 默认授予了很多系统组件很多必须的运行时权限!
涉及到的 DefaultPermissionGrantPolicy 内部方法也很多,但是最终都是调用了其内部的 grantRuntimePermissionsLPw 方法,该方法,我们签名有分析过!
这里就不在跟踪了!
5.1.2.1 权限集合
DefaultPermissionGrantPolicy 内部有多个 Set 集合,保存了要默认授予给应用的运行时权限!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
60private static final Set<String> PHONE_PERMISSIONS = new ArraySet<>();
static {
PHONE_PERMISSIONS.add(Manifest.permission.READ_PHONE_STATE);
PHONE_PERMISSIONS.add(Manifest.permission.CALL_PHONE);
PHONE_PERMISSIONS.add(Manifest.permission.READ_CALL_LOG);
PHONE_PERMISSIONS.add(Manifest.permission.WRITE_CALL_LOG);
PHONE_PERMISSIONS.add(Manifest.permission.ADD_VOICEMAIL);
PHONE_PERMISSIONS.add(Manifest.permission.USE_SIP);
PHONE_PERMISSIONS.add(Manifest.permission.PROCESS_OUTGOING_CALLS);
}
private static final Set<String> CONTACTS_PERMISSIONS = new ArraySet<>();
static {
CONTACTS_PERMISSIONS.add(Manifest.permission.READ_CONTACTS);
CONTACTS_PERMISSIONS.add(Manifest.permission.WRITE_CONTACTS);
CONTACTS_PERMISSIONS.add(Manifest.permission.GET_ACCOUNTS);
}
private static final Set<String> LOCATION_PERMISSIONS = new ArraySet<>();
static {
LOCATION_PERMISSIONS.add(Manifest.permission.ACCESS_FINE_LOCATION);
LOCATION_PERMISSIONS.add(Manifest.permission.ACCESS_COARSE_LOCATION);
}
private static final Set<String> CALENDAR_PERMISSIONS = new ArraySet<>();
static {
CALENDAR_PERMISSIONS.add(Manifest.permission.READ_CALENDAR);
CALENDAR_PERMISSIONS.add(Manifest.permission.WRITE_CALENDAR);
}
private static final Set<String> SMS_PERMISSIONS = new ArraySet<>();
static {
SMS_PERMISSIONS.add(Manifest.permission.SEND_SMS);
SMS_PERMISSIONS.add(Manifest.permission.RECEIVE_SMS);
SMS_PERMISSIONS.add(Manifest.permission.READ_SMS);
SMS_PERMISSIONS.add(Manifest.permission.RECEIVE_WAP_PUSH);
SMS_PERMISSIONS.add(Manifest.permission.RECEIVE_MMS);
SMS_PERMISSIONS.add(Manifest.permission.READ_CELL_BROADCASTS);
}
private static final Set<String> MICROPHONE_PERMISSIONS = new ArraySet<>();
static {
MICROPHONE_PERMISSIONS.add(Manifest.permission.RECORD_AUDIO);
}
private static final Set<String> CAMERA_PERMISSIONS = new ArraySet<>();
static {
CAMERA_PERMISSIONS.add(Manifest.permission.CAMERA);
}
private static final Set<String> SENSORS_PERMISSIONS = new ArraySet<>();
static {
SENSORS_PERMISSIONS.add(Manifest.permission.BODY_SENSORS);
}
private static final Set<String> STORAGE_PERMISSIONS = new ArraySet<>();
static {
STORAGE_PERMISSIONS.add(Manifest.permission.READ_EXTERNAL_STORAGE);
STORAGE_PERMISSIONS.add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
}
这里只是简单的列举出来!
5.1.2.2 Settings.onDefaultRuntimePermissionsGrantedLPr
1 | void onDefaultRuntimePermissionsGrantedLPr(int userId) { |
对于 RuntimePermissionsPersistence 我们前面有说过,这里会调用其 onDefaultRuntimePermissionsGrantedLPr 方法,重新保存一次运行时权限授予情况!
代码就不在跟踪了!
5.1.3 DPGrantPolicy.grantDefaultPermissionExceptions
grantDefaultPermissionExceptions 用于处理那些授予异常的情况,系统会将授予异常的权限保存到一个文件中!
1 | private void grantDefaultPermissionExceptions(int userId) { |
5.1.3.1 DPGrantPolicy.readDefaultPermissionExceptionsLPw
1 | private ArrayMap<String, List<DefaultPermissionGrant>> |
5.1.3.1.1 DPGrantPolicy.parse
1 | private void parse(XmlPullParser parser, Map<String, List<DefaultPermissionGrant>> |
5.1.3.1.2 DPGrantPolicy.parseExceptions
1 | private void parseExceptions(XmlPullParser parser, Map<String, List<DefaultPermissionGrant>> |
5.1.3.1.3 DPGrantPolicy.parsePermission
1 | private void parsePermission(XmlPullParser parser, List<DefaultPermissionGrant> |
5.1.3.1.4 new DefaultPermissionGrant
1 | private static final class DefaultPermissionGrant { |
DefaultPermissionGrant 对象的属性简单,这里不多看了!
5.1.4 DPGrantPolicy.grantRuntimePermissionsLPw - 默认授予核心方法
默认授予运行时权限,调用的是内部的两个 grantRuntimePermissionsLPw 方法:
1 | [1]private void grantRuntimePermissionsLPw(PackageParser.Package pkg, Set<String> permissions, |
其中,方法一会调用方法二,这是参数 boolean systemFixed 设置的是 false!
1 | private void grantRuntimePermissionsLPw(PackageParser.Package pkg, Set<String> permissions, |
最后调用的是五参的同名方法:systemFixed 表示是否设置 system fix,isDefaultPhoneOrSms 表示是否是默认的 phone or sms app,permissions 为该 package 要被默认授予的运行时权限集合:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90private void grantRuntimePermissionsLPw(PackageParser.Package pkg, Set<String> permissions,
boolean systemFixed, boolean isDefaultPhoneOrSms, int userId) {
//【1】再次校验应用是否有请求权限!
if (pkg.requestedPermissions.isEmpty()) {
return;
}
//【2】获得本次扫描的 system apk 的权限!
List<String> requestedPermissions = pkg.requestedPermissions;
Set<String> grantablePermissions = null;
//【3】如果是默认的 phone app 或者 sms app,如果其更新过,我们会默认授予更新过的 app 申明的权限
// 如果这是一个被更新过的其他类型的 system app,我们只会默认授予是那些 system 分区的被更新过得 app 申明过的权限!
if (!isDefaultPhoneOrSms && pkg.isUpdatedSystemApp()) {
PackageSetting sysPs = mService.mSettings.getDisabledSystemPkgLPr(pkg.packageName);
if (sysPs != null) {
if (sysPs.pkg.requestedPermissions.isEmpty()) {
return;
}
if (!requestedPermissions.equals(sysPs.pkg.requestedPermissions)) {
// 表示本次扫描的 package 申明过的权限;
grantablePermissions = new ArraySet<>(requestedPermissions);
// 替换为被更新过的 system app 申明的权限!!
requestedPermissions = sysPs.pkg.requestedPermissions;
}
}
}
//【4】遍历该 package 申明过的所有权限;
final int grantablePermissionCount = requestedPermissions.size();
for (int i = 0; i < grantablePermissionCount; i++) {
String permission = requestedPermissions.get(i);
//【4.1】如果这是一个被更新过的 system app,跳过那些 data 分区新 app 没有声明的权限!
if (grantablePermissions != null && !grantablePermissions.contains(permission)) {
continue;
}
//【4.2】接下来,就是授予权限权限的过程了!
if (permissions.contains(permission)) {
//【5.1.1.3.1】获得权限的 flags;
final int flags = mService.getPermissionFlags(permission, pkg.packageName, userId);
// If any flags are set to the permission, then it is either set in
// its current state by the system or device/profile owner or the user.
// In all these cases we do not want to clobber the current state.
// Unless the caller wants to override user choices. The override is
// to make sure we can grant the needed permission to the default
// sms and phone apps after the user chooses this in the UI.
//【4.2.1】如果该权限的 flags 没有设置任何标志位,或者是默认的 phone app 或者 sms app 会进入 IF 分支!
if (flags == 0 || isDefaultPhoneOrSms) {
//【4.2.1.1】对于 isDefaultPhoneOrSms 我们会再判断下是否设置了 system fix 或者 policy fix 标志位!
// 如果设置了,那么我们不会修改标志位!
final int fixedFlags = PackageManager.FLAG_PERMISSION_SYSTEM_FIXED
| PackageManager.FLAG_PERMISSION_POLICY_FIXED;
if ((flags & fixedFlags) != 0) {
continue;
}
//【4.2.1.2】这里调用了 PMS 的 grantRuntimePermission 方法,授予权限,不多说了!
mService.grantRuntimePermission(pkg.packageName, permission, userId);
if (DEBUG) {
Log.i(TAG, "Granted " + (systemFixed ? "fixed " : "not fixed ")
+ permission + " to default handler " + pkg.packageName);
}
//【4.2.1.3】更新该运行时权限的 flags,先只设置 FLAG_PERMISSION_GRANTED_BY_DEFAULT 标志位
// 如果为 system fix,还会设置 FLAG_PERMISSION_SYSTEM_FIXED 位!
int newFlags = PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT;
if (systemFixed) {
newFlags |= PackageManager.FLAG_PERMISSION_SYSTEM_FIXED;
}
// 这里调用了 PMS 的 updatePermissionFlags 方法,更新权限的 flags 为 newFlags!
mService.updatePermissionFlags(permission, pkg.packageName,
newFlags, newFlags, userId);
}
//【4.2.2】如果权限被设置了 FLAG_PERMISSION_GRANTED_BY_DEFAULT 和 FLAG_PERMISSION_SYSTEM_FIXED 标志位
// 但是本次授予是 no system fix,那么我们就要去掉 system fix 标志位!
if ((flags & PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT) != 0
&& (flags & PackageManager.FLAG_PERMISSION_SYSTEM_FIXED) != 0
&& !systemFixed) {
if (DEBUG) {
Log.i(TAG, "Granted not fixed " + permission + " to default handler "
+ pkg.packageName);
}
//【4.2.2.1】更新权限的 flags 去掉 system fix 标志位!
mService.updatePermissionFlags(permission, pkg.packageName,
PackageManager.FLAG_PERMISSION_SYSTEM_FIXED, 0, userId);
}
}
}
}
该方法我们就分析到这里!
5.1.4.1 PackageManagerS.getPermissionFlags
该方法用于获得权限的 flags;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
public int getPermissionFlags(String name, String packageName, int userId) {
if (!sUserManager.exists(userId)) {
return 0;
}
//【1】首先是校验是否具有相应的权限!
enforceGrantRevokeRuntimePermissionPermissions("getPermissionFlags");
enforceCrossUserPermission(Binder.getCallingUid(), userId,
true /* requireFullPermission */, false /* checkShell */,
"getPermissionFlags");
synchronized (mPackages) {
final PackageParser.Package pkg = mPackages.get(packageName);
if (pkg == null) {
return 0;
}
final BasePermission bp = mSettings.mPermissions.get(name);
if (bp == null) {
return 0;
}
SettingBase sb = (SettingBase) pkg.mExtras;
if (sb == null) {
return 0;
}
//【2】查询权限的 Flags!
PermissionsState permissionsState = sb.getPermissionsState();
return permissionsState.getPermissionFlags(name, userId);
}
}
5.1.4.1.1 PermissionsState.getPermissionFlags
1 | public int getPermissionFlags(String name, int userId) { |
下面是具体的获取运行时权限或者安装时权限的权限状态的方法,很简单,不多说了!1
2
3
4
5
6
7
8public PermissionState getInstallPermissionState(String name) {
return getPermissionState(name, UserHandle.USER_ALL);
}
public PermissionState getRuntimePermissionState(String name, int userId) {
enforceValidUserId(userId);
return getPermissionState(name, userId);
}
5.2 清除那些陈旧不用的用户和应用
代码段如下:1
2reconcileUsers(StorageManager.UUID_PRIVATE_INTERNAL);
reconcileApps(StorageManager.UUID_PRIVATE_INTERNAL);
5.2.1 PackageManagerService.reconcileUsers
该方法会检测清除不用的设备用户: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
51private void reconcileUsers(String volumeUuid) {
final List<File> files = new ArrayList<>();
// 收集 /data/user_de 目录下的所有文件;
Collections.addAll(files, FileUtils
.listFilesOrEmpty(Environment.getDataUserDeDirectory(volumeUuid)));
// 收集 /data/user 目录下的所有文件;
Collections.addAll(files, FileUtils
.listFilesOrEmpty(Environment.getDataUserCeDirectory(volumeUuid)));
// 收集 /data/system_de 目录下的所有文件;
Collections.addAll(files, FileUtils
.listFilesOrEmpty(Environment.getDataSystemDeDirectory()));
// 收集 /data/system 目录下的所有文件;
Collections.addAll(files, FileUtils
.listFilesOrEmpty(Environment.getDataSystemCeDirectory()));
for (File file : files) {
if (!file.isDirectory()) continue;
final int userId;
final UserInfo info;
try {
userId = Integer.parseInt(file.getName());
// 尝试获得设备用户对应的 UserInfo!
info = sUserManager.getUserInfo(userId);
} catch (NumberFormatException e) {
Slog.w(TAG, "Invalid user directory " + file);
continue;
}
// 判断用户是否无效!
boolean destroyUser = false;
if (info == null) {
logCriticalInfo(Log.WARN, "Destroying user directory " + file
+ " because no matching user was found");
destroyUser = true;
} else if (!mOnlyCore) {
try {
UserManagerService.enforceSerialNumber(file, info.serialNumber);
} catch (IOException e) {
logCriticalInfo(Log.WARN, "Destroying user directory " + file
+ " because we failed to enforce serial number: " + e);
destroyUser = true;
}
}
//【5.2.1.1】如果设备用户无效了,清楚该用户的所有数据!
if (destroyUser) {
synchronized (mInstallLock) {
destroyUserDataLI(volumeUuid, userId,
StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE);
}
}
}
}
第一步,收集了 /data/user_de,/data/user,/data/system_de 和 /data/system 目录下的文件,这些文件的名字,都是以 userId 开头的!
5.2.1.1 PackageManagerService.destroyUserDataLI
1 | private void destroyUserDataLI(String volumeUuid, int userId, int flags) { |
该函数的作用很简单,不多说了!
5.2.2 PackageManagerService.reconcileApps
清除那些在该用户下已经卸载的,无效的应用!
1 | private void reconcileApps(String volumeUuid) { |
5.2.2.1 PackageManagerService.assertPackageKnown
1 | private void assertPackageKnown(String volumeUuid, String packageName) |
该方法用于判断 package 是否有效!
5.2.2.2 PackageManagerService.removeCodePathLI
1 | void removeCodePathLI(File codePath) { |
该方法删除指定的 apk 文件!