Android 企业版是一套 API、基础设施组件与管理模式的统称,用于让企业组织大规模管理 Android 设备。其核心是设备策略框架 ,该框架是运行在 system‑server 内部的子系统,以DevicePolicyManagerService(DPMS)为核心,将高层企业管控意图("要求 6 位 PIN 码"、"在工作资料空间禁用摄像头")转化为 Android 全栈中具体可强制执行的变更。本章沿着 AOSP 真实源码梳理每一条关键执行路径:从声明管理组件的 XML 元数据,到两万五千行的 DPMS 实现,再到策略引擎解析层,最终抵达各个子系统执行器,使每一条策略真正落地生效。
61.1 企业版架构
61.1.1 问题场景
企业移动管理(EMM)必须平衡两组相互矛盾的诉求:
- 企业管控:组织需要强制执行安全策略、部署应用、推送配置、设备遗失时擦除数据、审计设备行为。
- 用户隐私:员工不希望雇主查看个人照片、读取私人消息、非工作时段追踪位置。
Android 企业版通过用户空间隔离(工作资料空间)、权限等级划分(设备所有者与资料所有者)、细粒度策略 API(现代 AOSP 中超过 250 项可独立管控的策略)共同化解上述矛盾。
61.1.2 管理模式
Android 定义了四种主要管理模式,每种模式在 IT 管控权限与用户自由度之间做出不同取舍。
| 管理模式 | 设备所有者 | 资料所有者 | 典型场景 |
|---|---|---|---|
| 完全托管模式 | IT 组织 | 无 | 企业配发设备 |
| 工作资料空间(BYOD 自带设备办公) | 员工 | IT 组织 | 员工个人设备 |
| COPE 企业所有、允许个人使用 | IT 组织 | IT 组织 | 企业设备,允许个人使用 |
| 传统设备管理器 | 员工 | 无 | 兼容 Android5.0 之前版本 |

61.1.3 设备所有者(DO)
设备所有者是拥有整台设备完整管理权限的设备策略客户端(DPC)应用。在设备初始化设置向导阶段完成配置(开发调试可通过 adb 完成)。 源码中设备所有者信息由以下类维护:
java
// frameworks/base/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
class Owners {
@GuardedBy("mData")
private final OwnersData mData;
// mData.mDeviceOwner 保存设备所有者的OwnerInfo
// mData.mDeviceOwnerUserId 标记设备所有者运行所在的用户id
}
关键特性:
- 单例:一台设备只允许存在一个设备所有者。
- 配置部署:设备开箱初始化(OOBE)阶段,可通过 NFC 碰传、二维码、零接触注册、
adb shell dpm set‑device‑owner完成设置。 - 管控范围:可设置全局策略(Wi‑Fi、时区、系统更新策略、恢复出厂保护)以及按用户维度的策略。
- 不可随意移除:一旦设置,仅可通过恢复出厂设置,或者由设备所有者自身调用
clearDeviceOwnerApp()进行移除。
DPMS 通过统计日志常量记录管理模式:
// frameworks/base/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java (约244‑250行)
import static com.android.server.devicepolicy.DevicePolicyStatsLog
.DEVICE_POLICY_MANAGEMENT_MODE__MANAGEMENT_MODE__DEVICE_OWNER;
import static com.android.server.devicepolicy.DevicePolicyStatsLog
.DEVICE_POLICY_MANAGEMENT_MODE__MANAGEMENT_MODE__COPE;
import static com.android.server.devicepolicy.DevicePolicyStatsLog
.DEVICE_POLICY_MANAGEMENT_MODE__MANAGEMENT_MODE__PROFILE_OWNER;
61.1.4 资料所有者(PO)
资料所有者 管理某一个 Android 用户(通常是托管工作资料空间)。和设备所有者不同,一台设备可以存在多个资料所有者,一个用户对应一个。 Owners类使用SparseArray存储资料所有者:
java
// Owners.java 内部 OwnersData
// mData.mProfileOwners 是 SparseArray<OwnerInfo>,以userId作为key
当Owners从磁盘加载配置时,会将所有者信息推送到多个子系统:
java
// Owners.java, load()
void load() {
synchronized (mData) {
int[] usersIds =
mUserManager.getAliveUsers().stream().mapToInt(u -> u.id).toArray();
mData.load(usersIds);
// ... 推送到 DeviceStateCache、ActivityTaskManager、PackageManager
notifyChangeLocked();
pushDeviceOwnerUidToActivityTaskManagerLocked();
pushProfileOwnerUidsToActivityTaskManagerLocked();
}
}
61.1.5 COPE(企业所有,支持个人使用)
COPE 是 Android11 引入的混合模式:设备归企业所有(存在设备所有者),同时用户拥有个人资料空间;工作资料内运行资料所有者,设备所有者可以对个人侧施加部分限制。
COPE 的属性编码在部署参数中:
java
// frameworks/base/core/java/android/app/admin/ManagedProfileProvisioningParams.java
public final class ManagedProfileProvisioningParams implements Parcelable {
private final boolean mOrganizationOwnedProvisioning;
// 该字段为true时,资料所有者获得针对个人资料的提升权限
// 例如可以挂起个人应用
}
UserManagerInternal内部的所有者类型标识区分三种场景:
// DevicePolicyManagerService.java 引用
import static com.android.server.pm.UserManagerInternal.OWNER_TYPE_DEVICE_OWNER;
import static com.android.server.pm.UserManagerInternal.OWNER_TYPE_PROFILE_OWNER;
import static com.android.server.pm.UserManagerInternal
.OWNER_TYPE_PROFILE_OWNER_OF_ORGANIZATION_OWNED_DEVICE;
61.1.6 BYOD(自带设备办公)
BYOD 模式下设备属于员工,仅创建工作资料空间,资料所有者仅管理该工作资料。IT 管理员无法管控个人侧,这是对用户隐私保护程度最高的管理模式。
61.1.7 管理模式决策流程

61.1.8 详解管理模式:策略作用域矩阵
下表展示各类 DPM API 在不同管理模式下是否可用。开发 DPC 时,理解这些作用域至关重要。
表格
| API 分类 | 设备所有者 DO | BYOD 资料所有者 PO | COPE 资料所有者 PO | 传统设备管理器 |
|---|---|---|---|---|
| 密码安全等级 | 支持 | 仅工作资料 | 工作资料 + 设备全局 | 支持 |
| 禁用摄像头 | 支持 | 仅工作资料 | 工作资料 + 设备全局 | 支持 |
| 禁用截屏 | 支持 | 仅工作资料 | 仅工作资料 | 不支持 |
| Wi‑Fi 配置 | 支持 | 不支持 | 不支持 | 不支持 |
| 系统更新策略 | 支持 | 不支持 | 不支持 | 不支持 |
| 恢复出厂 | 支持 | 仅资料擦除 | 仅资料擦除 | 支持 |
| 立即锁屏 | 支持 | 锁定工作资料 | 两者均可锁定 | 支持 |
| 安装 CA 证书 | 支持 | 仅工作资料 | 仅工作资料 | 不支持 |
| 安全日志 | 支持 | 不支持 | 支持 | 不支持 |
| 网络日志 | 支持 | 不支持 | 支持 | 不支持 |
| 挂起个人应用 | 无 | 不支持 | 支持 | 不支持 |
| 始终在线 VPN | 支持 | 仅工作资料 | 仅工作资料 | 不支持 |
| 跨资料策略 | 无 | 支持 | 支持 | 不支持 |
| 任务锁定模式 | 支持 | 支持 | 支持 | 不支持 |
| 应用限制 | 支持 | 仅工作资料 | 仅工作资料 | 不支持 |
| USB 数据信令控制 | 支持 | 不支持 | 不支持 | 不支持 |
61.1.9 Android 企业版功能演进
Android 各版本企业版能力变化:
| Android 版本 | 关键企业功能 |
|---|---|
| 5.0(Lollipop) | 工作资料空间、资料所有者、设备所有者 |
| 6.0(M) | COSU 企业专用单设备模式、始终在线 VPN |
| 7.0(Nougat) | 网络日志、安全日志、DPC 所有者转移 |
| 8.0(Oreo) | 临时用户、强制备份、配套 DPC |
| 9.0(Pie) | 合规校验、二维码部署增强 |
| 10 | COPE 企业所有托管资料模式 |
| 11 | 个人应用挂起、COPE 能力增强 |
| 12 | 合规确认、隐私仪表盘 |
| 13 | 基于角色的管理、细粒度权限 |
| 14 | 设备策略引擎、多管理员策略冲突解析 |
| 15 | 增强 MTE 内存标签扩展、审计日志、设备防盗 API |
| 16 | 内容保护策略、系统权限管理员 |
| 17 | 高级保护模式共存、多用户托管设备部署流程 |
Android16 新增三态内容保护策略setContentProtectionPolicy,以及system:权限前缀,允许受信任平台服务作为策略引擎管理员。Android17 在此基础上扩展:全新高级保护模式(AAPM)服务以系统管理员身份驱动多项设备策略(MTE、USB、安装未知来源应用),无头设备场景提供完整多用户托管设备部署流程。以上内容将在 61.8 节详细说明。
61.1.10 无头系统用户模式
现代 Android 支持无头系统用户模式,在车载、多用户设备场景尤为重要。DeviceAdminInfo定义三种无头模式:
// frameworks/base/core/java/android/app/admin/DeviceAdminInfo.java
public static final int HEADLESS_DEVICE_OWNER_MODE_UNSUPPORTED = 0;
public static final int HEADLESS_DEVICE_OWNER_MODE_AFFILIATED = 1;
public static final int HEADLESS_DEVICE_OWNER_MODE_SINGLE_USER = 2;
- 关联模式:设备所有者运行在系统用户,其余所有用户自动添加资料所有者。
- 单用户模式:设备所有者部署到第一个次级用户,禁止创建更多次级用户。
61.2 DevicePolicyManagerService
61.2.1 概述与类继承结构
DevicePolicyManagerService是 AOSP 中体量最大的系统服务之一,Android17 源码树约 24000 行代码,路径:frameworks/base/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java。 它实现IDevicePolicyManagerAIDL 接口,运行在 system‑server 进程内。

源码文件位置:
| 组件 | 文件路径 |
|---|---|
| AIDL 接口 | frameworks/base/core/java/android/app/admin/IDevicePolicyManager.aidl |
| 客户端 API | frameworks/base/core/java/android/app/admin/DevicePolicyManager.java |
| 服务实现 | frameworks/base/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java |
| 策略引擎 | frameworks/base/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java |
| 所有者信息管理 | frameworks/base/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java |
| 管理员状态 | frameworks/base/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java |
| 单用户数据 | frameworks/base/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyData.java |
61.2.2 DPMS 内部架构
梳理启动流程前,先了解 DPMS 内部组件及其依赖关系。

这套组件拆分是多年重构的结果。最初 DPMS 是单一巨型类,引擎、监控器、辅助类被逐步抽离,提升可维护性与可测试性。
61.2.3 服务注册与启动流程
SystemServer将 DPMS 注册为系统服务,启动生命周期遵循标准SystemService阶段。

