当前位置: 首页 > news >正文

Winscope高级疑问“Invisible due to”是如何来的呢?

背景:

在vip群中有学员朋友提出一个问题:
Winscope使用分析黑屏问题时候一个疑问,针对这个Winscope上面可以直接看Layer为啥不显示原因时候有展示一个““Invisible due to”。

可以看到学员朋友的这个黑屏问题原因是Invisible due to: null visible region,
学员就是对这个“null visible region”不太理解。
其实针对学员这个问题都还比较好解释,null visible region其实字面意思就是代表当前的Layer没有可以显示的区域,具体我这边也没有相关的设备和Winscope实际查看,大概猜想应该有2种原因,一种是Layer自身可能没有显示区域,第二种就是可能Layer可能被全覆盖啥的。

不过其实这个问题引发更大疑问那就是请问Winscope的Invisible due to的数据到底是哪里来的?到底应该去哪里调查这个Invisible due to数据来源?
下面开始剖析这个Invisible due to来源问题。

先Winscope本质原理展示

老版本就是跨进程调用SurfaceFlinger的1025接口,把相关proto数据导出到文件中,新版本变成Perfetto了,其实也是差不多的,都是SurfaceFlinger本身提供数据源头。

WinscopeFileMatcher(WINSCOPE_DIR,"layers_trace","layers_trace"),'su root service call SurfaceFlinger 1025 i32 1\necho "SF trace started."','su root service call SurfaceFlinger 1025 i32 0 >/dev/null 2>&1'

所以说SurfaceFlinger本质上只是提供这些Layer的原始数据,并不会对这些数据进行额外的处理判断逻辑。
那么这里的网页展示的“Invisible due to”就应该去html前端展示代码中调查。

源码分析部分:

因为新版本aosp15的Winscope的html都是需要nodejs才可以拉起运行了,所以这里为了方便分析,拿一个aosp13的Winscope的html,因为这个版本的html是可以直接离线运行,所有的前端核心代码逻辑都在html中。

源码分析切入点,可以考虑直接在html文件中搜“Invisible due to”这个关键字

