# DPM常见面试题

## 一、DPM基础概念

### Q1: 什么是DPM？它的作用是什么？

**A:** DPM（Device Policy Manager，设备策略管理器）是Android系统提供的企业设备管理框架。

**主要作用：**

1. 设备策略管理：管理企业设备的安全策略、合规策略
2. 设备控制：远程控制设备功能，如锁屏、擦除数据、禁用功能等
3. 应用管理：管理企业应用的安装、卸载、权限控制
4. 安全策略：强制密码策略、加密策略、网络策略等
5. 合规检查：检查设备是否符合企业安全策略
6. 远程管理：支持远程设备管理和监控

**应用场景：**

- 企业移动设备管理（MDM - Mobile Device Management）
- 企业移动应用管理（MAM - Mobile Application Management）
- 企业移动安全（EMM - Enterprise Mobility Management）
- BYOD（Bring Your Own Device）场景

### Q2: DPM在Android系统架构中的位置？

**A:** DPM在系统架构中的位置：

1. **系统服务层**
   - DevicePolicyManagerService：DPM的核心服务
   - 运行在system_server进程中
   - 通过Binder机制与应用通信

2. **Framework层**
   - DevicePolicyManager：应用层使用的API
   - DeviceAdminReceiver：设备管理员接收器
   - 通过`Context.DEVICE_POLICY_SERVICE`获取

3. **应用层**
   - 设备管理应用：实现DeviceAdminReceiver
   - 企业应用：使用DevicePolicyManager API

**架构关系：**

```
应用层 -> DevicePolicyManager -> Binder -> DevicePolicyManagerService -> 系统服务
```

### Q3: DPM与其他系统服务的关系？

**A:** DPM与其他系统服务的关系：

1. **DPM与AMS（ActivityManagerService）**
   - DPM可以控制应用的启动和运行
   - 可以禁用某些应用
   - 可以限制应用的使用时间

2. **DPM与PMS（PackageManagerService）**
   - DPM可以控制应用的安装和卸载
   - 可以管理应用权限
   - 可以限制应用安装来源

3. **DPM与UserManagerService**
   - DPM可以管理多用户策略
   - 可以限制用户切换
   - 可以控制用户创建和删除

4. **DPM与Security服务**
   - DPM可以设置密码策略
   - 可以强制设备加密
   - 可以管理证书

---

## 二、DeviceAdminReceiver

### Q4: 什么是DeviceAdminReceiver？如何实现？

**A:** DeviceAdminReceiver是设备管理员的接收器，用于接收系统发送的设备管理事件。

**实现步骤：**

1. **创建DeviceAdminReceiver子类**

```java
public class MyDeviceAdminReceiver extends DeviceAdminReceiver {
    
    @Override
    public void onEnabled(Context context, Intent intent) {
        // 设备管理员被启用
        super.onEnabled(context, intent);
    }
    
    @Override
    public void onDisabled(Context context, Intent intent) {
        // 设备管理员被禁用
        super.onDisabled(context, intent);
    }
    
    @Override
    public CharSequence onDisableRequested(Context context, Intent intent) {
        // 用户请求禁用设备管理员时调用
        // 返回提示信息
        return "禁用设备管理员将导致设备无法管理";
    }
    
    @Override
    public void onPasswordChanged(Context context, Intent intent, UserHandle user) {
        // 密码被修改
        super.onPasswordChanged(context, intent, user);
    }
    
    @Override
    public void onPasswordFailed(Context context, Intent intent, UserHandle user) {
        // 密码输入错误
        super.onPasswordFailed(context, intent, user);
    }
    
    @Override
    public void onPasswordSucceeded(Context context, Intent intent, UserHandle user) {
        // 密码输入正确
        super.onPasswordSucceeded(context, intent, user);
    }
}
```

2. **在AndroidManifest.xml中注册**

```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>
```

3. **创建设备管理员策略文件（res/xml/device_admin.xml）**

```xml
<?xml version="1.0" encoding="utf-8"?>
<device-admin xmlns:android="http://schemas.android.com/apk/res/android">
    <uses-policies>
        <limit-password />
        <watch-login />
        <reset-password />
        <force-lock />
        <wipe-data />
        <expire-password />
        <encrypted-storage />
        <disable-camera />
        <disable-keyguard-features />
    </uses-policies>
</device-admin>
```

### Q5: DeviceAdminReceiver的主要回调方法有哪些？

**A:** DeviceAdminReceiver的主要回调方法：

1. **生命周期回调**
   - `onEnabled()`：设备管理员被启用
   - `onDisabled()`：设备管理员被禁用
   - `onDisableRequested()`：用户请求禁用时的提示

