您的位置:首页 > 移动开发 > Android开发

Android学习心得(22) --- PackageManagerService源码解析platfrom.xml

2016-10-17 22:21 274 查看

新博客地址

blog.marssecure.com

platform.xml

Android中沿用Linux用户和组的来限制系统资源的访问,查看从Android真机pull出/etc/permissions/platform.xml



权限初始化

PackageManagerService构造函数会解析platform.xml,建立android权限和gid的对应关系。然后,扫描apk时,会由请求的权限找到对应的gid,并保存在Package类中。

由于Android很多都是使用permission来进行保护,需要在AndroidManifest中显示声明对应权限,有些在platfrom.xml中定义的权限须由特定用户组使用

下面来解析一下在该构造方法中对于plafrom.xml解析

源码分析

初始化处理permission文件

创建的时候,在构造方法中初始化systemConfig

public PackageManagerService(Context context, Installer installer, boolean factoryTest, boolean onlyCore) {
...
SystemConfig systemConfig = SystemConfig.getInstance()
...
}


getInstance()是创建一个SystemConfig对象

public static SystemConfig getInstance() {
synchronized (SystemConfig.class) {
if (sInstance == null) {
sInstance = new SystemConfig();
}
return sInstance;
}
}


SystemConfig构造方法中,使用readPermissions处理了系统和OEM厂商的配置和系统权限

SystemConfig() {
/system/etc/sysconfig
readPermissions(Environment.buildPath(
Environment.getRootDirectory(), "etc", "sysconfig"), false);
/system/etc/permissions
readPermissions(Environment.buildPath(
Environment.getRootDirectory(), "etc", "permissions"), false);
/oem/etc/sysconfig
readPermissions(Environment.buildPath(
Environment.getOemDirectory(), "etc", "sysconfig"), true);
/oem/etc/permissions
readPermissions(Environment.buildPath(
Environment.getOemDirectory(), "etc", "permissions"), true);
}


对于上面四个目录都使用了readPermissions函数读取

void readPermissions(File libraryDir, boolean onlyFeatures) {
// 从给定的文件夹中读取权限
....
// 迭代方式读取xml文件
File platformFile = null;
for (File f : libraryDir.listFiles()) {
// 最后单独处理platform.xml
if (f.getPath().endsWith("etc/permissions/platform.xml")) {
platformFile = f;
continue;
}
...
// 取到的xml结尾的文件,使用readPermissionsFromXml读取
readPermissionsFromXml(f, onlyFeatures);
}
// 最后读取平台权限以致其能最优先
if (platformFile != null) {
readPermissionsFromXml(platformFile, onlyFeatures);
}
}


不管是platform.xml还是其他的xml文件,都是调用readPermissionsFromXml函数处理,assign-permission解析后存放到mSystemPermissions中,uid和permission对应

ArraySet<String> perms = mSystemPermissions.get(uid);
if (perms == null) {
perms = new ArraySet<String>();
mSystemPermissions.put(uid, perms);
}
perms.add(perm);

permission将permission和gid存放到mPermissions中
PermissionEntry perm = mPermissions.get(name);
if (perm == null) {
perm = new PermissionEntry(name);
mPermissions.put(name, perm);
}


整体方法源代码

