Android 中的 AppOps(Application Operations) 是一套细粒度运行时权限控制机制,用于在传统 Android 权限模型之上提供更精细、动态的隐私与安全管控。它从 Android 4.3(API 18) 引入,并在后续版本中不断扩展,成为系统级隐私保护的核心组件之一。
一、AppOps 是什么?
AppOps = 对"已授权权限"的二次运行时拦截
传统权限(Permission):决定"能否安装/请求某能力"(如 RECORD_AUDIO)
AppOps:决定"即使有权限,当前是否允许实际使用该能力"
✅ 举例:
用户授予了录音权限(RECORD_AUDIO)
但通过 AppOps 可以 禁止其在后台录音(静默拒绝)
应用不会崩溃,但录不到声音
二、核心设计目标
表格
目标 说明
细粒度控制 不是"全有或全无",而是按场景控制(如前台允许、后台拒绝)
静默拦截 拒绝时不弹窗,避免打扰用户(与 Runtime Permission 不同)
系统/OEM 管控 厂商可基于 AppOps 实现"后台定位限制"、"自启动管理"等
企业设备管理 Device Owner 可强制设置 AppOps 策略
三、关键概念
. Op(Operation)
每个敏感行为对应一个操作码(整数),定义在 AppOpsManager 中:
java
编辑
public static final int OP_COARSE_LOCATION = 0;
public static final int OP_FINE_LOCATION = 1;
public static final int OP_RECORD_AUDIO = 30;
public static final int OP_CAMERA = 39;
public static final int OP_READ_CONTACTS = 45;
// ... 共 80+ 种 ops(Android 14)
完整列表见:AOSP AppOpsManager.java
. Mode(模式)
每个 Op 有三种运行模式:
表格
Mode 值 行为
MODE_ALLOWED 0 允许操作
MODE_IGNORED 2 静默拒绝(最常见)
MODE_ERRORED 3 抛出 SecurityException
⚠️ 注意:Android 9+ 统一使用 MODE_IGNORED = 2(旧版为 1)
. 作用对象
按 UID + 包名 维护策略
同一 UID 的多个包共享 AppOps 状态
四、工作原理
. 触发时机
当应用调用敏感 API 时,系统服务会主动检查 AppOps:
java
编辑
// 例如:AudioService 在录音前
int mode = mAppOps.noteOp(AppOpsManager.OP_RECORD_AUDIO, uid, packageName);
if (mode != AppOpsManager.MODE_ALLOWED) {
// 静默丢弃请求 或 抛异常
}
. 持久化存储
AppOps 策略保存在:
text
编辑
/data/system/appops.xml
示例内容:
xml
编辑
<appops>
<pkg n="com.example.recorder" u="0">
<op n="RECORD_AUDIO" m="2" /> <!-- m=2 表示 MODE_IGNORED -->
</pkg>
</appops>
. 修改方式
只有可信主体可修改:
adb shell appops set ...
Device Owner / Profile Owner
系统应用(signature|privileged)
普通应用无法修改自己或他人的敏感 AppOps
五、典型应用场景
✅ 1. 后台行为限制(Android 9+)
锁屏后自动将 OP_RECORD_AUDIO 设为 MODE_IGNORED
即使有权限也无法录音(除非使用前台服务)
✅ 2. 厂商定制功能
表格
厂商 功能 底层实现
小米 "后台禁止定位" appops set com.xxx LOCATION deny
华为 "禁止自启动" 控制 OP_RUN_IN_BACKGROUND
OPPO "电池优化" 自动 deny 后台 ops
✅ 3. 企业 MDM(移动设备管理)
Device Owner 应用可强制策略:
java
编辑
AppOpsManager appOps = getSystemService(AppOpsManager.class);
appOps.setMode(OP_CAMERA, uid, packageName, MODE_IGNORED); // 禁止拍照
✅ 4. 开发者调试
bash
编辑
查看某应用的 AppOps 状态
adb shell appops get com.example.app
模拟拒绝录音
adb shell appops set com.example.app RECORD_AUDIO deny
六、AppOps vs 权限(Permission)
表格
特性 权限(Permission) AppOps
控制层级 安装/请求时 运行时
用户可见性 弹窗授权 静默(用户通常不可见)
粒度 粗(全有/全无) 细(按场景、时间、状态)
可绕过性 Root 可绕过 系统级拦截,更难绕过
普通应用修改 可请求 ❌ 不能修改敏感 ops
💡 关系:
如果权限被拒绝 → 不会走到 AppOps 检查
如果权限被授予 → AppOps 决定是否真正放行
七、开发者如何使用?
. 检查自己的 AppOps 状态
java
编辑
AppOpsManager appOps = getSystemService(AppOpsManager.class);
int mode = appOps.checkOpNoThrow(AppOpsManager.OPSTR_RECORD_AUDIO,
Process.myUid(), getPackageName());
if (mode == AppOpsManager.MODE_ALLOWED) {
// 可安全录音
}
. 引导用户开启权限
java
编辑
// 跳转到应用详情页(部分 OEM 支持 AppOps 设置)
Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
intent.setData(Uri.parse("package:" + getPackageName()));
startActivity(intent);
⚠️ 注意:普通应用不能调用 setMode() 修改 OP_RECORD_AUDIO 等敏感操作!
八、限制与注意事项
不是安全边界:root 或系统应用可绕过
OEM 差异大:小米/华为等可能扩展自定义 ops
用户不可见:大多数用户不知道 AppOps 存在
Google Play 政策:滥用 AppOps(如偷偷开启麦克风)可能导致下架
九、总结
AppOps 是 Android 隐私架构的"第二道闸门":
在权限之上提供运行时动态控制
由系统/OEM/MDM 管理,普通应用只能读不能写(敏感 ops)
是实现"后台限制"、"电池优化"等功能的底层基石