ANR之RenderThread不可中断睡眠state=D

text 复制代码
 
"main" prio=5 tid=1 Native
  | group="main" sCount=1 dsCount=0 flags=1 obj=0x71db4b38 self=0xb40000770ebf27b0
  | sysTid=26519 nice=0 cgrp=foreground sched=0/0 handle=0x789581f4f8
  | state=S schedstat=( 189056125728 54507506891 540673 ) utm=12710 stm=6195 core=1 HZ=100
  | stack=0x7feb3d3000-0x7feb3d5000 stackSize=8192KB
  | held mutexes=
  native: #00 pc 000000000004b4cc  /apex/com.android.runtime/lib64/bionic/libc.so (syscall+28)
  native: #01 pc 000000000004f0b4  /apex/com.android.runtime/lib64/bionic/libc.so (__futex_wait_ex(void volatile*, bool, int, bool, timespec const*)+144)
  native: #02 pc 00000000000af2b4  /apex/com.android.runtime/lib64/bionic/libc.so (pthread_cond_wait+60)
  native: #03 pc 0000000000221054  /system/lib64/libhwui.so (android::uirenderer::renderthread::DrawFrameTask::postAndWait()+252)
  native: #04 pc 0000000000204c60  /system/lib64/libhwui.so (android::android_view_ThreadedRenderer_syncAndDrawFrame(_JNIEnv*, _jobject*, long, _jlongArray*, int)+84)
  at android.graphics.HardwareRenderer.nSyncAndDrawFrame(Native method)
  at android.graphics.HardwareRenderer.syncAndDrawFrame(HardwareRenderer.java:433)
  at android.view.ThreadedRenderer.draw(ThreadedRenderer.java:658)
  at android.view.ViewRootImpl.draw(ViewRootImpl.java:4117)
  at android.view.ViewRootImpl.performDraw(ViewRootImpl.java:3844)
  at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:3115)
  at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1959)
  at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:8191)
  at android.view.Choreographer$CallbackRecord.run(Choreographer.java:972)
  at android.view.Choreographer.doCallbacks(Choreographer.java:796)
  at android.view.Choreographer.doFrame(Choreographer.java:731)
  at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:957)
  at android.os.Handler.handleCallback(Handler.java:938)
  at android.os.Handler.dispatchMessage(Handler.java:99)
  at android.os.Looper.loop(Looper.java:223)
  at android.app.ActivityThread.main(ActivityThread.java:7705)
  at java.lang.reflect.Method.invoke(Native method)
  at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1001)
  
  
  "RenderThread" daemon prio=7 tid=2 Native
  | group="main" sCount=1 dsCount=0 flags=1 obj=0x131c1dc0 self=0x770ebf96f0
  | sysTid=26814 nice=-4 cgrp=foreground sched=0/0 handle=0x759001ecc0
  | state=D schedstat=( 169545217808 59675325470 756224 ) utm=10233 stm=6720 core=1 HZ=100
  | stack=0x758ff27000-0x758ff29000 stackSize=995KB
  | held mutexes=
  native: (backtrace::Unwind failed for thread 26814: Thread has not responded to signal in time)
  (no managed stack frames)

从 Android 系统线程的正常工作特性和该RenderThread的实际状态对比来看,此线程完全不正常,处于 "深度阻塞 + 高负载" 状态,是导致应用 ANR 的核心中间环节。以下从线程状态、耗时、调试信息三个维度拆解异常点:

一、先明确 RenderThread 的 "正常定位"

RenderThread是 Android 应用的专属渲染线程 (后台守护线程,daemon=true),职责是:

  1. 执行 UI 绘制指令(如 OpenGL ES 调用、图层合成、纹理加载);
  2. 与 GPU、显示驱动交互,完成 "主线程下发的渲染任务";
  3. 正常状态下应是 "短时运行 + 可调度 "------ 即大部分时间处于S(可中断睡眠,等待主线程的渲染指令)或R(运行态,执行渲染计算),且累计耗时与应用运行时间匹配(如运行 10 分钟,耗时通常几秒钟)。

二、此 RenderThread 的 3 个核心异常点