进入PHASE_BOOT_COMPLETED阶段后,服务处理延迟的恢复出厂动作,并确保设备所有者所属用户已经启动:
cpp
// DevicePolicyManagerService.java, onBootPhase()
case SystemService.PHASE_BOOT_COMPLETED:
// 理论上可以更早执行,但依赖RecoverySystem,过早阶段会发生阻塞
factoryResetIfDelayedEarlier();
ensureDeviceOwnerUserStarted();
break;
61.2.4 管理员组件模型
管理员组件是继承DeviceAdminReceiver的BroadcastReceiver子类。系统通过 Manifest 清单识别该组件。
XML
<!-- DPC应用 AndroidManifest.xml 示例 -->
<receiver
android:name=".MyDeviceAdminReceiver"
android:permission="android.permission.BIND_DEVICE_ADMIN">
<meta‑data
android:name="android.app.device_admin"
android:resource="@xml/device_admin" />
<intent‑filter>
<action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
</intent‑filter>
</receiver>
引用的 XML 资源声明该管理员需要使用哪些策略能力:
XML
<!-- res/xml/device_admin.xml -->
<device‑admin xmlns:android="http://schemas.android.com/apk/res/android">
<uses‑policies>
<limit‑password />
<watch‑login />
<reset‑password />
<force‑lock />
<wipe‑data />
<encrypted‑storage />
<disable‑camera />
<disable‑keyguard‑features />
</uses‑policies>
</device‑admin>
策略标签直接对应DeviceAdminInfo内常量:
java
// frameworks/base/core/java/android/app/admin/DeviceAdminInfo.java
public static final int USES_POLICY_LIMIT_PASSWORD = 0;
public static final int USES_POLICY_WATCH_LOGIN = 1;
public static final int USES_POLICY_RESET_PASSWORD = 2;
public static final int USES_POLICY_FORCE_LOCK = 3;
public static final int USES_POLICY_WIPE_DATA = 4;
public static final int USES_POLICY_SETS_GLOBAL_PROXY = 5;
public static final int USES_POLICY_EXPIRE_PASSWORD = 6;
public static final int USES_ENCRYPTED_STORAGE = 7;
public static final int USES_POLICY_DISABLE_CAMERA = 8;
public static final int USES_POLICY_DISABLE_KEYGUARD_FEATURES = 9;
61.2.5 ActiveAdmin:单管理员状态
当管理员组件被激活(普通设备管理员、资料所有者、设备所有者),DPMS 会创建ActiveAdmin对象,保存该管理员完整的策略状态。
java
// frameworks/base/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
class ActiveAdmin {
DeviceAdminInfo info;
PasswordPolicy passwordPolicy;
boolean disableCamera;
boolean disableScreenCapture;
boolean disableCallerIdAccess;
boolean disableContactsSearch;
boolean disableBluetoothContactSharing;
int disabledKeyguardFeatures;
long maximumTimeToUnlock;
int maximumFailedPasswordsForWipe;
boolean encryptionRequested;
boolean testOnlyAdmin;
// ... 数十个其他策略字段
}
ActiveAdmin内部定义序列化标签,用于将全部策略持久化写入 XML:
java
// ActiveAdmin.java
private static final String TAG_DISABLE_KEYGUARD_FEATURES = "disable‑keyguard‑features";
private static final String TAG_DISABLE_CAMERA = "disable‑camera";
private static final String TAG_DISABLE_CALLER_ID = "disable‑caller‑id";
private static final String TAG_DISABLE_CONTACTS_SEARCH = "disable‑contacts‑search";
private static final String TAG_DISABLE_BLUETOOTH_CONTACT_SHARING =
"disable‑bt‑contacts‑sharing";
private static final String TAG_DISABLE_SCREEN_CAPTURE = "disable‑screen‑capture";
private static final String TAG_DISABLE_ACCOUNT_MANAGEMENT = "disable‑account‑management";
private static final String TAG_ENCRYPTION_REQUESTED = "encryption‑requested";
private static final String TAG_MAX_FAILED_PASSWORD_WIPE = "max‑failed‑password‑wipe";
private static final String TAG_MAX_TIME_TO_UNLOCK = "max‑time‑to‑unlock";
private static final String TAG_PASSWORD_QUALITY = "password‑quality";
private static final String TAG_MIN_PASSWORD_LENGTH = "min‑password‑length";
// ...更多标签
61.2.6 DevicePolicyData:按用户维度状态
除每个管理员自身状态,DPMS 通过DevicePolicyData维护每个用户独立数据:
java
// frameworks/base/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyData.java
class DevicePolicyData {
private static final String TAG_ACCEPTED_CA_CERTIFICATES = "accepted‑ca‑certificate";
private static final String TAG_LOCK_TASK_COMPONENTS = "lock‑task‑component";
private static final String TAG_LOCK_TASK_FEATURES = "lock‑task‑features";
private static final String TAG_STATUS_BAR = "statusbar";
private static final String TAG_APPS_SUSPENDED = "apps‑suspended";
private static final String TAG_SECONDARY_LOCK_SCREEN = "secondary‑lock‑screen";
private static final String TAG_AFFILIATION_ID = "affiliation‑id";
private static final String TAG_LAST_SECURITY_LOG_RETRIEVAL = "last‑security‑log‑retrieval";
private static final String TAG_LAST_BUG_REPORT_REQUEST = "last‑bug‑report‑request";
private static final String TAG_LAST_NETWORK_LOG_RETRIEVAL = "last‑network‑log‑retrieval";
// ...
}
按用户保存的数据包含:
- 任务锁定模式配置(允许的包名、特性开关)
- 管理员安装的 CA 证书
- 关联 ID,用于判断用户之间是否归属同一企业
- 恢复出厂标记(待执行标记、原因)
- 密码托管令牌句柄
数据持久化到每个用户系统目录下 XML 文件:
/data/system/users/<userId>/device_policies.xml
/data/system/device_owner_2.xml
61.2.7 DevicePolicyEngine:多管理员策略冲突解析
Android14 起 AOSP 引入DevicePolicyEngine,处理多个管理管理员同时设置冲突策略的场景。这对于设备所有者、资料所有者、基于角色管理员共存至关重要。

引擎把策略分为两种作用域存储:
java
// frameworks/base/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java
final class DevicePolicyEngine {
// Map<userId, Map<policyKey, policyState>>
@GuardedBy("mLock")
private final Map<Integer, Map<PolicyKey, PolicyState<?>>> mLocalPolicies;
// Map<policyKey, policyState>
@GuardedBy("mLock")
private final Map<PolicyKey, PolicyState<?>> mGlobalPolicies;
}
61.2.8 冲突解析机制
每一条策略定义都会声明解析机制,用于解决多个管理员给出冲突取值时如何合并结果。
java
// frameworks/base/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java
private static final MostRestrictive<Boolean> FALSE_MORE_RESTRICTIVE =
new MostRestrictive<>(
List.of(new BooleanPolicyValue(false), new BooleanPolicyValue(true)));
private static final MostRestrictive<Boolean> TRUE_MORE_RESTRICTIVE =
new MostRestrictive<>(
List.of(new BooleanPolicyValue(true), new BooleanPolicyValue(false)));
所有解析机制都继承抽象类ResolutionMechanism<V>。Android17 内置 7 种具体实现,其中LeastRecent、ListUnion为该版本新增。
| 解析机制 | 源码文件 | 说明 | 示例策略 |
|---|---|---|---|
| MostRestrictive<V> | MostRestrictive.java | 按预定义顺序,取限制程度最高的值 | 禁用摄像头、禁用截屏 |
| TopPriority<V> | TopPriority.java | 按管理员权限优先级列表,取优先级最高管理员的值 | 任务锁定模式、持久首选 Activity |
| MostRecent<V> | MostRecent.java | 取最近一次设置的值 | 无严格顺序的单管理员配置项 |
| LeastRecent<V> | LeastRecent.java(Android17 新增) | 取最早设置的值,先写入优先 | 先写优先类策略 |
| PackageSetUnion | PackageSetUnion.java | 合并全部管理员的包集合取并集 | 禁止用户操作的应用包 |
| ListUnion<T> | ListUnion.java(Android17 新增) | 合并全部管理员列表并集 | 允许输入法列表类策略 |
| FlagUnion | FlagUnion.java | 全部管理员整型标记做按位或运算 | 锁屏特性禁用标记 |
示例:安全日志使用TRUE_MORE_RESTRICTIVE,只要任意管理员开启安全日志,最终就保持开启状态。
java
// PolicyDefinition.java
static PolicyDefinition<Boolean> SECURITY_LOGGING = new PolicyDefinition<>(
new NoArgsPolicyKey(DevicePolicyIdentifiers.SECURITY_LOGGING_POLICY),
TRUE_MORE_RESTRICTIVE,
POLICY_FLAG_GLOBAL_ONLY_POLICY,
PolicyEnforcerCallbacks::enforceSecurityLogging,
new BooleanPolicySerializer());
61.2.9 策略标记
每条PolicyDefinition携带标记位,控制策略作用域与行为。
java
// PolicyDefinition.java
private static final int POLICY_FLAG_NONE = 0;
private static final int POLICY_FLAG_GLOBAL_ONLY_POLICY = 1;
private static final int POLICY_FLAG_LOCAL_ONLY_POLICY = 1 << 1;
private static final int POLICY_FLAG_INHERITABLE = 1 << 2;
private static final int POLICY_FLAG_NON_COEXISTABLE_POLICY = 1 << 3;
static final int POLICY_FLAG_USER_RESTRICTION_POLICY = 1 << 4;
static final int POLICY_FLAG_SKIP_ENFORCEMENT_IF_UNCHANGED = 1 << 5;
private static final int POLICY_FLAG_PACKAGE_POLICY = 1 << 6;
GLOBAL_ONLY:策略作用域为整台设备(如自动时区)LOCAL_ONLY:策略仅作用于单个用户(如权限授予)INHERITABLE:子资料空间继承父用户策略NON_COEXISTABLE_POLICY:各管理员的值独立保存,不参与合并(例如应用限制)USER_RESTRICTION_POLICY:标记该策略属于用户限制,走特殊处理逻辑SKIP_ENFORCEMENT_IF_UNCHANGED:解析结果无变化时跳过执行回调,避免多余下层调用PACKAGE_POLICY:标记策略以包名为 key,应用卸载时引擎自动清理对应策略
61.2.10 EnforcingAdmin:策略引擎内管理员身份
EnforcingAdmin类在策略引擎内部抽象管理员身份。Android17 识别四类权限主体,使用常量字符串 / 前缀标识。
java
// frameworks/base/services/devicepolicy/java/com/android/server/devicepolicy/EnforcingAdmin.java
public final class EnforcingAdmin {
public static final String ROLE_AUTHORITY_PREFIX = "role:";
public static final String SYSTEM_AUTHORITY_PREFIX = "system:";
public static final String DPC_AUTHORITY = "enterprise";
public static final String DEVICE_ADMIN_AUTHORITY = "device_admin";
private final ComponentName mComponentName;
private final AdminKey mAdminKey;
private Set<String> mAuthorities;
private final boolean mIsRoleAuthority;
}
早期DevicePolicyEngine使用<packageName, userId>定位管理员。Android16/17 重构为封闭层级AdminKey(AdminKey.Package、AdminKey.Legacy、AdminKey.System),即使包名相同,企业管理员、传统设备管理员、系统管理员之间也不会发生 key 冲突。静态工厂方法为每类权限主体生成对应身份。
java
static EnforcingAdmin createEnterpriseEnforcingAdmin(
ComponentName componentName, int userId) {
return new EnforcingAdmin(
new AdminKey.Package(userId, componentName.getPackageName()),
componentName, /* isRoleAuthority */ false,
new HashSet<>(Set.of(DPC_AUTHORITY)));
}
static EnforcingAdmin createDeviceAdminEnforcingAdmin(
ComponentName componentName, int userId) {
return new EnforcingAdmin(
new AdminKey.Legacy(userId, componentName),
componentName, /* isRoleAuthority */ false,
new HashSet<>(Set.of(DEVICE_ADMIN_AUTHORITY)));
}
static EnforcingAdmin createSystemEnforcingAdmin(String systemEntity) {
return new EnforcingAdmin(
new AdminKey.System(systemEntity),
/* componentName */ null, /* isRoleAuthority */ false,
getSystemAuthority(systemEntity));
}
第四个工厂createRoleEnforcingAdmin仅接收包名与用户 ID(不需要ComponentName),解析该应用持有的角色,生成一组role:<roleName>权限标识。 SYSTEM_AUTHORITY_PREFIX(system:)与createSystemEnforcingAdmin这套机制是重要新增能力:受信任平台服务(典型如高级保护模式 AAPM)可以和 DPC 共用同一套策略引擎设置设备策略,本身不需要是 DPC 应用。 持久化权限字符串解析为android.app.admin.Authority对象的实现在getParcelableAuthority:enterprise映射为DpcAuthority;device_admin映射为DeviceAdminAuthority;role:前缀映射为RoleAuthority;system:前缀映射为SystemAuthority。
61.2.11 策略 API 权限模型
Android13 起,大量 DPM API 不再只依赖管理员ComponentName身份,改用细粒度权限。DPMS 导入大量MANAGE_DEVICE_POLICY_*权限。
java
// DevicePolicyManagerService.java (19‑49行)
import static android.Manifest.permission.MANAGE_DEVICE_POLICY_ACCOUNT_MANAGEMENT;
import static android.Manifest.permission.MANAGE_DEVICE_POLICY_APPS_CONTROL;
import static android.Manifest.permission.MANAGE_DEVICE_POLICY_APP_RESTRICTIONS;
import static android.Manifest.permission.MANAGE_DEVICE_POLICY_CAMERA;
import static android.Manifest.permission.MANAGE_DEVICE_POLICY_CERTIFICATES;
import static android.Manifest.permission.MANAGE_DEVICE_POLICY_FACTORY_RESET;
import static android.Manifest.permission.MANAGE_DEVICE_POLICY_INPUT_METHODS;
import static android.Manifest.permission.MANAGE_DEVICE_POLICY_KEYGUARD;
import static android.Manifest.permission.MANAGE_DEVICE_POLICY_LOCK;
import static android.Manifest.permission.MANAGE_DEVICE_POLICY_LOCK_CREDENTIALS;
import static android.Manifest.permission.MANAGE_DEVICE_POLICY_LOCK_TASK;
import static android.Manifest.permission.MANAGE_DEVICE_POLICY_SCREEN_CAPTURE;
import static android.Manifest.permission.MANAGE_DEVICE_POLICY_SECURITY_LOGGING;
import static android.Manifest.permission.MANAGE_DEVICE_POLICY_WIPE_DATA;
// ...更多权限
该机制允许非 DPC 应用(例如角色持有者)管控特定策略,而不需要完整设备所有者 / 资料所有者权限。
61.2.12 权限委托:共享管理员能力
设备所有者或资料所有者可以将部分管理能力委托给其他应用,而不需要授予完整管理员身份。
java
// DevicePolicyManager.java
public static final String DELEGATION_APP_RESTRICTIONS = "delegation‑app‑restrictions";
public static final String DELEGATION_BLOCK_UNINSTALL = "delegation‑block‑uninstall";
public static final String DELEGATION_CERT_INSTALL = "delegation‑cert‑install";
public static final String DELEGATION_CERT_SELECTION = "delegation‑cert‑selection";
public static final String DELEGATION_ENABLE_SYSTEM_APP = "delegation‑enable‑system‑app";
public static final String DELEGATION_INSTALL_EXISTING_PACKAGE =
"delegation‑install‑existing‑package";
public static final String DELEGATION_KEEP_UNINSTALLED_PACKAGES =
"delegation‑keep‑uninstalled‑packages";
public static final String DELEGATION_NETWORK_LOGGING = "delegation‑network‑logging";
public static final String DELEGATION_PACKAGE_ACCESS = "delegation‑package‑access";
public static final String DELEGATION_PERMISSION_GRANT = "delegation‑permission‑grant";
public static final String DELEGATION_SECURITY_LOGGING = "delegation‑security‑logging";
被委托的应用接收DelegatedAdminReceiver回调:
java
// frameworks/base/core/java/android/service/restrictions/DelegatedAdminReceiver.java
public class DelegatedAdminReceiver extends BroadcastReceiver {
// 接收委托操作回调,例如网络日志、安全日志、证书选择
}
61.2.13 策略持久化与 XML 格式
DPMS 把全部策略状态持久化为 XML。理解 XML 格式对于调试、解析dumpsys device_policy输出非常关键。
设备所有者文件/data/system/device_owner_2.xml
XML
<?xml version='1.0' encoding='utf‑8' standalone='yes' ?>
<root>
<device‑owner
package="com.example.dpc"
name="Enterprise DPC"
component="com.example.dpc/.MyDeviceAdminReceiver"
userRestrictionsMigrated="true" />
<device‑owner‑context userId="0" />
</root>
单用户策略文件/data/system/users/<userId>/device_policies.xml
XML
<?xml version='1.0' encoding='utf‑8' standalone='yes' ?>
<policies setup‑complete="true" provisioning‑state="3"
permission‑policy="0" device‑paired="true"
new‑user‑disclaimer="not_needed">
<admin name="com.example.dpc/.MyDeviceAdminReceiver">
<policies flags="255" />
<password‑quality value="327680" />
<min‑password‑length value="6" />
<password‑history‑length value="3" />
<max‑time‑to‑unlock value="300000" />
<max‑failed‑password‑wipe value="10" />
<disable‑camera value="true" />
<disable‑keyguard‑features value="56" />
<disable‑screen‑capture value="true" />
<encryption‑requested value="true" />
</admin>
<lock‑task‑component value="com.example.kiosk" />
<lock‑task‑features value="16" />
<affiliation‑id id="enterprise‑corp‑123" />
</policies>
XML 标签说明:
| XML 标签 | 说明 |
|---|---|
| password‑quality | 密码安全等级(十六进制常量) |
| min‑password‑length | 密码最小长度 |
| max‑time‑to‑unlock | 锁屏前最大空闲时长,单位毫秒 |
| max‑failed‑password‑wipe | 密码错误 N 次执行擦除 |
| disable‑camera | 禁用摄像头布尔标记 |
| disable‑keyguard‑features | 锁屏禁用特性位掩码 |
| lock‑task‑component | 任务锁定模式允许应用包名 |
| affiliation‑id | 企业关联标识 |
61.2.14 调用方身份与权限校验
每一次 DPM API 调用都会执行严格的调用者身份校验。CallerIdentity类保存调用上下文。
java
// frameworks/base/services/devicepolicy/java/com/android/server/devicepolicy/CallerIdentity.java
// 记录:调用UID、PID、包名、用户ID
// 用于校验调用方是否是激活管理员、DO、PO,或是持有对应MANAGE_DEVICE_POLICY_*权限
典型权限校验流程:

