本篇主要针对SystemConfig的流程进行一个梳理,SystemConfig翻译过来就是系统配置,对应于xxx/etc/目录下面的一些配置。systemserver进程在启动的时候从etc目录下读取这些配置文件,加载到系统中,供fw+app层进行调用判断对应的功能是否启用。
一、ETC系统配置加载
1、SystemServer初始化
参考https://blog.csdn.net/qq_27672101/article/details/136746558可以了解到,SystemServer进程在启动看门狗之后,就开始进行系统配置文件的解析:

参考https://blog.csdn.net/qq_27672101/article/details/150857253可以了解到,SystemServer进程通过线程池优先启动SystemConfig,然后在启动其他核心服务,为什么要优先启动呢?因为需要优先加载etc/目录下的配置文件。关键日志如下:

2、SystemConfig初始化
如上SystemServer通过线程池的方式SystemConfig::getInstance,这是一个典型的单例设计模式,这个过程直接会触发SystemConfig的构造函数调用:
java
//la.qssi16/frameworks/base/services/core/java/com/android/server/SystemConfig.java
public class SystemConfig {
static final String TAG = "SystemConfig";
static SystemConfig sInstance;
private final Injector mInjector;
// These are the built-in shared libraries that were read from the
// system configuration files. Keys are the library names; values are
// the individual entries that contain information such as filename
// and dependencies.
final ArrayMap<String, SharedLibraryEntry> mSharedLibraries = new ArrayMap<>();
// These are the features this devices supports that were read from the
// system configuration files.
final ArrayMap<String, FeatureInfo> mAvailableFeatures;
// These are the features which this device doesn't support; the OEM
// partition uses these to opt-out of features from the system image.
final ArraySet<String> mUnavailableFeatures = new ArraySet<>();
// These are the built-in uid -> permission mappings that were read from the
// system configuration files.
final SparseArray<ArraySet<String>> mSystemPermissions = new SparseArray<>();
final ArrayList<SplitPermissionInfo> mSplitPermissions = new ArrayList<>();
public static SystemConfig getInstance() {
if (!isSystemProcess()) Slog.wtf(TAG, "SystemConfig is being accessed by a process other than " + "system_server.");
synchronized (SystemConfig.class) {
#步骤一:单例模式实例化SystemConfig
if (sInstance == null) sInstance = new SystemConfig();
return sInstance;
}
}
SystemConfig() {
mInjector = new Injector();
#步骤二:mAvailableFeatures存储了系统配置了的FEATURES
mAvailableFeatures = mInjector.getReadOnlySystemEnabledFeatures();
TimingsTraceLog log = new TimingsTraceLog(TAG, Trace.TRACE_TAG_SYSTEM_SERVER);
log.traceBegin("readAllPermissions");
try {
//步骤三:读取解析所有etc目录下的配置文件
readAllPermissions();
//步骤四:读取解析公共库列表
readPublicNativeLibrariesList();
} finally {
log.traceEnd();
}
}
}
如上最核心的流程还是如下两个步骤:
- readAllPermissions:读取加载etc/sysconfig和etc/permissions所有配置
- readPublicNativeLibrariesList:读取加载public.libraries.txt配置的公共库
3、readPublicNativeLibrariesList
readPublicNativeLibrariesList加载公共库相对来说比较简单,这里先理一下它的流程:

如上函数总结如下:
- 先读取/vendor/etc/public.libraries.txt文件内容,并加载库名字到mSharedLibraries
- 再依次遍历/system/etc和/system_ext/etc和/product/etc/目录
- 找到类似public.libraries-?.txt文件,读取并加载库名字到mSharedLibraries
1)public.libraries-xxx.txt长什么样子?
我手上这台机器是高通平台A16的系统,cat出来内容如下:
- /vendor/etc/public.libraries.txt
SH4-2:/vendor/etc $ cat public.libraries.txt
- /system/etc/public.libraries.txt
SH4-2:/system/etc $ cat public.libraries.txt
See https://android.googlesource.com/platform/ndk/+/main/docs/PlatformApis.md
libbinder_ndk.so
libclang_rt.hwasan-aarch64-android.so 64 nopreload
libGLESv1_CM.so
libneuralnetworks.so nopreload
libwebviewchromium_plat_support.so
libz.so
SH4-2:/system/etc $ cat public.libraries-qti.txtlibbinauralrenderer_wrapper.qti.so
libhoaeffects.qti.so
SH4-2:/system_ext/etc $ cat public.libraries-qti.txtlibdiag_system.qti.so
libqesdk_ndk_platform.qti.so
2)mSharedLibraries.put有什么意义?
建立一个受控的、安全的"系统原生 API 开放接口",让第三方应用可以在不破坏系统安全的前提下,使用 Android 官方支持的底层能力(图形、音频、相机、AI 等)。
这既是 兼容性保障(所有设备都提供相同的公共库集合),也是 安全边界(禁止随意调用内部实现)。
主要如下几个使用场景:
- 安装时验证
<uses-native-library>声明

