1 /* 2 * Copyright (C) 2022 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.wm.traces.parser.layers 18 19 import android.graphics.Rect 20 import android.surfaceflinger.nano.Common 21 import android.surfaceflinger.nano.Common.RegionProto 22 import android.surfaceflinger.nano.Display 23 import android.surfaceflinger.nano.Layers 24 import com.android.server.wm.traces.common.ActiveBuffer 25 import com.android.server.wm.traces.common.Color 26 import com.android.server.wm.traces.common.RectF 27 import com.android.server.wm.traces.common.Size 28 import com.android.server.wm.traces.common.layers.BaseLayerTraceEntry 29 import com.android.server.wm.traces.common.layers.Layer 30 import com.android.server.wm.traces.common.layers.LayerTraceEntryBuilder 31 import com.android.server.wm.traces.common.region.Region 32 33 class LayerTraceEntryLazy( 34 override val timestamp: Long, 35 override val hwcBlob: String = "", 36 override val where: String = "", 37 private val ignoreLayersStackMatchNoDisplay: Boolean = true, 38 private val ignoreLayersInVirtualDisplay: Boolean = true, 39 private var displayProtos: Array<Display.DisplayProto> = emptyArray(), 40 private var layerProtos: Array<Layers.LayerProto> = emptyArray(), 41 private val orphanLayerCallback: ((Layer) -> Boolean)? = null 42 ) : BaseLayerTraceEntry() { 43 <lambda>null44 private val parsedEntry by lazy { 45 val layers = layerProtos.map { newLayer(it) }.toTypedArray() 46 val displays = displayProtos.map { newDisplay(it) }.toTypedArray() 47 val builder = LayerTraceEntryBuilder(timestamp, layers, displays, hwcBlob, where) 48 .setOrphanLayerCallback(orphanLayerCallback) 49 .ignoreLayersStackMatchNoDisplay(ignoreLayersStackMatchNoDisplay) 50 .ignoreVirtualDisplay(ignoreLayersInVirtualDisplay) 51 displayProtos = emptyArray() 52 layerProtos = emptyArray() 53 builder.build() 54 } 55 56 override val displays: Array<com.android.server.wm.traces.common.layers.Display> 57 get() = parsedEntry.displays 58 59 override val flattenedLayers: Array<Layer> 60 get() = parsedEntry.flattenedLayers 61 62 companion object { 63 64 @JvmStatic newLayernull65 fun newLayer(proto: Layers.LayerProto): Layer { 66 // Differentiate between the cases when there's no HWC data on 67 // the trace, and when the visible region is actually empty 68 val activeBuffer = proto.activeBuffer.toBuffer() 69 var visibleRegion = proto.visibleRegion.toRegion() 70 if (visibleRegion == null && activeBuffer.isEmpty) { 71 visibleRegion = Region.EMPTY 72 } 73 val crop = getCrop(proto.crop) 74 return Layer( 75 proto.name ?: "", 76 proto.id, 77 proto.parent, 78 proto.z, 79 visibleRegion, 80 activeBuffer, 81 proto.flags, 82 proto.bounds?.toRectF() ?: RectF.EMPTY, 83 proto.color.toColor(), 84 proto.isOpaque, 85 proto.shadowRadius, 86 proto.cornerRadius, 87 proto.type ?: "", 88 proto.screenBounds?.toRectF(), 89 Transform(proto.transform, proto.position), 90 proto.sourceBounds?.toRectF() ?: RectF.EMPTY, 91 proto.currFrame, 92 proto.effectiveScalingMode, 93 Transform(proto.bufferTransform, position = null), 94 proto.hwcCompositionType, 95 proto.hwcCrop.toRectF() ?: RectF.EMPTY, 96 proto.hwcFrame.toRect(), 97 proto.backgroundBlurRadius, 98 crop, 99 proto.isRelativeOf, 100 proto.zOrderRelativeOf, 101 proto.layerStack 102 ) 103 } 104 newDisplaynull105 fun newDisplay( 106 proto: Display.DisplayProto 107 ): com.android.server.wm.traces.common.layers.Display { 108 return com.android.server.wm.traces.common.layers.Display( 109 proto.id.toULong(), 110 proto.name, 111 proto.layerStack, 112 proto.size.toSize(), 113 proto.layerStackSpaceRect.toRect(), 114 Transform(proto.transform, position = null), 115 proto.isVirtual 116 ) 117 } 118 119 @JvmStatic toRectFnull120 fun Layers.FloatRectProto?.toRectF(): RectF? { 121 return this?.let { 122 RectF(left = left, top = top, right = right, bottom = bottom) 123 } 124 } 125 126 @JvmStatic toSizenull127 fun Common.SizeProto?.toSize(): Size { 128 return this?.let { 129 Size(this.w, this.h) 130 } ?: Size.EMPTY 131 } 132 133 @JvmStatic toColornull134 fun Common.ColorProto?.toColor(): Color { 135 if (this == null) { 136 return Color.EMPTY 137 } 138 return Color(r, g, b, a) 139 } 140 141 @JvmStatic toBuffernull142 fun Layers.ActiveBufferProto?.toBuffer(): ActiveBuffer { 143 if (this == null) { 144 return ActiveBuffer.EMPTY 145 } 146 return ActiveBuffer(width, height, stride, format) 147 } 148 149 @JvmStatic getCropnull150 fun getCrop(crop: Common.RectProto?): com.android.server.wm.traces.common.Rect? { 151 return when { 152 crop == null -> com.android.server.wm.traces.common.Rect.EMPTY 153 // crop (0,0) (-1,-1) means no crop 154 crop.right == -1 && crop.left == 0 && crop.bottom == -1 && crop.top == 0 -> 155 null 156 (crop.right - crop.left) <= 0 || (crop.bottom - crop.top) <= 0 -> 157 com.android.server.wm.traces.common.Rect.EMPTY 158 else -> 159 com.android.server.wm.traces.common.Rect( 160 crop.left, crop.top, crop.right, crop.bottom 161 ) 162 } 163 } 164 165 /** 166 * Extracts [Rect] from [RegionProto] by returning a rect that encompasses all 167 * the rectangles making up the region. 168 */ 169 @JvmStatic RegionProtonull170 fun RegionProto?.toRegion(): Region? { 171 return if (this == null) { 172 null 173 } else { 174 val rects = this.rect.map { it.toRect() }.toTypedArray() 175 return Region(rects) 176 } 177 } 178 179 @JvmStatic toRectnull180 fun Common.RectProto?.toRect(): com.android.server.wm.traces.common.Rect { 181 return if ((this == null) || 182 ((this.right - this.left) <= 0 || (this.bottom - this.top) <= 0) 183 ) { 184 com.android.server.wm.traces.common.Rect.EMPTY 185 } else { 186 com.android.server.wm.traces.common.Rect( 187 this.left, this.top, this.right, this.bottom 188 ) 189 } 190 } 191 } 192 } 193