SystemConfig.java是PKMS里一个很重要的类,用来解析一些系统配置信息的,然后将解析的结果赋值给SystemConfig里的各个数据结构,供我们查询。首先看一下它的构造方法(在PKMS的构造方法里最终会通过调用SystemConfig的构造方法去解析配置文件):
frameworks/base/core/java/com/android/server/SystemConfig.java
SystemConfig() {
TimingsTraceLog log = new TimingsTraceLog(TAG, Trace.TRACE_TAG_SYSTEM_SERVER);
log.traceBegin("readAllPermissions");
try {
readAllPermissions();
} finally {
log.traceEnd();
}
}
调用readAllPermissions()方法读取系统配置。
private void readAllPermissions() {
// Read configuration from system
readPermissions(Environment.buildPath(
Environment.getRootDirectory(), "etc", "sysconfig"), ALLOW_ALL);//读取system/etc/sysconfig目录
// Read configuration from the old permissions dir
readPermissions(Environment.buildPath(
Environment.getRootDirectory(), "etc", "permissions"), ALLOW_ALL);//读取system/etc/permissions目录
// Vendors are only allowed to customize these
int vendorPermissionFlag = ALLOW_LIBS | ALLOW_FEATURES | ALLOW_PRIVAPP_PERMISSIONS
| ALLOW_ASSOCIATIONS;
if (Build.VERSION.FIRST_SDK_INT <= Build.VERSION_CODES.O_MR1) {
// For backward compatibility
vendorPermissionFlag |= (ALLOW_PERMISSIONS | ALLOW_APP_CONFIGS);
}
readPermissions(Environment.buildPath(
Environment.getVendorDirectory(), "etc", "sysconfig"), vendorPermissionFlag);//读取vendor/etc/sysconfig目录
readPermissions(Environment.buildPath(
Environment.getVendorDirectory(), "etc", "permissions"), vendorPermissionFlag);//读取vendor/etc/permissions目录
String vendorSkuProperty = SystemProperties.get(VENDOR_SKU_PROPERTY, "");//vendor/etc/vintf/manifest_SKU.xml里如果定义了SKU,那么SKU就是属性 ro.boot.product.vendor.sku的值,按照这个值去读取对应的目录
if (!vendorSkuProperty.isEmpty()) {
String vendorSkuDir = "sku_" + vendorSkuProperty;
readPermissions(Environment.buildPath(
Environment.getVendorDirectory(), "etc", "sysconfig", vendorSkuDir),
vendorPermissionFlag);
readPermissions(Environment.buildPath(
Environment.getVendorDirectory(), "etc", "permissions", vendorSkuDir),
vendorPermissionFlag);
}
// Allow ODM to customize system configs as much as Vendor, because /odm is another
// vendor partition other than /vendor.
int odmPermissionFlag = vendorPermissionFlag;
readPermissions(Environment.buildPath(
Environment.getOdmDirectory(), "etc", "sysconfig"), odmPermissionFlag);//读取odm/etc/sysconfig目录
readPermissions(Environment.buildPath(
Environment.getOdmDirectory(), "etc", "permissions"), odmPermissionFlag);//读取odm/etc/permissions目录
String skuProperty = SystemProperties.get(SKU_PROPERTY, "");//odm/etc/vintf/manifest_SKU.xml里如果定义了SKU,那么SKU就是属性 ro.boot.product.hardware.sku 的值,按照这个值去读取对应的目录
if (!skuProperty.isEmpty()) {
String skuDir = "sku_" + skuProperty;
readPermissions(Environment.buildPath(
Environment.getOdmDirectory(), "etc", "sysconfig", skuDir), odmPermissionFlag);
readPermissions(Environment.buildPath(
Environment.getOdmDirectory(), "etc", "permissions", skuDir),
odmPermissionFlag);
}
// Allow OEM to customize these
int oemPermissionFlag = ALLOW_FEATURES | ALLOW_OEM_PERMISSIONS | ALLOW_ASSOCIATIONS;
readPermissions(Environment.buildPath(
Environment.getOemDirectory(), "etc", "sysconfig"), oemPermissionFlag);//读取oem/etc/sysconfig目录
readPermissions(Environment.buildPath(
Environment.getOemDirectory(), "etc", "permissions"), oemPermissionFlag);//读取oem/etc/permissions目录
// Allow Product to customize all system configs
readPermissions(Environment.buildPath(
Environment.getProductDirectory(), "etc", "sysconfig"), ALLOW_ALL);//读取product/etc/sysconfig目录
readPermissions(Environment.buildPath(
Environment.getProductDirectory(), "etc", "permissions"), ALLOW_ALL);//读取product/etc/permissions目录
// Allow /system_ext to customize all system configs
readPermissions(Environment.buildPath(
Environment.getSystemExtDirectory(), "etc", "sysconfig"), ALLOW_ALL);//读取system_ext/etc/sysconfig目录
readPermissions(Environment.buildPath(
Environment.getSystemExtDirectory(), "etc", "permissions"), ALLOW_ALL);//读取system_ext/etc/permissions目录
// Skip loading configuration from apex if it is not a system process.
if (!isSystemProcess()) {//必须在system进程里
return;
}
// Read configuration of libs from apex module.
// TODO: Use a solid way to filter apex module folders?
for (File f: FileUtils.listFilesOrEmpty(Environment.getApexDirectory())) {
if (f.isFile() || f.getPath().contains("@")) {//过滤文件和包含@的路径文件
continue;
}
readPermissions(Environment.buildPath(f, "etc", "permissions"), ALLOW_LIBS);//读取apex/etc/permissions目录
}
}
可以看出readAllPermissions()方法主要是读取各个目录下etc/permissions和etc/sysconfig目录下的文件,permissionFlag参数表示xml文件内允许被解析的tag类型。
public 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;//表示platform.xml文件
for (File f : libraryDir.listFiles()) {//遍历目录下的文件
if (!f.isFile()) {//过滤不是文件的内容
continue;
}
// We'll read platform.xml last
if (f.getPath().endsWith("etc/permissions/platform.xml")) {//platform.xml最后读取,先跳过
platformFile = f;
continue;
}
if (!f.getPath().endsWith(".xml")) {//只解析.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);//开始解析xml文件
}
// Read platform permissions last so it will take precedence
if (platformFile != null) {
readPermissionsFromXml(platformFile, permissionFlag);//读取platform.xml文件
}
}
这个方法主要是对目录的权限进行检查,然后遍历目录下的文件,其核心方法还是调用readPermissionsFromXml()方法读取xml类型文件里面的各个节点,例如:premission、features、library等,然后将解析的结果分别放到SystemConfig对应的数据结构里。platform.xml文件放到最后读取。
private void readPermissionsFromXml(File permFile, int permissionFlag) {
FileReader permReader = null;
try {
permReader = new FileReader(permFile);//根据路径创建FileReader实例,用于读取文件
} catch (FileNotFoundException e) {
Slog.w(TAG, "Couldn't find or open permissions file " + permFile);
return;
}
Slog.i(TAG, "Reading permissions from " + permFile);
final boolean lowRam = ActivityManager.isLowRamDeviceStatic();//是否是低内存设备
try {
XmlPullParser parser = Xml.newPullParser();//用于解析xml类型文件
parser.setInput(permReader);
int type;
while ((type=parser.next()) != parser.START_TAG
&& type != parser.END_DOCUMENT) {//以文件的start和end为解析范围
;
}
if (type != parser.START_TAG) {
throw new XmlPullParserException("No start tag found");
}
if (!parser.getName().equals("permissions") && !parser.getName().equals("config")) {//只解析permissions和config类型的内容
throw new XmlPullParserException("Unexpected start tag in " + permFile
+ ": found " + parser.getName() + ", expected 'permissions' or 'config'");
}
final boolean allowAll = permissionFlag == ALLOW_ALL;//是否允许解析所有类型节点,下面会用到,下同。
final boolean allowLibs = (permissionFlag & ALLOW_LIBS) != 0;//是否允许解析library类型节点
final boolean allowFeatures = (permissionFlag & ALLOW_FEATURES) != 0;//是否允许解析feature类型节点
final boolean allowPermissions = (permissionFlag & ALLOW_PERMISSIONS) != 0;//是否允许解析permission类型节点
......
while (true) {//开始解析
XmlUtils.nextElement(parser);
if (parser.getEventType() == XmlPullParser.END_DOCUMENT) {
break;
}
String name = parser.getName();//获取节点名称
if (name == null) {
XmlUtils.skipCurrentTag(parser);
continue;
}
switch (name) {
case "group": {//解析xml文件中节点为group类型的内容,下同。
if (allowAll) {//是否允许解析所有类型节点
String gidStr = parser.getAttributeValue(null, "gid");
if (gidStr != null) {
int gid = android.os.Process.getGidForName(gidStr);
mGlobalGids = appendInt(mGlobalGids, gid);
} else {
Slog.w(TAG, "<" + name + "> without gid in " + permFile + " at "
+ parser.getPositionDescription());
}
} else {
logNotAllowedInPartition(name, permFile, parser);
}
XmlUtils.skipCurrentTag(parser);
} break;
case "permission": {
if (allowPermissions) {
String perm = parser.getAttributeValue(null, "name");
if (perm == null) {
Slog.w(TAG, "<" + name + "> without name in " + permFile + " at "
+ parser.getPositionDescription());
XmlUtils.skipCurrentTag(parser);
break;
}
perm = perm.intern();
readPermission(parser, perm);
} else {
logNotAllowedInPartition(name, permFile, parser);
XmlUtils.skipCurrentTag(parser);
}
} break;
......
default: {
Slog.w(TAG, "Tag " + name + " is unknown in "
+ permFile + " at " + parser.getPositionDescription());
XmlUtils.skipCurrentTag(parser);
} break;
}
}
} catch (XmlPullParserException e) {
Slog.w(TAG, "Got exception parsing permissions.", e);
} catch (IOException e) {
Slog.w(TAG, "Got exception parsing permissions.", e);
} finally {
IoUtils.closeQuietly(permReader);
}
// Some devices can be field-converted to FBE, so offer to splice in
// those features if not already defined by the static config
if (StorageManager.isFileEncryptedNativeOnly()) {
addFeature(PackageManager.FEATURE_FILE_BASED_ENCRYPTION, 0);//可以添加一些额外的feature
addFeature(PackageManager.FEATURE_SECURELY_REMOVES_USERS, 0);
}
......
}