Android冻屏

adb shell dumpsys window windows > window.txt

过滤 has_drawn

mDrawState 是 Android 窗口管理服务(WMS)中,用来描述窗口绘制状态的关键变量,它有几个典型值:

  • NO_SURFACE:窗口还没有创建 Surface
  • COMMIT_DRAW_PENDING:窗口绘制请求已提交,但还没完成
  • READY_TO_SHOW:绘制已提交,Surface 还没显示
  • HAS_DRAWN :窗口首次绘制完成,且内容已经成功上屏显示,处于稳定可见状态

窗口还没画出来(HAS_DRAWN 状态为 false)

窗口已经画出来了(HAS_DRAWN 状态为 true)

怎么看哪个窗口在最顶端

字段 含义 作用
layer 窗口的 Z 轴层级值 越大越靠上,同一屏幕上层级最高的窗口就是最顶端的
type 窗口类型(Window Type) 系统窗口(如悬浮窗、系统弹窗)默认层级高于普通应用窗口
isOnScreen / visible 窗口是否可见且在屏幕上 只有同时为 true 的窗口,才会实际参与显示层级排序

二、结合你的日志,教你一步步定位最顶端窗口

我们用你截图里的日志举例,手把手拆解:

1. 先看 layer 值:谁的数字大,谁就在最上面

你日志里的这一行:

Surface: shown=true layer=0 alpha=1.0 rect=(0.0,0.0) transform=(1.0, 0.0, 0.0, 0.0, 1.0)

规则:

  • 日志里所有窗口的 layer 值,数值越大,Z 轴越靠上,显示优先级越高
  • 比如 A 窗口 layer=10,B 窗口 layer=5,那么 A 窗口一定在 B 窗口的上面。

注意:部分日志会用负数表示层级(比如 layer=-1 表示在底层),但核心逻辑不变:数值越大越靠上

2. 再看窗口类型 type:特殊窗口天生优先级更高

你日志里的关键信息:

这里的 ty=APPLICATION_OVERLAY(即 TYPE_APPLICATION_OVERLAY)是悬浮窗 / 系统覆盖窗口类型 ,它的层级天生就高于普通的 APPLICATION 类型窗口,哪怕 layer 值看起来不大,也会盖在普通应用窗口上面。

常见窗口类型优先级(从高到低):

  1. 系统级窗口(如状态栏、系统弹窗、Toast)
  2. APPLICATION_OVERLAY 悬浮窗 / 系统警告窗口
  3. 普通应用的 Activity 窗口
  4. 应用内部的 Dialog/Toast

3. 排除不可见窗口:只看 shown=true + isOnScreen=true

日志里这两个字段:

cpp 复制代码
Surface: shown=true
isOnScreen=true
isVisible=true

三、给你一个通用的排查步骤

  1. 过滤有效窗口 :先筛出所有 shown=trueisOnScreen=trueisVisible=true 的窗口,排除不可见的。
  2. layer 排序 :把这些窗口按 layer 值从大到小排序,第一个就是当前层级最高的窗口。
  3. 结合窗口类型二次确认 :如果有 APPLICATION_OVERLAY、系统窗口类型,优先级默认高于普通应用窗口,哪怕 layer 值相同,也会盖在上面。
  4. zOrder 字段(部分日志有) :部分 WMS 日志会直接输出 zOrder,值越大越靠上,直接看最大值即可。

还可以看

adb shell dumpsys SurfaceFlinger > Surface

过滤 focesed

一、先搞懂 dumpsys SurfaceFlinger 输出的核心结构

这个命令输出的日志,核心是SurfaceFlinger(Android 的屏幕合成服务)当前的图层列表,决定了屏幕上每个窗口的绘制顺序和最终显示效果。

关键信息分为两部分:

  1. 图层列表(Layers):每个 Surface(窗口)的层级、状态、大小、透明度
  2. 合成状态:是否在刷新、是否合成成功,直接关联冻屏问题

二、结合你的日志,手把手分析

你的截图里就是典型的 SurfaceFlinger 图层列表,我们一行行拆解:

1. 每一行代表一个图层(Surface)

格式是固定的:rel 0 | [PID] | CLIENT | 0 | [视口/大小] | [位置/透明度] | [标记]

举你日志里的例子:

