接力上一篇:PackageManagerService Android 8.1 源码解读 05
六、五部曲 - PMS之权限扫描
a、分析此 “PMS之权限扫描” 的目标是: PackageManagerService中执行构造函数()后,需求对【/system/etc/permissions】中的各种xml进行扫描,进行相应的权限存储,让以后可以使用,这就是本次“PMS之权限扫描”分析的目的。
b、权限扫描:PackageManagerService执行构造函数()时,通过单例对象SystemConfig的readPermissionsFromXml()来扫描读取/system/etc/permissions中的xml文件,包括platform.xml和系统支持的各种硬件模块的feature主要工作:
public PackageManagerService(Context context, Installer installer,
boolean factoryTest, boolean onlyCore) {
......省略代码
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "get system config");
SystemConfig systemConfig = SystemConfig.getInstance();
mGlobalGids = systemConfig.getGlobalGids();
mSystemPermissions = systemConfig.getSystemPermissions();
mAvailableFeatures = systemConfig.getAvailableFeatures();
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
......省略代码
}
// 构造函数读取配置权限
SystemConfig() {
// Read configuration from system
readPermissions(Environment.buildPath(
Environment.getRootDirectory(), "etc", "sysconfig"), ALLOW_ALL);
// Read configuration from the old permissions dir
readPermissions(Environment.buildPath(
Environment.getRootDirectory(), "etc", "permissions"), ALLOW_ALL);
// Allow Vendor to customize system configs around libs, features, permissions and apps
int vendorPermissionFlag = ALLOW_LIBS | ALLOW_FEATURES | ALLOW_PERMISSIONS |
ALLOW_APP_CONFIGS;
readPermissions(Environment.buildPath(
Environment.getVendorDirectory(), "etc", "sysconfig"), vendorPermissionFlag);
readPermissions(Environment.buildPath(
Environment.getVendorDirectory(), "etc", "permissions"), vendorPermissionFlag);
// Allow ODM to customize system configs around libs, features and apps
int odmPermissionFlag = ALLOW_LIBS | ALLOW_FEATURES | ALLOW_APP_CONFIGS;
readPermissions(Environment.buildPath(
Environment.getOdmDirectory(), "etc", "sysconfig"), odmPermissionFlag);
readPermissions(Environment.buildPath(
Environment.getOdmDirectory(), "etc", "permissions"), odmPermissionFlag);
// Only allow OEM to customize features
readPermissions(Environment.buildPath(
Environment.getOemDirectory(), "etc", "sysconfig"), ALLOW_FEATURES);
readPermissions(Environment.buildPath(
Environment.getOemDirectory(), "etc", "permissions"), ALLOW_FEATURES);
}
c、SystemConfig 的 readPermissions函数:此函数目的:(扫描/system/etc/permissions中文件,调readPermissionsFromXml()进行解析,存入SsytemConfig相应的成员数组变量中)
void readPermissions(File libraryDir, int permissionFlag) {
// Read permissions from given directory.
// 如果文件不存在,或者文件不是目录,直接返回
if (!libraryDir.exists() || !libraryDir.isDirectory()) {
if (permissionFlag == ALLOW_ALL) {
Slog.w(TAG, "No directory " + libraryDir + ", skipping");
}
return;
}
// 文件不可读,直接返回
if (!libraryDir.canRead()) {
Slog.w(TAG, "Directory " + libraryDir + " cannot be read");
return;
}
// Iterate over the files in the directory and scan .xml files
File platformFile = null;
// 列表目录下定位文件
for (File f : libraryDir.listFiles()) {
// 最后才读取 platform.xml 文件
if (f.getPath().endsWith("etc/permissions/platform.xml")) {
platformFile = f;
continue;
}
// 过滤不是.xml结尾的文件
if (!f.getPath().endsWith(".xml")) {
Slog.i(TAG, "Non-xml file " + f + " in " + libraryDir + " directory, ignoring");
continue;
}
// 文件不可读
if (!f.canRead()) {
Slog.w(TAG, "Permissions library file " + f + " cannot be read");
continue;
}
// 开始读取文件
readPermissionsFromXml(f, permissionFlag);
}
// Read platform permissions last so it will take precedence
if (platformFile != null) {
// 到这里最后才读取 platform.xml 文件,可以覆盖之前的权限
readPermissionsFromXml(platformFile, permissionFlag);
}
}
d、readPermissionsFromXml()方法,解析xml的标签节点,存入mGlobalGids、mPermissions、mSystemPermissions等成员变量中,供其他进行调用
private void readPermissionsFromXml(File permFile, int permissionFlag) {
FileReader permReader = null;
try {
permReader = new FileReader(permFile);
} catch (FileNotFoundException e) {
Slog.w(TAG, "Couldn't find or open permissions file " + permFile);
return;
}
// 获取lowRam变量,主要是看设备是否为低内存设备
final boolean lowRam = ActivityManager.isLowRamDeviceStatic();
try {
// 用pull解析xml文件
XmlPullParser parser = Xml.newPullParser();
parser.setInput(permReader);
......省略代码
while (true) {
XmlUtils.nextElement(parser);
if (parser.getEventType() == XmlPullParser.END_DOCUMENT) {
break;
}
String name = parser.getName();
// 解析 group 标签,前面介绍的 XML 文件中没有单独使用该标签的地方
if ("group".equals(name) && allowAll) {
String gidStr = parser.getAttributeValue(null, "gid");
if (gidStr != null) {
int gid = android.os.Process.getGidForName(gidStr);
// 转换 XML 中的 gid字符串为整型,并保存到 mGlobalGids 中
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) && allowPermissions) {
//解析 permission 标签
String perm = parser.getAttributeValue(null, "name");
if (perm == null) {
Slog.w(TAG, "<permission> without name in " + permFile + " at "
+ parser.getPositionDescription());
XmlUtils.skipCurrentTag(parser);
continue;
}
perm = perm.intern();
// 调用 readPermission 处理,存入mPermissions
readPermission(parser, perm);
} else if ......
......省略很多代码
}
e、查看 XML文件:adb devices && adb shell
k37mv1_bsp:/ # ls -la /system/etc/permissions/
total 76
drwxr-xr-x 2 root root 4096 2009-01-01 00:00 .
drwxr-xr-x 21 root root 4096 2009-01-01 00:00 ..
-rw-r--r-- 1 root root 748 2009-01-01 00:00 android.software.webview.xml
-rw-r--r-- 1 root root 828 2009-01-01 00:00 com.android.location.provider.xml
-rw-r--r-- 1 root root 828 2009-01-01 00:00 com.android.media.remotedisplay.xml
-rw-r--r-- 1 root root 820 2009-01-01 00:00 com.android.mediadrm.signer.xml
-rw-r--r-- 1 root root 193 2009-01-01 00:00 mediatek-packages-teleservice.xml
-rw-r--r-- 1 root root 9244 2009-01-01 00:00 platform.xml
-rw-r--r-- 1 root root 156 2009-01-01 00:00 pms_sysapp_removable_system_list.txt
-rw-r--r-- 1 root root 8144 2009-01-01 00:00 privapp-permissions-mediatek.xml
-rw-r--r-- 1 root root 20917 2009-01-01 00:00 privapp-permissions-platform.xml
k37mv1_bsp:/ #
然后在导出去:adb pull /system/etc/permissions
/system/etc/permissions中会存在很多的xml文件,例如我们看下 android.software.webview.xml的
文件,内容如下: 里面只有一个feature "android.software.webview",大部分的xml都是类似的定义方式
f、让我们来简单的看下/system/etc/permissions/platform.xml的内容
<?xml version="1.0" encoding="utf-8"?>
<permissions>
<!-- ================================================================== -->
<!-- ================================================================== -->
<!-- ================================================================== -->
<!-- The following tags are associating low-level group IDs with
permission names. By specifying such a mapping, you are saying
that any application process granted the given permission will
also be running with the given group ID attached to its process,
so it can perform any filesystem (read, write, execute) operations
allowed for that group. -->
<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.BLUETOOTH_STACK" >
<group gid="bluetooth" />
<group gid="wakelock" />
<group gid="uhid" />
</permission>
<permission name="android.permission.NET_TUNNELING" >
<group gid="vpn" />
</permission>
<permission name="android.permission.INTERNET" >
<group gid="inet" />
</permission>
<permission name="android.permission.READ_LOGS" >
<group gid="log" />
</permission>
<permission name="android.permission.WRITE_MEDIA_STORAGE" >
<group gid="media_rw" />
<group gid="sdcard_rw" />
</permission>
<permission name="android.permission.ACCESS_MTP" >
<group gid="mtp" />
</permission>
<permission name="android.permission.NET_ADMIN" >
<group gid="net_admin" />
</permission>
<!-- The group that /cache belongs to, linked to the permission
set on the applications that can access /cache -->
<permission name="android.permission.ACCESS_CACHE_FILESYSTEM" >
<group gid="cache" />
</permission>
<!-- RW permissions to any system resources owned by group 'diag'.
This is for carrier and manufacture diagnostics tools that must be
installable from the framework. Be careful. -->
<permission name="android.permission.DIAGNOSTIC" >
<group gid="input" />
<group gid="diag" />
</permission>
<!-- Group that can read detailed network usage statistics -->
<permission name="android.permission.READ_NETWORK_USAGE_HISTORY">
<group gid="net_bw_stats" />
</permission>
<!-- Group that can modify how network statistics are accounted -->
<permission name="android.permission.UPDATE_DEVICE_STATS">
<group gid="net_bw_acct" />
</permission>
<permission name="android.permission.LOOP_RADIO" >
<group gid="loop_radio" />
</permission>
<!-- Hotword training apps sometimes need a GID to talk with low-level
hardware; give them audio for now until full HAL support is added. -->
<permission name="android.permission.MANAGE_VOICE_KEYPHRASES">
<group gid="audio" />
</permission>
<permission name="android.permission.ACCESS_BROADCAST_RADIO" >
<!-- /dev/fm is gid media, not audio -->
<group gid="media" />
</permission>
<!-- These are permissions that were mapped to gids but we need
to keep them here until an upgrade from L to the current
version is to be supported. These permissions are built-in
and in L were not stored in packages.xml as a result if they
are not defined here while parsing packages.xml we would
ignore these permissions being granted to apps and not
propagate the granted state. From N we are storing the
built-in permissions in packages.xml as the saved storage
is negligible (one tag with the permission) compared to
the fragility as one can remove a built-in permission which
no longer needs to be mapped to gids and break grant propagation. -->
<permission name="android.permission.READ_EXTERNAL_STORAGE" />
<permission name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!-- ================================================================== -->
<!-- ================================================================== -->
<!-- ================================================================== -->
<!-- The following tags are assigning high-level permissions to specific
user IDs. These are used to allow specific core system users to
perform the given operations with the higher-level framework. For
example, we give a wide variety of permissions to the shell user
since that is the user the adb shell runs under and developers and
others should have a fairly open environment in which to
interact with the system. -->
<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.GET_PROCESS_STATE_AND_OOM_SCORE" uid="media" />
<assign-permission name="android.permission.CAPTURE_AUDIO_OUTPUT" uid="media" />
<!-- AudioServer is separated from mediaServer on Android N0, so AudioServer will
check mediaServer permission when mediaServer call audioServer through binder,
so add CAPTURE_AUDIO_OUTPUT permission for mediaServer. -->
<assign-permission name="android.permission.MODIFY_AUDIO_SETTINGS" uid="audioserver" />
<assign-permission name="android.permission.ACCESS_SURFACE_FLINGER" uid="audioserver" />
<assign-permission name="android.permission.WAKE_LOCK" uid="audioserver" />
<assign-permission name="android.permission.UPDATE_DEVICE_STATS" uid="audioserver" />
<assign-permission name="android.permission.UPDATE_APP_OPS_STATS" uid="audioserver" />
<assign-permission name="android.permission.MODIFY_AUDIO_SETTINGS" uid="cameraserver" />
<assign-permission name="android.permission.ACCESS_SURFACE_FLINGER" uid="cameraserver" />
<assign-permission name="android.permission.WAKE_LOCK" uid="cameraserver" />
<assign-permission name="android.permission.UPDATE_DEVICE_STATS" uid="cameraserver" />
<assign-permission name="android.permission.UPDATE_APP_OPS_STATS" uid="cameraserver" />
<assign-permission name="android.permission.GET_PROCESS_STATE_AND_OOM_SCORE" uid="cameraserver" />
<assign-permission name="android.permission.ACCESS_SURFACE_FLINGER" uid="graphics" />
<!-- This is a list of all the libraries available for application
code to link against. -->
<library name="android.test.mock"
file="/system/framework/android.test.mock.jar" />
<library name="android.test.runner"
file="/system/framework/android.test.runner.jar" />
<library name="javax.obex"
file="/system/framework/javax.obex.jar" />
<library name="org.apache.http.legacy"
file="/system/framework/org.apache.http.legacy.jar" />
<!-- These are the standard packages that are white-listed to always have internet
access while in power save mode, even if they aren't in the foreground. -->
<allow-in-power-save package="com.android.providers.downloads" />
<!-- These are the standard packages that are white-listed to always have internet
access while in data mode, even if they aren't in the foreground. -->
<allow-in-data-usage-save package="com.android.providers.downloads" />
<!-- This is a core platform component that needs to freely run in the background -->
<allow-in-power-save package="com.android.cellbroadcastreceiver" />
<allow-in-power-save package="com.android.shell" />
<!-- These are the packages that are white-listed to be able to run as system user -->
<system-user-whitelisted-app package="com.android.settings" />
<!-- These are the packages that shouldn't run as system user -->
<system-user-blacklisted-app package="com.android.wallpaper.livepicker" />
</permissions>
以上platform.xml中出现的标签种类则较为多样,它们的含义分别是:
platform.xml中出现的标签种类则较为多样,它们的含义分别是:
<group>:根据name获取gid
<permission >标签:把属性name所描述的权限赋予给<group>标签中属性gid所表示的用户组,一个权限
可以有一个或多个group对象,当一个APK授权于这个这个权限时,它同时属于这几个组
<assign-permission>标签:把属性name所描述的权限赋予给uid属性所表示的用户
<split-permission>标签:一个权限可以扩展出一个新的权限
<library>标签:除framework中动态库以外的,所有系统会自动加载的动态库
<feature>标签:硬件支持的一些feature
<oem-permission>标签:oem厂商自己定义的一些权限
<privapp-permission>标签:来自system、vendor、product、system_ext的privapp权限分别存
储,这是防止供应商分区中的xml授权于系统分区中的私有应用权限
最后将上面xml解析出来的数据做如下存储:
<group>标签gid属性的值会存放在mGlobalGids数组中;
总结:权限扫描,扫描/system/etc/permissions中的xml,存入相应的结构体中,供之后权限管理使
用
=============================================
============
<permission>标签,解析得到的值会存放在mPermissions集合中;
<assign-permission>标签解析得到的值会存放在mSystemPermissions中;
<split-permission>存储在mSplitPermissions
<library>标签解析得到的值会存放在mSharedLibraries中;
<feature>存储在mAvaliableFeatures
<oem-permission>存储在mOemPermissions
<privapp-permission>会根据不同的存储路径,分别存储在mVendorPrivAppPermissions、
mProductPrivAppPermissions、mSystemExtPrivAppPermissions、mPrivAppPermissions
g、总结:权限扫描,扫描/system/etc/permissions中的xml,存入相应的结构体中,供之后权限管理使用