深入Android 12 Input系统:手把手调试‘BlockUntrustedTouches’的三种模式
深入Android 12 Input系统:手把手调试‘BlockUntrustedTouches’的三种模式
在Android 12中,Input系统的安全机制迎来了一项重要升级—— BlockUntrustedTouches 策略。这项特性专门针对那些可能被恶意应用利用的触摸事件漏洞,为系统定制开发者和ROM开发者提供了更精细的触摸事件控制能力。本文将带你从源码层深入剖析这一机制,并通过实际操作演示如何调试和验证三种不同模式的效果。
1. BlockUntrustedTouches机制解析
Android 12引入的 BlockUntrustedTouches 机制核心目的是防止"点击劫持"攻击。这种攻击方式下,恶意应用可能通过覆盖透明或半透明窗口来窃取用户的触摸输入。系统通过 InputDispatcher.cpp 中的 findTouchedWindowTargetsLocked 函数实现这一防护。
三种工作模式的区别 :
| 模式 | 常量值 | 行为特征 | 适用场景 |
|---|---|---|---|
| DISABLED | 0 | 完全禁用拦截功能 | 兼容性测试场景 |
| PERMISSIVE | 1 | 记录但不拦截可疑触摸 | 调试过渡阶段 |
| BLOCK | 2 | 主动拦截可疑触摸事件 | 生产环境安全策略 |
在底层实现上,系统通过 InputWindowInfo 结构体中的关键属性来判断窗口的可信度:
// InputWindowInfo关键属性
struct InputWindowInfo {
int32_t touchOcclusionMode; // 触摸遮挡处理模式
float alpha; // 窗口透明度
bool visible; // 窗口可见性
bool trustedOverlay; // 是否为可信覆盖层
// ...其他属性
};
当触摸事件发生时,系统会执行以下判断逻辑:
- 检查
mBlockUntrustedTouchesMode当前设置 - 计算触摸点的
TouchOcclusionInfo - 根据
isTouchTrustedLocked决定是否拦截
2. 调试环境搭建与模式切换
要有效调试 BlockUntrustedTouches 行为,我们需要配置完整的调试环境并掌握模式切换方法。
必备工具准备 :
- 已root的Android 12设备或模拟器
- ADB调试工具(建议使用最新版)
- 开启开发者选项中的"指针位置"显示
- 编译好的AOSP源码(用于查阅具体实现)
全局模式切换命令 :
# 查看当前模式
adb shell settings get global block_untrusted_touches
# 设置为DISABLED模式
adb shell settings put global block_untrusted_touches 0
# 设置为PERMISSIVE模式
adb shell settings put global block_untrusted_touches 1
# 设置为BLOCK模式
adb shell settings put global block_untrusted_touches 2
应用级例外设置 :
# 为特定应用禁用拦截
adb shell am compat disable BLOCK_UNTRUSTED_TOUCHES com.example.app
# 重置应用的拦截设置
adb shell am compat reset BLOCK_UNTRUSTED_TOUCHES com.example.app
提示:模式切换后需要重启相关Activity才能生效,可以通过
am restart命令强制刷新。
3. TouchOcclusionInfo生成与验证
TouchOcclusionInfo 是判断是否拦截触摸事件的核心数据结构,了解其生成过程对调试至关重要。
关键字段解析 :
hasBlockingOcclusion:当上层窗口设置touchOcclusionMode==BLOCK_UNTRUSTED时为trueobscuringOpacity:基于窗口alpha值计算的累积不透明度obscuringPackage/Uid:造成遮挡的应用信息
启用调试日志的方法:
# 启用触摸遮挡调试日志
adb shell setprop log.tag.InputDispatcher DEBUG
典型的日志分析要点:
- 查找
Untrusted touch due to occlusion关键字 - 注意
obscuringPackage和obscuringUid的标识 - 观察
obscuringOpacity与阈值(默认0.8)的比较
透明度计算示例 : 假设有两个重叠窗口:
- 窗口A:alpha=0.5
- 窗口B:alpha=0.6
实际计算方式为:
总不透明度 = 1 - (1 - 0.5) * (1 - 0.6) = 1 - 0.2 = 0.8
4. 实战调试案例与问题排查
在实际调试过程中,我们可能会遇到各种边界情况。以下是几个典型场景的调试方法。
案例1:意外拦截问题 症状:合法触摸事件被错误拦截 排查步骤:
- 检查
DEBUG_TOUCH_OCCLUSION日志 - 确认窗口的
touchOcclusionMode设置 - 验证
visible和trustedOverlay属性 - 检查是否有透明但未设置
ALLOW模式的覆盖层
案例2:拦截失效问题 症状:应该拦截的触摸事件仍然通过 排查步骤:
- 确认全局模式是否为
BLOCK - 检查目标应用是否被加入例外列表
- 验证
mMaximumObscuringOpacityForTouch阈值 - 检查窗口层级关系是否正确
实用调试技巧 :
- 使用
dumpsys input命令获取当前Input状态 - 通过
getevent -l监控原始输入事件 - 修改
frameworks/base/core/res/res/values/config.xml中的默认阈值 - 在
InputDispatcher.cpp中添加自定义日志输出
5. 高级定制与性能考量
对于系统定制开发者,可能需要深度调整 BlockUntrustedTouches 的行为。这里有几个进阶方向:
策略定制点 :
- 修改默认模式(
Settings.Global.BLOCK_UNTRUSTED_TOUCHES_MODE) - 调整透明度阈值(
Settings.Global.MAXIMUM_OBSCURING_OPACITY_FOR_TOUCH) - 扩展例外应用列表(
PACKAGE_BLOCKLIST_FOR_UNTRUSTED_TOUCHES_TOAST)
性能优化建议 :
- 避免在
computeTouchOcclusionInfoLocked中添加复杂计算 - 对频繁调用的窗口属性进行缓存
- 在系统负载高时降级为
PERMISSIVE模式 - 优化
canBeObscuredBy的判断逻辑
在Android 13中,这套机制又有了新的演进,包括:
- 新增
FLOATING模式处理悬浮窗口 - 改进多显示器场景下的行为一致性
- 增强
TouchOcclusionInfo的调试信息
通过本文介绍的方法论,开发者可以建立起完整的 BlockUntrustedTouches 调试能力,无论是进行系统定制还是解决实际问题,都能做到有的放矢。
更多推荐



所有评论(0)