1 /* 2 * Copyright (C) 2023 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 android.tools.device.traces.parsers.wm 18 19 import android.tools.common.Timestamp 20 import android.tools.common.Timestamps 21 import android.tools.common.parsers.AbstractTraceParser 22 import android.tools.common.traces.wm.Transition 23 import android.tools.common.traces.wm.TransitionChange 24 import android.tools.common.traces.wm.TransitionType 25 import android.tools.common.traces.wm.TransitionsTrace 26 import android.tools.common.traces.wm.WmTransitionData 27 import com.android.server.wm.shell.nano.TransitionTraceProto 28 29 /** Parser for [TransitionsTrace] objects */ 30 class WmTransitionTraceParser : 31 AbstractTraceParser< 32 TransitionTraceProto, 33 com.android.server.wm.shell.nano.Transition, 34 Transition, 35 TransitionsTrace 36 >() { 37 override val traceName: String = "Transition trace (WM)" 38 createTracenull39 override fun createTrace(entries: List<Transition>): TransitionsTrace { 40 return TransitionsTrace(entries.toTypedArray()) 41 } 42 doDecodeByteArraynull43 override fun doDecodeByteArray(bytes: ByteArray): TransitionTraceProto = 44 TransitionTraceProto.parseFrom(bytes) 45 46 override fun shouldParseEntry(entry: com.android.server.wm.shell.nano.Transition): Boolean { 47 return true 48 } 49 getEntriesnull50 override fun getEntries( 51 input: TransitionTraceProto 52 ): List<com.android.server.wm.shell.nano.Transition> = input.transitions.toList() 53 54 override fun getTimestamp(entry: com.android.server.wm.shell.nano.Transition): Timestamp { 55 requireValidTimestamp(entry) 56 57 if (entry.createTimeNs != 0L) { 58 return Timestamps.from(elapsedNanos = entry.createTimeNs) 59 } 60 if (entry.sendTimeNs != 0L) { 61 return Timestamps.from(elapsedNanos = entry.sendTimeNs) 62 } 63 if (entry.abortTimeNs != 0L) { 64 return Timestamps.from(elapsedNanos = entry.abortTimeNs) 65 } 66 if (entry.finishTimeNs != 0L) { 67 return Timestamps.from(elapsedNanos = entry.finishTimeNs) 68 } 69 if (entry.startingWindowRemoveTimeNs != 0L) { 70 return Timestamps.from(elapsedNanos = entry.startingWindowRemoveTimeNs) 71 } 72 73 error("No valid timestamp available in entry") 74 } 75 onBeforeParsenull76 override fun onBeforeParse(input: TransitionTraceProto) {} 77 doParsenull78 override fun doParse( 79 input: TransitionTraceProto, 80 from: Timestamp, 81 to: Timestamp, 82 addInitialEntry: Boolean 83 ): TransitionsTrace { 84 val uncompressedTransitionsTrace = super.doParse(input, from, to, addInitialEntry) 85 return uncompressedTransitionsTrace.asCompressed() 86 } 87 doParseEntrynull88 override fun doParseEntry(entry: com.android.server.wm.shell.nano.Transition): Transition { 89 require(entry.id != 0) { "Entry needs a non null id" } 90 requireValidTimestamp(entry) 91 92 val changes = 93 if (entry.targets.isEmpty()) null 94 else 95 entry.targets 96 .map { 97 TransitionChange( 98 TransitionType.fromInt(it.mode), 99 it.layerId, 100 it.windowId, 101 ) 102 } 103 .toTypedArray() 104 105 return Transition( 106 entry.id, 107 wmData = 108 WmTransitionData( 109 createTime = 110 if (entry.createTimeNs == 0L) null 111 else Timestamps.from(elapsedNanos = entry.createTimeNs), 112 sendTime = 113 if (entry.sendTimeNs == 0L) null 114 else Timestamps.from(elapsedNanos = entry.sendTimeNs), 115 abortTime = 116 if (entry.abortTimeNs == 0L) null 117 else Timestamps.from(elapsedNanos = entry.abortTimeNs), 118 finishTime = 119 if (entry.finishTimeNs == 0L) null 120 else Timestamps.from(elapsedNanos = entry.finishTimeNs), 121 startingWindowRemoveTime = 122 if (entry.startingWindowRemoveTimeNs == 0L) null 123 else Timestamps.from(elapsedNanos = entry.startingWindowRemoveTimeNs), 124 startTransactionId = 125 if (entry.startTransactionId == 0L) null 126 else entry.startTransactionId.toString(), 127 finishTransactionId = 128 if (entry.finishTransactionId == 0L) null 129 else entry.finishTransactionId.toString(), 130 type = if (entry.type == 0) null else TransitionType.fromInt(entry.type), 131 changes = changes, 132 ), 133 ) 134 } 135 companion object { requireValidTimestampnull136 private fun requireValidTimestamp(entry: com.android.server.wm.shell.nano.Transition) { 137 require( 138 entry.createTimeNs != 0L || 139 entry.sendTimeNs != 0L || 140 entry.abortTimeNs != 0L || 141 entry.finishTimeNs != 0L || 142 entry.startingWindowRemoveTimeNs != 0L 143 ) { 144 "Requires at least one non-null timestamp" 145 } 146 } 147 } 148 } 149