第1章 无障碍线程架构全景
本章界定AOSP无障碍子系统在Android系统中的位置,从进程、线程维度拆解整体层次结构,明确各核心线程的角色与通信边界。通过一张分层架构图建立全局视角,并深入数据流向、控制信任链路及工程落地要点。
学习目标:读完本章后,你应该能够口头描述无障碍子系统涉及哪些进程/线程、数据如何从物理操作流转到AccessibilityService,以及为什么当前架构如此设计。
1.1 边界定义
无障碍子系统跨越三个进程边界:
- UI进程(每个应用主进程)—— 生成AccessibilityNodeInfo树,响应触摸/滚动事件。
- 系统服务进程(system_server)—— 运行AccessibilityManagerService(AMS),负责全局调度、窗口管理、注入事件。
- 辅助服务进程(AccessibilityService所在进程)—— 接收被筛选的事件,执行自动化操作或反馈。
线程边界:每个进程的主线程(UI Thread/Service主线程)主导无障碍交互;AMS内部使用独立HandlerThread处理事件路由,避免阻塞主线程。
1.2 分层与组件职责
| 层级 | 核心组件 | 线程角色 | 职责 |
|---|---|---|---|
| 应用框架层 | ViewRootImpl, ViewAccessibilityDelegate | UI主线程 | 监听系统AccessibilityState,构建并推送节点树,响应探索点击 |
| 系统服务层 | AccessibilityManagerService | Binder线程、HandlerThread | 注册/注销服务、事件分发、焦点管理、手势注入、窗口追踪 |
| 辅助服务层 | AccessibilityService | 主线程 + 可选工作线程 | 解析事件,执行自定义逻辑(如朗读、自动化点击) |
1.3 关键数据流向与信任链路
- 输入事件:用户触控 → InputDispatcher → ViewRootImpl(UI线程)
- 节点推送:UI线程通过Binder将AccessibilityEvent及节点信息发送至AMS。
- AMS分发:AMS HandlerThread按服务注册的
packageNames、eventTypes过滤,通过Binder回调目标AccessibilityService。 - 服务处理:AccessibilityService主线程收到回调,可再派发到工作线程避免ANR。
- 信任链路:Binder验证调用方UID;AMS校验服务是否拥有
BIND_ACCESSIBILITY_SERVICE权限;节点数据仅允许系统进程或已绑定的服务读取。
信任链路关键点:AccessibilityService无法直接访问其他应用的内存,所有节点信息通过AMS中转,且AMS会校验窗口所属包名与服务注册的filter是否匹配。避免恶意服务窥探隐私。
1.4 选型权衡
- Binder IPC vs ContentProvider:Binder提供同步/异步双向通信,适合高频率事件流;ContentProvider更重且仅适合数据查询。选择Binder是性能最优解。
- HandlerThread vs ExecutorService:AMS内部使用HandlerThread保证事件顺序处理,避免多线程并发导致状态不一致;辅助服务可选用ExecutorService处理CPU密集型任务,但需自行同步。
- 每应用单进程模型:每个AccessibilityService运行在独立进程中,与UI进程隔离,牺牲部分进程间通信开销,但提升了安全性和稳定性(服务crash不影响应用)。
1.5 风险点
常见风险:
- ANR:AccessibilityService在主线程中执行耗时操作(如网络请求、大量节点遍历)。应优先将重任务移入工作线程。
- 优先级翻转:当服务线程优先级低于UI线程时,可能长时间竞争锁。建议使用
android:process="xxx"并设置适当线程优先级。 - 内存泄漏:节点树过大或未及时释放节点引用,导致服务进程OOM。应按需复用
AccessibilityNodeInfo实例。 - 死锁:AMS在分发事件时若持有锁而服务Btinder回调中又反向调AMS,可能形成循环等待。AMS设计上使用非重入锁,且回调在独立Handler线程执行。
1.6 落地步骤
- 在AndroidManifest中声明服务并绑定
android.permission.BIND_ACCESSIBILITY_SERVICE。 - 在
onAccessibilityEvent()中接收事件;若需耗时处理,立即使用HandlerThread或Executors切换线程。 - 通过
getWindows()或findFocus()获取节点树,提取数据。 - 使用
performAction()执行点击、长按等操作时注意检查isEnabled()和isImportantForAccessibility()。 - 调用
setServiceInfo()动态调整事件过滤,避免接收无关事件浪费CPU。 - 监控性能:使用
StrictMode检测主线程磁盘/网络访问,确保无ANR。
1.7 验收标准
| 验收项 | 期望指标 | 验证方法 |
|---|---|---|
| 事件响应延迟 | ≤ 50 ms(从物理触摸到服务收到事件) | 在事件回调中记录时间戳,对比InputDispatch时间 |
| 节点获取耗时 | ≤ 10 ms(单个窗口) | System.currentTimeMillis()前后差值 |
| 主线程空闲率 | ≥ 90%(服务进程主线程无阻塞) | Profile工具 / 插桩 |
| 无ANR | 连续24小时运行无ANR日志 | 日志监控 + 系统anr目录检查 |