2. **密码相关回调**
   - `onPasswordChanged()`：密码被修改
   - `onPasswordFailed()`：密码输入错误
   - `onPasswordSucceeded()`：密码输入正确
   - `onPasswordExpiring()`：密码即将过期

3. **安全事件回调**
   - `onLockTaskModeEntering()`：进入锁定任务模式
   - `onLockTaskModeExiting()`：退出锁定任务模式
   - `onUserAdded()`：用户被添加
   - `onUserRemoved()`：用户被删除
   - `onUserStarted()`：用户启动
   - `onUserStopped()`：用户停止

4. **系统更新回调**
   - `onSystemUpdatePending()`：系统更新待处理
   - `onBugreportShared()`：Bug报告被共享
   - `onBugreportFailed()`：Bug报告失败
   - `onBugreportSharingTimedOut()`：Bug报告超时

5. **网络事件回调**
   - `onChoosePrivateKeyAlias()`：选择私钥别名
   - `onSecurityLogsAvailable()`：安全日志可用

---

## 三、DevicePolicyManager API

### Q6: DevicePolicyManager的主要功能有哪些？

**A:** DevicePolicyManager的主要功能：

1. **密码策略管理**
   - 设置密码最小长度
   - 设置密码复杂度要求
   - 设置密码过期时间
   - 强制密码策略

2. **设备锁定控制**
   - 锁定设备
   - 设置锁屏超时时间
   - 禁用锁屏功能
   - 清除锁屏密码

3. **数据擦除**
   - 擦除设备数据
   - 擦除应用数据
   - 恢复出厂设置

4. **应用管理**
   - 安装应用
   - 卸载应用
   - 隐藏应用
   - 禁用应用

5. **功能控制**
   - 禁用相机
   - 禁用截屏
   - 禁用USB调试
   - 禁用安装未知来源应用

6. **网络策略**
   - 设置VPN配置
   - 管理WiFi配置
   - 控制网络访问

### Q7: 如何使用DevicePolicyManager设置密码策略？

**A:** 设置密码策略的步骤：

1. **获取DevicePolicyManager实例**

```java
DevicePolicyManager dpm = (DevicePolicyManager) 
    getSystemService(Context.DEVICE_POLICY_SERVICE);
ComponentName admin = new ComponentName(this, MyDeviceAdminReceiver.class);
```

2. **检查设备管理员是否激活**

```java
if (!dpm.isAdminActive(admin)) {
    // 激活设备管理员
    Intent intent = new Intent(DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN);
    intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, admin);
    intent.putExtra(DevicePolicyManager.EXTRA_ADD_EXPLANATION, 
        "需要设备管理员权限来设置密码策略");
    startActivityForResult(intent, REQUEST_CODE_ENABLE_ADMIN);
    return;
}
```

3. **设置密码策略**

```java
// 设置密码最小长度
dpm.setPasswordMinimumLength(admin, 8);

// 设置密码质量要求
dpm.setPasswordQuality(admin, 
    DevicePolicyManager.PASSWORD_QUALITY_NUMERIC); // 数字密码
// 或
dpm.setPasswordQuality(admin, 
    DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC); // 字母数字密码

// 设置密码最小字母数
dpm.setPasswordMinimumLetters(admin, 1);

// 设置密码最小数字数
dpm.setPasswordMinimumNumeric(admin, 1);

// 设置密码最小符号数
dpm.setPasswordMinimumSymbols(admin, 1);

// 设置密码最小大写字母数
dpm.setPasswordMinimumUpperCase(admin, 1);

// 设置密码最小小写字母数
dpm.setPasswordMinimumLowerCase(admin, 1);

// 设置密码过期时间（毫秒）
dpm.setPasswordExpirationTimeout(admin, 30 * 24 * 60 * 60 * 1000L); // 30天

// 设置密码历史长度（不能重复使用最近N个密码）
dpm.setPasswordHistoryLength(admin, 5);

// 强制设置密码
dpm.setPasswordQuality(admin, DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC);
dpm.lockNow(); // 立即锁定设备，要求用户设置密码
```

### Q8: 如何使用DevicePolicyManager控制设备功能？

**A:** 控制设备功能的常用方法：

1. **锁定设备**

```java
// 立即锁定设备
dpm.lockNow();

// 设置锁屏超时时间（毫秒）
dpm.setMaximumTimeToLock(admin, 5 * 60 * 1000L); // 5分钟
```

2. **禁用功能**

```java
// 禁用相机
dpm.setCameraDisabled(admin, true);

// 禁用截屏
dpm.setScreenCaptureDisabled(admin, true);

// 禁用USB调试（需要系统权限）
// 通过系统属性设置
SystemProperties.set("persist.sys.usb.config", "none");
```

3. **控制应用安装**