private void readPermissionsFromXml(File permFile, boolean onlyFeatures) {
FileReader permReader = null;
permReader = new FileReader(permFile);
// 当前系统是否对低内存支持
final boolean lowRam = ActivityManager.isLowRamDeviceStatic();

try {
XmlPullParser parser = Xml.newPullParser();
parser.setInput(permReader);

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

if (type != parser.START_TAG) {
throw new XmlPullParserException("No start tag found");
}

if (!parser.getName().equals("permissions") && !parser.getName().equals("config")) {
throw new XmlPullParserException("Unexpected start tag in " + permFile
+ ": found " + parser.getName() + ", expected 'permissions' or 'config'");
}

while (true) {
XmlUtils.nextElement(parser);
String name = parser.getName();
if ("group".equals(name) && !onlyFeatures) {
String gidStr = parser.getAttributeValue(null, "gid");
if (gidStr != null) {
int gid = android.os.Process.getGidForName(gidStr);
mGlobalGids = appendInt(mGlobalGids, gid);
} else {
Slog.w(TAG, "<group> without gid in " + permFile + " at "
+ parser.getPositionDescription());
}

XmlUtils.skipCurrentTag(parser);
continue;

} else if ("permission".equals(name) && !onlyFeatures) {
String perm = parser.getAttributeValue(null, "name");
perm = perm.intern();
readPermission(parser, perm);

} else if ("assign-permission".equals(name) && !onlyFeatures) {
String perm = parser.getAttributeValue(null, "name");
String uidStr = parser.getAttributeValue(null, "uid");
int uid = Process.getUidForName(uidStr);
perm = perm.intern();
ArraySet<String> perms = mSystemPermissions.get(uid);
if (perms == null) {
perms = new ArraySet<String>();
mSystemPermissions.put(uid, perms);
}
perms.add(perm);
XmlUtils.skipCurrentTag(parser);

} else if ("library".equals(name) && !onlyFeatures) {
String lname = parser.getAttributeValue(null, "name");
String lfile = parser.getAttributeValue(null, "file");
if (lname == null) {
Slog.w(TAG, "<library> without name in " + permFile + " at "
+ parser.getPositionDescription());
} else if (lfile == null) {
Slog.w(TAG, "<library> without file in " + permFile + " at "
+ parser.getPositionDescription());
} else {
//Log.i(TAG, "Got library " + lname + " in " + lfile);
mSharedLibraries.put(lname, lfile);
}
XmlUtils.skipCurrentTag(parser);
continue;

} else if ("feature".equals(name)) {
String fname = parser.getAttributeValue(null, "name");
boolean allowed;
if (!lowRam) {
allowed = true;
} else {
String notLowRam = parser.getAttributeValue(null, "notLowRam");
allowed = !"true".equals(notLowRam);
}
if (fname == null) {
Slog.w(TAG, "<feature> without name in " + permFile + " at "
+ parser.getPositionDescription());
} else if (allowed) {
//Log.i(TAG, "Got feature " + fname);
FeatureInfo fi = new FeatureInfo();
fi.name = fname;
mAvailableFeatures.put(fname, fi);
}
XmlUtils.skipCurrentTag(parser);
continue;

} else if ("unavailable-feature".equals(name)) {
String fname = parser.getAttributeValue(null, "name");
if (fname == null) {
Slog.w(TAG, "<unavailable-feature> without name in " + permFile + " at "
+ parser.getPositionDescription());
} else {
mUnavailableFeatures.add(fname);
}
XmlUtils.skipCurrentTag(parser);
continue;

} else if ("allow-in-power-save".equals(name) && !onlyFeatures) {
String pkgname = parser.getAttributeValue(null, "package");
if (pkgname == null) {
Slog.w(TAG, "<allow-in-power-save> without package in " + permFile + " at "
+ parser.getPositionDescription());
} else {
mAllowInPowerSave.add(pkgname);
}
XmlUtils.skipCurrentTag(parser);
continue;

} else if ("fixed-ime-app".equals(name) && !onlyFeatures) {
String pkgname = parser.getAttributeValue(null, "package");
if (pkgname == null) {
Slog.w(TAG, "<fixed-ime-app> without package in " + permFile + " at "
+ parser.getPositionDescription());
} else {
mFixedImeApps.add(pkgname);
}
XmlUtils.skipCurrentTag(parser);
continue;

} else {
XmlUtils.skipCurrentTag(parser);
continue;
}
}
} catch (XmlPullParserException e) {
...
} finally {
IoUtils.closeQuietly(permReader);
}

for (String fname : mUnavailableFeatures) {
if (mAvailableFeatures.remove(fname) != null) {
Slog.d(TAG, "Removed unavailable feature " + fname);
}
}
}


看platfrom.xml文件中内容,permission将属性name中权限赋予group中gid用户组,assign-permission把属性name中权限赋予uid用户

<permissions>
<permission name="android.permission.BLUETOOTH_ADMIN" >
<group gid="net_bt_admin" />
</permission>
<permission name="android.permission.BLUETOOTH" >
<group gid="net_bt" />
</permission>
<permission name="android.permission.INTERNET" >
<group gid="inet" />
</permission>
...
<assign-permission name="android.permission.MODIFY_AUDIO_SETTINGS" uid="media" />
<assign-permission name="android.permission.ACCESS_SURFACE_FLINGER" uid="media" />
<assign-permission name="android.permission.WAKE_LOCK" uid="media" />
<assign-permission name="android.permission.UPDATE_DEVICE_STATS" uid="media" />
<assign-permission name="android.permission.UPDATE_APP_OPS_STATS" uid="media" />
<assign-permission name="android.permission.ACCESS_SURFACE_FLINGER" uid="graphics" />
<library name="android.test.runner"
file="/system/framework/android.test.runner.jar" />
<library name="javax.obex"
file="/system/framework/javax.obex.jar"/>
<library name="javax.btobex"
file="/system/framework/javax.btobex.jar"/>
<!--网络访问的白名单,即使他们不在前面-->
<allow-in-power-save package="com.android.providers.downloads" />
</permissions>


未来:

下一步会去研究一下安装apk时候权限解析的源代码,更好理解权限在整个系统中的运用。希望对大家有所帮助,也希望你可以一直支持我们MarsSecure。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: