1 /* 2 * Copyright (C) 2021 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.surfaceflinger.nano.Layers 20 import android.surfaceflinger.nano.Layerstrace 21 import android.util.Log 22 import com.android.server.wm.traces.common.layers.Layer 23 import com.android.server.wm.traces.common.layers.BaseLayerTraceEntry 24 import com.android.server.wm.traces.common.layers.LayersTrace 25 import com.android.server.wm.traces.parser.LOG_TAG 26 import com.google.protobuf.nano.InvalidProtocolBufferNanoException 27 import kotlin.math.max 28 import kotlin.system.measureTimeMillis 29 30 /** 31 * Parser for [LayersTrace] objects containing traces or state dumps 32 **/ 33 class LayersTraceParser { 34 companion object { 35 /** 36 * Parses [LayersTrace] from [data] and uses the proto to generates a list 37 * of trace entries, storing the flattened layers into its hierarchical structure. 38 * 39 * @param data binary proto data 40 * @param orphanLayerCallback a callback to handle any unexpected orphan layers 41 */ 42 @JvmOverloads 43 @JvmStatic parseFromTracenull44 fun parseFromTrace( 45 data: ByteArray, 46 ignoreLayersStackMatchNoDisplay: Boolean = true, 47 ignoreLayersInVirtualDisplay: Boolean = true, 48 orphanLayerCallback: ((Layer) -> Boolean)? = null 49 ): LayersTrace { 50 var fileProto: Layerstrace.LayersTraceFileProto? = null 51 try { 52 measureTimeMillis { 53 fileProto = Layerstrace.LayersTraceFileProto.parseFrom(data) 54 }.also { 55 Log.v(LOG_TAG, "Parsing proto (Layers Trace): ${it}ms") 56 } 57 } catch (e: Exception) { 58 throw RuntimeException(e) 59 } 60 return fileProto?.let { 61 parseFromTrace( 62 it, 63 ignoreLayersStackMatchNoDisplay, 64 ignoreLayersInVirtualDisplay, 65 orphanLayerCallback 66 ) 67 } ?: error("Unable to read trace file") 68 } 69 70 /** 71 * Parses [LayersTrace] from [proto] and uses the proto to generates a list 72 * of trace entries, storing the flattened layers into its hierarchical structure. 73 * 74 * @param proto Parsed proto data 75 * @param orphanLayerCallback a callback to handle any unexpected orphan layers 76 */ 77 @JvmOverloads 78 @JvmStatic parseFromTracenull79 fun parseFromTrace( 80 proto: Layerstrace.LayersTraceFileProto, 81 ignoreLayersStackMatchNoDisplay: Boolean = true, 82 ignoreLayersInVirtualDisplay: Boolean = true, 83 orphanLayerCallback: ((Layer) -> Boolean)? = null 84 ): LayersTrace { 85 val entries: MutableList<BaseLayerTraceEntry> = ArrayList() 86 var traceParseTime = 0L 87 for (traceProto: Layerstrace.LayersTraceProto in proto.entry) { 88 val entryParseTime = measureTimeMillis { 89 val entry = LayerTraceEntryLazy( 90 traceProto.elapsedRealtimeNanos, 91 traceProto.hwcBlob, 92 traceProto.where, 93 ignoreLayersStackMatchNoDisplay, 94 ignoreLayersInVirtualDisplay, 95 traceProto.displays, 96 traceProto.layers.layers, 97 orphanLayerCallback 98 ) 99 entries.add(entry) 100 } 101 traceParseTime += entryParseTime 102 } 103 Log.v( 104 LOG_TAG, "Parsing duration (Layers Trace): ${traceParseTime}ms " + 105 "(avg ${traceParseTime / max(entries.size, 1)}ms per entry)" 106 ) 107 return LayersTrace(entries.toTypedArray()) 108 } 109 110 /** 111 * Parses [LayersTrace] from [proto] and uses the proto to generates 112 * a list of trace entries. 113 * 114 * @param proto Parsed proto data 115 */ 116 @JvmStatic 117 @Deprecated( 118 "This functions parsers old SF dumps. Now SF dumps create a " + 119 "single entry trace, for new dump use [parseFromTrace]" 120 ) parseFromLegacyDumpnull121 fun parseFromLegacyDump(proto: Layers.LayersProto): LayersTrace { 122 val entry = LayerTraceEntryLazy( 123 timestamp = 0, 124 displayProtos = emptyArray(), 125 layerProtos = proto.layers, 126 ignoreLayersStackMatchNoDisplay = false, 127 ignoreLayersInVirtualDisplay = false 128 ) 129 return LayersTrace(entry) 130 } 131 132 /** 133 * Parses [LayersTrace] from [data] and uses the proto to generates 134 * a list of trace entries. 135 * 136 * @param data binary proto data 137 */ 138 @JvmStatic 139 @Deprecated( 140 "This functions parsers old SF dumps. Now SF dumps create a " + 141 "single entry trace, for new dump use [parseFromTrace]" 142 ) parseFromLegacyDumpnull143 fun parseFromLegacyDump(data: ByteArray?): LayersTrace { 144 val traceProto = try { 145 Layers.LayersProto.parseFrom(data) 146 } catch (e: InvalidProtocolBufferNanoException) { 147 throw RuntimeException(e) 148 } 149 return parseFromLegacyDump(traceProto) 150 } 151 } 152 }