```java
// 设置允许安装的应用包名列表
dpm.setPermittedAccessibilityServices(admin, permittedPackages);

// 设置允许使用的输入法列表
dpm.setPermittedInputMethods(admin, permittedInputMethods);
```

4. **擦除数据**

```java
// 擦除设备数据（恢复出厂设置）
dpm.wipeData(0);

// 擦除应用数据（需要系统权限）
// 通过PackageManager删除应用数据
```

5. **管理证书**

```java
// 安装证书
dpm.installCaCert(admin, certificateBytes);

// 卸载证书
dpm.uninstallCaCert(admin, certificate);
```

### Q9: 如何使用DevicePolicyManager管理应用？

**A:** 应用管理功能：

1. **安装应用**

```java
// 静默安装应用（需要系统权限）
// 通过PackageManager安装
PackageInstaller.Session session = packageInstaller.openSession(sessionId);
session.write("app.apk", 0, -1, inputStream);
session.commit(createIntentSender());
```

2. **卸载应用**

```java
// 通过PackageManager卸载
packageManager.deletePackage(packageName, 
    new PackageDeleteObserver(), PackageManager.DELETE_ALL_USERS);
```

3. **隐藏应用**

```java
// 隐藏应用（需要系统权限）
// 通过PackageManager设置应用隐藏
packageManager.setApplicationEnabledSetting(packageName,
    PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER,
    PackageManager.DONT_KILL_APP);
```

4. **禁用应用**

```java
// 禁用应用
packageManager.setApplicationEnabledSetting(packageName,
    PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
    PackageManager.DONT_KILL_APP);
```

---

## 四、设备管理员激活

### Q10: 如何激活设备管理员？

**A:** 激活设备管理员的步骤：

1. **创建激活Intent**

```java
ComponentName admin = new ComponentName(this, MyDeviceAdminReceiver.class);
DevicePolicyManager dpm = (DevicePolicyManager) 
    getSystemService(Context.DEVICE_POLICY_SERVICE);

if (!dpm.isAdminActive(admin)) {
    Intent intent = new Intent(DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN);
    intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, admin);
    intent.putExtra(DevicePolicyManager.EXTRA_ADD_EXPLANATION,
        "需要激活设备管理员以管理设备安全策略");
    startActivityForResult(intent, REQUEST_CODE_ENABLE_ADMIN);
}
```

2. **处理激活结果**

```java
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    
    if (requestCode == REQUEST_CODE_ENABLE_ADMIN) {
        if (resultCode == RESULT_OK) {
            // 设备管理员已激活
            Toast.makeText(this, "设备管理员已激活", Toast.LENGTH_SHORT).show();
        } else {
            // 用户取消了激活
            Toast.makeText(this, "需要激活设备管理员", Toast.LENGTH_SHORT).show();
        }
    }
}
```

3. **检查激活状态**

```java
boolean isActive = dpm.isAdminActive(admin);
if (isActive) {
    // 设备管理员已激活，可以使用DPM功能
} else {
    // 需要激活设备管理员
}
```

### Q11: 如何取消设备管理员？

**A:** 取消设备管理员的方法：

1. **应用主动取消**

```java
ComponentName admin = new ComponentName(this, MyDeviceAdminReceiver.class);
DevicePolicyManager dpm = (DevicePolicyManager) 
    getSystemService(Context.DEVICE_POLICY_SERVICE);

if (dpm.isAdminActive(admin)) {
    dpm.removeActiveAdmin(admin);
    // 设备管理员已被取消
}
```

2. **用户在设置中取消**
   - 用户可以在"设置 -> 安全 -> 设备管理器"中取消设备管理员
   - 取消时会触发`DeviceAdminReceiver.onDisableRequested()`
   - 可以返回提示信息，但不能阻止取消

3. **处理取消请求**

```java
@Override
public CharSequence onDisableRequested(Context context, Intent intent) {
    // 返回提示信息
    return "取消设备管理员将导致设备无法管理，是否确定取消？";
}
```

---

## 五、密码策略

### Q12: DPM支持哪些密码策略？

**A:** DPM支持的密码策略：

1. **密码质量要求**
   - `PASSWORD_QUALITY_UNSPECIFIED`：无要求
   - `PASSWORD_QUALITY_BIOMETRIC_WEAK`：生物识别（弱）
   - `PASSWORD_QUALITY_SOMETHING`：任意密码
   - `PASSWORD_QUALITY_NUMERIC`：数字密码
   - `PASSWORD_QUALITY_NUMERIC_COMPLEX`：复杂数字密码
   - `PASSWORD_QUALITY_ALPHABETIC`：字母密码
   - `PASSWORD_QUALITY_ALPHANUMERIC`：字母数字密码
   - `PASSWORD_QUALITY_COMPLEX`：复杂密码（包含字母、数字、符号）

