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 !== void 0 && 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 does not have color fill, shadow or blur');
    }if (!this._occludedBy_0.isEmpty()) {
      var occludedByIds = joinToString(this._occludedBy_0, ', ', void 0, void 0, void 0, void 0, 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');
    return copyToArray(reasons);
  }});

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

  Object.defineProperty(Layer.prototype, 'hasEffects', {configurable: true, get: function () {
    if (this.isColorLayer) {
      return true;
    }return this.isEffectLayer && (this.fillsColor || this.drawsShadows);
  }});
  Object.defineProperty(Layer.prototype, 'isBufferLayer', {configurable: true, get: function () {
    return equals(this.type, 'BufferStateLayer') || equals(this.type, 'BufferQueueLayer');
  }});
  Object.defineProperty(Layer.prototype, 'isColorLayer', {configurable: true, get: function () {
    return equals(this.type, 'ColorLayer');
  }});
  Object.defineProperty(Layer.prototype, 'isContainerLayer', {configurable: true, get: function () {
    return equals(this.type, 'ContainerLayer');
  }});
  Object.defineProperty(Layer.prototype, 'isEffectLayer', {configurable: true, get: function () {
    return equals(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);
  }});
  function Layer$get_Layer$visibilityReason$lambda(it) {
    return it.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实战干货,请关注下面“千里马学框架”

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

千里马学框架

帮助你了,就请我喝杯咖啡

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值