Skip to content

默认权限策略

追踪 Android 17 默认权限授予的系统组件、默认 handler、allowlist 和批量提交路径。

基于android-17.0.0_r1
AndroidDefaultPermissionGrantPolicy默认权限PermissionManager源码阅读

默认权限策略 ​

本文承接 权限框架、权限类型 和 权限授予。DefaultPermissionGrantPolicy 不是普通 runtime grant 的 UI,也不是 privapp-permissions 静态白名单;它在系统启动、新用户创建和默认 handler 变化时,根据系统身份、known package、provider 和配置例外,为特定包初始化 runtime permission 状态。本文专讲 Android 17 真实 Java 策略类的选择、缓存、fixed/allowlist flags 和撤销边界。

1. 策略入口 ​

1.1 一次批处理 ​

源码文件:frameworks/base/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java

java
public void grantDefaultPermissions(int userId) {
    final DelayingPackageManagerCache pm =
            new DelayingPackageManagerCache();

    grantPermissionsToSysComponentsAndPrivApps(pm, userId);
    grantDefaultSystemHandlerPermissions(pm, userId);
    grantSignatureAppsNotificationPermissions(pm, userId);
    grantDefaultPermissionExceptions(pm, userId);

    // 最后一次性提交缓存中的 flags/grants
    pm.apply();
}

一次默认授权由四个阶段组成:系统组件/特权 app、默认 system handler、platform-signature app 的通知权限、配置例外。DelayingPackageManagerCache 把操作延迟到最后 apply(),避免每个权限都独立触发持久化和监听。

1.2 user scope ​

默认权限函数接收 userId,并不隐含 USER_ALL。系统启动会为既有用户分别调用;新用户创建时只初始化新用户。角色/默认 handler 变化也按目标 user 重新计算,防止 user 0 的授权泄漏到工作 profile。

2. 包操作封装 ​

2.1 抽象操作 ​

源码文件:frameworks/base/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java

java
private interface PackageManagerWrapper {
    int getPermissionFlags(String permission,
            PackageInfo pkg, UserHandle user);
    void updatePermissionFlags(String permission,
            PackageInfo pkg, int flagMask,
            int flagValues, UserHandle user);
    void grantPermission(String permission,
            PackageInfo pkg, UserHandle user);
    void revokePermission(String permission,
            PackageInfo pkg, UserHandle user);
    boolean isGranted(String permission,
            PackageInfo pkg, UserHandle user);
}

策略只依赖 wrapper,不把 PackageManagerInternal 或 PermissionService 细节散落到每个默认 handler 分支。这个接口还允许测试替换包查询和 grant 行为。

2.2 延迟实现 ​

NO_PM_CACHE 直接调用 PermissionManager 内部 API;DelayingPackageManagerCache 则缓存 PackageInfo、permission flags 和待执行操作。默认入口使用延迟实现,公开的单个 handler 变更 API 可以使用 no-cache,确保角色切换后立即生效。

3. 系统组件 ​

3.1 选择包 ​

源码文件:frameworks/base/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java

java
private void grantPermissionsToSysComponentsAndPrivApps(
        DelayingPackageManagerCache pm, int userId) {
    final List<PackageInfo> packages =
            mContext.getPackageManager()
                    .getInstalledPackagesAsUser(
                            DEFAULT_PACKAGE_INFO_QUERY_FLAGS,
                            UserHandle.USER_SYSTEM);
    for (PackageInfo pkg : packages) {
        if (pkg == null) continue;
        pm.addPackageInfo(pkg.packageName, pkg);
        if (!pm.isSysComponentOrPersistentPlatformSignedPrivApp(pkg)
                || !doesPackageSupportRuntimePermissions(pkg)
                || ArrayUtils.isEmpty(pkg.requestedPermissions)) {
            continue;
        }
        grantRuntimePermissionsForSystemPackage(pm, userId, pkg);
    }
}

候选包必须是系统组件或持久 platform-signed privileged app,并且支持 runtime permissions、声明了 requested permissions。默认策略不是“给所有 priv-app 全部危险权限”。

3.2 fixed 授予 ​

java
private void grantPermissionsToSystemPackage(
        PackageManagerWrapper pm, String packageName,
        int userId, boolean systemFixed,
        Set<String>... permissionGroups) {
    if (!pm.isSystemPackage(packageName)) return;
    grantPermissionsToPackage(
            pm, pm.getSystemPackageInfo(packageName),
            userId, systemFixed,
            false, true, permissionGroups);
}

