第四章 Handler 机制在无障碍中的应用:创建与管理、跨线程消息投递、线程局部性保证

4.1 边界定义

Handler 机制在 AOSP 无障碍架构中承担着「异步消息桥接」的核心角色,其边界覆盖以下三个维度:

  • 创建与管理:AccessibilityService 内部如何实例化 Handler,如何绑定到主线程 Looper,以及 Handler 的生命周期与 Service 生命周期的对齐关系。
  • 跨线程消息投递:无障碍事件(如触摸、焦点变化、窗口状态)从 SystemServer 的 Binder 线程池投递到 AccessibilityService 主线程消息队列的完整路径。
  • 线程局部性保证:保证消息处理不跨线程交叉、Handler 与 Looper 之间的一对一绑定、以及消息顺序的有序性。

4.2 分层视图

层次角色Handler 相关职责
SystemServer 层事件生产者通过 Binder 回调将无障碍事件序列化后投递到服务端代理
AccessibilityService 客户端层事件消费者创建 Handler 绑定主线程 Looper,接收并分发消息
消息传递中间层跨进程/跨线程桥接Binder 驱动 & 主线程消息队列(MessageQueue)作为传输介质
语义执行层回调触发Handler.handleMessage() 中执行具体无障碍逻辑(如触控反馈、焦点导航)

4.3 组件职责

  • AccessibilityService.Handler:由服务实例在 onServiceConnected() 中创建,默认绑定到主线程 Looper,负责接收来自系统的事件消息。
  • AccessibilityService.Callback:系统端通过 Binder 调用 notifyAccessibilityEvent(),内部将事件封装为 Message 发送到 Handler。
  • MessageQueue:主线程的消息队列,保证所有消息串行处理,避免并发冲突。
  • Looper:主线程的事件循环,绑定到 Handler 的 getLooper() 输出。

4.4 数据流 / 控制流 / 信任链路

数据流:物理事件 → InputManager → WindowManagerService → AccessibilityManagerService → Binder → 服务端代理 → Handler.sendMessage() → MessageQueue → Looper.loop() → handleMessage()。

控制流:系统事件触发 → 权限校验 → 跨进程 Binder 线程池中的线程调用回调 → 回调内构造 Message 并设置 target 为 AccessibilityService 的 Handler → 投递到主线程消息队列。

信任链路:仅允许系统签名进程(system_server)通过 Binder 调用 IAccessibilityServiceConnection 接口向服务发送消息;第三方应用无权伪造事件。Handler 的创建者(AccessibilityService)与消息接收者必须在同一进程,且 Looper 必须为服务主线程 Looper,保证消息来源的不可篡改性。

4.5 选型权衡

对比项Handler + Looper直接回调(Binder 线程执行)
线程安全天然串行,无需加锁需锁保护共享状态,易死锁
延迟控制可设定 Message 的 when,支持延迟/定时无延迟机制,立刻执行
生命周期耦合Handler 弱引用 Service,Looper 随线程消亡回调持有 Service 强引用导致泄漏
跨线程开销内存拷贝 + 队列排队,但可控无队列,直接调用但阻塞 Binder 线程

建议:在无障碍服务中始终使用 Handler 进行消息中转,避免在 Binder 回调中直接执行重量级操作。

4.6 风险点

  • 消息积压:若 handleMessage() 耗时过长,主线程消息队列拥堵,导致新事件响应延迟甚至 ANR。
  • Handler 泄漏:Handler 内部类隐式持有外部 AccessibilityService 引用,若 Service 销毁时 MessageQueue 中仍有未处理消息,会导致 Service 无法被 GC。
  • 线程局部性破坏:若在子线程中创建 Handler 但不手动调用 Looper.prepare(),或错误地将 Handler 绑定到非主线程 Looper,导致事件无法正确到达主线程。
  • 消息顺序乱序:Binder 线程池可能多线程同时投递,但 Handler 的消息队列本身有序,风险较低;但若在 handleMessage 中又 post 新消息,需注意递归深度。

4.7 落地步骤

  1. 确定 Looper:在 onServiceConnected() 中通过 getMainLooper() 获取主线程 Looper。
  2. 创建 Handler:
    private final Handler mHandler = new Handler(getMainLooper()) {
        @Override
        public void handleMessage(Message msg) {
            // 根据 msg.what 处理事件
        }
    };
  3. 注册 Binder 回调:在 onServiceConnected() 中调用 getServiceInterface().registerCallback(callback)。
  4. 回调内发送消息:
    private final IAccessibilityServiceClient.Stub mClientCallback = new IAccessibilityServiceClient.Stub() {
        @Override
        public void onAccessibilityEvent(AccessibilityEvent event) {
            Message.obtain(mHandler, MSG_EVENT, event).sendToTarget();
        }
    };
  5. 生命周期清理:在 onDestroy() 中调用 mHandler.removeCallbacksAndMessages(null),并置空回调引用。

4.8 验收标准

验收项通过条件
消息不丢失连续触发 1000 次事件,服务端 handleMessage 统计数与触发数一致
消息顺序事件 Timestamp 单调递增,无乱序
线程局部性在 handleMessage 中调用 Thread.currentThread() 始终等于主线程
无泄漏Service 销毁后,dumpsys meminfo 中无本 Service 残留对象
延迟从事件产生到 handleMessage 执行平均延迟 < 5ms(无 CPU 压力下)

4.9 核心设计图:Handler 跨线程消息投递与线程局部性

AccessibilityService Handler 跨线程消息投递结构 SystemServer AccessibilityManagerService Binder 线程池 (跨进程调用) Binder 回调 AccessibilityService Binder 代理 (执行 onAccessibilityEvent) Handler (主线程Looper) .sendMessage() MessageQueue (串行队列) Looper.loop() (取出消息) handleMessage() (执行无障碍逻辑) 线程局部性保证 • Handler 绑定主线程 Looper • 所有消息在主线程串行处理 • Binder 线程仅做消息投递 • 生命周期内 Looper 唯一且不中断 风险提示:Handler 内部类需使用静态类 + WeakReference,否则 Service 销毁时消息队列残留导致内存泄漏

4.10 关键实现要点

  • 静态 Handler 类:始终将 Handler 声明为静态内部类,并通过 WeakReference<AccessibilityService> 持有外部引用,防止内存泄漏。
  • 消息对象复用:使用 Message.obtain() 避免大量创建短生命周期对象,减轻 GC 压力。
  • 批量事件 coalesce:对于高频事件(如 TYPE_TOUCH_EXPLORATION_GESTURE_END),可在 Handler 中设置 removeMessages(MSG_EVENT) 后重新发送,丢弃过期消息。
  • 调试日志:在 handleMessage 入口和出口打印线程 ID 与消息类型,用于验证线程局部性。

总结:Handler 在无障碍服务中扮演着「事件脱耦合器」的角色——它解耦了 Binder 线程的同步调用与主线程的异步处理,同时通过 Looper 保证了线程局部性和消息顺序。正确创建和管理 Handler,是构建稳定、无泄漏无障碍服务的基石。