SystemConfig.java is a very important class in PKMS, which is used to parse some system configuration information, and then assign the parsed results to each data structure in SystemConfig for us to query. First look at its construction method (in the construction method of PKMS, the configuration file will be parsed by calling the construction method of 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(); } }
Call the readAllPermissions() method to read the system configuration.
private void readAllPermissions() { // Read configuration from system readPermissions(Environment. buildPath( Environment.getRootDirectory(), "etc", "sysconfig"), ALLOW_ALL);//Read system/etc/sysconfig directory // Read configuration from the old permissions dir readPermissions(Environment. buildPath( Environment.getRootDirectory(), "etc", "permissions"), ALLOW_ALL);//Read system/etc/permissions directory // 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);//Read vendor/etc/sysconfig directory readPermissions(Environment. buildPath( Environment.getVendorDirectory(), "etc", "permissions"), vendorPermissionFlag);//Read vendor/etc/permissions directory String vendorSkuProperty = SystemProperties.get(VENDOR_SKU_PROPERTY, "");//vendor/etc/vintf/manifest_SKU.xml If SKU is defined, then SKU is the value of attribute ro.boot.product.vendor.sku, according to this value to read the corresponding directory 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);//Read odm/etc/sysconfig directory readPermissions(Environment. buildPath( Environment.getOdmDirectory(), "etc", "permissions"), odmPermissionFlag);//Read odm/etc/permissions directory String skuProperty = SystemProperties.get(SKU_PROPERTY, "");//odm/etc/vintf/manifest_SKU.xml If SKU is defined, then SKU is the value of attribute ro.boot.product.hardware.sku, according to this value to read the corresponding directory 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);//Read oem/etc/sysconfig directory readPermissions(Environment. buildPath( Environment.getOemDirectory(), "etc", "permissions"), oemPermissionFlag);//Read oem/etc/permissions directory // Allow Product to customize all system configs readPermissions(Environment. buildPath( Environment.getProductDirectory(), "etc", "sysconfig"), ALLOW_ALL);//Read product/etc/sysconfig directory readPermissions(Environment. buildPath( Environment.getProductDirectory(), "etc", "permissions"), ALLOW_ALL);//Read product/etc/permissions directory // Allow /system_ext to customize all system configs readPermissions(Environment. buildPath( Environment.getSystemExtDirectory(), "etc", "sysconfig"), ALLOW_ALL);//Read system_ext/etc/sysconfig directory readPermissions(Environment. buildPath( Environment.getSystemExtDirectory(), "etc", "permissions"), ALLOW_ALL);//Read system_ext/etc/permissions directory // Skip loading configuration from apex if it is not a system process. if (!isSystemProcess()) {//Must be in the system process 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("@")) {//filter files and path files containing @ continue; } readPermissions(Environment.buildPath(f, "etc", "permissions"), ALLOW_LIBS);//Read the apex/etc/permissions directory } }
It can be seen that the readAllPermissions() method mainly reads the files in the etc/permissions and etc/sysconfig directories in each directory, and the permissionFlag parameter indicates the tag type that is allowed to be parsed in the xml file.
public void readPermissions(File libraryDir, int permissionFlag) { // Read permissions from given directory. if (!libraryDir.exists() || !libraryDir.isDirectory()) {//Directory does not exist if (permissionFlag == ALLOW_ALL) {//All types are allowed to parse Slog.w(TAG, "No directory " + libraryDir + ", skipping"); } return; } if (!libraryDir.canRead()) {//When the directory is unreadable, return directly Slog.w(TAG, "Directory " + libraryDir + " cannot be read"); return; } // Iterate over the files in the directory and scan .xml files File platformFile = null;//Indicates the platform.xml file for (File f : libraryDir.listFiles()) {//traverse the files in the directory if (!f.isFile()) {//Filter content that is not a file continue; } // We'll read platform.xml last if (f.getPath().endsWith("etc/permissions/platform.xml")) {//platform.xml is read last, skip first platformFile = f; continue; } if (!f.getPath().endsWith(".xml")) {//Only parse the .xml file Slog.i(TAG, "Non-xml file " + f + " in " + libraryDir + " directory, ignoring"); continue; } if (!f.canRead()) {//The file is not allowed to be read, skip. Slog.w(TAG, "Permissions library file " + f + " cannot be read"); continue; } readPermissionsFromXml(f, permissionFlag);//Start parsing the xml file } // Read platform permissions last so it will take precedence if (platformFile != null) { readPermissionsFromXml(platformFile, permissionFlag);//Read platform.xml file } }
This method is mainly to check the permissions of the directory, and then traverse the files in the directory. The core method is to call the readPermissionsFromXml() method to read each node in the xml type file, such as: premission, features, library, etc., and then parse the The results are placed in the corresponding data structure of SystemConfig. The platform.xml file is read last.
private void readPermissionsFromXml(File permFile, int permissionFlag) { FileReader permReader = null; try { permReader = new FileReader(permFile);//Create a FileReader instance according to the path for reading files } 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();//Whether it is a low memory device try { XmlPullParser parser = Xml.newPullParser();//Used to parse xml type files parser.setInput(permReader); int type; while ((type=parser.next()) != parser.START_TAG & amp; & amp; type != parser.END_DOCUMENT) {//Using the start and end of the file as the parsing range ; } if (type != parser. START_TAG) { throw new XmlPullParserException("No start tag found"); } if (!parser.getName().equals("permissions") & amp; & amp; !parser.getName().equals("config")) {//Only parse the contents of permissions and config types throw new XmlPullParserException("Unexpected start tag in " + permFile + ": found " + parser.getName() + ", expected 'permissions' or 'config'"); } final boolean allowAll = permissionFlag == ALLOW_ALL;// Whether to allow parsing of all types of nodes, which will be used below, the same below. final boolean allowLibs = (permissionFlag & amp; ALLOW_LIBS) != 0;//Whether to allow parsing of library type nodes final boolean allowFeatures = (permissionFlag & amp; ALLOW_FEATURES) != 0;//Whether to allow parsing feature type nodes final boolean allowPermissions = (permissionFlag & amp; ALLOW_PERMISSIONS) != 0;//Whether to allow parsing permission type nodes ?… while (true) {//Start parsing XmlUtils. nextElement(parser); if (parser. getEventType() == XmlPullParser. END_DOCUMENT) { break; } String name = parser.getName();//Get node name if (name == null) { XmlUtils.skipCurrentTag(parser); continue; } switch (name) { case "group": {//Analyze the content of the group type node in the xml file, the same below. if (allowAll) {//Whether to allow parsing of all types of nodes 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);//You can add some additional features addFeature(PackageManager. FEATURE_SECURELY_REMOVES_USERS, 0); } ?… }