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