Android 开机权限白名单默认授予系统app权限

之前不明白为什么权限白名单不生效,现在通过分析系统加载流程,得到了答案

以前在android 8.1的时候,直接在privapp-permissions-mediatek.xml里添加对应app想要的运行时权限就可以了,但是在另外的项目里发现即使写了权限白名单也没用。
device/mediatek/common/device.mk里看到

PRODUCT_COPY_FILES += $(call add-to-product-copy-files-if-exists,vendor/mediatek/proprietary/frameworks/base/data/etc/privapp-permissions-mediatek.xml:system/etc/permissions/privapp-permissions-mediatek.xml)
PRODUCT_COPY_FILES += $(call add-to-product-copy-files-if-exists,vendor/mediatek/proprietary/frameworks/base/data/etc/system-ext-permissions-mediatek.xml:$(TARGET_COPY_OUT_SYSTEM_EXT)/etc/permissions/system-ext-permissions-mediatek.xml)
PRODUCT_COPY_FILES += $(call add-to-product-copy-files-if-exists,vendor/mediatek/proprietary/frameworks/base/data/etc/product-permissions-mediatek.xml:$(TARGET_COPY_OUT_PRODUCT)/etc/permissions/product-permissions-mediatek.xml)

privapp-permissions-mediatek.xml
system-ext-permissions-mediatek.xml
product-permissions-mediatek.xml
这三个文件都被内置到etc目录下
然后他们的内容也都是写的权限白名单,而且有相同的包名,也就是说有重复或者覆盖的可能。
分析系统流程发现

PermissionManagerService.java

SystemConfig systemConfig = SystemConfig.getInstance();

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

SystemConfig() {
    try {
        readAllPermissions();
    } finally {
        log.traceEnd();
    }
}

private void readAllPermissions() {
     // Read configuration from system
     readPermissions(Environment.buildPath(
             Environment.getRootDirectory(), "etc", "sysconfig"), ALLOW_ALL);
     readPermissions(Environment.buildPath(
             Environment.getVendorDirectory(), "etc", "sysconfig"), vendorPermissionFlag);
     readPermissions(Environment.buildPath(
             Environment.getOdmDirectory(), "etc", "permissions"), odmPermissionFlag);
     readPermissions(Environment.buildPath(
             Environment.getProductDirectory(), "etc", "sysconfig"), ALLOW_ALL);
     readPermissions(Environment.buildPath(
             Environment.getSystemExtDirectory(), "etc", "permissions"), ALLOW_ALL);

}

会把 system vendor product odm systemext 目录下的permission xml文件全都解析出来

case "privapp-permissions": {
 if (allowPrivappPermissions) {
     // privapp permissions from system, vendor, product and system_ext
     // partitions are stored separately. This is to prevent xml files in
     // the vendor partition from granting permissions to priv apps in the
     // system partition and vice versa.
     boolean vendor = permFile.toPath().startsWith(
             Environment.getVendorDirectory().toPath() + "/")
             || permFile.toPath().startsWith(
             Environment.getOdmDirectory().toPath() + "/");
     boolean product = permFile.toPath().startsWith(
             Environment.getProductDirectory().toPath() + "/");
     boolean systemExt = permFile.toPath().startsWith(
             Environment.getSystemExtDirectory().toPath() + "/");
     if (vendor) {
         readPrivAppPermissions(parser, mVendorPrivAppPermissions,
                 mVendorPrivAppDenyPermissions);
     } else if (product) {
         readPrivAppPermissions(parser, mProductPrivAppPermissions,
                 mProductPrivAppDenyPermissions);
     } else if (systemExt) {
         readPrivAppPermissions(parser, mSystemExtPrivAppPermissions,
                 mSystemExtPrivAppDenyPermissions);
     } else {
         readPrivAppPermissions(parser, mPrivAppPermissions,
                 mPrivAppDenyPermissions);
     }
 } else {
     logNotAllowedInPartition(name, permFile, parser);
     XmlUtils.skipCurrentTag(parser);
 }
} break;

再然后根据app的属性来决定加载哪个xml文件,
如果编译的时候编译app到 systemext 目录,那么加载的就会是system-ext-permissions-mediatek.xml里面的白名单权限。
这样一来,我们如果写的不是这个文件里,就不会生效。

白名单权限授权过程

PermissionManagerService

public void onNewUserCreated(int userId)

            
private void updateAllPermissions(@Nullable String volumeUuid, boolean sdkUpdated,
            @NonNull PermissionCallback callback)
private void updatePermissions(final @Nullable String changingPkgName,
  final @Nullable AndroidPackage changingPkg,
  final @Nullable String replaceVolumeUuid,
  @UpdatePermissionFlags int flags,
  final @Nullable PermissionCallback callback)
