第2章 主线程与工作线程划分

单线程串行事件处理是AOSP无障碍服务默认的线程模型核心前提。AccessibilityService实例的所有生命周期回调、事件分发、onAccessibilityEvent()和onInterrupt()均委派给单一的主线程(通常称为main thread)。这一设计大幅降低了内部状态管理的复杂度,但也在长时间操作或阻塞调用场景下直接导致ANR风险。工作线程划分的目标正是将耗时计算、IO、模型推理等任务剥离出主线程,同时保持事件顺序和UI响应性。

2.1 边界定义

维度 主线程边界 工作线程边界
负责的生命周期 onServiceConnected(), onAccessibilityEvent(), onInterrupt(), onUnbind() 自定义任务(解析、过滤、推理、日志)
数据所有权 短期事件对象(AccessibilityEvent引用) 派生数据(结构化记录、缓存快照)
可访问资源 UI树、AccessibilityService本身 数据库、网络、本地模型文件
必须避免的操作 阻塞、锁竞争、内存分配循环 直接修改AccessibilityService状态

2.2 分层与组件职责

  • 主线程层:运行系统创建的ActivityThread主Looper,负责事件入队、分发、轻量预处理及最终UI反馈。通过Handler将工作线程结果回写到主线程。
  • 工作线程层:开发者自行管理,推荐使用ThreadPoolExecutor或HandlerThread。核心职责包括:结构化信息提取、NLP/OCR模型推理、本地数据持久化、远程上报。
  • 通信层:以Handler+MessageQueue为主线的异步消息传递机制。工作线程通过post/sendMessage将结果发送到主线程Handler,主线程通过obtainMessage发出任务指令。
🔑 关键原则:主线程只做事件分发与状态读取,所有耗时操作必须显式委托给工作线程;工作线程不持有AccessibilityService直接引用,只通过消息传递结果。
无障碍服务主线程与工作线程通信架构 主线程 Looper + Handler onAccessibilityEvent MessageQueue 有序消息队列 主线程Handler 工作线程池 ThreadPoolExecutor Worker-1 Worker-2 Worker-3 事件入队 工作线程消费 结果回调(post) ⚠️ 信任链路要求 工作线程必须通过主线程Handler投递结果,严禁直接修改AccessibilityService内部字段或UI树

2.3 数据流与控制流

  1. 控制流方向:SystemServer → AccessibilityService主线程 → Handler.sendMessage() → MessageQueue → 工作线程池 → 处理 → post Runnable → 主线程Handler → onAccessibilityEvent回调(已更新状态)。
  2. 数据流载体:主线程通过Message.obj或Bundle传递原始事件轻量拷贝;工作线程产出结构化结果(JSON、ProtoBuf或Entity),通过Handler.obtainMessage()回传。
  3. 信任链路:主线程只信任从工作线程投递的消息对象类型(强类型检查),工作线程不信任外部队列的未校验数据(输入净化是工作线程自身职责)。

2.4 选型权衡

方案 优点 缺点 适用场景
HandlerThread 天然序列化、避免竞态 单通道吞吐上限低 事件按序处理,任务量≤1000/秒
ThreadPoolExecutor 高并发、可调内核数 需要额外同步逻辑 CPU密集型OCR/ML推理,任务可并行
协程(Kotlin) 轻量、结构化并发 依赖协程上下文切换,调试复杂 Android 12+ 新项目,团队熟悉协程
WorkManager 延迟可靠、保活性强 不适合毫秒级实时响应 日志上报、离线分析等非实时后台任务
⚠️ 风险点:
• 主线程饥饿:工作线程若频繁向主线程post大量高优先级任务,会导致事件分发延迟,引发ANR预兆(InputDispatcher超时)。
• 死锁:主线程等待工作线程结果时,工作线程又等待主线程释放锁。
• 竞态条件:多个工作线程同时更新主线程Handler消息序列时,若未使用synchronized或Handler.sendMessageAtFrontOfQueue滥用,造成事件乱序。
• 线程泄漏:工作线程持有Context或Handler隐式引用,导致AccessibilityService无法被GC回收。

2.5 落地步骤

  1. 识别边界操作:审计onAccessibilityEvent中的所有方法调用,耗时超过5ms的标记为“工作线程候选”。
  2. 定义线程模型:根据并发需求选择HandlerThread或ThreadPoolExecutor,核心参数配置在onServiceConnected中初始化。
  3. 实现通信适配器:封装MainHandler单例,提供postToWorker()和postResult()方法。
  4. 编写单元测试:使用Robolectric模拟主线程Looper,验证工作线程任务是否在预期线程执行,消息投递是否有序。
  5. 上线前压力测试:模拟高频事件流(200次/秒),确保工作线程池未打满、主线程消息队列长度稳定在<100。

2.6 验收标准

  • ✅ onAccessibilityEvent中无任何阻塞调用(sleep()、同步IO、Future.get())。
  • ✅ 工作线程池线程数稳定,无内存泄漏(通过LeakCanary验证Activity/Service泄漏)。
  • ✅ 主线程ANR触发阈值(5秒)下,事件处理延迟不超过30ms。
  • ✅ 所有工作线程结果回传使用Handler.post(),不存在直接修改AccessibilityService实例的情况。
  • ✅ 线程间通信覆盖Message.what、Message.obj、Runnable三种模式,异常传递(RemoteException)有统一兜底。