[toc]
本文基于 Android 7.1.1 源码分析,如有错误,欢迎指正,谢谢!
0 综述
AppOpsService 的初始化是在 ActivityManagerService 启动的时候:
1 | public ActivityManagerService(Context systemContext) { |
1 new AppOpsService
创建 AppOpsService 的时候,传入了一个 File 对象,用于访问 /data/system/appops.xml 文件!
1 | public AppOpsService(File storagePath, Handler handler) { |
我们来看下,appops.xml 文件的内容:
1 | <?xml version='1.0' encoding='utf-8' standalone='yes' ?> |
内容我们先简单的分析下:
- uid 用于记录和 uid 相关的限制信息;
- pkg 用于记录和具体应用的限制信息;
2 AppOpsService.readState
AppOpsService 启动的时候,会读取本地持久化文件,恢复上一次的数据!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
70void readState() {
synchronized (mFile) {
synchronized (this) {
FileInputStream stream;
try {
stream = mFile.openRead();
} catch (FileNotFoundException e) {
Slog.i(TAG, "No existing app ops " + mFile.getBaseFile() + "; starting empty");
return;
}
boolean success = false;
mUidStates.clear();
try {
XmlPullParser parser = Xml.newPullParser();
parser.setInput(stream, StandardCharsets.UTF_8.name());
int type;
while ((type = parser.next()) != XmlPullParser.START_TAG
&& type != XmlPullParser.END_DOCUMENT) {
;
}
if (type != XmlPullParser.START_TAG) {
throw new IllegalStateException("no start tag found");
}
int outerDepth = parser.getDepth();
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
&& (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
continue;
}
String tagName = parser.getName();
if (tagName.equals("pkg")) {
//【1】读取 pkg 标签;
readPackage(parser);
} else if (tagName.equals("uid")) {
//【2】读取 uid 标签;
readUidOps(parser);
} else {
Slog.w(TAG, "Unknown element under <app-ops>: "
+ parser.getName());
XmlUtils.skipCurrentTag(parser);
}
}
success = true;
} catch (IllegalStateException e) {
Slog.w(TAG, "Failed parsing " + e);
} catch (NullPointerException e) {
Slog.w(TAG, "Failed parsing " + e);
} catch (NumberFormatException e) {
Slog.w(TAG, "Failed parsing " + e);
} catch (XmlPullParserException e) {
Slog.w(TAG, "Failed parsing " + e);
} catch (IOException e) {
Slog.w(TAG, "Failed parsing " + e);
} catch (IndexOutOfBoundsException e) {
Slog.w(TAG, "Failed parsing " + e);
} finally {
if (!success) {
mUidStates.clear();
}
try {
stream.close();
} catch (IOException e) {
}
}
}
}
}
readState 会 pkg 和 uid 标签的数据,然后保存到内部的数据结构中!
2.1 AppOpsService.readUid[1] - 读取 uid 的 op 信息
首先,解析的是 uid 信息!
1 | <uid n="1001"> |
解释一下:
- uid 的 n 属性表示 uid 的取值;
- op 的 n 属性表示 op 的数值,m 表示 op 的 mode 值;
我们来看看解析的过程!
1 | void readUidOps(XmlPullParser parser) throws NumberFormatException, |
我们看到,创建了一个 UidState 对象,封装对 uid 的 op 控制,uidState.opModes 则保存了该 uid 的所有 op 和控制情况的映射关系!
2.1.1 getUidStateLocked
1 | private UidState getUidStateLocked(int uid, boolean edit) { |
AppOpsService 有一个内部的 SparseArray,用于保存 uid 和其对应的 UidState 的映射关系!1
private final SparseArray<UidState> mUidStates = new SparseArray<>();
2.1.2 new UidState
1 | private static final class UidState { |
UidState.pkgOps 是一个 ArrayMap,key 为 packageName,而 value 为 Ops,Ops 用于封装该 package 所有的 Op 控制数据!
这里涉及到了一个 Ops 类,我们来看下他的结构!
2.1.2.1 new Ops
可以看到 Ops 本质上是一个 SparseArray,用于记录 package 的所有 Op 控制信息!1
2
3
4
5
6
7
8
9
10
11public final static class Ops extends SparseArray<Op> {
public final String packageName; // 所属的 package
public final UidState uidState; // 所属的 UidState
public final boolean isPrivileged;
public Ops(String _packageName, UidState _uidState, boolean _isPrivileged) {
packageName = _packageName;
uidState = _uidState;
isPrivileged = _isPrivileged;
}
}
保存的规则是:下标为 op,值为控制情况!
2.2 AppOpsService.readPackage - 读取 package 的 op 信息
我们来看下 readPackage 解析的数据:
1 | <pkg n="com.android.settings"> // readPackage 解析 |
解释一下:
- pkg 的 n 属性表示包名;
- uid 的 n 表示应用包所属的 uid 值,uid 的 p 表示应用包是否是特权应用;
- op 的 n 属性表示 op 的数值,m 表示 op 的 mode 值;
首先是解析 pkg 标签!1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23void readPackage(XmlPullParser parser) throws NumberFormatException,
XmlPullParserException, IOException {
//【1】获取包名 package name!
String pkgName = parser.getAttributeValue(null, "n");
int outerDepth = parser.getDepth();
int type;
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("uid")) {
//【2.1.1】这里的 uid 标签是 pkg 标签的子标签!
readUid(parser, pkgName);
} else {
Slog.w(TAG, "Unknown element under <pkg>: "
+ parser.getName());
XmlUtils.skipCurrentTag(parser);
}
}
}
继续来看:
2.2.1 AppOpsService.readUid[2]
然后是解析子 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
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
90void readUid(XmlPullParser parser, String pkgName) throws NumberFormatException,
XmlPullParserException, IOException {
//【1】解析 n 属性,uid;
int uid = Integer.parseInt(parser.getAttributeValue(null, "n"));
//【2】解析 p 属性,是否是特权应用;
String isPrivilegedString = parser.getAttributeValue(null, "p");
boolean isPrivileged = false;
if (isPrivilegedString == null) {
try {
IPackageManager packageManager = ActivityThread.getPackageManager();
if (packageManager != null) {
//【3】获得 pkg 对应的 ApplicationInfo 对象!
ApplicationInfo appInfo = ActivityThread.getPackageManager()
.getApplicationInfo(pkgName, 0, UserHandle.getUserId(uid));
if (appInfo != null) {
isPrivileged = (appInfo.privateFlags
& ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
}
} else {
return;
}
} catch (RemoteException e) {
Slog.w(TAG, "Could not contact PackageManager", e);
}
} else {
//【4】是否是特权应用!
isPrivileged = Boolean.parseBoolean(isPrivilegedString);
}
int outerDepth = parser.getDepth();
int type;
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();
//【5】解析 op 标签!
if (tagName.equals("op")) {
//【2.2.1.1】创建一个 Op 对象,封装 op 标签的属性!
// 解析 n 属性,表示 op 的类别,保存到 Op.op!
Op op = new Op(uid, pkgName, Integer.parseInt(parser.getAttributeValue(null, "n")));
String mode = parser.getAttributeValue(null, "m"); // 解析 m 属性,用于获取该 op 的 mode 情况!
if (mode != null) {
op.mode = Integer.parseInt(mode);
}
String time = parser.getAttributeValue(null, "t"); // 解析 t 属性,用于获取该 op 的授予情况!
if (time != null) {
op.time = Long.parseLong(time);
}
time = parser.getAttributeValue(null, "r"); // 解析 r 属性,用于获取该 op 的拒绝时间!
if (time != null) {
op.rejectTime = Long.parseLong(time);
}
String dur = parser.getAttributeValue(null, "d"); // 解析 d 属性,用于获取该 op 的时间间隔!
if (dur != null) {
op.duration = Integer.parseInt(dur);
}
String proxyUid = parser.getAttributeValue(null, "pu"); // 解析 pu 属性,用于获取该 op 的代理 uid!
if (proxyUid != null) {
op.proxyUid = Integer.parseInt(proxyUid);
}
String proxyPackageName = parser.getAttributeValue(null, "pp"); // 解析 pp 属性,用于获取该 op 的代理 pkg!
if (proxyPackageName != null) {
op.proxyPackageName = proxyPackageName;
}
//【2.1.1】获得 uid 对应的 UidState 状态对象!
UidState uidState = getUidStateLocked(uid, true);
if (uidState.pkgOps == null) {
// 如果 uidState.pkgOps 为 null,初始化!
uidState.pkgOps = new ArrayMap<>();
}
//【2.2.1.1】从 uidState.pkgOps 获得该 package 的 Ops 集合
// 如果为 null,会创建一个新的 Ops!
Ops ops = uidState.pkgOps.get(pkgName);
if (ops == null) {
ops = new Ops(pkgName, uidState, isPrivileged);
// 将其添加到 uidState.pkgOps 中!
uidState.pkgOps.put(pkgName, ops);
}
// 保存 op 类别和对应的控制情况!
ops.put(op.op, op);
} else {
Slog.w(TAG, "Unknown element under <pkg>: "
+ parser.getName());
XmlUtils.skipCurrentTag(parser);
}
}
}
整个过程很简单,不多说了!
2.2.1.1 new Op
创建一个 Op 对象,封装 package 的每一个 Operation 信息!1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19public final static class Op {
public final int uid; // 所属 uid
public final String packageName; // 所属 package
public int proxyUid = -1;
public String proxyPackageName;
public final int op; // 操作码,表示一个访问操作!
public int mode; // 操作的控制信息!
public int duration;
public long time;
public long rejectTime;
public int nesting;
public Op(int _uid, String _packageName, int _op) {
uid = _uid;
packageName = _packageName;
op = _op;
mode = AppOpsManager.opToDefaultMode(op); // 计算 op 的默认控制状态!
}
}
3 AppOpsService.startWatchingMode
在 AMS 的构造函数中,接着启动了对 AppOpsManager.OP_RUN_IN_BACKGROUND op 操作的监听!1
2
3
4
5
6
7
8
9
10
11mAppOpsService.startWatchingMode(AppOpsManager.OP_RUN_IN_BACKGROUND, null,
new IAppOpsCallback.Stub() {
public void opChanged(int op, int uid, String packageName) {
if (op == AppOpsManager.OP_RUN_IN_BACKGROUND && packageName != null) {
if (mAppOpsService.checkOperation(op, uid, packageName)
!= AppOpsManager.MODE_ALLOWED) {
runInBackgroundDisabled(uid);
}
}
}
});
可以看到,这里传入了一个回调:1
2
3
4
5
6
7
8
9
10
11
12
13
14new IAppOpsCallback.Stub() {
public void opChanged(int op, int uid, String packageName) {
//【1】当 op 为 AppOpsManager.OP_RUN_IN_BACKGROUND 时,并且 packageName 不为 null
// 这时候会检查 packageName 是有允许在后台运行!
if (op == AppOpsManager.OP_RUN_IN_BACKGROUND && packageName != null) {
//【1.1】检查是否有权限执行 op 操作,关于这部分内容,我们后面再分析!
if (mAppOpsService.checkOperation(op, uid, packageName)
!= AppOpsManager.MODE_ALLOWED) {
//【3.2.1】如果不允许,ams 会 stop 掉该进程!
runInBackgroundDisabled(uid);
}
}
}
}
这个 Callback 是一个 IAppOpsCallback.Stub 对象,用于跨进程通信,为什么是个桩对象呢?我们后面会知道!
op 参数表示的是要监听的 op 操作;packageName 表示要监听的具体的 package,这里传入的是 null;callback 表示当 op 操作发生改变时,要执行的回调!
1 |
|
AppOpsService 内部有多个集合:1
2
3//【1】用与 IBinder 作和对应的回调 Callback 的映射关系!
final ArrayMap<IBinder, Callback> mModeWatchers
= new ArrayMap<IBinder, Callback>();
用于保存远程回调 IAppOpsCallback.Stub 和其对应的死亡仆告对象 Callback 的映射关系,当 IAppOpsCallback.Stub 死亡后,Callback.binderDied 会被触发,然
1 | //【1】用与保存 op 操作和对应的回调 Callback 的映射关系! |
而 mOpModeWatchers 和 mPackageModeWatchers 则是从不同的角度来建立监听关系:mOpModeWatchers 是从具体 op 的角度,而 mPackageModeWatchers 则是从 package 的角度!
可以看到 Callback 实例的作用是,作为远程回调的死亡仆告对象,用于停止监听!!
3.1 new Callback - 死亡回调
我们来看下 Callback 对象的创建,同时 Callback 又是一个 DeathRecipient 对象,用来监听远程 IAppOpsCallback 桩对象是否死亡!1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21public final class Callback implements DeathRecipient {
final IAppOpsCallback mCallback;
public Callback(IAppOpsCallback callback) {
mCallback = callback;
try {
//【1】将自身注册为一个死亡仆告对象!
mCallback.asBinder().linkToDeath(this, 0);
} catch (RemoteException e) {
}
}
public void unlinkToDeath() { //【2】解除注册!
mCallback.asBinder().unlinkToDeath(this, 0);
}
public void binderDied() { //【3.1.1】当远程桩对象死亡后,停止监听!
stopWatchingMode(mCallback);
}
}
当远程的 IAppOpsCallback.Stub 死亡后,AppOpsService.stopWatchingMode 会被执行!
3.1.1 AppOpsService.stopWatchingMode
1 |
|
流程很简单,不多说了!
3.2 AMS 对 OP_RUN_IN_BACKGROUND 的处理
再次回到 AMS 的构造器中去看看:
1 | //【1】当 op 为 AppOpsManager.OP_RUN_IN_BACKGROUND 时,并且 packageName 不为 null |
AMS 中并没有监听某个具体的 package 的 op 变化,所以 packageName 传入的是 null;AMS 关心的是 AppOpsManager.OP_RUN_IN_BACKGROUND 操作的变化!
当有 op 发生变化后,opChanged 方法会被调用,这时 AMS 会判断如果 op 为 AppOpsManager.OP_RUN_IN_BACKGROUND,同时 packageName 不为 null;
这时,AMS 会调用 mAppOpsService.checkOperation 判断该应用是否允许后台运行,如果不允许,那么,会调用 runInBackgroundDisabled 方法 stop 掉进程!
3.2.1 runInBackgroundDisabled
1 | final void runInBackgroundDisabled(int uid) { |
3.2.2 doStopUidLocked
1 | final void doStopUidLocked(int uid, final UidRecord uidRec) { |
这里就不多说了!
4 AppOpsService.publish - publish 到 ServiceManager 中!
我们回到 ActivityManagerService 的 start 方法中去看看:1
2
3
4
5
6
7
8
9
10private void start() {
Process.removeAllProcessGroups();
mProcessCpuThread.start();
mBatteryStatsService.publish(mContext);
//【1】调用了 AppOpsService 方法!
mAppOpsService.publish(mContext);
Slog.d("AppOps", "AppOpsService published");
LocalServices.addService(ActivityManagerInternal.class, new LocalService());
}
我们来看看 AppOpsService.publish!1
2
3
4public void publish(Context context) {
mContext = context;
ServiceManager.addService(Context.APP_OPS_SERVICE, asBinder());
}
将自身注册进入 ServiceManager 中!
5 AppOpsService.systemReady
我们回到 ActivityManagerService 的 systemReady 方法中去看看:
1 |
|
去看看 mAppOpsService 的 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
81public void systemReady() {
synchronized (this) {
boolean changed = false;
for (int i = mUidStates.size() - 1; i >= 0; i--) {
UidState uidState = mUidStates.valueAt(i);
//【×5.1】获取属于该 uid 的所有 PacakgeName!
String[] packageNames = getPackagesForUid(uidState.uid);
if (ArrayUtils.isEmpty(packageNames)) {
//【1】如果属于该 uid 的 package 为 null,从 mUidStates 中移除!
uidState.clear();
mUidStates.removeAt(i);
changed = true;
continue;
}
// 如果 uidState.pkgOps 为 null,跳过!
ArrayMap<String, Ops> pkgs = uidState.pkgOps;
if (pkgs == null) {
continue;
}
//【2】我们知道 uidState.pkgOps 保存了该 uid 下所有的 package 的 op 信息!
Iterator<Ops> it = pkgs.values().iterator();
while (it.hasNext()) { // 遍历每一个 package 的 Op 信息!
Ops ops = it.next();
int curUid = -1;
try {
//【2.1】首先,通过包名获得 package 的 uid!
curUid = AppGlobals.getPackageManager().getPackageUid(ops.packageName,
PackageManager.MATCH_UNINSTALLED_PACKAGES,
UserHandle.getUserId(ops.uidState.uid));
} catch (RemoteException ignored) {
}
//【2.2】然后和 op 所属的 uid 进行比较,如果不相等,说明 package 信息发生了变化!
// 移除旧的 Ops 集合!
if (curUid != ops.uidState.uid) {
Slog.i(TAG, "Pruning old package " + ops.packageName
+ "/" + ops.uidState + ": new uid=" + curUid);
it.remove();
changed = true;
}
}
if (uidState.isDefault()) {
//【3】移除那些没有对应 Package 和 Ops 的 UidState!
mUidStates.removeAt(i);
}
}
if (changed) {
//【5.2】如果 changed 为 true,表示 UidState,或者 Ops 发生了变化,更新本地持久化文件!
scheduleFastWriteLocked();
}
}
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 (noteOperation(AppOpsManager.OP_READ_EXTERNAL_STORAGE, uid,
packageName) != AppOpsManager.MODE_ALLOWED) {
return Zygote.MOUNT_EXTERNAL_NONE;
}
if (noteOperation(AppOpsManager.OP_WRITE_EXTERNAL_STORAGE, uid,
packageName) != AppOpsManager.MODE_ALLOWED) {
return Zygote.MOUNT_EXTERNAL_READ;
}
return Zygote.MOUNT_EXTERNAL_WRITE;
}
public boolean hasExternalStorage(int uid, String packageName) {
final int mountMode = getMountMode(uid, packageName);
return mountMode == Zygote.MOUNT_EXTERNAL_READ
|| mountMode == Zygote.MOUNT_EXTERNAL_WRITE;
}
});
}
5.1 getPackagesForUid
获取 uid 所有的 package:
1 | private static String[] getPackagesForUid(int uid) { |
以数组形式放回!
5.2 scheduleFastWriteLocked
更新本地的持久化文件!1
2
3
4
5
6
7
8private void scheduleFastWriteLocked() {
if (!mFastWriteScheduled) {
mWriteScheduled = true;
mFastWriteScheduled = true;
mHandler.removeCallbacks(mWriteRunner);
mHandler.postDelayed(mWriteRunner, 10*1000); //
}
}
这里的 mHandler 是由 AMS 创建的一个子线程的 Handler!
1 | final Runnable mWriteRunner = new Runnable() { |
继续来看!!
5.3 writeState
我们来看下,如何更新持久化文件!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
115void writeState() {
synchronized (mFile) {
//【5.2.1】获得所有 package 的 Op 信息!
List<AppOpsManager.PackageOps> allOps = getPackagesForOps(null);
FileOutputStream stream;
try {
stream = mFile.startWrite();
} catch (IOException e) {
Slog.w(TAG, "Failed to write state: " + e);
return;
}
try {
XmlSerializer out = new FastXmlSerializer();
out.setOutput(stream, StandardCharsets.UTF_8.name());
out.startDocument(null, true);
out.startTag(null, "app-ops"); //【1】写入 app-ops 标签!
final int uidStateCount = mUidStates.size();
for (int i = 0; i < uidStateCount; i++) { //【2】首先写入 uid 标签!
UidState uidState = mUidStates.valueAt(i);
if (uidState.opModes != null && uidState.opModes.size() > 0) {
out.startTag(null, "uid");
out.attribute(null, "n", Integer.toString(uidState.uid)); //【2.1】写入 n 属性!
SparseIntArray uidOpModes = uidState.opModes;
final int opCount = uidOpModes.size();
for (int j = 0; j < opCount; j++) {
final int op = uidOpModes.keyAt(j);
final int mode = uidOpModes.valueAt(j);
out.startTag(null, "op"); //【2.2】写入 op 子标签,和对应的 n,m 属性!
out.attribute(null, "n", Integer.toString(op));
out.attribute(null, "m", Integer.toString(mode));
out.endTag(null, "op");
}
out.endTag(null, "uid");
}
}
if (allOps != null) { // 如果 allOps 不为 null,那就开始写入 pkg 标签!
String lastPkg = null;
for (int i=0; i<allOps.size(); i++) {
AppOpsManager.PackageOps pkg = allOps.get(i);
if (!pkg.getPackageName().equals(lastPkg)) {
if (lastPkg != null) {
out.endTag(null, "pkg");
}
lastPkg = pkg.getPackageName();
out.startTag(null, "pkg"); // 写入 pkg 标签
out.attribute(null, "n", lastPkg); // 写入 n 属性,包名
}
out.startTag(null, "uid"); // 写入 uid 子标签
out.attribute(null, "n", Integer.toString(pkg.getUid())); // 写入 n 属性,uid 的值
synchronized (this) {
Ops ops = getOpsRawLocked(pkg.getUid(), pkg.getPackageName(), false);
// 写入 p 属性,表示是否是 Privileged!
if (ops != null) {
out.attribute(null, "p", Boolean.toString(ops.isPrivileged));
} else {
out.attribute(null, "p", Boolean.toString(false));
}
}
List<AppOpsManager.OpEntry> ops = pkg.getOps(); // 处理该 package 的 Ops!
for (int j=0; j<ops.size(); j++) {
AppOpsManager.OpEntry op = ops.get(j);
out.startTag(null, "op"); // 写入 op 标签;
out.attribute(null, "n", Integer.toString(op.getOp())); // 写入 n 属性,op 码;
// 写入 m 属性,表示控制状态,这里先调用了 AppOpsManager.opToDefaultMode 来计算下
// 默认的控制状态。如果 op 的控制状态不等于默认值才会写入!
if (op.getMode() != AppOpsManager.opToDefaultMode(op.getOp())) {
out.attribute(null, "m", Integer.toString(op.getMode()));
}
// 写入 t 属性!
long time = op.getTime();
if (time != 0) {
out.attribute(null, "t", Long.toString(time));
}
// 写入 r 属性!
time = op.getRejectTime();
if (time != 0) {
out.attribute(null, "r", Long.toString(time));
}
// 写入 d 属性!
int dur = op.getDuration();
if (dur != 0) {
out.attribute(null, "d", Integer.toString(dur));
}
// 写入 pu 属性!
int proxyUid = op.getProxyUid();
if (proxyUid != -1) {
out.attribute(null, "pu", Integer.toString(proxyUid));
}
// 写入 pp 属性!
String proxyPackageName = op.getProxyPackageName();
if (proxyPackageName != null) {
out.attribute(null, "pp", proxyPackageName);
}
out.endTag(null, "op");
}
out.endTag(null, "uid");
}
if (lastPkg != null) {
out.endTag(null, "pkg");
}
}
out.endTag(null, "app-ops");
out.endDocument();
mFile.finishWrite(stream);
} catch (IOException e) {
Slog.w(TAG, "Failed to write state, restoring backup.", e);
mFile.failWrite(stream);
}
}
}
writeState 的流程还是很简单的!
5.3.1 getPackagesForOps
该方法用于获得所有 package 的 Op 信息,参数 ops 表示只收集其指定的 op 信息!
1 |
|
5.3.1.1 collectOps
参数 int[] ops 用于指定特定的 Op,这样我们会只收集这些特定的 Ops,当然这里我们要收集所有 package 的 Op 信息,所以 int[] ops 传入 null;
1 | private ArrayList<AppOpsManager.OpEntry> collectOps(Ops pkgOps, int[] ops) { |
collectOps 方法很简单,不多说了!
5.3.1.1.1 new AppOpsManager.OpEntry
1 | public static class OpEntry implements Parcelable { |
OpEntry 的结构很简单,不多说了!
5.3.1.2 new AppOpsManager.PackageOps
1 | public static class PackageOps implements Parcelable { |
PackageOps 的结构很简单,不多说了!
5.3.2 getOpsRawLocked
getOpsRawLocked 方法用于获得 package 的 Ops 列表!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
71private Ops getOpsRawLocked(int uid, String packageName, boolean edit) {
//【1】获得 uid 对应的 UidState!
UidState uidState = getUidStateLocked(uid, edit);
if (uidState == null) {
return null;
}
if (uidState.pkgOps == null) {
if (!edit) {
return null;
}
uidState.pkgOps = new ArrayMap<>();
}
//【2】获得 package 对应的 Ops 集合!
Ops ops = uidState.pkgOps.get(packageName);
if (ops == null) { // 处理 package 的 ops 为 null 的特殊情况!
if (!edit) {
return null;
}
boolean isPrivileged = false;
//【3】如果 uid 不为 null,需要校验 uid 是否一致!
if (uid != 0) {
final long ident = Binder.clearCallingIdentity();
try {
int pkgUid = -1;
try {
//【3.1】获得该 package 的 ApplicationInfo 对象!
ApplicationInfo appInfo = ActivityThread.getPackageManager()
.getApplicationInfo(packageName,
PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
UserHandle.getUserId(uid));
//【3.2】获得 package 的 uid,并判断是否是 FLAG_PRIVILEGED 的!
if (appInfo != null) {
pkgUid = appInfo.uid;
isPrivileged = (appInfo.privateFlags
& ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
} else {
// 如果 appInfo 为 null,那就判断一些特殊 uid 的情况!
if ("media".equals(packageName)) {
pkgUid = Process.MEDIA_UID;
isPrivileged = false;
} else if ("audioserver".equals(packageName)) {
pkgUid = Process.AUDIOSERVER_UID;
isPrivileged = false;
} else if ("cameraserver".equals(packageName)) {
pkgUid = Process.CAMERASERVER_UID;
isPrivileged = false;
}
}
} catch (RemoteException e) {
Slog.w(TAG, "Could not contact PackageManager", e);
}
//【3.3】检查 uid 是否发生变化,如果有变化,无效,那就返回 null!
if (pkgUid != uid) {
RuntimeException ex = new RuntimeException("here");
ex.fillInStackTrace();
Slog.w(TAG, "Bad call: specified package " + packageName
+ " under uid " + uid + " but it is really " + pkgUid, ex);
return null;
}
} finally {
Binder.restoreCallingIdentity(ident);
}
}
//【4】如果该 package 的 Ops 为 null,那就会
// 给该 package 重新创建一个 Ops,并添加到所属的 uidState.pkgOps 中!
ops = new Ops(packageName, uidState, isPrivileged);
uidState.pkgOps.put(packageName, ops);
}
return ops; // 返回该 package 的 Ops 列表!
}
方法很简单,不多说了!