61.2.15 线程安全与锁机制
DPMS 使用全局锁对象做同步。
java
// DevicePolicyManagerService.java
// getLockObject() 返回主同步锁对象
// 大量方法使用该锁做synchronized保证数据一致性
Owners类使用自身mData锁保护所有者数据;DevicePolicyEngine使用mLock保护策略状态。同时获取多把锁时必须小心避免死锁。
61.2.16 策略执行完整流程
管理员调用 DPM API,请求依次经过多层组件:

61.2.17 Binder 缓存
DPMS 使用IpcDataCache,对高频查询策略状态避免重复 Binder 调用。DevicePolicyCacheImpl提供进程内缓存,缓存项包括:截屏是否禁用、摄像头是否禁用、密码复杂度等。
java
// frameworks/base/services/devicepolicy/java/com/android/server/devicepolicy/
// DevicePolicyCacheImpl.java
// Caches: screen-capture-disallowed users, password quality, permission
// policy, launcher shortcut overrides, sensors-permission grant, and
// content protection policy
当所有者信息发生变更,缓存主动失效:
java
// Owners.java
private void pushToDevicePolicyManager() {
DevicePolicyManagerService.invalidateBinderCaches();
}
61.3 工作资料空间
61.3.1 概念模型
工作资料空间是 Android 的托管资料:和个人资料运行在同一台设备上,拥有完全独立:
- 应用实例(独立副本)
- 数据目录
/data/user/<profileUserId>/ - 联系人数据库
- 日历存储
- 通知栏分组
- 独立 FBE 基于文件加密密钥
在桌面 Launcher 中用户看到 "工作" 标签,工作应用图标带有公文包角标。

61.3.2 创建托管工作资料
工作资料通过DevicePolicyManagerAPI 创建,核心入口:createAndProvisionManagedProfile()
java
// DevicePolicyManager.java
// @SystemApi
public UserHandle createAndProvisionManagedProfile(
@NonNull ManagedProfileProvisioningParams provisioningParams)
throws ProvisioningException { ... }
部署参数控制资料初始化配置:
java
// ManagedProfileProvisioningParams.java
public final class ManagedProfileProvisioningParams implements Parcelable {
@NonNull private final ComponentName mProfileAdminComponentName;
@NonNull private final String mOwnerName;
@Nullable private final String mProfileName;
@Nullable private final Account mAccountToMigrate;
private final boolean mLeaveAllSystemAppsEnabled;
private final boolean mOrganizationOwnedProvisioning;
private final boolean mKeepAccountOnMigration;
@NonNull private final PersistableBundle mAdminExtras;
}
服务端 DPMS 协调整套创建流程:

DevicePolicyManagerService实现会在创建前做大量前置条件校验:
java
// DevicePolicyManagerService.java, createAndProvisionManagedProfile()
@Override
public UserHandle createAndProvisionManagedProfile(
@NonNull ManagedProfileProvisioningParams provisioningParams,
@NonNull String callerPackage) {
Objects.requireNonNull(provisioningParams, "provisioningParams is null");
Objects.requireNonNull(callerPackage, "callerPackage is null");
// ...权限校验、前置条件校验、创建资料
}
61.3.3 托管资料部署前置条件
DPMS 执行大量前置检查才允许创建托管资料,状态码可以定位失败原因。
java
// DevicePolicyManager.java
public static final int STATUS_OK = 0;
public static final int STATUS_ACCOUNTS_NOT_EMPTY = 3;
public static final int STATUS_CANNOT_ADD_MANAGED_PROFILE = 7;
public static final int STATUS_HAS_DEVICE_OWNER = 1;
public static final int STATUS_USER_HAS_PROFILE_OWNER = 2;
public static final int STATUS_USER_SETUP_COMPLETED = 4;
public static final int STATUS_MANAGED_USERS_NOT_SUPPORTED = 8;
public static final int STATUS_NOT_SYSTEM_USER = 9;
// ...更多状态码
61.3.4 跨资料 Intent 过滤器
跨资料 Intent 过滤器控制哪些 Intent 可以跨越工作‑个人边界。DPC 通过下面 API 配置。
java
// DevicePolicyManager.java
public static final int FLAG_PARENT_CAN_ACCESS_MANAGED = 0x0001;
public static final int FLAG_MANAGED_CAN_ACCESS_PARENT = 0x0002;
@RequiresPermission(value = MANAGE_DEVICE_POLICY_PROFILE_INTERACTION,
conditional = true)
public void addCrossProfileIntentFilter(
@Nullable ComponentName admin, IntentFilter filter, int flags) { ... }
当个人应用发出匹配跨资料过滤器的 Intent,系统会把请求解析到工作资料(或反向,取决于 flag)。

跨资料小组件提供者对应策略定义在PolicyDefinition.java,由ActiveAdmin读取存储。
java
// PolicyDefinition.java (引用自ActiveAdmin)
private static final String TAG_CROSS_PROFILE_WIDGET_PROVIDERS =
"cross‑profile‑widget‑providers";
61.3.5 工作模式开关
用户可以手动打开、关闭工作资料。工作资料暂停时:全部工作应用挂起,通知隐藏,工作数据不可访问。
资料状态变更系统会发出特定广播:
java
// DevicePolicyManagerService.java
import static android.content.Intent.ACTION_MANAGED_PROFILE_AVAILABLE;
import static android.content.Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE;
DPMS 跟踪资料状态;COPE 模式下,如果工作资料关闭超过设定时长,可以触发挂起个人应用。
java
// ActiveAdmin.java
private static final String TAG_SUSPEND_PERSONAL_APPS = "suspend‑personal‑apps";
private static final String TAG_PROFILE_MAXIMUM_TIME_OFF = "profile‑max‑time‑off";
private static final String TAG_PROFILE_OFF_DEADLINE = "profile‑off‑deadline";
61.3.6 COPE 模式:个人应用挂起
企业归属设备场景,当工作资料关闭超过配置的超时时间,资料所有者可以挂起个人应用。PersonalAppsSuspensionHelper负责计算哪些个人应用需要被挂起。
java
// frameworks/base/services/devicepolicy/java/com/android/server/devicepolicy/PersonalAppsSuspensionHelper.java
public final class PersonalAppsSuspensionHelper {
// 判断待挂起个人应用,以下应用排除:
// ‑输入法
// ‑无障碍服务
// ‑默认短信应用
// ‑必需系统应用
}
挂起状态常量定义在DevicePolicyManager:
java
// DevicePolicyManager.java
public static final int PERSONAL_APPS_NOT_SUSPENDED = 0;
public static final int PERSONAL_APPS_SUSPENDED_EXPLICITLY = 1;
public static final int PERSONAL_APPS_SUSPENDED_PROFILE_TIMEOUT = 2;
61.3.7 工作资料数据隔离
工作资料通过多层机制实现数据隔离。
隔离分层

各边界独立强制执行:
- 文件系统:每个用户拥有独立
/data/user/<uid>目录;FBE 模式下每个用户 CE 存储拥有独立密钥。工作资料锁定时 CE 密钥被回收,工作数据不可访问。 - ContentProvider:框架把查询路由到对应用户实例;个人应用查询联系人默认只能看到个人联系人,除非显式开启跨资料访问。
- 包可见性:默认一个资料中的应用看不到另一个资料的应用;
PackageManager基于调用用户过滤返回结果。 - 网络:工作资料可以拥有独立 VPN、代理、网络偏好;DPMS 通过
ConnectivityManager完成配置。
java
// DevicePolicyManagerService.java
import static android.net.ConnectivityManager.PROFILE_NETWORK_PREFERENCE_DEFAULT;
import static android.net.ConnectivityManager.PROFILE_NETWORK_PREFERENCE_ENTERPRISE;
import static android.net.ConnectivityManager
.PROFILE_NETWORK_PREFERENCE_ENTERPRISE_BLOCKING;
import static android.net.ConnectivityManager
.PROFILE_NETWORK_PREFERENCE_ENTERPRISE_NO_FALLBACK;
61.3.8 工作资料托管 eSIM 卡订阅
支持 eSIM 的设备,工作资料可以拥有托管通信订阅:
java
// frameworks/base/core/java/android/app/admin/ManagedSubscriptionsPolicy.java
public final class ManagedSubscriptionsPolicy implements Parcelable {
// 控制工作资料内托管eSIM订阅处理逻辑
}
61.3.9 保持资料后台运行
较新特性:用户把工作资料切到 "静默暂停" 状态,进程依然可以保持运行。
java
// DevicePolicyData.java
private static final String TAG_KEEP_PROFILES_RUNNING = "keep‑profiles‑running";
该特性用于:即使用户关闭工作开关,工作应用仍可以接收推送、同步数据。
61.3.10 工作资料电话业务
工作资料暂停时,DPMS 可以展示未接工作来电通知。 引用字符串资源包含标题、正文、开启工作资料按钮文本。
java
// DevicePolicyManagerService.java (referenced string resources)
import static android.app.admin.DevicePolicyResources.Strings.Core
.WORK_PROFILE_TELEPHONY_PAUSED_BODY;
import static android.app.admin.DevicePolicyResources.Strings.Core
.WORK_PROFILE_TELEPHONY_PAUSED_TITLE;
import static android.app.admin.DevicePolicyResources.Strings.Core
.WORK_PROFILE_TELEPHONY_PAUSED_TURN_ON_BUTTON;
61.3.11 删除工作资料
当工作资料被删除(用户操作、管理员触发、策略违规),DPMS 发送对应通知。资源字符串包含:密码多次错误删除资料、通用删除、企业设备删除、通知标题。
java
// Referenced string resources
import static android.app.admin.DevicePolicyResources.Strings.Core
.WORK_PROFILE_DELETED_FAILED_PASSWORD_ATTEMPTS_MESSAGE;
import static android.app.admin.DevicePolicyResources.Strings.Core
.WORK_PROFILE_DELETED_GENERIC_MESSAGE;
import static android.app.admin.DevicePolicyResources.Strings.Core
.WORK_PROFILE_DELETED_ORG_OWNED_MESSAGE;
import static android.app.admin.DevicePolicyResources.Strings.Core
.WORK_PROFILE_DELETED_TITLE;
61.4 设备管理员
61.4.1 DeviceAdminReceiver:管理员回调接口
DeviceAdminReceiver是所有管理员组件的基类,继承BroadcastReceiver,提供各类策略事件回调。
java
// frameworks/base/core/java/android/app/admin/DeviceAdminReceiver.java
public class DeviceAdminReceiver extends BroadcastReceiver {
// 生命周期广播
public static final String ACTION_DEVICE_ADMIN_ENABLED
= "android.app.action.DEVICE_ADMIN_ENABLED";
public static final String ACTION_DEVICE_ADMIN_DISABLE_REQUESTED
= "android.app.action.DEVICE_ADMIN_DISABLE_REQUESTED";
public static final String ACTION_DEVICE_ADMIN_DISABLED
= "android.app.action.DEVICE_ADMIN_DISABLED";
// 密码相关广播
public static final String ACTION_PASSWORD_CHANGED
= "android.app.action.ACTION_PASSWORD_CHANGED";
public static final String ACTION_PASSWORD_FAILED
= "android.app.action.ACTION_PASSWORD_FAILED";
public static final String ACTION_PASSWORD_SUCCEEDED
= "android.app.action.ACTION_PASSWORD_SUCCEEDED";
public static final String ACTION_PASSWORD_EXPIRING
= "android.app.action.ACTION_PASSWORD_EXPIRING";
}

61.4.2 管理员生命周期
管理员生命周期遵循一套固定执行顺序:

