背景:
在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实战干货,请关注下面“千里马学框架”

162

被折叠的 条评论
为什么被折叠?



