第1章 AOSP线程模型全景
Android 系统的线程模型是构建稳定、高性能系统的基石。AOSP(Android Open Source Project)中,线程贯穿从 Linux 内核调度到 Android 运行时(ART)、再到应用框架层的每一个模块。理解线程分类、优先级范围、调度策略、进程上下文以及核心/辅助线程的划分,是掌握线程调度与模块边界控制的前提。
学习目标:在本章结束时,你应当能准确描述 AOSP 中六类主要线程的用途,解释 nice 值与实时优先级的差异,并能在 procfs 中确认任意线程的调度策略与优先级。
1.1 线程分类
AOSP 中的线程按用途和创建来源可分为以下六类,每类线程在进程上下文、调度策略和优先级上均有显著差异。
| 线程分类 | 典型名称 | 所属进程示例 | 创建机制 | 调度策略/优先级 | 关键特征 |
|---|---|---|---|---|---|
| UI 主线程 | 主线程 (ActivityThread) |
应用进程、system_server | Zygote fork + ART 初始化 | SCHED_NORMAL nice 值通常为 0~-5 |
负责界面更新、触摸事件分发;阻塞会导致 ANR |
| Binder 线程 | Binder:xxx_1 Binder:xxx_2 |
所有使用 Binder 的服务进程 | libbinder 线程池自动创建(默认最大 16) | SCHED_NORMAL nice 值 0~-2 |
用于进程间通信(IPC);高并发场景可调整线程池数 |
| Handler 工作线程 | HandlerThread AsyncTask #1 |
应用进程、服务进程 | HandlerThread.start() | SCHED_NORMAL nice 值通常 10~19 |
处理 Looper 消息队列;优先级低,避免抢占主线程 |
| 实时事件线程 | InputReader SensorService |
system_server、surfaceflinger | 系统服务启动时创建 | SCHED_FIFO / SCHED_RR 优先级 1~99 |
处理触摸、传感器事件;需低抖动,避免丢帧 |
| 渲染线程 | RenderThread HWUIThread |
应用进程、surfaceflinger | HWUI 初始化创建 | SCHED_NORMAL nice 值 -1~-3 |
执行 GPU 绘制命令;与主线程异步协同 |
| 系统后台线程 | watchdog JIT 编译线程 GC 线程 |
system_server、zygote64 | ART / 系统服务创建 | SCHED_NORMAL / SCHED_BATCH nice 值 0~19 |
执行 GC、JIT、监控任务;可配置 CPU cgroup 限制 |
1.2 优先级范围与调度策略
AOSP 的线程调度基于 Linux 内核,但叠加了 Android 特有的 cgroup 和 sched_policy 抽象层。线程优先级通过 nice 值(-20~19)和 实时优先级(1~99)共同表达。
- SCHED_NORMAL(CFS 调度器):所有普通线程默认策略,nice 值范围 -20~19。系统默认 nice 值为 0。Android 通过
setpriority()或android.os.Process.setThreadPriority()调整。 - SCHED_FIFO / SCHED_RR(实时调度):实时线程使用,优先级 1~99,值越大优先级越高。仅具有
CAP_SYS_NICE能力的线程(如系统服务)可设置。AOSP 严格控制实时线程数量,防止锁死内核。 - SCHED_BATCH(批处理调度):适用于长时间运行的 CPU 密集型任务,不会抢占交互线程。nice 值范围与 SCHED_NORMAL 相同。
- SCHED_IDLE(空闲调度):仅当 CPU 空闲时才执行,常用于后台低优先级任务(如 GC 后台扫描)。
实践验证命令:查看任意进程的线程优先级与调度策略
# 查看 system_server 所有线程
adb shell ps -T -p `pidof system_server` | head -20
# 查看某个线程的调度详情 (例如 TID 12345)
adb shell cat /proc/12345/task/12345/sched
# 查看线程的 nice 值、调度策略、优先级
adb shell cat /proc/12345/task/12345/stat | awk '{print "nice=" $19 ", policy=" $41}'
# 使用 schedstat 查看线程的 CPU 运行时统计
adb shell cat /proc/12345/task/12345/schedstat
1.3 进程上下文与线程池组织
每个 AOSP 进程拥有独立的地址空间、文件描述符表、信号处理器和线程组。线程间共享进程级资源(堆、静态变量)。线程池的规模直接影响系统吞吐量和调度压力。
| 进程 | 典型线程数量 | 主要线程池 | 调度上下文 |
|---|---|---|---|
system_server |
60~120 | Binder 线程 16、Watchdog、SensorService、ActivityManager | 系统核心,高优先级,限制 cgroup 为 top-app |
surfaceflinger |
20~30 | Binder 线程 4、CompositionEngine、HWComposer 线程 | 实时帧合成,部分线程使用 SCHED_FIFO |
audioserver |
15~20 | AudioFlinger 工作线程、Effect 线程 | 音频回放,使用 SCHED_FIFO 避免 Xrun |
zygote |
30~50 | Binder 线程 8、GC 线程、JIT 编译线程 | 孵化应用进程,nice 值 0~10 |
| 普通应用进程 | 10~80 | 主线程、2~4 Binder 线程、RenderThread、AsyncTask | 受 cgroup foreground 或 background 限制 |
1.4 核心线程与辅助线程
核心线程是进程赖以正常工作的关键线程,其延迟或阻塞会直接导致功能异常(如 ANR、丢帧、音频卡顿)。辅助线程负责后台计算、缓存刷新、编译优化等非关键任务,允许在 CPU 负载高时被降速或抢占。
- 核心线程识别准则:
- 其阻塞会导致用户可感知的 UI 冻结或系统服务超时。
- 通常设置略低于实时的高静态优先级(nice -5~0)或直接使用 SCHED_FIFO。
- 例如:主线程、InputReader、AudioFlinger 写线程、Composer 线程。
- 辅助线程管理策略:
- 优先使用低 nice 值(10~19)或 SCHED_BATCH。
- 通过
cpuset限制其运行在小核(LITTLE cluster)上。 - 利用
schedtune.boost或uclamp动态调整频率。
常见陷阱:在应用层通过
Process.setThreadPriority(Process.THREAD_PRIORITY_URGENT_DISPLAY) 将辅助线程优先级提升至 -4 以上,可能导致后台线程抢占主线程调度,引发 UI 卡顿。核心/辅助线程的优先级应保持清晰边界,避免滥用高优先级。
1.5 调试线程信息的实用命令
以下命令用于在开发阶段快速检查线程状态、优先级和调度策略。
# 1. 列出进程所有线程及 nice 值
adb shell ps -T -eo pid,tid,nice,comm | grep 'surfaceflinger\|system_server'
# 2. 获取线程的完整状态
adb shell cat /proc/$(pidof system_server)/task/12345/status | grep -E 'Name|State|Tgid|Pid'
# 3. 查看线程的 CPU 亲缘性
adb shell taskset -p 12345
# 4. 实时查看内核调度事件(仅限 eng/userdebug 版本)
adb shell su root perf trace -e sched:sched_switch -p $(pidof surfaceflinger)