61.4.3 密码策略
密码策略是最常用管理员能力。Android 提供两套方案。
传统等级模式(已废弃,但兼容保留)
java
// DevicePolicyManager.java
public static final int PASSWORD_QUALITY_UNSPECIFIED = 0;
public static final int PASSWORD_QUALITY_BIOMETRIC_WEAK = 0x8000;
public static final int PASSWORD_QUALITY_SOMETHING = 0x10000;
public static final int PASSWORD_QUALITY_NUMERIC = 0x20000;
public static final int PASSWORD_QUALITY_NUMERIC_COMPLEX = 0x30000;
public static final int PASSWORD_QUALITY_ALPHABETIC = 0x40000;
public static final int PASSWORD_QUALITY_ALPHANUMERIC = 0x50000;
public static final int PASSWORD_QUALITY_COMPLEX = 0x60000;
现代复杂度模式(推荐)
java
// DevicePolicyManager.java
public static final int PASSWORD_COMPLEXITY_NONE = 0;
public static final int PASSWORD_COMPLEXITY_LOW = 0x10000;
public static final int PASSWORD_COMPLEXITY_MEDIUM = 0x30000;
public static final int PASSWORD_COMPLEXITY_HIGH = 0x50000;
复杂度对应要求:
| 等级 | PIN 码 | 图案 | 密码 |
|---|---|---|---|
| LOW | 4 位以上数字 | 任意 | 4 字符以上 |
| MEDIUM | 4 位以上,禁止重复 / 连续序列 | 任意 | 4 字符以上 |
| HIGH | 8 位以上,禁止重复 / 连续序列 | 不可用 | 6 字符以上,字母 + 数字 |
ActiveAdmin内部使用独立对象存储密码全部配置:
java
// ActiveAdmin.java
PasswordPolicy passwordPolicy = new PasswordPolicy();
// 字段包含:quality、length、大小写字母、数字、符号、非字母字符、历史记录长度
61.4.4 密码过期
管理员强制定期修改密码。
java
// ActiveAdmin.java
private static final String TAG_PASSWORD_EXPIRATION_DATE = "password‑expiration‑date";
private static final String TAG_PASSWORD_EXPIRATION_TIMEOUT = "password‑expiration‑timeout";
密码即将过期时,向管理员发送ACTION_PASSWORD_EXPIRING广播,管理员提示用户修改密码。
61.4.5 密码最大错误尝试次数
管理员配置密码多次输错自动擦除数据。
java
// ActiveAdmin.java
private static final String TAG_MAX_FAILED_PASSWORD_WIPE = "max‑failed‑password‑wipe";
阈值触发后:资料所有者只会擦除工作资料;设备所有者执行整机恢复出厂。
61.4.6 设备锁定
USES_POLICY_FORCE_LOCK策略允许管理员立即锁定设备,或是设置设备自动锁定前的最大空闲时长。
java
// DeviceAdminInfo.java
public static final int USES_POLICY_FORCE_LOCK = 3;
java
// ActiveAdmin.java
private static final String TAG_MAX_TIME_TO_UNLOCK = "max-time-to-unlock";
private static final String TAG_STRONG_AUTH_UNLOCK_TIMEOUT = "strong-auth-unlock-timeout";
调用lockNow()时,设备策略管理服务(DPMS)会触发强身份认证。
java
// DevicePolicyManagerService.java(引用常量)
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker
.STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW;
61.4.7 加密策略
管理员可以要求开启存储加密。
java
// DeviceAdminInfo.java
public static final int USES_ENCRYPTED_STORAGE = 7;
java
// ActiveAdmin.java
private static final String TAG_ENCRYPTION_REQUESTED = "encryption-requested";
设备策略管理服务通过DevicePolicyManager提供的常量查询加密状态。
java
// DevicePolicyManager.java
public static final int ENCRYPTION_STATUS_ACTIVE_PER_USER = 5;
// 表示基于文件的加密已激活
61.4.8 相机禁用策略
相机禁用策略为布尔型策略,支持按用户配置或者全局配置。
java
// DeviceAdminInfo.java
public static final int USES_POLICY_DISABLE_CAMERA = 8;
java
// ActiveAdmin.java
private static final String TAG_DISABLE_CAMERA = "disable-camera";
在策略引擎内部,相机禁用采用**取最严格值(TRUE_MORE_RESTRICTIVE)**的解析规则:只要任意一个管理员禁用相机,相机就保持禁用状态。

61.4.9 截屏禁用
与相机禁用类似,截屏功能可以按用户维度禁用。
java
// ActiveAdmin.java
private static final String TAG_DISABLE_SCREEN_CAPTURE = "disable-screen-capture";
61.4.10 锁屏界面功能禁用
管理员可以选择性禁用锁屏界面的各项功能。
java
// DeviceAdminInfo.java
public static final int USES_POLICY_DISABLE_KEYGUARD_FEATURES = 9;
java
// DevicePolicyManager.java(锁定任务相关特性)
public static final int LOCK_TASK_FEATURE_KEYGUARD = ...;
public static final int LOCK_TASK_FEATURE_NOTIFICATIONS = ...;
public static final int LOCK_TASK_FEATURE_OVERVIEW = ...;
public static final int LOCK_TASK_FEATURE_GLOBAL_ACTIONS = ...;
public static final int LOCK_TASK_FEATURE_HOME = ...;
KEYGUARD_DISABLED_FEATURES策略在策略引擎中有特殊处理逻辑。
java
// PolicyDefinition.java(引用)
static final PolicyDefinition KEYGUARD_DISABLED_FEATURES = ...;
61.4.11 恢复出厂设置(数据擦除)
管理员权限中最高风险的操作就是擦除设备数据。
java
// DeviceAdminInfo.java
public static final int USES_POLICY_WIPE_DATA = 4;
java
// DevicePolicyManager.java(擦除标记位)
public static final int WIPE_EXTERNAL_STORAGE = 0x0001;
public static final int WIPE_RESET_PROTECTION_DATA = 0x0002;
public static final int WIPE_EUICC = 0x0004;
public static final int WIPE_SILENTLY = 0x0008;
设备策略管理服务内部实现会委托给FactoryResetter执行。
java
// DevicePolicyManagerService.java(内部注入器类)
.build().factoryReset();
如果系统尚未完全启动,恢复出厂设置操作可以延后执行。
java
// DevicePolicyData.java
public static final int FACTORY_RESET_FLAG_ON_BOOT = 1;
public static final int FACTORY_RESET_FLAG_WIPE_EXTERNAL_STORAGE = 2;
public static final int FACTORY_RESET_FLAG_WIPE_EUICC = 4;
public static final int FACTORY_RESET_FLAG_WIPE_FACTORY_RESET_PROTECTION = 8;
61.4.12 恢复出厂设置保护(FRP)
恢复出厂设置保护用于阻止未授权的恢复出厂操作。管理员可以配置恢复出厂之后,哪些账号可以解锁设备。
java
// frameworks/base/core/java/android/app/admin/FactoryResetProtectionPolicy.java
public final class FactoryResetProtectionPolicy implements Parcelable {
// 包含允许的账号列表,以及FRP功能是否开启
}
61.4.13 账号管理
管理员可以管控哪些账号类型允许新增、删除。
java
// ActiveAdmin.java
private static final String TAG_DISABLE_ACCOUNT_MANAGEMENT = "disable-account-management";
private static final String TAG_ACCOUNT_TYPE = "account-type";
61.4.14 VPN 策略
管理员可以强制开启带锁定模式的始终在线 VPN。

开启锁定模式之后:
- 在 VPN 连接成功前,全部网络流量都会被拦截。
- VPN 一旦断开,流量会再次被拦截。
- 部分系统流量(如网络门户检测流量)可以配置豁免。
61.4.15 受控服务管控
管理员可以限制允许运行的无障碍服务与输入法。
java
// ActiveAdmin.java
private static final String TAG_PERMITTED_ACCESSIBILITY_SERVICES =
"permitted‑accessiblity‑services"; // 保留源码中原有的拼写错误
private static final String TAG_PERMITTED_IMES = "permitted‑imes";
private static final String TAG_PERMITTED_NOTIFICATION_LISTENERS =
"permitted‑notification‑listeners";
该机制保证受管理环境下,只运行经过审批的无障碍服务与键盘输入法,防止恶意输入法、无障碍服务造成数据泄露。
61.4.16 按流量计费的数据管控
管理员可以阻止指定应用使用按流量计费的网络(蜂窝移动数据)。
java
// ActiveAdmin.java
private static final String TAG_METERED_DATA_DISABLED_PACKAGES =
"metered_data_disabled_packages";
61.4.17 可信代理管理
管理员可以管控可信代理(智能解锁相关功能)。
java
// ActiveAdmin.java
private static final String TAG_MANAGE_TRUST_AGENT_FEATURES =
"manage‑trust‑agent‑features";
private static final String TAG_TRUST_AGENT_COMPONENT_OPTIONS =
"trust‑agent‑component‑options";
private static final String TAG_TRUST_AGENT_COMPONENT = "component";
61.4.18 就近投屏 / 推送策略
管理员可以管控通知、应用的就近推送功能。
java
// ActiveAdmin.java
private static final String TAG_NEARBY_NOTIFICATION_STREAMING_POLICY =
"nearby‑notification‑streaming‑policy";
private static final String TAG_NEARBY_APP_STREAMING_POLICY =
"nearby‑app‑streaming‑policy";
61.4.19 组织标识
管理员可以设置组织名称与主题颜色,用于系统界面标识。
java
// ActiveAdmin.java
private static final String TAG_ORGANIZATION_COLOR = "organization‑color";
private static final String TAG_ORGANIZATION_NAME = "organization‑name";
组织名称会显示在设置界面,以及与受管理工作资料相关的通知当中。
61.4.20 支持提示消息
管理员可以设置向用户展示的简短、详细两类支持提示消息。
java
// ActiveAdmin.java
private static final String TAG_SHORT_SUPPORT_MESSAGE = "short‑support‑message";
private static final String TAG_LONG_SUPPORT_MESSAGE = "long‑support‑message";
短消息展示在设置页面管理员条目旁;长消息展示策略相关的完整说明信息。
61.4.21 会话提示消息(多用户)
针对多用户设备(例如共享平板),管理员可以设置会话开始、结束提示消息。
java
// ActiveAdmin.java
private static final String TAG_START_USER_SESSION_MESSAGE = "start_user_session_message";
private static final String TAG_END_USER_SESSION_MESSAGE = "end_user_session_message";
61.4.22 用户限制
除了专门的策略 API 之外,设备所有者与工作资料所有者可以设置用户限制,用于限制设备各项功能。
java
// ActiveAdmin.java
private static final String TAG_USER_RESTRICTIONS = "user‑restrictions";
private static final String TAG_DEFAULT_ENABLED_USER_RESTRICTIONS =
"default‑enabled‑user‑restrictions";
private static final String TAG_RESTRICTION = "restriction";
常用用户限制:
UserManager.DISALLOW_INSTALL_APPS禁止安装应用UserManager.DISALLOW_UNINSTALL_APPS禁止卸载应用UserManager.DISALLOW_CONFIG_WIFI禁止配置 Wi‑FiUserManager.DISALLOW_SHARE_LOCATION禁止位置共享UserManager.DISALLOW_MODIFY_ACCOUNTS禁止修改账号UserManager.DISALLOW_CONFIG_BLUETOOTH禁止配置蓝牙UserManager.DISALLOW_USB_FILE_TRANSFER禁止 USB 文件传输UserManager.DISALLOW_DEBUGGING_FEATURES禁止调试功能UserManager.DISALLOW_CONFIG_VPN禁止配置 VPNUserManager.DISALLOW_FACTORY_RESET禁止恢复出厂设置UserManager.DISALLOW_REMOVE_MANAGED_PROFILE禁止删除受管理工作资料UserManager.DISALLOW_ADD_USER禁止新增用户UserManager.DISALLOW_MOUNT_PHYSICAL_MEDIA禁止挂载物理存储介质UserManager.DISALLOW_OUTGOING_CALLS禁止拨出电话UserManager.DISALLOW_SMS禁止短信UserManager.DISALLOW_CELLULAR_2G禁止 2G 蜂窝网络
策略引擎对用户限制做特殊处理:
java
// PolicyDefinition.java
private static final int POLICY_FLAG_USER_RESTRICTION_POLICY = 1 << 4;
/*
* 将该标记添加到用户限制类策略上。
* 存在专门API处理用户限制策略,依靠该标记识别这类策略。
*/
61.4.23 锁定任务模式
锁定任务模式将设备限定运行指定应用,适用于自助终端、专用设备场景。
java
// DevicePolicyManager.java
public static final int LOCK_TASK_FEATURE_BLOCK_ACTIVITY_START_IN_TASK = ...;
public static final int LOCK_TASK_FEATURE_GLOBAL_ACTIONS = ...;
public static final int LOCK_TASK_FEATURE_HOME = ...;
public static final int LOCK_TASK_FEATURE_KEYGUARD = ...;
public static final int LOCK_TASK_FEATURE_NOTIFICATIONS = ...;
public static final int LOCK_TASK_FEATURE_OVERVIEW = ...;
public static final int LOCK_TASK_FEATURE_QUICK_SETTINGS = ...;
public static final int LOCK_TASK_FEATURE_SYSTEM_INFO = ...;
该策略定义使用**最高优先级(TopPriority)**解析规则。
java
// PolicyDefinition.java
static PolicyDefinition LOCK_TASK = new PolicyDefinition<>(
new NoArgsPolicyKey(DevicePolicyIdentifiers.LOCK_TASK_POLICY),
new TopPriority<>(List.of(
EnforcingAdmin.getRoleAuthorityOf(ROLE_SYSTEM_FINANCED_DEVICE_CONTROLLER),
EnforcingAdmin.DPC_AUTHORITY)),
POLICY_FLAG_LOCAL_ONLY_POLICY,
(LockTaskPolicy value, Context context, Integer userId, PolicyKey policyKey) ->
PolicyEnforcerCallbacks.setLockTask(value, context, userId),
new LockTaskPolicySerializer());
61.5 受管理配置
61.5.1 应用限制框架
受管理配置(又称为应用限制)允许管理员向受管理应用下发键‑值形式配置。这是无需用户交互即可配置工作应用的核心机制。