- 运行时允许
System.loadLibrary("xxx")成功加载

- 构建应用的 native library search path

- 支持多 ABI 和架构隔离

4、readAllPermissions
readAllPermissions的逻辑也比较简单,读取xml并根据xml语法加载相关配置,但是这里的配置就非常的多,如下代码

1)加载所有XML配置文件
java
public class SystemConfig {
static final String TAG = "SystemConfig";
// property for runtime configuration differentiation
private static final String SKU_PROPERTY = "ro.boot.product.hardware.sku";
// property for runtime configuration differentiation in vendor
private static final String VENDOR_SKU_PROPERTY = "ro.boot.product.vendor.sku";
// property for runtime configuration differentation in product
private static final String PRODUCT_SKU_PROPERTY = "ro.boot.hardware.sku";
// property for runtime configuration differentiation based on baseband type
private static final String NO_RIL_PROPERTY = "ro.radio.noril";
// 由SystemServer.java开启线程池调用此方法读取系统配置,主要是etc/sysconfig和etc/permissions目录下的xml文件
private void readAllPermissionsFromXml() {
final XmlPullParser parser = Xml.newPullParser();
// Read configuration from system
readPermissions(parser, Environment.buildPath( Environment.getRootDirectory(), "etc", "sysconfig"), ALLOW_ALL);
// Read configuration from the old permissions dir
readPermissions(parser, Environment.buildPath( Environment.getRootDirectory(), "etc", "permissions"), ALLOW_ALL);
// Vendors are only allowed to customize these
int vendorPermissionFlag = ALLOW_LIBS | ALLOW_FEATURES | ALLOW_PRIVAPP_PERMISSIONS | ALLOW_SIGNATURE_PERMISSIONS | ALLOW_ASSOCIATIONS | ALLOW_VENDOR_APEX;
if (Build.VERSION.DEVICE_INITIAL_SDK_INT <= Build.VERSION_CODES.O_MR1) {
// For backward compatibility
vendorPermissionFlag |= (ALLOW_PERMISSIONS | ALLOW_APP_CONFIGS);
}
//核心流程1:读取vendor分区相关配置,例如vendor/etc/sysconfig目录和vendor/etc/permissions目录
readPermissions(parser, Environment.buildPath( Environment.getVendorDirectory(), "etc", "sysconfig"), vendorPermissionFlag);
readPermissions(parser, Environment.buildPath( Environment.getVendorDirectory(), "etc", "permissions"), vendorPermissionFlag);
//核心流程2:读取vendor分区SKU相关配置,如果ro.boot.product.vendor.sku属性值是cell,那么读取的是vendor/etc/sku_cell/sysconfig目录
String vendorSkuProperty = SystemProperties.get(VENDOR_SKU_PROPERTY, "");
if (!vendorSkuProperty.isEmpty()) {
String vendorSkuDir = "sku_" + vendorSkuProperty;
readPermissions(parser, Environment.buildPath( Environment.getVendorDirectory(), "etc", "sysconfig", vendorSkuDir), vendorPermissionFlag);
readPermissions(parser, Environment.buildPath( Environment.getVendorDirectory(), "etc", "permissions", vendorSkuDir), vendorPermissionFlag);
}
//核心流程3:读取vendor分区noRil相关配置,如果ro.radio.noril属性值是yes,表示当前设备不支持通信功能,那么读取的是vendor/etc/noRil/sysconfig目录
boolean noRilSupport = SystemProperties.getBoolean(NO_RIL_PROPERTY, false);
if (noRilSupport) {
String noRilDir = "noRil";
readPermissions(parser, Environment.buildPath( Environment.getVendorDirectory(), "etc", "sysconfig", noRilDir), vendorPermissionFlag);
readPermissions(parser, Environment.buildPath( Environment.getVendorDirectory(), "etc", "permissions", noRilDir), vendorPermissionFlag);
}
//核心流程4:读取odm分区相关配置,是odm/etc/sysconfig目录和odm/etc/permissions目录
int odmPermissionFlag = vendorPermissionFlag;
readPermissions(parser, Environment.buildPath( Environment.getOdmDirectory(), "etc", "sysconfig"), odmPermissionFlag);
readPermissions(parser, Environment.buildPath( Environment.getOdmDirectory(), "etc", "permissions"), odmPermissionFlag);
//核心流程5:读取odm分区相关配置,如果ro.boot.product.hardware.sku属性值是cell,那么读取的是odm/etc/sku_cell/sysconfig目录
String skuProperty = SystemProperties.get(SKU_PROPERTY, "");
if (!skuProperty.isEmpty()) {
String skuDir = "sku_" + skuProperty;
readPermissions(parser, Environment.buildPath( Environment.getOdmDirectory(), "etc", "sysconfig", skuDir), odmPermissionFlag);
readPermissions(parser, Environment.buildPath( Environment.getOdmDirectory(), "etc", "permissions", skuDir), odmPermissionFlag);
}
//核心流程6:读取oem分区相关配置,是oem/etc/sysconfig目录和oem/etc/permissions目录
int oemPermissionFlag = ALLOW_FEATURES | ALLOW_OEM_PERMISSIONS | ALLOW_ASSOCIATIONS | ALLOW_VENDOR_APEX;
readPermissions(parser, Environment.buildPath( Environment.getOemDirectory(), "etc", "sysconfig"), oemPermissionFlag);
readPermissions(parser, Environment.buildPath( Environment.getOemDirectory(), "etc", "permissions"), oemPermissionFlag);
int productPermissionFlag = ALLOW_FEATURES | ALLOW_LIBS | ALLOW_PERMISSIONS | ALLOW_APP_CONFIGS | ALLOW_PRIVAPP_PERMISSIONS | ALLOW_SIGNATURE_PERMISSIONS | ALLOW_HIDDENAPI_WHITELISTING | ALLOW_ASSOCIATIONS | ALLOW_OVERRIDE_APP_RESTRICTIONS | ALLOW_IMPLICIT_BROADCASTS | ALLOW_VENDOR_APEX;
if (Build.VERSION.DEVICE_INITIAL_SDK_INT <= Build.VERSION_CODES.R) {
productPermissionFlag = ALLOW_ALL;
}
//核心流程7:读取product分区相关配置,是product/etc/sysconfig目录和product/etc/permissions目录
readPermissions(parser, Environment.buildPath( Environment.getProductDirectory(), "etc", "sysconfig"), productPermissionFlag);
readPermissions(parser, Environment.buildPath( Environment.getProductDirectory(), "etc", "permissions"), productPermissionFlag);
//核心流程8:读取product分区SKU相关配置,如果ro.boot.product.vendor.sku属性值是cell,那么读取的是product/etc/sku_cell/sysconfig目录
String productSkuProperty = SystemProperties.get(PRODUCT_SKU_PROPERTY, "");
if (!productSkuProperty.isEmpty()) {
String productSkuDir = "sku_" + productSkuProperty;
readPermissions(parser, Environment.buildPath( Environment.getProductDirectory(), "etc", "sysconfig", productSkuDir), productPermissionFlag);
readPermissions(parser, Environment.buildPath( Environment.getProductDirectory(), "etc", "permissions", productSkuDir), productPermissionFlag);
}
// Allow /system_ext to customize all system configs
readPermissions(parser, Environment.buildPath( Environment.getSystemExtDirectory(), "etc", "sysconfig"), ALLOW_ALL);
readPermissions(parser, Environment.buildPath( Environment.getSystemExtDirectory(), "etc", "permissions"), ALLOW_ALL);
// Skip loading configuration from apex if it is not a system process.
if (!isSystemProcess()) return;
// Read configuration of features, libs and priv-app permissions from apex module.
int apexPermissionFlag = ALLOW_LIBS | ALLOW_FEATURES | ALLOW_PRIVAPP_PERMISSIONS | ALLOW_SIGNATURE_PERMISSIONS;
// 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(parser, Environment.buildPath(f, "etc", "permissions"), apexPermissionFlag);
}
}
}
如上代码流程总结如下:
- 加载根目录下的配置
文件/etc/sysconfig和/etc/permissions 加载vendor目录下的配置文件/vendor/etc/sysconfig和/vendor/etc/permissions加载vendor目录下的sku配置文件/vendor/etc/sku_xxx/sysconfig和/vendor/etc/sku_xxx/permissions加载vendor目录下的noRil配置文件/vendor/etc/noRil/sysconfig和/vendor/etc/noRil/permissions加载odm目录下的配置文件/odm/etc/sysconfig和/odm/etc/permissions加载odm目录下的sku配置文件/odm/etc/sku_xxx/sysconfig和/odm/etc/sku_xxx/permissions加载oem目录下的配置文件/oem/etc/sysconfig和/oem/etc/permissions加载product目录下的配置文件/product/etc/sysconfig和/product/etc/permissions加载product目录下的sku配置文件/product/etc/sku_xxx/sysconfig和/product/etc/sku_xxx/permissions加载system_ext目录下的配置文件/system_ext/etc/sysconfig和/system_ext/etc/permissions加载apex目录下的配置文件/apex/etc/sysconfig和/apex/etc/permissions
2)根据当前系统环境特性加载Feature
readAllPermissionsFromEnvironment函数就不再是从xml中读取,而是根据当前系统的一些特性,动态选择添加的一些功能,这些功能通常都是与AOSP有关,当然我们也可以在里面添加我们的一些定制化,其源码如下:
java
private void readAllPermissionsFromEnvironment() {
// ------------------------------------------------------------------
// 1. 文件级加密(FBE)相关特性
// ------------------------------------------------------------------
// 某些设备可在出厂后通过"现场升级"方式启用文件级加密(Field Conversion to FBE),
// 因此如果当前系统启用了 FBE,就动态添加相关特性,即使静态配置中未声明。
if (StorageManager.isFileEncrypted()) {
// 表示设备支持文件级加密(File-Based Encryption)
addFeature(PackageManager.FEATURE_FILE_BASED_ENCRYPTION, 0);
// 表示设备能安全地移除用户数据(配合 FBE 实现)
addFeature(PackageManager.FEATURE_SECURELY_REMOVES_USERS, 0);
}
// ------------------------------------------------------------------
// 2. 可插拔存储(Adoptable Storage)支持
// ------------------------------------------------------------------
// 为旧设备提供兼容性:如果设备支持 adoptable storage(即 SD 卡可格式化为内部存储),
// 但其静态配置文件未声明该特性,则在此补充。
if (StorageManager.hasAdoptable()) {
addFeature(PackageManager.FEATURE_ADOPTABLE_STORAGE, 0);
}
// ------------------------------------------------------------------
// 3. 内存等级特性(Low-RAM vs Normal-RAM)
// ------------------------------------------------------------------
// 根据设备是否被标记为"低内存设备"来声明对应的内存特性。
// 这会影响系统行为(如后台进程限制、动画关闭等)和应用适配策略。
if (ActivityManager.isLowRamDeviceStatic()) {
addFeature(PackageManager.FEATURE_RAM_LOW, 0); // 低内存设备
} else {
addFeature(PackageManager.FEATURE_RAM_NORMAL, 0); // 普通内存设备
}
// ------------------------------------------------------------------
// 4. 增量交付(Incremental Delivery)支持
// ------------------------------------------------------------------
// 如果系统支持增量 APK 安装(即只下载/安装部分模块),则添加对应特性。
// 特性值为 IncrementalManager 的版本号,用于表示支持级别。
final int incrementalVersion = IncrementalManager.getVersion();
if (incrementalVersion > 0) {
addFeature(PackageManager.FEATURE_INCREMENTAL_DELIVERY, incrementalVersion);
}
// ------------------------------------------------------------------
// 5. 应用枚举(App Enumeration)默认启用
// ------------------------------------------------------------------
// 如果系统默认启用了应用枚举限制(即应用无法随意查询其他已安装应用列表),
// 则声明该特性,供应用检测和适配。
if (PackageManager.APP_ENUMERATION_ENABLED_BY_DEFAULT) {
addFeature(PackageManager.FEATURE_APP_ENUMERATION, 0);
}
// ------------------------------------------------------------------
// 6. IPsec 隧道支持(从 Android Q 开始)
// ------------------------------------------------------------------
// 如果设备初始 SDK 版本 >= Android Q(API 29),则默认支持 IPsec 隧道功能。
// 这通常用于企业 VPN 或网络虚拟化场景。
if (Build.VERSION.DEVICE_INITIAL_SDK_INT >= Build.VERSION_CODES.Q) {
addFeature(PackageManager.FEATURE_IPSEC_TUNNELS, 0);
}
// ------------------------------------------------------------------
// 7. 启用 IPsec 隧道迁移逻辑(针对特定 Android 版本)
// ------------------------------------------------------------------
// 根据 Android 版本(如 V / S / R / U 等)决定是否启用 IPsec 隧道的迁移机制。
// 具体逻辑在 enableIpSecTunnelMigrationOnVsrUAndAbove() 中实现。
enableIpSecTunnelMigrationOnVsrUAndAbove();
// ------------------------------------------------------------------
// 8. EROFS(Enhanced Read-Only File System)支持检测
// ------------------------------------------------------------------
// EROFS 是华为贡献给 Linux 内核的高性能只读文件系统,Android 用于 system 分区。
// 根据内核版本决定声明哪个级别的 EROFS 特性:
if (isErofsSupported()) {
if (isKernelVersionAtLeast(5, 10)) {
// 内核 5.10+:完整 EROFS 支持
addFeature(PackageManager.FEATURE_EROFS, 0);
} else if (isKernelVersionAtLeast(4, 19)) {
// 内核 4.19~5.9:旧版 EROFS(legacy)
addFeature(PackageManager.FEATURE_EROFS_LEGACY, 0);
}
}
}
3)解析XML的规则
xml文件的解析规则,具体实现还是在readPermissionsFromXml函数中,该函数代码逻辑其实也比较简单,就是单纯的解析xml文件字符串,然后提取关键字,然后针对这些关键字进行分别处理,添加到对应的列表中。如下代码:


