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, Transition, android.tools.traces.wm.Transition, TransitionsTrace 33 >() { 34 override val traceName: String = "Transition trace (WM)" 35 createTracenull36 override fun createTrace( 37 entries: Collection<android.tools.traces.wm.Transition> 38 ): TransitionsTrace { 39 return TransitionsTrace(entries) 40 } 41 doDecodeByteArraynull42 override fun doDecodeByteArray(bytes: ByteArray): TransitionTraceProto = 43 TransitionTraceProto.parseFrom(bytes) 44 45 override fun shouldParseEntry(entry: com.android.server.wm.shell.nano.Transition): Boolean { 46 return true 47 } 48 getEntriesnull49 override fun getEntries( 50 input: TransitionTraceProto 51 ): Collection<com.android.server.wm.shell.nano.Transition> = input.transitions.toList() 52 53 override fun getTimestamp(entry: com.android.server.wm.shell.nano.Transition): Timestamp { 54 requireValidTimestamp(entry) 55 56 if (entry.createTimeNs != 0L) { 57 return Timestamps.from(elapsedNanos = entry.createTimeNs) 58 } 59 if (entry.sendTimeNs != 0L) { 60 return Timestamps.from(elapsedNanos = entry.sendTimeNs) 61 } 62 if (entry.abortTimeNs != 0L) { 63 return Timestamps.from(elapsedNanos = entry.abortTimeNs) 64 } 65 if (entry.finishTimeNs != 0L) { 66 return Timestamps.from(elapsedNanos = entry.finishTimeNs) 67 } 68 if (entry.startingWindowRemoveTimeNs != 0L) { 69 return Timestamps.from(elapsedNanos = entry.startingWindowRemoveTimeNs) 70 } 71 72 error("No valid timestamp available in entry") 73 } 74 onBeforeParsenull75 override fun onBeforeParse(input: TransitionTraceProto) {} 76 doParsenull77 override fun doParse( 78 input: TransitionTraceProto, 79 from: Timestamp, 80 to: Timestamp, 81 addInitialEntry: Boolean 82 ): TransitionsTrace { 83 val uncompressedTransitionsTrace = super.doParse(input, from, to, addInitialEntry) 84 return uncompressedTransitionsTrace.asCompressed() 85 } 86 doParseEntrynull87 override fun doParseEntry( 88 entry: com.android.server.wm.shell.nano.Transition 89 ): android.tools.traces.wm.Transition { 90 require(entry.id != 0) { "Entry needs a non null id" } 91 requireValidTimestamp(entry) 92 93 val changes = 94 if (entry.targets.isEmpty()) { 95 null 96 } else { 97 entry.targets.map { 98 TransitionChange( 99 TransitionType.fromInt(it.mode), 100 it.layerId, 101 it.windowId, 102 ) 103 } 104 } 105 106 return android.tools.traces.wm.Transition( 107 entry.id, 108 wmData = 109 WmTransitionData( 110 createTime = entry.createTimeNs.toTimestamp(), 111 sendTime = entry.sendTimeNs.toTimestamp(), 112 abortTime = entry.abortTimeNs.toTimestamp(), 113 finishTime = entry.finishTimeNs.toTimestamp(), 114 startingWindowRemoveTime = entry.startingWindowRemoveTimeNs.toTimestamp(), 115 startTransactionId = entry.startTransactionId.toTransactionId(), 116 finishTransactionId = entry.finishTransactionId.toTransactionId(), 117 type = 118 if (entry.type == 0) { 119 null 120 } else { 121 TransitionType.fromInt(entry.type) 122 }, 123 changes = changes, 124 ), 125 ) 126 } 127 Longnull128 private fun Long.toTimestamp() = 129 if (this == 0L) { 130 null 131 } else { 132 Timestamps.from(elapsedNanos = this) 133 } 134 toTransactionIdnull135 private fun Long.toTransactionId() = 136 if (this == 0L) { 137 null 138 } else { 139 this 140 } 141 142 companion object { requireValidTimestampnull143 private fun requireValidTimestamp(entry: com.android.server.wm.shell.nano.Transition) { 144 require( 145 entry.createTimeNs != 0L || 146 entry.sendTimeNs != 0L || 147 entry.abortTimeNs != 0L || 148 entry.finishTimeNs != 0L || 149 entry.startingWindowRemoveTimeNs != 0L 150 ) { 151 "Requires at least one non-null timestamp" 152 } 153 } 154 } 155 } 156