61.5.2 限制项类型
配置限制以Bundle形式传递,内部存放带类型的键值对。应用在 XML 资源文件中声明自身支持的限制项。
XML
<restriction
android:key="server_url"
android:restrictionType="string"
android:title="@string/server_url_title"
android:description="@string/server_url_description"
android:defaultValue="https://mail.example.com/" />
<restriction
android:key="allow_personal_use"
android:restrictionType="bool"
android:title="@string/personal_use_title"
android:defaultValue="false" />
<restriction
android:key="max_attachment_size"
android:restrictionType="integer"
android:title="@string/max_attachment_title"
android:defaultValue="10" />
支持的限制类型:
| XML 类型 | Java 类型 |
|---|---|
| bool | boolean |
| string | String |
| integer | int |
| multi‑select | String\[\] |
| choice | String |
| bundle | Bundle(嵌套) |
| bundle_array | Parcelable\[\] |
61.5.3 应用限制权限委托
app‑restrictions能力支持权限委托。
java
// DevicePolicyManager.java
public static final String DELEGATION_APP_RESTRICTIONS = "delegation‑app‑restrictions";
EMM 代理可以将配置管理权限委托给专门的配置应用。
61.5.4 RestrictionsManager
应用通过RestrictionsManager读取受管理配置。
java
// android.content.RestrictionsManager
public Bundle getApplicationRestrictions() { ... }
public List getManifestRestrictions(String packageName) { ... }
RestrictionsReceiver让应用可以异步接收限制配置变更。
java
// frameworks/base/core/java/android/service/restrictions/RestrictionsReceiver.java
// DevicePolicyManager.java导入该类
import android.service.restrictions.RestrictionsReceiver;
61.5.5 策略引擎处理逻辑
应用限制使用NON_COEXISTABLE_POLICY标记,代表各个管理员的限制独立存储,不会做合并。
java
// PolicyDefinition.java
// POLICY_FLAG_NON_COEXISTABLE_POLICY = 1 << 3
/*
* 标记含义:各个管理员策略互相独立,不执行合并解析。
* 例如不同管理员针对同一个包设置的应用限制,不做合并,各自保存,查询时互相独立。
*/
61.5.6 受管理配置架构

61.5.7 常用场景受管理配置示例
VPN 配置:
XML
<restriction android:key="vpn_protocol" android:restrictionType="choice"
android:entries="@array/vpn_protocols"
android:entryValues="@array/vpn_protocol_values" />
邮件配置:
XML
<restriction android:key="email_server" android:restrictionType="string" />
<restriction android:key="email_port" android:restrictionType="integer" />
<restriction android:key="use_ssl" android:restrictionType="bool" />
Wi‑Fi 配置(由 DPC 完成配置):
XML
<restriction android:key="wifi_ssid" android:restrictionType="string" />
<restriction android:key="wifi_security_type" android:restrictionType="choice" />
61.6 COPE 模式与完全托管设备
61.6.1 完全托管设备配置
完全托管设备在初始化设置阶段通过provisionFullyManagedDevice()完成配置。
java
// frameworks/base/core/java/android/app/admin/FullyManagedDeviceProvisioningParams.java
public final class FullyManagedDeviceProvisioningParams implements Parcelable {
@NonNull private final ComponentName mDeviceAdminComponentName;
@NonNull private final String mOwnerName;
private final boolean mLeaveAllSystemAppsEnabled;
@Nullable private final String mTimeZone;
private final long mLocalTime;
@Nullable private final Locale mLocale;
private final boolean mDeviceOwnerCanGrantSensorsPermissions;
@NonNull private final PersistableBundle mAdminExtras;
private final boolean mDemoDevice;
}
61.6.2 设备配置入口
Android 支持多种设备配置入口:

dpm set‑device‑owner 这条 shell 命令不会走 provisionFullyManagedDevice() ;它在 DevicePolicyManagerServiceShellCommand.runSetDeviceOwner() 中的处理逻辑是:直接先后调用 setActiveAdmin() 和 setDeviceOwner()。 而 provisionFullyManagedDevice() 是系统应用 ManagedProvisioning 使用的入口函数。
设备配置相关 Intent:
java
// DevicePolicyManager.java
public static final String ACTION_PROVISION_MANAGED_DEVICE
= "android.app.action.PROVISION_MANAGED_DEVICE";
public static final String ACTION_PROVISION_MANAGED_PROFILE
= "android.app.action.PROVISION_MANAGED_PROFILE";
public static final String ACTION_PROVISION_MANAGED_USER
= "android.app.action.PROVISION_MANAGED_USER";
61.6.3 设备所有者能力
设备所有者拥有最全面管控权限。
| 分类 | 能力 |
|---|---|
| 网络 | 设置全局代理、配置 Wi‑Fi、配置 VPN、配置私有 DNS |
| 安全 | 开启安全日志、开启网络日志、生成证明密钥 |
| 应用 | 静默安装 / 卸载应用、隐藏应用、冻结应用、阻止卸载 |
| 系统 | 设置系统更新策略、重启设备、设置时间与时区 |
| 用户 | 创建 / 删除用户、切换用户、设置关联 ID |
| 硬件 | 禁用相机、禁用截屏、禁用 USB 数据 |
| 电话 | 配置 APN、管理 SIM 卡订阅 |
| 标识 | 设置组织名称、设置设备所有者锁屏信息 |
61.6.4 COPE 架构
COPE 模式:个人侧具备设备所有者权限,工作资料内具备资料所有者权限。关键标记为mOrganizationOwnedProvisioning。
java
// ManagedProfileProvisioningParams.java
private final boolean mOrganizationOwnedProvisioning;
标记开启时,工作资料所有者对个人资料获得额外管控能力:
- 工作资料长时间未使用时,可以冻结个人应用。
- 在设备级别锁屏强制密码策略。
- 管控整机网络日志。
- 读取设备硬件标识(IMEI、序列号)。

61.6.5 COPE 模式与完全托管设备对比
| 特性 | 完全托管 | COPE |
|---|---|---|
| 是否存在设备所有者 | 是 | 否(资料所有者,拥有提升权限) |
| 是否允许个人应用 | 由 IT 决定 | 是(核心设计目标) |
| IT 是否可见个人应用 | IT 可以查看 | IT 无法查看 |
| 是否存在工作资料 | 可选 | 必须存在 |
| 用户能否删除工作资料 | 不能 | 不能(组织所属模式) |
| 恢复出厂控制 | 完全控制 | 通过 FRP 保护 |
| 个人应用冻结 | 不适用 | 支持(工作长时间未使用) |
61.6.6 分期设备模式
Android 支持分期设备模式,用于分期付款设备。
java
// DevicePolicyManager.java
public static final int DEVICE_OWNER_TYPE_DEFAULT = 0;
public static final int DEVICE_OWNER_TYPE_FINANCED = 1;
分期设备控制器使用ROLE_SYSTEM_FINANCED_DEVICE_CONTROLLER角色,在策略解析中拥有高优先级。
java
// PolicyDefinition.java(锁定任务示例)
new TopPriority<>(List.of(
EnforcingAdmin.getRoleAuthorityOf(ROLE_SYSTEM_FINANCED_DEVICE_CONTROLLER),
EnforcingAdmin.DPC_AUTHORITY))
61.6.7 系统更新策略
设备所有者可以控制系统更新执行方式。
java
// Owners.java引用
import android.app.admin.SystemUpdatePolicy;
import android.app.admin.SystemUpdateInfo;
四种更新策略:
- 自动:更新可用就立即安装
- 时间窗口:在配置好的维护窗口内安装
- 延后更新:最多延后 30 天
- 冻结时段:指定日期区间完全阻止更新
java
// DevicePolicyManager.java
// FreezePeriod用于阻止更新,例如大促节假日
import android.app.admin.FreezePeriod;
61.6.8 始终在线 VPN
设备所有者、资料所有者可以强制启用始终在线 VPN。
java
// ActiveAdmin.java
private static final String TAG_ALWAYS_ON_VPN_PACKAGE = "vpn‑package";
配置始终在线 VPN 之后,VPN 未建立前全部网络流量拦截(锁定模式)。
61.7 跨资料通信
61.7.1 跨资料边界
工作‑个人资料边界是 Android 企业版最重要安全特性。默认情况下,一个资料内应用不能访问另一个资料的应用与数据。跨资料通信必须显式开启。

61.7.2 跨资料 Intent 过滤器
DPC 管控可以跨资料传递的 Intent。
java
// DevicePolicyManager.java
public void addCrossProfileIntentFilter(
@Nullable ComponentName admin,
IntentFilter filter,
int flags) { ... }
public void clearCrossProfileIntentFilters(
@Nullable ComponentName admin) { ... }
标记控制跳转方向:
java
// DevicePolicyManager.java
public static final int FLAG_PARENT_CAN_ACCESS_MANAGED = 0x0001;
// 个人应用可以解析Intent跳转至工作应用
public static final int FLAG_MANAGED_CAN_ACCESS_PARENT = 0x0002;
// 工作应用可以解析Intent跳转至个人应用
61.7.3 默认跨资料 Intent 过滤器
DPC 未配置任何规则前,系统自带默认跨资料 Intent 过滤器,保障基础功能。典型场景:
- 电话拨号:个人拨号器展示工作联系人
- Web 链接:跨资料跳转打开网页
- 设置:任意资料访问系统设置
61.7.4 CrossProfileApps API
CrossProfileApps提供高层 API 用于跨资料交互。
java
// frameworks/base/core/java/android/content/pm/CrossProfileApps.java
public class CrossProfileApps {
public static final String ACTION_CAN_INTERACT_ACROSS_PROFILES_CHANGED =
"android.content.pm.action.CAN_INTERACT_ACROSS_PROFILES_CHANGED";
// 在另一个资料启动Activity
public void startMainActivity(
ComponentName component, UserHandle targetUser) { ... }
// 获取支持跨资料交互的目标用户
public List getTargetUserProfiles() { ... }
// 判断是否允许跨资料交互
public boolean canInteractAcrossProfiles() { ... }
public boolean canRequestInteractAcrossProfiles() { ... }
}
61.7.5 应用清单声明跨资料能力
想要跨资料交互的应用,需要在 AndroidManifest 声明对应能力。
XML
<manifest>
<application android:crossProfile="true">
<!-- App can receive CAN_INTERACT_ACROSS_PROFILES_CHANGED
in manifest receivers -->
</application>
</manifest>
61.7.6 个人应用读取工作联系人
个人拨号界面展示工作联系人是最常见跨资料能力,受多条策略管控。
java
// ActiveAdmin.java
private static final String TAG_DISABLE_CALLER_ID = "disable‑caller‑id";
private static final String TAG_DISABLE_CONTACTS_SEARCH = "disable‑contacts‑search";
private static final String TAG_DISABLE_BLUETOOTH_CONTACT_SHARING =
"disable‑bt‑contacts‑sharing";
管理员可以独立管控:
- 跨资料来电号码识别(来电显示工作联系人名称)
- 跨资料联系人搜索(个人应用检索工作联系人)
- 蓝牙联系人同步(车载套件蓝牙同步工作联系人)

61.7.7 跨资料日历
管理员可以允许个人日历应用读取工作日历事件。
java
// ActiveAdmin.java
private static final String TAG_CROSS_PROFILE_CALENDAR_PACKAGES =
"cross‑profile‑calendar‑packages";
private static final String TAG_CROSS_PROFILE_CALENDAR_PACKAGES_NULL =
"cross‑profile‑calendar‑packages‑null";
61.7.8 跨资料桌面小组件
允许工作资料小组件在个人桌面显示。
java
// ActiveAdmin.java
private static final String TAG_CROSS_PROFILE_WIDGET_PROVIDERS =
"cross‑profile‑widget‑providers";
private static final String TAG_PROVIDER = "provider";
策略引擎中定义对应策略。
java
// PolicyDefinition.java(引用)
static final PolicyDefinition<...> CROSS_PROFILE_WIDGET_PROVIDER = ...;
61.7.9 跨资料应用包白名单
管理员配置允许跨资料通信的应用包集合。
java
// ActiveAdmin.java
private static final String TAG_CROSS_PROFILE_PACKAGES = "cross‑profile‑packages";
61.7.10 打通个人‑工作应用
该属性支持应用同时在两个用户配置文件之间协同工作:
XML
<!-- 应用清单文件 -->
<application android:crossProfile="true">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
当应用声明 crossProfile="true" 后,将获得多项能力:
- 可以通过清单静态注册的广播接收器接收
CAN_INTERACT_ACROSS_PROFILES_CHANGED广播(不局限于运行时动态注册)。 - 系统可弹窗提示用户,为该应用授予跨配置文件交互权限。
- 应用可调用
CrossProfileApps.canInteractAcrossProfiles()查询自身是否已拥有该权限。
61.7.11 跨资料数据共享模式
跨用户配置文件之间共享数据存在多种实现方案:

| 模式 | 管控方 | 使用场景 |
|---|---|---|
| Intent 跳转模式 | 管理员配置过滤器 | 打开链接、内容分享 |
| ContentProvider 模式 | 管理员 + 系统管控 | 联系人、日历查询 |
| 直接启动模式 | 应用 + 用户 + 管理员授权 | 在个人 / 工作应用实例间切换 |
| 剪贴板模式 | 管理员管控开关 | 跨资料复制粘贴 |
61.7.12 跨资料 ContentProvider 访问
系统提供特殊 URI 用于跨资料 ContentProvider 访问;联系人场景使用ContactsContract.Directory。
java
// DevicePolicyManager.java导入
import android.provider.ContactsContract.Directory;
带有ENTERPRISE标记的 Directory 代表可以对个人资料开放的工作联系人;系统根据管理员的来电显示、联系人搜索策略做访问控制。
61.7.13 跨资料交互完整流程