1. 线程状态state=D:不可中断睡眠(致命异常)

  • state=D的含义 :Linux 线程状态中的 "Uninterruptible Sleep(不可中断睡眠)",表示线程正在等待某个必须完成的资源 / 操作 (如硬件 IO 响应、内核锁释放、GPU 驱动反馈),此时即使系统发送调试信号(如SIGQUIT)也无法唤醒线程,只能等待资源就绪。

  • 正常 RenderThread 的状态

    • 等待渲染指令时:state=S(可中断睡眠,主线程下发指令后可立即唤醒);
    • 执行渲染计算时:state=R(运行态,短时占用 CPU/GPU);
  • 此线程的异常性state=D意味着 RenderThread "卡死后完全无响应"------ 既无法接收主线程的新渲染指令,也无法继续处理已有的渲染任务,直接导致主线程(等待渲染同步)阻塞。

2. 调度耗时schedstat:超 200 秒累计耗时 + 高内核态占比(严重负载异常)

schedstat字段格式:(用户态耗时ns, 内核态耗时ns, 被调度次数),换算后:

指标 数值(换算后) 正常范围(前台应用) 异常分析
累计用户态耗时 169545217808ns ≈ 169s 与应用运行时间匹配(如 10 分钟运行≈5s) 用户态耗时高:说明线程频繁执行渲染计算(如列表项绘制、图片解码),但因 CPU 被抢占(其他进程占 44% CPU),计算过程被反复打断,耗时被拉长;
累计内核态耗时 59675325470ns ≈ 59.7s 通常占总耗时的 5%-10% 内核态耗时占比 30%(59.7/229.2):说明线程频繁调用内核接口(如 GPU 驱动交互、显存分配),且每次调用都被阻塞(如 GPU 忙、驱动响应慢),属于 "内核级阻塞";
被调度次数 756224 次 运行 10 分钟≈1-2 万次 调度频繁但执行效率极低:每次被调度后,要么因 CPU 不足无法执行,要么因等待硬件资源(GPU)再次进入阻塞,导致 "调度次数多但实际渲染进度慢"。

3. Backtrace Unwind 失败:线程无响应调试信号(深度阻塞)

  • 正常情况 :Android ANR 文件会打印RenderThreadnative调用栈(如调用了libGLESv2_adreno.so(GPU 驱动库)、libhwui.so(Android 渲染库)的哪些函数),帮助定位具体阻塞点(如卡在 "GPU 纹理上传" 还是 "图层合成");
  • 此线程的异常backtrace::Unwind failed for thread 26814: Thread has not responded to signal in time------ 系统尝试发送SIGQUIT信号获取线程栈,但线程处于state=D(不可中断),完全无法响应信号,导致 "无法定位具体阻塞的渲染步骤";
  • 隐含问题state=D下的线程不仅 "无法处理业务任务(渲染)",连 "调试信号" 都无法响应,属于深度无响应状态,是线程阻塞的极端情况。

三、异常的连锁影响:直接导致主线程阻塞

结合之前 ANR 分析的 "主线程卡在syncAndDrawFrame"(等待渲染同步),此RenderThread的异常会形成 "死等链":

  1. 主线程在MusicPlayingListActivity下发 "列表渲染指令" 给RenderThread
  2. RenderThread因 "CPU 被抢占 + GPU 资源忙" 进入state=D,无法执行渲染;
  3. 主线程需等待RenderThread完成渲染后才能调用syncAndDrawFrame同步结果,导致主线程被 "卡死";
  4. 主线程被卡死→无法处理用户的DOWN触摸事件→等待 5 秒后触发 "输入分发超时 ANR"。

四、总结:此 RenderThread 的异常性质

它不是 "正常负载高",而是 "阻塞性异常"------ 核心问题不是 "渲染任务多",而是 "任务无法被执行(CPU/GPU 资源被抢占)+ 线程自身陷入不可中断状态",最终成为 ANR 的 "关键导火索"。

相关推荐
煤球王子2 小时前
简单学:Android14中的Bluetooth—PBAP下载
android
小趴菜82272 小时前
安卓接入Max广告源
android
齊家治國平天下2 小时前
Android 14 系统 ANR (Application Not Responding) 深度分析与解决指南
android·anr
ZHANG13HAO2 小时前
Android 13.0 Framework 实现应用通知使用权默认开启的技术指南
android
【ql君】qlexcel2 小时前
Android 安卓RIL介绍
android·安卓·ril
写点啥呢2 小时前
android12解决非CarProperty接口深色模式设置后开机无法保持
android·车机·aosp·深色模式·座舱
IT酷盖2 小时前
Android解决隐藏依赖冲突
android·前端·vue.js
努力学习的小廉4 小时前
初识MYSQL —— 数据库基础
android·数据库·mysql
风起云涌~4 小时前
【Android】浅谈androidx.startup.InitializationProvider
android