第1章 AOSP线程模型全景

Android 系统的线程模型是构建稳定、高性能系统的基石。AOSP(Android Open Source Project)中,线程贯穿从 Linux 内核调度到 Android 运行时(ART)、再到应用框架层的每一个模块。理解线程分类、优先级范围、调度策略、进程上下文以及核心/辅助线程的划分,是掌握线程调度与模块边界控制的前提。

学习目标:在本章结束时,你应当能准确描述 AOSP 中六类主要线程的用途,解释 nice 值与实时优先级的差异,并能在 procfs 中确认任意线程的调度策略与优先级。
AOSP 线程模型全景分层结构 AOSP 线程模型全景分层结构 Linux 内核调度器(SCHED_NORMAL / SCHED_FIFO / SCHED_RR / CFS) AOSP 关键进程(system_server / surfaceflinger / audioserver / mediaserver / zygote) 每个进程拥有独立的进程上下文、线程池、虚拟内存空间 核心线程(Core Threads) 主线程(UI Thread) Binder 主线程(binder_1, binder_2) 关键服务线程(Watchdog, IO 调度) 实时事件处理线程(Input Reader) 需高优先级 / 实时策略保障 辅助线程(Auxiliary Threads) Handler 异步工作线程 后台任务线程(AsyncTask, WorkManager) GPU 渲染线程(RenderThread) JIT / GC 编译线程 通常使用 SCHED_NORMAL,低 nice 值 调度策略转换点 (通过 sched_setscheduler) 每线程调度元数据:nice 值、sched_policy、cgroup 分组、cpu 亲和性 可通过 /proc/[pid]/task/[tid]/sched 实时查看

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)