1 /* <lambda>null2 * 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.common.flicker.extractors 18 19 import android.tools.common.Timestamp 20 import android.tools.common.Timestamps 21 import android.tools.common.io.Reader 22 import android.tools.common.traces.events.Cuj 23 import android.tools.common.traces.events.CujType 24 import android.tools.common.traces.wm.Transition 25 import kotlin.math.max 26 import kotlin.math.min 27 28 class TaggedScenarioExtractor( 29 private val targetTag: CujType, 30 private val transitionMatcher: TransitionMatcher, 31 private val adjustCuj: CujAdjust 32 ) : ScenarioExtractor { 33 override fun extract(reader: Reader): List<TraceSlice> { 34 val cujTrace = reader.readCujTrace() ?: error("Missing CUJ trace") 35 36 val targetCujEntries = 37 cujTrace.entries 38 .filter { it.cuj === targetTag } 39 .filter { !it.canceled } 40 .map { adjustCuj.adjustCuj(it, reader) } 41 42 if (targetCujEntries.isEmpty()) { 43 // No scenarios to extract here 44 return emptyList() 45 } 46 47 return targetCujEntries.map { cujEntry -> 48 val associatedTransition = 49 transitionMatcher.getMatches(reader, cujEntry).firstOrNull() 50 ?: error("Missing associated transition") 51 52 require( 53 cujEntry.startTimestamp.hasAllTimestamps && cujEntry.endTimestamp.hasAllTimestamps 54 ) 55 56 val startTimestamp = 57 estimateScenarioStartTimestamp(cujEntry, associatedTransition, reader) 58 val endTimestamp = estimateScenarioEndTimestamp(cujEntry, associatedTransition, reader) 59 60 TraceSlice( 61 startTimestamp, 62 endTimestamp, 63 associatedCuj = cujEntry.cuj, 64 associatedTransition = associatedTransition 65 ) 66 } 67 } 68 69 private fun estimateScenarioStartTimestamp( 70 cujEntry: Cuj, 71 associatedTransition: Transition?, 72 reader: Reader 73 ): Timestamp { 74 val interpolatedStartTimestamp = 75 if (associatedTransition != null) { 76 Utils.interpolateStartTimestampFromTransition(associatedTransition, reader) 77 } else { 78 null 79 } 80 81 return Timestamps.from( 82 elapsedNanos = 83 min( 84 cujEntry.startTimestamp.elapsedNanos, 85 interpolatedStartTimestamp?.elapsedNanos ?: cujEntry.startTimestamp.elapsedNanos 86 ), 87 systemUptimeNanos = 88 min( 89 cujEntry.startTimestamp.systemUptimeNanos, 90 interpolatedStartTimestamp?.systemUptimeNanos 91 ?: cujEntry.startTimestamp.systemUptimeNanos 92 ), 93 unixNanos = 94 min( 95 cujEntry.startTimestamp.unixNanos, 96 interpolatedStartTimestamp?.unixNanos ?: cujEntry.startTimestamp.unixNanos 97 ) 98 ) 99 } 100 101 private fun estimateScenarioEndTimestamp( 102 cujEntry: Cuj, 103 associatedTransition: Transition?, 104 reader: Reader 105 ): Timestamp { 106 val interpolatedEndTimestamp = 107 if (associatedTransition != null) { 108 Utils.interpolateFinishTimestampFromTransition(associatedTransition, reader) 109 } else { 110 null 111 } 112 113 return Timestamps.from( 114 elapsedNanos = 115 max( 116 cujEntry.endTimestamp.elapsedNanos, 117 interpolatedEndTimestamp?.elapsedNanos ?: -1L 118 ), 119 systemUptimeNanos = 120 max( 121 cujEntry.endTimestamp.systemUptimeNanos, 122 interpolatedEndTimestamp?.systemUptimeNanos ?: -1L 123 ), 124 unixNanos = 125 max(cujEntry.endTimestamp.unixNanos, interpolatedEndTimestamp?.unixNanos ?: -1L) 126 ) 127 } 128 } 129