if(layer!==null&&layer!==void0&&layer.visibilityReason){var reason="";if(Array.isArray(layer.visibilityReason)){reason=layer.visibilityReason.join(", ");}else{reason=layer.visibilityReason;//这里是理由数据来源赋值}summary.push({key:'Invisible due to',value:reason//这里是理由});}

上面可以看出这里主要就要看layer的visibilityReason这个变量,下面搜这个关键字“visibilityReason”就可以查到如下这块相关代码:

//这里是visibilityReason核心的设置部分Object.defineProperty(Layer.prototype,'visibilityReason',{configurable:true,get:function(){var tmp$,tmp$_0,tmp$_1;if(this.isVisible){return[];}var reasons=ArrayList_init();if(this.isContainerLayer)reasons.add_11rb$('ContainerLayer');if(this.isHiddenByPolicy)reasons.add_11rb$('Flag is hidden');if(this.isHiddenByParent){reasons.add_11rb$('Hidden by parent '+toString((tmp$=this.parent)!=null?tmp$.name:null));}if(this.isBufferLayer&&this.isActiveBufferEmpty)reasons.add_11rb$('Buffer is empty');if(this.color.isEmpty)reasons.add_11rb$('Alpha is 0');if(((tmp$_0=this.crop)!=null?tmp$_0.isEmpty:null)===true)reasons.add_11rb$('Crop is 0x0');if(this.bounds.isEmpty)reasons.add_11rb$('Bounds is 0x0');if(!this.transform.isValid)reasons.add_11rb$('Transform is invalid');if(this.isRelativeOf&&this.zOrderRelativeOf==null){reasons.add_11rb$('RelativeOf layer has been removed');}if(this.isEffectLayer&&!this.fillsColor&&!this.drawsShadows&&!this.hasBlur){reasons.add_11rb$('Effect layer doesnothave color fill,shadoworblur');}if(!this._occludedBy_0.isEmpty()){var occludedByIds=joinToString(this._occludedBy_0,', ',void0,void0,void0,void0,Layer$get_Layer$visibilityReason$lambda);reasons.add_11rb$('Layer is occluded by: '+occludedByIds);}if(((tmp$_1=this.visibleRegion)!=null?tmp$_1.isEmpty:null)===true){reasons.add_11rb$('Visible region calculated by Composition Engine is empty');}if(reasons.isEmpty())reasons.add_11rb$('Unknown');returncopyToArray(reasons);}});

那么这些具体理由变量又是哪里来的呢?也可以查到如下代码,下面代码就是html中解析layer等数据后,根据layer数据变量等进行相关判断得出。

Object.defineProperty(Layer.prototype,'hasEffects',{configurable: true, get:function(){if(this.isColorLayer){returntrue;}return this.isEffectLayer&&(this.fillsColor||this.drawsShadows);}});Object.defineProperty(Layer.prototype,'isBufferLayer',{configurable: true, get:function(){returnequals(this.type,'BufferStateLayer')||equals(this.type,'BufferQueueLayer');}});Object.defineProperty(Layer.prototype,'isColorLayer',{configurable: true, get:function(){returnequals(this.type,'ColorLayer');}});Object.defineProperty(Layer.prototype,'isContainerLayer',{configurable: true, get:function(){returnequals(this.type,'ContainerLayer');}});Object.defineProperty(Layer.prototype,'isEffectLayer',{configurable: true, get:function(){returnequals(this.type,'EffectLayer');}});Object.defineProperty(Layer.prototype,'isHiddenByParent',{configurable: true, get:function(){var tmp$, tmp$_0;return!this.isRootLayer&&(((tmp$=this.parent)!=null ? tmp$.isHiddenByPolicy:null)===true||((tmp$_0=this.parent)!=null ? tmp$_0.isHiddenByParent:null)===true);}});functionLayer$get_Layer$visibilityReason$lambda(it){returnit.id.toString();}

比如这里以isHiddenByParent变量为例子,就是靠layer的一系列判断决定,具体可以看它的判断逻辑。

!this.isRootLayer&&(((tmp$=this.parent)!=null ? tmp$.isHiddenByPolicy:null)===true||((tmp$_0=this.parent)!=null ? tmp$_0.isHiddenByParent:null)===true);

上面Winscope.html文件在马哥的wms课程中有提供。

更多fw实战干货,请关注下面“千里马学框架”

http://www.jsqmd.com/news/463222/

相关文章:

  • HoRain云--Python爬虫必看:NoneType错误终极解决指南
  • 3种方法:如何将PPT文件变成PPS放映格式
  • 多租户数据隔离实战:衡石科技如何保障企业级SaaS服务的数据安全?
  • 论文人狂喜!Paperxie 界面深度拆解:毕业论文初稿 + 绘图 + 排版 + AI 率,一个页面全搞定
  • HoRain云--MySQL锁机制:高并发与数据安全艺术
  • 论文写作新范式:Paperzz 如何破解毕业论文初稿、绘图、排版与 AI 率四大难题
  • 【游戏设计】潜行游戏
  • 2026 毕业论文破局指南:Paperzz 一站式搞定初稿、绘图、排版与 AI 率,告别毕业季焦虑
  • 消费增值:商业新赛道上绿色积分的“王者”
  • ssm+java2026年毕设商场后台管理系统【源码+论文】
  • 拒绝 API 堆砌:当“AI 龙虾”打破传统软件工程的确定性边界
  • 孩子沉迷手机不用愁!oppo远程管控vivo,家长高效兼顾工作和管娃
  • 音视频对齐 webrtc解决方案
  • 01---js基础
  • Python 底层调试和性能分析的高级技巧,主要用于解决 C 扩展、解释器内核级别的问题,或者对 Python 程序进行深度性能剖析
  • Matlab _ Simulink仿真设计 自动化,电气工程和电子信息相关专业仿真都可电力电子仿真,整流逆变电路仿真,电机双闭环调速、模糊 PID 仿真, LQR 仿真,风力发电、光储微电网系统、电机
  • 工业架构实战:打通MES与AGV机器人梯控系统的通信与状态机设计
  • 图像算法中难样本优化策略
  • 云端部署避坑指南:OpenClaw 3.2 接入 DeepSeek、Kimi 与通义千问的深度复盘
  • ssm+java2026年毕设商超零售送货到家购物系统【源码+论文】
  • 一文理清端口、ARP、ICMP、CDN 核心逻辑,新手也能轻松入门(兼顾通俗与专业)
  • 2026新疆中央空调优质服务商推荐指南 - 优质品牌商家
  • matlab anybody opensim包括人机耦合建模、缩放、运动学_逆动力学分析,以及自由度扩建、肌肉重建、RRA_CMC仿真,从理论到代码手把手教会运动生物力学数据代处理、辅导
  • B级数据中心机房建设规划设计方案(PPT文件)
  • 告别论文焦虑:PaperXie 手把手带你搞定毕业论文初稿,绘图排版 AI 率一步到位
  • 可视挖耳勺怎么选择?可视挖耳勺哪个品牌好?挖耳勺推荐避坑!
  • 南京,无锡,上海等六大城市高端腕表维修去哪里:劳力士/欧米茄等品牌养护+正规门店实测推荐 - 时光修表匠
  • 下载 DeepSeek 代码并训练专属模型参数(全流程指南)
  • 颗粒度检测仪品牌推荐 西恩士工业实力出圈成优选 - 技术权威说
  • 看懂 DeepSeek 源码:从「能跑」到「吃透」的阶梯式指南