61.8 合规与安全
61.8.1 安全日志
安全日志采集设备上安全相关事件。SecurityLogMonitor管理日志缓冲区。
java
// frameworks/base/services/devicepolicy/java/com/android/server/devicepolicy/
// SecurityLogMonitor.java
class SecurityLogMonitor implements Runnable {
/*
* 该类管理安全日志访问。维护待设备所有者拉取的日志缓冲区。
* 通过JNI接口从logd读取日志,暂存直到设备所有者拉取,避免日志丢失。
* 设备所有者读取接口做访问频率限制。
* 每两小时或者缓冲区达到阈值,通知DPC读取日志。
*/
}
安全日志事件示例:
- ADB 连接断开与建立
- 应用进程启动
- 锁屏解锁、锁屏上锁
- 存储介质挂载卸载
- 系统开关机
- 密码修改、密码错误
- 证书安装
- 密钥生成事件
61.8.2 审计日志
除传统安全日志之外,Android 还支持审计日志。
java
// PolicyDefinition.java
static PolicyDefinition AUDIT_LOGGING = new PolicyDefinition<>(
new NoArgsPolicyKey(DevicePolicyIdentifiers.AUDIT_LOGGING_POLICY),
TRUE_MORE_RESTRICTIVE,
POLICY_FLAG_GLOBAL_ONLY_POLICY,
PolicyEnforcerCallbacks::enforceAuditLogging,
new BooleanPolicySerializer());
客户端DevicePolicyManager提供接口:setAuditLogEnabled(boolean)、isAuditLogEnabled(),通过setAuditLogEventCallback()注册流式回调,底层基于IAuditLogEventsCallback AIDL。
java
// frameworks/base/core/java/android/app/admin/DevicePolicyManager.java
public void setAuditLogEnabled(boolean enabled) { ... }
public boolean isAuditLogEnabled() { ... }
public void setAuditLogEventCallback(Executor executor,
Consumer<List> callback) {
// 将Consumer包装为IAuditLogEventsCallback.Stub
}
传统安全日志为批量缓冲,缓冲区满才通知管理员;审计日志事件产生就推送到回调,适合做近实时合规监控。 服务端对应接口:IDevicePolicyManager的setAuditLogEnabled(String callerPackage, boolean enabled)、isAuditLogEnabled(String callerPackage)。
61.8.3 网络日志
网络日志采集 DNS 查询、TCP 连接事件。
java
// frameworks/base/services/devicepolicy/java/com/android/server/devicepolicy/
// NetworkLogger.java
final class NetworkLogger {
private final DevicePolicyManagerService mDpm;
private final PackageManagerInternal mPm;
private final AtomicBoolean mIsLoggingEnabled = new AtomicBoolean(false);
private final int mTargetUserId;
}
NetworkLogger注册INetdEventCallback拦截网络事件。
java
// NetworkLogger.java
private final INetdEventCallback mNetdEventCallback = new BaseNetdEventCallback() {
@Override
public void onDnsEvent(int netId, int eventType, int returnCode,
String hostname, String[] ipAddresses, int ipAddressesCount,
long timestamp, int uid) {
if (!mIsLoggingEnabled.get()) return;
if (!shouldLogNetworkEvent(uid)) return;
DnsEvent dnsEvent = new DnsEvent(hostname, ipAddresses,
ipAddressesCount, mPm.getNameForUid(uid), timestamp);
sendNetworkEvent(dnsEvent);
}
@Override
public void onConnectEvent(String ipAddr, int port,
long timestamp, int uid) {
if (!mIsLoggingEnabled.get()) return;
// 过滤并组装事件,逻辑同上
}
};
NetworkLoggingHandler做事件批处理。

61.8.4 设备证明
DPC 借助硬件安全密钥向远端服务器证明设备身份。
java
// DevicePolicyManager.java
public static final int ID_TYPE_BASE_INFO = 1; // 厂商基础信息
public static final int ID_TYPE_SERIAL = 2; // 序列号
public static final int ID_TYPE_IMEI = 4; // IMEI
public static final int ID_TYPE_MEID = 8; // MEID
public static final int ID_TYPE_INDIVIDUAL_ATTESTATION = 16; // 设备唯一密钥
设备证明流程:

密钥对附带完整证书链,可校验 Google 根 CA;证书扩展包含 OS 版本、安全补丁版本、启动状态、设备硬件标识。
61.8.5 设备证明证书链结构
证明证书链拥有一套固定结构,由远端服务端完成校验:

证书扩展( OID:1.3.6.1.4.1.11129.2.1.17)包含:
| 字段 | 说明 |
|---|---|
| attestationVersion | 证明格式版本 |
| attestationSecurityLevel | TEE / StrongBox |
| keymasterVersion | KeyMaster/KeyMint 版本 |
| keymasterSecurityLevel | 执行安全环境 |
| attestationChallenge | 服务器下发随机挑战串 |
| uniqueId | 设备唯一 ID(按需开启) |
| softwareEnforced | 软件层面密钥属性 |
| teeEnforced | 硬件强制密钥属性 |
teeEnforced内服务器可校验内容:
- osVersion Android 系统版本
- osPatchLevel 安全补丁版本
- rootOfTrust 校验启动状态、公钥、设备锁状态
- attestationApplicationId 请求应用签名证书 SHA‑256
61.8.6 证书管理
DPC 可以安装 CA 根证书、客户端证书。
java
// DevicePolicyManager.java(委托权限)
public static final String DELEGATION_CERT_INSTALL = "delegation‑cert‑install";
public static final String DELEGATION_CERT_SELECTION = "delegation‑cert‑selection";
CertificateMonitor跟踪管理员安装证书。
// frameworks/base/services/devicepolicy/java/com/android/server/devicepolicy/
// CertificateMonitor.java
// 监控管理员安装的CA证书
61.8.7 密码合规检查
DPC 可以校验当前密码是否满足策略要求。
java
// DevicePolicyManager.java
// isActivePasswordSufficient() ------ 校验是否满足管理员密码策略
// getPasswordComplexity() ------ 返回当前密码复杂度等级
@RequiresPermission(REQUEST_PASSWORD_COMPLEXITY)
public static final String EXTRA_PASSWORD_COMPLEXITY =
"android.app.extra.PASSWORD_COMPLEXITY";
合规检查 Intent:
java
// DevicePolicyManager.java
public static final String ACTION_CHECK_POLICY_COMPLIANCE
= "android.app.action.CHECK_POLICY_COMPLIANCE";
61.8.8 合规确认
Android12 起,系统要求 DPC 确认设备合规状态。
// DeviceAdminReceiver.java
public static final String ACTION_COMPLIANCE_ACKNOWLEDGEMENT_REQUIRED
= "android.app.action.COMPLIANCE_ACKNOWLEDGEMENT_REQUIRED";
61.8.9 安全补丁校验
DPC 可以读取设备安全补丁版本,并强制最低补丁等级。DPMS 导入系统更新查询权限。
java
// DevicePolicyManagerService.java
import static android.Manifest.permission
.MANAGE_DEVICE_POLICY_QUERY_SYSTEM_UPDATES;
61.8.10 USB 数据信号管控
高安全环境下可以禁用 USB 数据功能。
java
// DevicePolicyManagerService.java
import static android.Manifest.permission
.MANAGE_DEVICE_POLICY_USB_DATA_SIGNALLING;
61.8.11 内存标记扩展 MTE
硬件支持的设备,DPC 可以开启 MTE 增强内存安全。
java
// DevicePolicyManagerService.java
import static android.Manifest.permission.MANAGE_DEVICE_POLICY_MTE;
// PolicyDefinition.java
import static android.app.admin.DevicePolicyIdentifiers.MEMORY_TAGGING_POLICY;
61.8.12 内容保护
DPC 使用三态策略管控内容保护。
java
// frameworks/base/core/java/android/app/admin/DevicePolicyManager.java
public static final int CONTENT_PROTECTION_NOT_CONTROLLED_BY_POLICY = 0;
public static final int CONTENT_PROTECTION_DISABLED = 1;
public static final int CONTENT_PROTECTION_ENABLED = 2;
setContentProtectionPolicy、getContentProtectionPolicy走策略引擎,对应标识DevicePolicyIdentifiers.CONTENT_PROTECTION_POLICY;客户端 API 受权限MANAGE_DEVICE_POLICY_CONTENT_PROTECTION管控。 默认值CONTENT_PROTECTION_NOT_CONTROLLED_BY_POLICY代表策略不干预系统原有设置,区分 "不表态" 与显式关闭。
61.8.13 设备被盗状态
Android 提供设备被盗状态查询 API。
java
// DevicePolicyManager.java(标记)
import static android.app.admin.flags.Flags.FLAG_DEVICE_THEFT_API_ENABLED;
// DevicePolicyManagerService.java
import static android.Manifest.permission.QUERY_DEVICE_STOLEN_STATE;
61.8.14 设备策略完整状态
DPC 可以读取设备全部策略快照。
java
// frameworks/base/core/java/android/app/admin/DevicePolicyState.java
public final class DevicePolicyState implements Parcelable {
// 设备上全部生效策略完整快照
}
61.8.15 企业专属设备 ID
为保护隐私,Android 生成企业专属稳定设备标识,避免直接暴露硬件序列号。
java
// frameworks/base/services/devicepolicy/java/com/android/server/devicepolicy/
// EnterpriseSpecificIdCalculator.java
// 生成每个企业独立稳定设备ID,不暴露硬件标识符
61.8.16 远程 Bugreport
DPC 可以远程请求抓取设备 bugreport 日志。
java
// frameworks/base/services/devicepolicy/java/com/android/server/devicepolicy/
// RemoteBugreportManager.java
// 处理管理员发起的远程bugreport请求
// DevicePolicyData.java
private static final String TAG_LAST_BUG_REPORT_REQUEST = "last‑bug‑report‑request";
61.8.17 Wi‑Fi SSID 策略
管理员管控设备允许连接的 Wi‑Fi 网络。
java
// ActiveAdmin.java引用WifiSsidPolicy
import android.app.admin.WifiSsidPolicy;
// 两种模式
import static android.app.admin.WifiSsidPolicy.WIFI_SSID_POLICY_TYPE_ALLOWLIST;
import static android.app.admin.WifiSsidPolicy.WIFI_SSID_POLICY_TYPE_DENYLIST;
- 白名单模式:仅允许列表内 SSID 连接
- 黑名单模式:阻止列表内 SSID 连接
61.8.18 私有 DNS 策略
管理员可以配置私有 DNS(DNS‑over‑TLS)。
java
// DevicePolicyManager.java
public static final int PRIVATE_DNS_MODE_OFF = 1;
public static final int PRIVATE_DNS_MODE_OPPORTUNISTIC = 2;
public static final int PRIVATE_DNS_MODE_PROVIDER_HOSTNAME = 3;
public static final int PRIVATE_DNS_MODE_UNKNOWN = 0;
public static final int PRIVATE_DNS_SET_NO_ERROR = 0;
public static final int PRIVATE_DNS_SET_ERROR_FAILURE_SETTING = 1;
61.8.19 优先网络服务
面向企业场景实现专属网络路径。
java
// ActiveAdmin引用
import android.app.admin.PreferentialNetworkServiceConfig;
管理员配置企业网络偏好,让工作流量使用指定网络切片、企业 APN。
61.8.20 APN 配置(电话模块)
设备所有者管理 APN 接入点。
java
// DevicePolicyManagerService.java
import static android.provider.Telephony.Carriers.DPC_URI;
import static android.provider.Telephony.Carriers.ENFORCE_KEY;
import static android.provider.Telephony.Carriers.ENFORCE_MANAGED_URI;
import static android.provider.Telephony.Carriers.INVALID_APN_ID;
61.8.21 应用包策略
管理员针对特定能力做应用包黑白名单,例如跨资料 Intent 处理。
java
// DevicePolicyManager.java引用
import android.app.admin.PackagePolicy;
// PackagePolicy用于针对能力配置包白/黑名单(如跨资料Intent处理)
61.8.22 临时用户
设备所有者可以强制创建临时用户;用户退出登录全部数据自动删除。
java
// ActiveAdmin.java
private static final String TAG_FORCE_EPHEMERAL_USERS = "force_ephemeral_users";
适合教育、零售共享设备。
61.8.23 受保护应用包
管理员保护指定应用包,阻止用户卸载、篡改。
java
// DevicePolicyData.java
private static final String TAG_PROTECTED_PACKAGES = "protected‑packages";
61.8.24 绕过角色资格校验
企业场景,管理员可以给不满足常规条件的应用授予系统角色。
// DevicePolicyData.java
private static final String TAG_BYPASS_ROLE_QUALIFICATIONS =
"bypass‑role‑qualifications";
61.8.25 第二道锁屏
管理员开启第二层锁屏界面。
java
// DevicePolicyData.java
private static final String TAG_SECONDARY_LOCK_SCREEN = "secondary‑lock‑screen";
DPC 可以实现额外合规校验锁屏,在系统锁屏之前或之后展示。
61.8.26 应用豁免
管理员将指定应用豁免部分系统限制。
java
// DevicePolicyManager.java
public static final int EXEMPT_FROM_ACTIVITY_BG_START_RESTRICTION = ...;
public static final int EXEMPT_FROM_DISMISSIBLE_NOTIFICATIONS = ...;
public static final int EXEMPT_FROM_HIBERNATION = ...;
public static final int EXEMPT_FROM_POWER_RESTRICTIONS = ...;
public static final int EXEMPT_FROM_SUSPENSION = ...;
保证 VPN 客户端、管理代理这类关键企业应用,不受电池优化、应用冻结策略影响。
61.8.27 完整合规架构