2. **密码长度要求**
   - `setPasswordMinimumLength()`：最小长度
   - 默认最小长度为4

3. **密码复杂度要求**
   - `setPasswordMinimumLetters()`：最小字母数
   - `setPasswordMinimumNumeric()`：最小数字数
   - `setPasswordMinimumSymbols()`：最小符号数
   - `setPasswordMinimumUpperCase()`：最小大写字母数
   - `setPasswordMinimumLowerCase()`：最小小写字母数
   - `setPasswordMinimumNonLetter()`：最小非字母字符数

4. **密码历史**
   - `setPasswordHistoryLength()`：密码历史长度
   - 防止用户重复使用最近N个密码

5. **密码过期**
   - `setPasswordExpirationTimeout()`：密码过期时间
   - 密码过期后强制用户修改密码

### Q13: 如何实现密码策略的强制执行？

**A:** 强制执行密码策略的方法：

1. **设置密码质量要求**

```java
// 设置密码质量要求
dpm.setPasswordQuality(admin, 
    DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC);

// 设置密码最小长度
dpm.setPasswordMinimumLength(admin, 8);

// 设置密码复杂度
dpm.setPasswordMinimumLetters(admin, 1);
dpm.setPasswordMinimumNumeric(admin, 1);
dpm.setPasswordMinimumSymbols(admin, 1);
```

2. **强制锁定设备**

```java
// 立即锁定设备，要求用户设置符合策略的密码
dpm.lockNow();
```

3. **检查密码是否符合策略**

```java
// 检查当前密码是否符合策略
boolean isPasswordSufficient = dpm.isActivePasswordSufficient();

if (!isPasswordSufficient) {
    // 密码不符合策略，强制用户修改
    dpm.lockNow();
}
```

4. **监听密码变化**

```java
// 在DeviceAdminReceiver中监听密码变化
@Override
public void onPasswordChanged(Context context, Intent intent, UserHandle user) {
    // 密码被修改，检查是否符合策略
    DevicePolicyManager dpm = (DevicePolicyManager) 
        context.getSystemService(Context.DEVICE_POLICY_SERVICE);
    
    if (!dpm.isActivePasswordSufficient()) {
        // 密码不符合策略，可以采取进一步措施
    }
}
```

---

## 六、设备锁定和擦除

### Q14: 如何使用DPM锁定设备？

**A:** 锁定设备的方法：

1. **立即锁定**

```java
// 立即锁定设备
dpm.lockNow();
```

2. **设置锁屏超时**

```java
// 设置锁屏超时时间（毫秒）
dpm.setMaximumTimeToLock(admin, 5 * 60 * 1000L); // 5分钟
```

3. **清除锁屏密码**

```java
// 清除锁屏密码（需要系统权限）
dpm.resetPassword("", DevicePolicyManager.RESET_PASSWORD_REQUIRE_ENTRY);
```

4. **设置锁屏消息**

```java
// 设置锁屏时显示的消息
dpm.setLockTaskPackages(admin, new String[]{"com.example.app"});
```

### Q15: 如何使用DPM擦除设备数据？

**A:** 擦除设备数据的方法：

1. **擦除所有数据（恢复出厂设置）**

```java
// 擦除设备所有数据
dpm.wipeData(0);

// 擦除设备数据并保留外部存储
dpm.wipeData(DevicePolicyManager.WIPE_EXTERNAL_STORAGE);
```

2. **擦除应用数据（需要系统权限）**

```java
// 通过PackageManager删除应用数据
packageManager.deleteApplicationDataFiles(packageName, 
    new IPackageDataObserver.Stub() {
        @Override
        public void onRemoveCompleted(String packageName, boolean succeeded) {
            // 删除完成
        }
    });
```

3. **擦除前的准备**

```java
// 在擦除前可以保存重要数据
// 发送通知给用户
// 记录擦除操作日志
```

**注意：**

- `wipeData()`会立即擦除设备，无法撤销
- 需要谨慎使用，建议在擦除前进行确认
- 某些设备可能不支持擦除功能

---

## 七、应用管理

### Q16: DPM如何管理企业应用？

**A:** DPM管理企业应用的方法：

1. **应用安装管理**

```java
// 设置允许安装的应用包名列表
List<String> permittedPackages = new ArrayList<>();
permittedPackages.add("com.example.app1");
permittedPackages.add("com.example.app2");

dpm.setPermittedAccessibilityServices(admin, permittedPackages);
```

2. **应用隐藏和显示**

```java
// 隐藏应用（需要系统权限）
packageManager.setApplicationEnabledSetting(packageName,
    PackageManager.COMPONENT_ENABLED_STATE_HIDDEN,
    PackageManager.DONT_KILL_APP);

// 显示应用
packageManager.setApplicationEnabledSet