cpp 复制代码
com.android.launcher3/...QuickstepLauncher#363
rel 0 | 1 | CLIENT | 0 | 0 1440 2960 | 0.0 0.0 1440.0 2960.0 | []
  • com.android.launcher3/...:图层所属的包名 / 窗口,这里是桌面 Launcher
  • #363:图层的唯一 ID,后续可以用它关联 WMS 日志
  • rel 0:相对层级(rel = relative z-order),数字越大越靠上
  • 1:进程 PID,Launcher 的进程号是 1(system_server 进程)
  • 0 1440 2960:图层的大小,这里是 1440×2960(全屏桌面)
  • 0.0 0.0 1440.0 2960.0:图层在屏幕上的位置(从 (0,0) 到 (1440,2960),全屏)
  • []:图层标记,空表示正常,[*] 表示该图层是当前的 "脏区域"(需要刷新)

2. 关键判断点:谁在最顶端?

看两个核心字段:

(1)rel(相对层级)

rel 就是图层的 Z 轴顺序,数值越大,越靠上。你日志里的图层:

  • Launcher:rel 0
  • 你的 App Sys2038:com.example.mysystemdialog.MainActivity#361rel 0
  • 你的 App Sys2038:com.example.mysystemdialog.MainActivity#372rel 0
  • 状态栏 StatusBar#80rel 0
  • 导航栏 NavigationBar0#73rel 0

⚠️ 这里的 rel 0 不代表层级相同,因为 dumpsys SurfaceFlinger 输出的图层列表是从上到下排序的

  • 日志里越靠下的行,层级越高,越在屏幕上方
  • 你日志里的顺序:Launcher → App#361 → App#372 → StatusBar → NavigationBar所以层级从低到高是:Launcher < App#361 < App#372 < StatusBar < NavigationBar也就是NavigationBar(导航栏)在最顶端,其次是状态栏,然后是你的两个 App 窗口
(2)[*] 标记

你日志里 App#372 这一行:

这里的 [*] 表示:这个图层是当前需要刷新的脏区域 ,也就是 SurfaceFlinger 正在处理的图层。如果冻屏时,只有这个图层一直带 [*] 但没有后续刷新,说明:

  • 你的 App 提交了刷新请求,但 SurfaceFlinger 没有合成成功,或者 App 没有继续提交新的帧。

3. 结合冻屏问题,重点看这几个状态

(1)图层是否存在且显示
  • 如果你的 App 图层不在列表里,说明窗口已经被销毁,冻屏和它无关。
  • 如果图层存在,但 alpha=0visible=false(部分版本日志会显示),说明窗口被隐藏,也不会导致冻屏。
(2)是否有新的帧提交

正常情况下,SurfaceFlinger 每 16ms 会刷新一次图层列表。如果冻屏时,你的 App 图层的位置、大小、标记一直不变,说明:

  • App 主线程阻塞,无法生成新的帧
  • App 的 Surface 被意外销毁,无法提交新的 Buffer
  • SurfaceFlinger 合成卡住,没有把新的帧刷到屏幕上

过滤掉 无法触摸页面

相关推荐
abcnull17 小时前
用javaparser做精准测试
java·ast·静态代码分析·精准测试·javaparser
叶小鸡17 小时前
Java 篇-项目实战-苍穹外卖-笔记汇总
java·开发语言·笔记
AI人工智能+电脑小能手17 小时前
【大白话说Java面试题】【Java基础篇】第22题:HashMap 和 HashSet 有哪些区别
java·开发语言·哈希算法·散列表·hash
juniperhan17 小时前
Flink 系列第21篇:Flink SQL 函数与 UDF 全解读:类型推导、开发要点与 Module 扩展
java·大数据·数据仓库·分布式·sql·flink
ID_1800790547317 小时前
Python 实现亚马逊商品详情 API 数据准确性校验(极简可用 + JSON 参考)
java·python·json
c++之路18 小时前
C++23概述
java·c++·c++23
专注API从业者19 小时前
Open Claw 京东商品监控选品实战:一键抓取、实时监控、高效选品
java·服务器·数据库
liang_jy19 小时前
Android View Tag
android
摇滚侠19 小时前
DBeaver 导入数据库 导入 SQL 文件 MySQL 备份恢复
java·数据库·mysql