3. 实时线程优先级配置

3.1 调优目标

在实时音视频、传感器数据处理、播放渲染等场景中,线程的响应优先级直接决定端到端延迟。调优的核心目标在于:

  • 降低调度时延:关键线程(如音频回调、GPU提交)必须优先获得时间片,避免被普通后台线程抢占。
  • 保证确定性:在负载波动时,实时线程的调度延迟波动应小于 1ms 级别。
  • 避免优先级反转:当实时线程等待低优先级锁时,需通过优先级继承或天花板协议恢复。
经验值:Android 平台下,音频渲染线程优先级通常需设置为 THREAD_PRIORITY_URGENT_AUDIO(-19),但该值仍低于 Linux 实时范围(1~99)。如需硬实时能力,必须使用 SCHED_FIFO 或 SCHED_RR 并结合 root/CAP_SYS_NICE 权限。

3.2 接口对比:sys.setpriority vs setThreadPriority

Android 提供两层优先级设置接口:Java 层 setThreadPriority 和 Native 层 sys/setpriority() 系统调用。两者在能力、范围和权限约束上存在显著差异:

维度setThreadPriority (Java)sys.setpriority (Native)
调用层次Java API → JNI → libcutils → syscall直接调用 glibc 封装
优先级范围-20(最高)~ 19(最低),仅 nice 值-20~19 且支持 SCHED_FIFO/SCHED_RR(通过 sched_setscheduler)
线程粒度仅作用于调用线程可指定进程/进程组/用户
权限要求普通 app 可设置降低优先级(正整数),但不能提高(负值)设置 nice 值需要 CAP_SYS_NICE 或 root;实时策略需要 root
典型错误无返回值,静默失败返回 -1 并设置 errno
// Java 层 – 设置线程为最高音频优先级
android.os.Process.setThreadPriority(
    android.os.Process.THREAD_PRIORITY_URGENT_AUDIO);

// Native 层 – 设置当前线程为实时 FIFO 优先级 90(需 root)
#include <sys/resource.h>
#include <sched.h>

struct sched_param param = { .sched_priority = 90 };
if (sched_setscheduler(0, SCHED_FIFO, ¶m) == -1) {
    perror("sched_setscheduler failed");
}

3.3 权限限制深入分析

Android 对实时优先级施加了严格的访问控制,主要分为两类:

  • nice 值限制:普通应用只能将 nice 值调高(降低优先级),调低(提高优先级)需要 android.permission.SET_PROCESS_LIMIT 或系统签名。即使有权限,也不允许低于 -10(Android 9+ 限制)。
  • 实时调度策略限制:SCHED_FIFO / SCHED_RR 需要 CAP_SYS_NICE 能力。该能力仅授予系统进程(如 audioserver、mediaserver)和具有 root 权限的 ADB shell。
常见陷阱:setThreadPriority 设置负值时 不会抛出异常,但实际不会生效。许多开发者调用后发现延迟无改善却不知原因,务必通过 cat /proc/<pid>/task/<tid>/stat 检查优先级字段(第 19 列)验证。
调优检查流程:
  1. 确认线程需要的是 nice 值优化还是实时调度策略。
  2. 若为实时策略,确保进程运行于 system UID 或具有 CAP_SYS_NICE。
  3. 调用后读取 /proc/self/task/[tid]/sched 中的 policy 和 rt_priority 验证。
实时线程优先级设置流程与权限校验 Java setThreadPriority Native sys.setpriority JNI / syscall 内核权限检查 CAP_SYS_NICE / Android 权限 允许:应用优先级 拒绝:静默丢弃 CFS / RT 调度器 按优先级分配时间片 注意 nice 值可绕过权限? 否,调低同样需权限 推荐方式 使用 C++ SDK 调用 sched_setscheduler

3.4 缺陷排查与验证命令

# 查看指定线程的调度策略与实时优先级
adb shell cat /proc/`pid`/task/`tid`/sched

# 仅查看 nice 值(第19列)
adb shell cat /proc/`pid`/task/`tid`/stat | awk '{print $19}'

# 动态修改测试(需 root)
adb shell chrt -f -p 90 `tid`
adb shell chrt -p `tid`