系统组件可以按 systemFixed=true 授予,使用户不能在 Settings 中撤销;默认 handler 某些权限只普通授予,让用户仍可改变。fixed 是策略选择,不由 permission protectionLevel 自动决定。

4. 默认 Handler ​

4.1 Provider 注入 ​

源码文件:frameworks/base/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java

java
private void grantDefaultSystemHandlerPermissions(
        PackageManagerWrapper pm, int userId) {
    final PackagesProvider dialerProvider;
    final PackagesProvider smsProvider;
    final PackagesProvider locationProvider;
    synchronized (mLock) {
        dialerProvider = mDialerAppPackagesProvider;
        smsProvider = mSmsAppPackagesProvider;
        locationProvider = mLocationPackagesProvider;
    }
    final String[] dialers = dialerProvider == null
            ? null : dialerProvider.getPackages(userId);
    final String[] smsApps = smsProvider == null
            ? null : smsProvider.getPackages(userId);
    final String[] locations = locationProvider == null
            ? null : locationProvider.getPackages(userId);

默认 handler 的真实包名来自 provider/role/intent resolution,而非固定字符串。provider 在 mLock 下取出,调用 getPackages(userId) 时已经脱离策略锁;返回 null 时策略会通过默认 intent handler 查询兜底。

4.2 handler 权限组 ​

java
if (dialers == null) {
    final String dialer = getDefaultSystemHandlerActivityPackage(
            pm, Intent.ACTION_DIAL, userId);
    grantDefaultPermissionsToDefaultSystemDialerApp(
            pm, dialer, userId);
} else {
    for (String dialer : dialers) {
        grantDefaultPermissionsToDefaultSystemDialerApp(
                pm, dialer, userId);
    }
}

if (smsApps == null) {
    final String sms = getDefaultSystemHandlerActivityPackageForCategory(
            pm, Intent.CATEGORY_APP_MESSAGING, userId);
    grantDefaultPermissionsToDefaultSystemSmsApp(pm, sms, userId);
}

拨号器会获得 PHONE、CONTACTS、SMS、MICROPHONE、CAMERA 等组合,短信 app 也有自己的集合。每个 helper 仍会过滤 package 是否 system、是否支持 runtime 和是否真正 requested permission。

4.3 通知权限 ​

java
private void grantSignatureAppsNotificationPermissions(
        PackageManagerWrapper pm, int userId) {
    final List<PackageInfo> packages =
            mContext.getPackageManager().getInstalledPackagesAsUser(
                    DEFAULT_PACKAGE_INFO_QUERY_FLAGS,
                    UserHandle.USER_SYSTEM);
    for (PackageInfo pkg : packages) {
        if (pkg == null
                || !pkg.applicationInfo.isSystemApp()
                || !pkg.applicationInfo.isSignedWithPlatformKey()) {
            continue;
        }
        grantRuntimePermissionsForSystemPackage(
                pm, userId, pkg, NOTIFICATION_PERMISSIONS);
    }
}

POST_NOTIFICATIONS 的默认授予使用 system app + platform key 条件,不等于所有通知权限都由 manifest 安装自动授予。最终是否被 AppOps/用户设置影响仍由通知和权限服务继续判断。

5. 权限授予实现 ​

5.1 requested 过滤 ​

java
private void grantRuntimePermissions(
        PackageManagerWrapper pm, PackageInfo pkg,
        Set<String> permissions, boolean systemFixed,
        boolean ignoreSystemPackage,
        boolean whitelistRestrictedPermissions,
        int userId) {
    if (pkg == null || ArrayUtils.isEmpty(pkg.requestedPermissions)) {
        return;
    }
    for (String permission : permissions) {
        if (!ArrayUtils.contains(
                pkg.requestedPermissions, permission)) {
            continue;
        }
        final PermissionInfo info = pm.getPermissionInfo(permission);
        if (info == null || !info.isRuntime()) {
            continue;
        }
        if (!ignoreSystemPackage && !pm.isSystemPackage(pkg.packageName)) {
            continue;
        }
        pm.grantPermission(permission, pkg,
                UserHandle.of(userId));
        pm.updatePermissionFlags(permission, pkg,
                PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT
                        | (systemFixed
                        ? PackageManager.FLAG_PERMISSION_SYSTEM_FIXED : 0),
                PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT
                        | (systemFixed
                        ? PackageManager.FLAG_PERMISSION_SYSTEM_FIXED : 0),
                UserHandle.of(userId));
    }
}

默认策略不强行授予未声明权限,也不处理 normal/signature 等非 runtime permission。whitelistRestrictedPermissions 还会把 restricted 权限加入 allowlist,单独影响 restriction flags;它和 grant 本身是两个操作。

5.2 缓存提交 ​

java
public void grantDefaultPermissions(int userId) {
    final DelayingPackageManagerCache pm =
            new DelayingPackageManagerCache();
    grantPermissionsToSysComponentsAndPrivApps(pm, userId);
    grantDefaultSystemHandlerPermissions(pm, userId);
    grantSignatureAppsNotificationPermissions(pm, userId);
    grantDefaultPermissionExceptions(pm, userId);
    pm.apply();
}

批处理保证同一个用户的默认权限变更尽量一起提交。某个包缺失、权限未声明或不支持 runtime 时,helper 跳过该项,不应因此把整个系统启动判定为失败。

6. 配置例外 ​

6.1 XML 输入 ​

默认权限例外来自设备配置目录中的 XML。每条 exception 至少包含 package、permission、fixed/allowlist 等策略属性;DefaultPermissionGrantPolicy 读取后仍会验证包存在、权限是 runtime、包是否允许获得该权限。

6.2 例外边界 ​

配置例外不是 privileged permission allowlist 的替代品。它主要影响 runtime pregrant/restricted allowlist;signature/internal 的保护仍由 PermissionService 的 protection 规则和签名判断决定。

7. 撤销与变化 ​

7.1 Handler 变化 ​

当默认拨号器、短信或 telephony data service 发生变化,策略会对旧包撤销由默认策略授予的权限,再对新包执行 grant。撤销通常只清理 GRANTED_BY_DEFAULT/system-fixed 对应来源,不能删除用户独立授予。

7.2 用户创建 ​

新用户创建时,策略以该 userId 重新解析 handlers 和 exceptions。由于 PackageUserState、runtime flags、AppOps exemption 都按用户保存,系统 user 的默认授权不会直接复制到新 profile。

8. 失败与验证 ​

8.1 包缺失 ​

默认 handler provider 返回不存在包时,策略跳过;解析不到 intent handler 也不会授予虚构包。日志和 dumpsys package 应显示最终选中的 system handler。

8.2 权限未声明 ​

即使权限组列表包含 CAMERA/PHONE,目标包未在 requested permissions 中也不会授予。验证时必须同时检查 Manifest 请求和最终 flags,不能只检查策略常量。

8.3 固定边界 ​

对拨号器等 system handler 检查 FLAG_PERMISSION_SYSTEM_FIXED;再切换默认 handler,确认旧包的默认来源被撤销但用户独立 grant 不被误删。

8.4 用户隔离 ​

创建新 user 或 work profile,比较每个用户的 handler 和默认权限 flags。若 provider 为不同用户返回不同包,授予结果也应分离。

bash
adb shell dumpsys package <package.name>
adb shell pm check-permission <permission> <package.name> --user 0
adb shell cmd role get-role-holders <role.name> --user 0

9. 源码路线 ​

  1. DefaultPermissionGrantPolicy.grantDefaultPermissions:掌握四阶段批处理。
  2. PackageManagerWrapper/DelayingPackageManagerCache:理解权限操作和提交时机。
  3. grantPermissionsToSysComponentsAndPrivApps:系统组件/priv-app 候选条件。
  4. grantDefaultSystemHandlerPermissions:provider、intent handler 和权限组。
  5. grantRuntimePermissions:requested、runtime、systemFixed 和 restricted allowlist。
  6. grantDefaultPermissionExceptions:设备配置例外。
  7. handler 变化与 user 创建入口:继续阅读撤销和 user-scoped 初始化。

DefaultPermissionGrantPolicy 是“默认身份到权限状态”的策略编排器:它先按 user 解析系统组件和 handler,再验证包声明与 runtime 类型,通过缓存批量修改 grant/fixed/allowlist flags。它不替代 PermissionService 的安全检查,也不等于静态 privileged allowlist;遇到默认权限问题时,应同时检查候选包、requested permissions、flags 来源、用户和 AppOps 状态。