61.8.28 高级保护模式作为系统管理员
Android16 引入,Android17 扩展高级保护模式 AAPM。设置界面一个总开关,一键开启整套加固安全配置。
架构关键点:AAPM 不属于 DPMS,也不是 DPC 应用;它是独立系统服务,以系统管理员身份复用 61.2 介绍的策略引擎驱动设备策略。服务与客户端 API 不在 devicepolicy 包下。
java
// frameworks/base/services/core/java/com/android/server/security/advancedprotection/
// AdvancedProtectionService.java 系统服务
// frameworks/base/core/java/android/security/advancedprotection/
// AdvancedProtectionManager.java @SystemService客户端
public static final String ADVANCED_PROTECTION_SYSTEM_ENTITY =
"android.security.advancedprotection";
每一项加固能力是services/core/java/com/android/server/security/advancedprotection/features/目录下的 FeatureHook,ID 在AdvancedProtectionManager定义。
java
// AdvancedProtectionManager.java
public static final int FEATURE_ID_DISALLOW_CELLULAR_2G = 0;
public static final int FEATURE_ID_DISALLOW_INSTALL_UNKNOWN_SOURCES = 1;
public static final int FEATURE_ID_DISALLOW_USB = 2;
public static final int FEATURE_ID_DISALLOW_WEP = 3;
public static final int FEATURE_ID_ENABLE_MTE = 4;
public static final int FEATURE_ID_DISALLOW_INSECURE_WIFI_AUTOJOIN = 5;
public static final int FEATURE_ID_RESTRICT_NON_TOOL_A11Y_SERVICES = 6;
与设备策略模块桥接示例(MTE):
java
// MemoryTaggingExtensionHook.java
mDevicePolicyManager.setMtePolicy(ADVANCED_PROTECTION_SYSTEM_ENTITY, mtePolicy);
调用的是系统重载接口setMtePolicy(String systemEntity, int policy),底层调用IDevicePolicyManager.setMtePolicyBySystem(systemEntity, policy);DPMS 内部通过createSystemEnforcingAdmin(ADVANCED_PROTECTION_SYSTEM_ENTITY)记录该系统管理员的策略。 AAPM 的策略和 DPC 策略进入同一策略引擎,按正常规则做解析,不会互相强制覆盖。
Android17 内置 4 个 Hook 实现,均继承AdvancedProtectionHook: MemoryTaggingExtensionHook、DisallowInstallUnknownSourcesAdvancedProtectionHook、DisallowCellular2GAdvancedProtectionHook、UsbDataAdvancedProtectionHook。
前三者走 DPMS,两种调用路径:
- MTE 调用
setMtePolicy(ADVANCED_PROTECTION_SYSTEM_ENTITY, ...) - 禁止未知来源、禁止 2G,调用
addUserRestrictionGlobally(systemEntity, ...)写入 DPMS,作为系统管理员的用户限制,和 DPC 策略共存。
USB 处理特殊:不使用用户限制 。开启时调用setUsbDataSignalIfPossible(...),受锁屏状态控制;设备锁屏时关闭 USB 数据通路,解锁恢复,底层调用IUsbManagerInternal.enableUsbDataSignal;不存在DISALLOW_USB这个 UserManager 常量,FEATURE_ID_DISALLOW_USB仅作为 Hook 标识。