private void restorePermissionState(@NonNull AndroidPackage pkg, boolean replace,
        @Nullable String packageOfInterest, @Nullable PermissionCallback callback)
        {
        ...
	if (bp.isSignature()) {
       // For all apps signature permissions are install time ones.
        allowedSig = grantSignaturePermission(perm, pkg, ps, bp, origPermissions);
        if (allowedSig) {
            grant = GRANT_INSTALL;
        }
    }
    ...
}

起决定作用的就是这里是否能找到白名单权限hasPrivappWhitelistEntry

private boolean hasPrivappWhitelistEntry(String perm, AndroidPackage pkg) {
ArraySet<String> wlPermissions;
 if (pkg.isVendor()) {
     wlPermissions =SystemConfig.getInstance().getVendorPrivAppPermissions(pkg.getPackageName());
 } else if (pkg.isProduct()) {
     wlPermissions=SystemConfig.getInstance().getProductPrivAppPermissions(pkg.getPackageName());
 } else if (pkg.isSystemExt()) {
     wlPermissions =SystemConfig.getInstance().getSystemExtPrivAppPermissions(
                     pkg.getPackageName());
 } else {
     wlPermissions = SystemConfig.getInstance().getPrivAppPermissions(pkg.getPackageName());
 }

 return wlPermissions != null && wlPermissions.contains(perm);
}

SystemConfig.getInstance().getPrivAppPermissions获取的权限名单列表,就是开机加载的白名单列表。

总结:

权限白名单可以使系统app开机即可获取运行时权限,因为在开机过程中会去检测权限是否有白名单,而对应的白名单会根据app编译的路径而做不同的更改。
例如:Launcher的makefile里添加了LOCAL_SYSTEM_EXT_MODULE := true,所以编译的结果会是Launcher被编译到了system\system_ext路径下,而对应的白名单权限,就会去加载system-ext-permissions-mediatek.xml这个文件里的列表。

### Kotlin 实现应用程序自启动及跳转至自启动管理页面 为了使应用程序能够在设备重启后自动启动,在 Android 中通常有两种方式来实现这一功能: #### 方式一:通过广播接收器监听系统启动完成事件 当手机开机完成后会发送 `BOOT_COMPLETED` 广播消息,因此可以在应用中注册一个广播接收者用于监听该广播,并在接收到此广播时启动相应的 Activity 或服务。 ```xml <receiver android:name=".BootReceiver"> <intent-filter> <action android:name="android.intent.action.BOOT_COMPLETED"/> </intent-filter> </receiver> ``` 接着定义对应的 BootReceiver 类处理逻辑[^1]: ```kotlin class BootReceiver : BroadcastReceiver() { override fun onReceive(context: Context?, intent: Intent?) { if ("android.intent.action.BOOT_COMPLETED" == intent?.action){ val startIntent = Intent(context, MainActivity::class.java) context?.startActivity(startIntent.apply{ flags = Intent.FLAG_ACTIVITY_NEW_TASK }) } } } ``` 需要注意的是从 Android 8.0 开始引入了后台执行限制政策,这使得直接启动 activity 变得更加困难。对于这种情况可以考虑创建前台服务作为中介间接激活目标组件[^2]。 #### 方式二:引导用户前往权限设置界面开启自启授权 由于不同厂商定制 ROM 对于 App 的管控策略有所差异,部分机型可能不会默认授予新安装的应用程序自启动权限。此时可以通过提供按钮让用户自行打开系统的相应配置项来进行调整。 以下是获取某些品牌(如小米、华为等)自带安全中心内的白名单列表路径的方法之一: ```kotlin fun gotoAutoStartSetting(activity: Activity): Boolean { try { when (Build.MANUFACTURER.toLowerCase()) { "xiaomi" -> { // 小米 val intent = Intent("miui.intent.action.APP_PERM_EDITOR") .setClassName( "com.miui.securitycenter", "com.miui.permcenter.autostart.AutoStartManagementActivity" ) activity.startActivity(intent) return true } "huawei" -> { // 华为 val intent = Intent() .setComponent(ComponentName( "com.huawei.systemmanager", "com.huawei.systemmanager.optimize.process.ProtectActivity")) activity.startActivity(intent) return true } // 添加其他品牌的判断... else -> {} } } catch (e: Exception) {} Toast.makeText(activity,"当前设备暂无特殊权限设置",Toast.LENGTH_SHORT).show() return false } ``` 以上代码片段展示了针对特定制造商提供的 API 访问其特有的自启动管理界面的方式。不过鉴于各版本之间可能存在变动以及隐私保护等因素的影响,建议开发者们关注官方文档更新并测试兼容性[^3]。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值