二、ETC系统配置读取
我们经常遇到如下代码调用,核心逻辑就是应用程序通过Context拿到PackageManager,然后通过其hasSystemFeature函数来判断当前系统是否支持某个FEATURE。
java
private boolean supportOMAPIReaders() {
final PackageManager pm = InstrumentationRegistry.getContext().getPackageManager();
return (pm.hasSystemFeature(PackageManager.FEATURE_SE_OMAPI_UICC)
|| pm.hasSystemFeature(PackageManager.FEATURE_SE_OMAPI_ESE)
|| pm.hasSystemFeature(PackageManager.FEATURE_SE_OMAPI_SD));
}
那么它是如何判断的呢?怎么和第一章的etc目录下的配置建立联系的呢?
1、ApplicationPackageManager
Context这里实际上使用了装饰者模式,最后获取到的getPackageManager拿到了pm对象,pm对象的实例就是ApplicationPackageManager,注意他处于客户端进程。从这里的命名可以了解到有如下几个作用:
- Application表示为应用进程对应的实例对象,可以理解为一个应用进程对应一个ApplicationContext
- PackageManager表示为应用进程作为PMS系统服务的客户端管理对象,即该应用进程可以通过此对象去和PMS系统服务进行binder通信
2、hasSystemFeature
普通应用通过hasSystemFeature方法来判断当前系统拥有的Feature(功能),然而从第一节可以知道ApplicationPackageManager是属于应用端进程的,那么它如何能知道当前系统拥有的feature呢?就必须去向PMS获取?我们具体来研究一下他是直接向PMS获取的吗?
java
//la.qssi16/frameworks/base/core/java/android/app/ApplicationPackageManager.java
public class ApplicationPackageManager extends PackageManager {
private static final String TAG = "ApplicationPackageManager";
@UnsupportedAppUsage
protected ApplicationPackageManager(ContextImpl context, IPackageManager pm) {
mContext = context;
mPM = pm;
//是否缓存系统功能?通常情况是true
mUseSystemFeaturesCache = isSystemFeaturesCacheEnabledAndAvailable();
}
@Override
public boolean hasSystemFeature(String name) {
return hasSystemFeature(name, 0);
}
@Override
public boolean hasSystemFeature(String name, int version) {
//步骤一:Build time-defined system features
Boolean maybeHasSystemFeature = RoSystemFeatures.maybeHasFeature(name, version);
if (maybeHasSystemFeature != null) {
return maybeHasSystemFeature;
}
//步骤二:SDK-defined system features
if (mUseSystemFeaturesCache) {
maybeHasSystemFeature = SystemFeaturesCache.getInstance().maybeHasFeature(name, version);
if (maybeHasSystemFeature != null) {
return maybeHasSystemFeature;
}
}
//步骤三:IPC-retrieved system features
return mHasSystemFeatureCache.query(new HasSystemFeatureQuery(name, version));
}
}
如上代码根据注释可以总结如下三个步骤:
- 从RoSystemFeatures获取对应功能:编译阶段生成的默认FEATURE配置
- 从SystemFeaturesCache查找对应功能,通过SDK feature缓存的FEATURE配置
- 从mHasSystemFeatureCache.query查找对应功能,内部使用了IPC机制向系统服务PMS进行了请求
所以重点还是第三步,mHasSystemFeatureCache如何通过IPC的方式向系统PMS服务进行请求呢?来看看mHasSystemFeatureCache是如何生成的:

通过这种方式拿到了getPackageManager客户端对象,这个客户端对象就是PackageMnager接口,前面几章SystemXXXServcie基本上就能很容易理解这种讨论,这其实就是像PMS服务进行请求,跨进程通信调用PMS的hasSystemFeature接口。详细可以参考https://blog.csdn.net/qq_27672101/article/details/140658955