重要规则:DPC 不能静默撤销 AAPM 开启的保护。用户主动开启高级保护模式后,部分特性使用系统管理员写入的严格值;企业管理员配置 "允许" 无法覆盖用户主动开启的加固项。
61.8.29 多用户托管设备配置
无头系统用户模式,配置流程不能假设设备所有者运行在人机交互用户。Android17 新增多用户托管设备配置路径专门解决该场景。
DevicePolicyManager新增客户端接口:
java
// frameworks/base/core/java/android/app/admin/DevicePolicyManager.java
public static final String ACTION_PROVISION_MULTIUSER_MANAGED_DEVICE =
"android.app.admin.action.PROVISION_MULTIUSER_MANAGED_DEVICE";
public static final String ACTION_PROVISION_MULTIUSER_MANAGED_USER =
"android.app.admin.action.PROVISION_MULTIUSER_MANAGED_USER";
// 新配置返回码
public static final int RESULT_MULTIUSER_MANAGED_DEVICE_PROVISIONED = 124;
// 启动配置状态机(系统API)
public void startMultiuserManagedDeviceProvisioning();
参数 Parcelable:MultiuserManagedDeviceProvisioningParams、MultiuserManagedUserProvisioningParams,对应 AIDL 序列化类;结果回调MultiuserDeviceProvisioningCompletion.java。旧版MultiUserDeviceProvisioningParams标记废弃。
概念上做分离:"配置整机设备" 和 "在设备上配置托管用户";设备所有者绑定无头 system user,再创建各个托管用户,和HEADLESS_DEVICE_OWNER_MODE_SINGLE_USER、HEADLESS_DEVICE_OWNER_MODE_AFFILIATED配套使用。
61.8.30 策略版本与迁移
策略引擎会把解析完成状态持久化磁盘,因此磁盘 XML 做版本管理,OTA 升级时自动迁移旧版本策略。
java
// frameworks/base/services/devicepolicy/java/com/android/server/devicepolicy/
// DevicePolicyManagerService.java
static final int DPMS_VERSION = 6;
// 开机阶段
upgrader.upgradePolicy(DPMS_VERSION);
PolicyVersionUpgrader.upgradePolicy(int)按版本号逐次升级,从磁盘版本迭代到DPMS_VERSION,改写策略字段,更新存储版本。例如版本 5 升级到 6 会修改布尔策略默认值,加载旧文件使用旧默认,保存升级后版本。
单独PolicyMigrator.migrateV1PoliciesToDevicePolicyEngineLocked()完成 Android13 及更早版本旧策略一次性迁移,把旧版输入法管控、账号禁用等策略转换为新引擎格式。
迁移逻辑运行 DPMS 锁内,在系统开机阶段执行;大版本 OTA 第一次开机时会执行策略数据迁移,之后设备管理 API 才完全就绪。
61.8.31 企业 RCS 消息归档
Android17 新增,企业管控接收 RCS 归档消息的应用。RcsArchivalAppTracker跟踪每个用户唯一归档包名。
java
// frameworks/base/services/devicepolicy/java/com/android/server/devicepolicy/
// RcsArchivalAppTracker.java
/* 跟踪企业RCS归档应用 */
// KEY_ARCHIVAL_PACKAGE = "messages_archival"
// 映射:userId → 当前被授予归档权限的包名
托管设备环境,可以把 RCS 归档能力授权给指定应用用于合规留存;更换应用时可以干净回收权限,避免权限泛滥。
61.9 动手实践
本节提供实操练习,基于 AOSP 源码与 Android 开发工具探索设备策略框架。
61.9.1 练习 1:查看 DPMS 源码
查看设备策略管理器服务的代码规模:
# 统计主服务文件行数
wc -l frameworks/base/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
# 预期:Android 17代码树中约24000行
# 统计devicepolicy包下所有Java文件数量
find frameworks/base/services/devicepolicy/ -name "*.java" | wc -l
# 列出全部策略定义常量
grep -n "static PolicyDefinition" \
frameworks/base/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java
# 统计DPMS引入的MANAGE_DEVICE_POLICY_*权限数量
grep "MANAGE_DEVICE_POLICY_" \
frameworks/base/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java \
| wc -l
61.9.2 练习 2:探索 DPM 客户端 API
# 统计DevicePolicyManager中的公开API方法数量
grep -c "public.*(" \
frameworks/base/core/java/android/app/admin/DevicePolicyManager.java
# 列出所有委托作用域
grep "DELEGATION_" \
frameworks/base/core/java/android/app/admin/DevicePolicyManager.java \
| grep "public static final"
# 查找所有PASSWORD_COMPLEXITY相关常量
grep "PASSWORD_COMPLEXITY_" \
frameworks/base/core/java/android/app/admin/DevicePolicyManager.java
# 列出所有与设备预置相关的Action
grep "ACTION_PROVISION" \
frameworks/base/core/java/android/app/admin/DevicePolicyManager.java
61.9.3 练习 3:构建极简设备管理应用
创建一个极简设备管理应用,理解管理组件的生命周期。
步骤 1:创建管理接收器
java
// MyDeviceAdminReceiver.java
package com.example.myadmin;
import android.app.admin.DeviceAdminReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.UserHandle;
import android.util.Log;
public class MyDeviceAdminReceiver extends DeviceAdminReceiver {
private static final String TAG = "MyDeviceAdmin";
@Override
public void onEnabled(Context context, Intent intent) {
Log.i(TAG, "Device admin enabled");
}
@Override
public void onDisabled(Context context, Intent intent) {
Log.i(TAG, "Device admin disabled");
}
@Override
public void onPasswordChanged(Context context, Intent intent,
UserHandle user) {
Log.i(TAG, "Password changed for user: " + user);
}
@Override
public void onPasswordFailed(Context context, Intent intent,
UserHandle user) {
Log.i(TAG, "Password failed for user: " + user);
}
@Override
public void onPasswordSucceeded(Context context, Intent intent,
UserHandle user) {
Log.i(TAG, "Password succeeded for user: " + user);
}
}
步骤 2:创建管理策略 XML
XML
<!-- res/xml/device_admin.xml -->
<device-admin xmlns:android="http://schemas.android.com/apk/res/android">
<uses-policies>
<limit-password />
<watch-login />
<force-lock />
<wipe-data />
<disable-camera />
</uses-policies>
</device-admin>
步骤 3:在清单文件中声明
XML
<receiver
android:name=".MyDeviceAdminReceiver"
android:exported="true"
android:permission="android.permission.BIND_DEVICE_ADMIN">
<meta-data
android:name="android.app.device_admin"
android:resource="@xml/device_admin" />
<intent-filter>
<action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
</intent-filter>
</receiver>
步骤 4:创建管理 Activity
java
// AdminActivity.java
package com.example.myadmin;
import android.app.Activity;
import android.app.admin.DevicePolicyManager;
import android.content.ComponentName;
import android.content.Context;
import android.os.Bundle;
import android.util.Log;
public class AdminActivity extends Activity {
private static final String TAG = "MyDeviceAdmin";
private DevicePolicyManager mDPM;
private ComponentName mAdminComponent;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mDPM = (DevicePolicyManager)
getSystemService(Context.DEVICE_POLICY_SERVICE);
mAdminComponent = new ComponentName(this,
MyDeviceAdminReceiver.class);
if (mDPM.isAdminActive(mAdminComponent)) {
Log.i(TAG, "Admin is active");
logPolicyState();
} else {
Log.i(TAG, "Admin is NOT active");
}
}
private void logPolicyState() {
Log.i(TAG, "Password sufficient: "
+ mDPM.isActivePasswordSufficient());
Log.i(TAG, "Encryption status: "
+ mDPM.getStorageEncryptionStatus());
Log.i(TAG, "Camera disabled: "
+ mDPM.getCameraDisabled(mAdminComponent));
}
}
61.9.4 练习 4:配置测试设备所有者
在模拟器上使用 ADB 体验设备所有者功能:
# 启动全新模拟器(恢复出厂状态)
emulator -avd Pixel_8_API_35 -wipe-data
# 完成初始化设置后,设置设备所有者
# (必须在用户完成设置流程之前执行)
adb shell dpm set-device-owner com.example.myadmin/.MyDeviceAdminReceiver
# 验证设备所有者已设置
adb shell dumpsys device_policy
# 查看设备策略XML文件
adb shell cat /data/system/device_owner_2.xml
# 查看每个用户的策略数据
adb shell cat /data/system/users/0/device_policies.xml
61.9.5 练习 5:创建并查看工作资料
# 在已安装DPC测试应用的模拟器上执行:
# 列出当前所有用户
adb shell pm list users
# 创建受管理资料(使用TestDPC或同类应用)
# 创建完成后,再次列出用户
adb shell pm list users
# 预期输出:UserInfo{10:Work profile:...}
# 查看工作资料的策略数据
adb shell cat /data/system/users/10/device_policies.xml
# 列出工作资料内安装的应用包
adb shell pm list packages --user 10
# 查看跨资料Intent过滤器校验信息
adb shell dumpsys package intent-filter-verifications
# 切换工作模式(使受管理资料不可用)
adb shell am broadcast -a android.intent.action.MANAGED_PROFILE_UNAVAILABLE \
--user 0
61.9.6 练习 6:探索托管配置
# 为工作资料内的应用设置应用限制
adb shell content call \
--uri content://com.android.providers.settings \
--method GET_system \
--arg device_provisioned
# 导出设备策略状态
adb shell dumpsys device_policy | grep -A 20 "Active Admins"
# 在策略导出结果中查找应用限制
adb shell dumpsys device_policy | grep -A 10 "application-restrictions"
61.9.7 练习 7:分析策略引擎的解析逻辑
研究策略引擎如何处理冲突策略:
# 在源码中查找所有策略解析机制
grep -r "class.*Resolution\|MostRestrictive\|TopPriority\|PackageSetUnion\|MostRecent" \
frameworks/base/services/devicepolicy/java/com/android/server/devicepolicy/ \
--include="*.java" -l
# 列出全部策略定义
grep "static.*PolicyDefinition" \
frameworks/base/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java
# 查找策略执行器回调中的CompletableFuture
grep "static.*CompletableFuture" \
frameworks/base/services/devicepolicy/java/com/android/server/devicepolicy/PolicyEnforcerCallbacks.java \
| head -20
61.9.8 练习 8:安全与网络日志
# 开启安全日志(需要设备所有者权限)
adb shell dpm set-device-owner com.example.myadmin/.MyDeviceAdminReceiver
# 代码中调用:
# dpm.setSecurityLoggingEnabled(admin, true);
# 查看安全日志状态
adb shell dumpsys device_policy | grep -A 5 "Security Log"
# 查看网络日志状态
adb shell dumpsys device_policy | grep -A 5 "Network Log"
# 查看SecurityLogMonitor实现代码行数
wc -l frameworks/base/services/devicepolicy/java/com/android/server/devicepolicy/SecurityLogMonitor.java
# 查看NetworkLogger实现代码行数
wc -l frameworks/base/services/devicepolicy/java/com/android/server/devicepolicy/NetworkLogger.java
61.9.9 练习 9:跟踪一次策略调用的完整调用栈
跟踪setCameraDisabled()调用,从客户端 API 一路到策略执行:
# 1. 定位客户端方法
grep -n "setCameraDisabled" \
frameworks/base/core/java/android/app/admin/DevicePolicyManager.java | head -5
# 2. 定位AIDL接口方法
grep -n "setCameraDisabled" \
frameworks/base/core/java/android/app/admin/IDevicePolicyManager.aidl
# 3. 定位服务端实现
grep -n "setCameraDisabled" \
frameworks/base/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java | head -5
# 4. 查找该策略的解析定义
grep -n "CAMERA\|camera.*disable" \
frameworks/base/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java
# 5. 查找执行器回调
grep -n "camera\|Camera" \
frameworks/base/services/devicepolicy/java/com/android/server/devicepolicy/PolicyEnforcerCallbacks.java | head -5
# 6. 查找CameraService读取该策略的位置
grep -rn "DevicePolicyCache\|isCameraDisabled\|CAMERA_DISABLED" \
frameworks/base/services/core/ --include="*.java" | head -10
61.9.10 练习 10:构建具备托管配置的完整 DPC
开发一个演示托管配置功能的 DPC。
步骤 1:被托管应用的限制规则 schema
XML
<!-- managed-app/res/xml/app_restrictions.xml -->
<restrictions xmlns:android="http://schemas.android.com/apk/res/android">
<restriction
android:key="server_url"
android:restrictionType="string"
android:title="Server URL"
android:description="The server URL for syncing data"
android:defaultValue="https://default.example.com" />
<restriction
android:key="auto_sync"
android:restrictionType="bool"
android:title="Auto Sync"
android:description="Enable automatic data synchronization"
android:defaultValue="true" />
<restriction
android:key="sync_interval_minutes"
android:restrictionType="integer"
android:title="Sync Interval"
android:description="Minutes between automatic syncs"
android:defaultValue="30" />
<restriction
android:key="allowed_file_types"
android:restrictionType="multi-select"
android:title="Allowed File Types"
android:description=""
android:entries="@array/file_types"
android:entryValues="@array/file_type_values" />
</restrictions>
步骤 2:DPC 推送配置
java
// DPC:向受托管应用推送限制配置
public void configureApp(ComponentName admin) {
DevicePolicyManager dpm = getSystemService(DevicePolicyManager.class);
Bundle restrictions = new Bundle();
restrictions.putString("server_url", "https://corp.example.com");
restrictions.putBoolean("auto_sync", true);
restrictions.putInt("sync_interval_minutes", 15);
restrictions.putStringArray("allowed_file_types",
new String[]{"pdf", "docx", "xlsx"});
dpm.setApplicationRestrictions(admin,
"com.example.managedapp", restrictions);
}
步骤 3:受托管应用读取限制配置
java
// 受托管应用:读取限制配置
public void loadConfig() {
RestrictionsManager rm = getSystemService(RestrictionsManager.class);
Bundle restrictions = rm.getApplicationRestrictions();
String serverUrl = restrictions.getString("server_url",
"https://default.example.com");
boolean autoSync = restrictions.getBoolean("auto_sync", true);
int syncInterval = restrictions.getInt("sync_interval_minutes", 30);
Log.i(TAG, "Server: " + serverUrl);
Log.i(TAG, "Auto sync: " + autoSync);
Log.i(TAG, "Interval: " + syncInterval + " min");
}
// 注册监听配置变更
private void registerForChanges() {
IntentFilter filter = new IntentFilter(
Intent.ACTION_APPLICATION_RESTRICTIONS_CHANGED);
registerReceiver(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
loadConfig(); // 重新加载限制配置
}
}, filter);
}
61.9.11 练习 11:探索所有权转移 API
设备所有者与资料所有者权限可以在不同 DPC 应用之间转移。
java
// DevicePolicyManager API
public void transferOwnership(ComponentName admin,
ComponentName target, PersistableBundle bundle) { ... }
bash
# 查找transferOwnership的服务端实现
grep -n "transferOwnership" \
frameworks/base/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java \
| head -5
# 查看转移元数据管理器
cat frameworks/base/services/devicepolicy/java/com/android/server/devicepolicy/TransferOwnershipMetadataManager.java \
| head -30
TransferOwnershipMetadataManager在转移过程中跟踪管理员类型:
java
// TransferOwnershipMetadataManager.java
static final String ADMIN_TYPE_DEVICE_OWNER = "device-owner";
static final String ADMIN_TYPE_PROFILE_OWNER = "profile-owner";
61.9.12 练习 12:ADB 设备策略命令
DPMS 提供 Shell 命令接口:
# 查看全部dpm支持命令
adb shell dpm help
# 核心命令:
adb shell dpm set-device-owner <component>
adb shell dpm set-profile-owner <component>
adb shell dpm remove-active-admin <component>
adb shell dpm set-active-admin <component>
# DevicePolicyManagerService同时支持dumpsys
adb shell dumpsys device_policy
# dumpsys输出关键模块:
# - Device Owner(设备所有者)
# - Profile Owner (per user)(各用户的资料所有者)
# - Active Admins (per user)(各用户的活跃管理员)
# - Policy states(策略状态)
# - Affiliation IDs(关联ID)
# - Security/Network logging status(安全/网络日志状态)
Shell 命令处理实现文件:
frameworks/base/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerServiceShellCommand.java
61.9.13 练习 13:跨资料通信
测试跨资料 Intent 解析:
# 确认工作资料已存在
adb shell pm list users
# 查看当前跨资料Intent过滤器
adb shell dumpsys device_policy | grep -A 30 "cross-profile"
# 测试跨资料Intent解析
# 在个人资料中打开网页链接
adb shell am start -a android.intent.action.VIEW \
-d "https://example.com" --user 0
# 查看Intent是否在工作资料中被解析处理
adb shell dumpsys activity activities | grep -B 2 -A 5 "example.com"
代码配置跨资料 Intent 过滤器:
java
// 在DPC中,为网页浏览添加跨资料过滤器
DevicePolicyManager dpm = getSystemService(DevicePolicyManager.class);
ComponentName admin = new ComponentName(this,
MyDeviceAdminReceiver.class);
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_VIEW);
filter.addCategory(Intent.CATEGORY_BROWSABLE);
filter.addDataScheme("https");
// 允许个人应用在工作浏览器中打开链接
dpm.addCrossProfileIntentFilter(admin, filter,
DevicePolicyManager.FLAG_PARENT_CAN_ACCESS_MANAGED);
// 允许工作应用在个人浏览器中打开链接
dpm.addCrossProfileIntentFilter(admin, filter,
DevicePolicyManager.FLAG_MANAGED_CAN_ACCESS_PARENT);
61.9.14 练习 14:实现密码复杂度强制策略
java
// DPC:强制密码复杂度
public void enforcePasswordPolicy(ComponentName admin) {
DevicePolicyManager dpm = getSystemService(DevicePolicyManager.class);
// 现代方式:使用密码复杂度
// (要求targetSdk >= 31)
dpm.setRequiredPasswordComplexity(PASSWORD_COMPLEXITY_HIGH);
// 检查当前密码是否满足要求
boolean sufficient = dpm.isActivePasswordSufficient();
Log.i(TAG, "Password sufficient: " + sufficient);
if (!sufficient) {
// 拉起修改密码界面
Intent intent = new Intent(
DevicePolicyManager.ACTION_SET_NEW_PASSWORD);
intent.putExtra(DevicePolicyManager.EXTRA_PASSWORD_COMPLEXITY,
PASSWORD_COMPLEXITY_HIGH);
startActivity(intent);
}
// 设置密码错误多少次后自动擦除数据
dpm.setMaximumFailedPasswordsForWipe(admin, 10);
// 设置无操作自动锁屏超时(5分钟)
dpm.setMaximumTimeToLock(admin, 5 * 60 * 1000);
}
61.9.15 练习 15:设备认证校验
java
// DPC:生成带认证信息的密钥对
public void performDeviceAttestation(ComponentName admin) {
DevicePolicyManager dpm = getSystemService(DevicePolicyManager.class);
try {
KeyGenParameterSpec spec = new KeyGenParameterSpec.Builder(
"attestation-key",
KeyProperties.PURPOSE_SIGN | KeyProperties.PURPOSE_VERIFY)
.setDigests(KeyProperties.DIGEST_SHA256)
.setAttestationChallenge(
generateServerChallenge()) // 来自服务端的nonce
.build();
AttestedKeyPair keyPair = dpm.generateKeyPair(admin, "EC", spec,
DevicePolicyManager.ID_TYPE_SERIAL
| DevicePolicyManager.ID_TYPE_IMEI);
if (keyPair != null) {
List<Certificate> chain = keyPair.getAttestationRecord();
Log.i(TAG, "Attestation chain length: " + chain.size());
// 将证书链发送给服务端完成校验
sendAttestationToServer(chain);
}
} catch (Exception e) {
Log.e(TAG, "Attestation failed", e);
}
}
private byte[] generateServerChallenge() {
// 生产环境中该值由EMM服务端下发
byte[] challenge = new byte[32];
new java.security.SecureRandom().nextBytes(challenge);
return challenge;
}
61.9.16 练习 16:端到端工作资料 + 托管配置
本练习完整串联资料创建、应用安装、托管配置全流程。
java
// 步骤1:创建工作资料
public void setupWorkProfile() {
DevicePolicyManager dpm = getSystemService(DevicePolicyManager.class);
ManagedProfileProvisioningParams params =
new ManagedProfileProvisioningParams.Builder(
new ComponentName("com.example.dpc",
"com.example.dpc.MyDeviceAdminReceiver"),
"Corporate IT")
.setProfileName("Work")
.setOrganizationOwnedProvisioning(false) // BYOD模式
.build();
try {
UserHandle workProfile =
dpm.createAndProvisionManagedProfile(params);
Log.i(TAG, "Work profile created: " + workProfile);
configureWorkProfile(workProfile);
} catch (ProvisioningException e) {
Log.e(TAG, "Provisioning failed", e);
}
}
// 步骤2:配置工作资料
private void configureWorkProfile(UserHandle workProfile) {
DevicePolicyManager dpm = getSystemService(DevicePolicyManager.class);
ComponentName admin = new ComponentName("com.example.dpc",
"com.example.dpc.MyDeviceAdminReceiver");
// 设置工作资料密码策略
dpm.setRequiredPasswordComplexity(PASSWORD_COMPLEXITY_MEDIUM);
// 配置跨资料联系人
// (允许个人电话应用读取工作联系人)
// dpm.setCrossProfileContactsSearchDisabled(admin, false);
// 向工作邮箱应用推送托管配置
Bundle emailConfig = new Bundle();
emailConfig.putString("server", "mail.corp.example.com");
emailConfig.putInt("port", 993);
emailConfig.putBoolean("use_ssl", true);
dpm.setApplicationRestrictions(admin,
"com.example.workmail", emailConfig);
// 设置组织名称
dpm.setOrganizationName(admin, "Example Corp");
}
61.9.17 核心源码文件参考
如需进一步研究,下面是关键源码文件:
| 文件 | 用途 |
|---|---|
| frameworks/base/core/java/android/app/admin/DevicePolicyManager.java | 客户端 API(18700 + 行) |
| frameworks/base/core/java/android/app/admin/DeviceAdminReceiver.java | 管理接收器回调接口 |
| frameworks/base/core/java/android/app/admin/DeviceAdminInfo.java | 管理元数据解析 |
| frameworks/base/core/java/android/app/admin/IDevicePolicyManager.aidl | Binder 跨进程接口 |
| frameworks/base/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java | 服务实现(25000 + 行) |
| frameworks/base/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java | 多管理员策略解析引擎 |
| frameworks/base/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java | 策略定义与解析机制 |
| frameworks/base/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java | 每个管理员的策略状态 |
| frameworks/base/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java | 设备所有者 / 资料所有者管理 |
| frameworks/base/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyData.java | 按用户存储的策略持久化数据 |
| frameworks/base/services/devicepolicy/java/com/android/server/devicepolicy/EnforcingAdmin.java | 策略引擎中的管理员身份对象 |
| frameworks/base/services/devicepolicy/java/com/android/server/devicepolicy/SecurityLogMonitor.java | 安全事件日志 |
| frameworks/base/services/devicepolicy/java/com/android/server/devicepolicy/NetworkLogger.java | 网络事件日志 |
| frameworks/base/services/devicepolicy/java/com/android/server/devicepolicy/CertificateMonitor.java | CA 证书监控 |
| frameworks/base/services/devicepolicy/java/com/android/server/devicepolicy/PersonalAppsSuspensionHelper.java | COPE 模式个人应用冻结 |
| frameworks/base/core/java/android/app/admin/ManagedProfileProvisioningParams.java | 工作资料预置参数 |
| frameworks/base/core/java/android/app/admin/FullyManagedDeviceProvisioningParams.java | 全设备管理预置参数 |
| frameworks/base/core/java/android/content/pm/CrossProfileApps.java | 跨资料交互 API |
| frameworks/base/core/java/android/app/admin/FactoryResetProtectionPolicy.java | FRP 恢复出厂保护策略 |
小结
Android 企业级框架是 AOSP 内部最复杂子系统之一,仅核心服务与客户端 API 代码量就超过 40000 行。下面是关键架构要点:
管理模式(完全托管设备、工作资料 / BYOD、COPE)提供从 IT 完全管控到最大限度保护用户隐私的不同管控能力。模式在设备预置阶段就确定,直接决定可以执行哪些策略。
DevicePolicyManagerService 是策略的核心调度中心。代码约 24000 行,属于 AOSP 体量最大系统服务之一。它校验调用方权限,交由策略引擎完成策略解析,将版本化状态持久化存储为 XML(Android17 中 DPMS_VERSION=6),并通知其他子系统策略发生变更。
Android14 引入 DevicePolicyEngine,正式支持多管理员策略解析。Android17 内置 7 种解析策略:MostRestrictive、TopPriority、MostRecent、LeastRecent、PackageSetUnion、ListUnion、FlagUnion;同时定义 4 种管理员权限类别:企业管理员、传统设备管理员、role 角色管理员、新增的 system 系统管理员。这套机制让 DPC 管理应用、基于角色的管理员、旧版设备管理员、高级保护模式这类可信系统服务可以共存并协同处理同一套策略。
工作资料依托 Android 多用户机制,为工作数据提供一套密码学隔离的容器。跨资料通信严格受控,由 Intent 过滤器、ContentProvider 访问控制、CrossProfileApps API 共同管控。
安全基础设施包含安全日志(来自 logd 事件)、网络日志(通过 netd 采集 DNS、TCP 事件)、硬件级设备认证、证书管理、合规校验;以上全部能力用于向企业提供可核验的设备状态证明。
权限模型已经演进:从需要指定管理员 ComponentName,过渡到细粒度MANAGE_DEVICE_POLICY_*系列权限,支持非 DPC 应用通过 Role 角色、委托机制参与设备管理。