最近刚做完通知权限管理的功能,在这里做一下记录。
单个应用的权限管理需要使用到 AppOpsManager 的接口,接下来通过代码记录下:
AppOpsManager 是对外的管理接口,真正实现功能的是 AppOpsService。
一、AppOpsManager的工作流程
1、 AppOpsService 初始化:
public ActivityManagerService(Context systemContext) {
mContext = systemContext;
mFactoryTest = FactoryTest.getMode();
mSystemThread = ActivityThread.currentActivityThread();
....
// TODO: Move creation of battery stats service outside of activity manager service.
File dataDir = Environment.getDataDirectory();
File systemDir = new File(dataDir, "system");
systemDir.mkdirs();
....
mAppOpsService = new AppOpsService(new File(systemDir, "appops.xml"), mHandler);
mAppOpsService.startWatchingMode(AppOpsManager.OP_RUN_IN_BACKGROUND, null,
new IAppOpsCallback.Stub() {
@Override 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);
}
}
}
});
从以上代码可知应用信息的储存在“data/system/appops.xml”文件中,格式为:
初始化 AppOpsService 同时,解析appops.xml文件中的信息并储存在名为 UidState 的内部类中:
void readState() {
synchronized (mFile) {
synchronized (this) {
FileInputStream stream;
try {
stream = mFile.openRead();
} catch (FileNotFoundException e) {
....
return;
}
boolean success = false;
mUidStates.clear();
try {
XmlPullParser parser = Xml.newPullParser();
parser.setInput(stream, StandardCharsets.UTF_8.name());
int type;
....
String tagName = parser.getName();
if (tagName.equals("pkg")) {
//读取每个应用权限信息,并保存至UidState.pkgOps变量
readPackage(parser);
} else if (tagName.equals("uid")) {
//读取每个应用对应的相关权限以及权限状态,并保存至UidState.opModes变量
readUidOps(parser);
} else {
Slog.w(TAG, "Unknown element under : "
+ parser.getName());
XmlUtils.skipCurrentTag(parser);
}
}
success = true;
} catch (IllegalStateException e) {
....
}
}
}
}
void readPackage(XmlPullParser parser) throws NumberFormatException,
XmlPullParserException, IOException {
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)) {
....
String tagName = parser.getName();
if (tagName.equals("uid")) {
readUid(parser, pkgName);
} else {
....
}
}
}
void readUid(XmlPullParser parser, String pkgName) throws