1 /*
<lambda>null2  * 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.common.service.processors
18 
19 import com.android.server.wm.traces.common.DeviceStateDump
20 import com.android.server.wm.traces.common.layers.LayerTraceEntry
21 import com.android.server.wm.traces.common.layers.LayersTrace
22 import com.android.server.wm.traces.common.service.ITagProcessor
23 import com.android.server.wm.traces.common.tags.Tag
24 import com.android.server.wm.traces.common.tags.TagState
25 import com.android.server.wm.traces.common.tags.TagTrace
26 import com.android.server.wm.traces.common.tags.Transition
27 import com.android.server.wm.traces.common.windowmanager.WindowManagerState
28 import com.android.server.wm.traces.common.windowmanager.WindowManagerTrace
29 
30 /**
31  * This class implements the relevant methods such as generating tags, creating dumps for the
32  * WindowManager and SurfaceFlinger traces, and ensuring the 1:1 correspondence between the start
33  * and end tags invariant is maintained by [BaseFsmState].
34  */
35 abstract class TransitionProcessor(internal val logger: (String) -> Unit) : ITagProcessor {
36     abstract val transition: Transition
37     abstract fun getInitialState(tags: MutableMap<Long, MutableList<Tag>>): BaseState
38 
39     abstract inner class BaseState(
40         tags: MutableMap<Long, MutableList<Tag>>
41     ) : BaseFsmState(tags, logger, transition) {
42         abstract override fun doProcessState(
43             previous: DeviceStateDump<WindowManagerState, LayerTraceEntry>?,
44             current: DeviceStateDump<WindowManagerState, LayerTraceEntry>,
45             next: DeviceStateDump<WindowManagerState, LayerTraceEntry>
46         ): FSMState
47     }
48 
49     /**
50      * Add the start and end tags corresponding to the transition from
51      * the WindowManager and SurfaceFlinger traces
52      * @param wmTrace - WindowManager trace
53      * @param layersTrace - SurfaceFlinger trace
54      * @return [TagTrace] - containing all the newly generated tags in states with
55      * timestamps
56      */
57     override fun generateTags(
58         wmTrace: WindowManagerTrace,
59         layersTrace: LayersTrace
60     ): TagTrace {
61         val tags = mutableMapOf<Long, MutableList<Tag>>()
62         var currPosition: FSMState? = getInitialState(tags)
63 
64         val dumpList = createDumpList(wmTrace, layersTrace)
65         val dumpIterator = dumpList.iterator()
66 
67         // keep always a reference to previous, current and next states
68         var previous: DeviceStateDump<WindowManagerState, LayerTraceEntry>?
69         var current: DeviceStateDump<WindowManagerState, LayerTraceEntry>? = null
70         var next: DeviceStateDump<WindowManagerState, LayerTraceEntry>? = dumpIterator.next()
71         while (currPosition != null) {
72             previous = current
73             current = next
74             next = if (dumpIterator.hasNext()) dumpIterator.next() else null
75             requireNotNull(current) { "Current state shouldn't be null" }
76             val newPosition = currPosition.process(previous, current, next)
77             currPosition = newPosition
78         }
79 
80         return buildTagTrace(tags)
81     }
82 
83     private fun buildTagTrace(tags: MutableMap<Long, MutableList<Tag>>): TagTrace {
84         val tagStates = tags.map { entry ->
85             val timestamp = entry.key
86             val stateTags = entry.value
87             TagState(timestamp.toString(), stateTags.toTypedArray())
88         }
89         return TagTrace(tagStates.toTypedArray(), source = "")
90     }
91 
92     companion object {
93         internal fun createDumpList(
94             wmTrace: WindowManagerTrace,
95             layersTrace: LayersTrace
96         ): List<DeviceStateDump<WindowManagerState, LayerTraceEntry>> {
97             val wmTimestamps = wmTrace.map { it.timestamp }.toTypedArray()
98             val layersTimestamps = layersTrace.map { it.timestamp }.toTypedArray()
99             val fullTimestamps = setOf(*wmTimestamps, *layersTimestamps).sorted()
100 
101             return fullTimestamps.map { baseTimestamp ->
102                 val wmState = wmTrace
103                     .lastOrNull { it.timestamp <= baseTimestamp }
104                     ?: wmTrace.first()
105                 val layerState = layersTrace
106                     .lastOrNull { it.timestamp <= baseTimestamp }
107                     ?: layersTrace.first()
108                 DeviceStateDump(wmState, layerState)
109             }.distinctBy { Pair(it.wmState.timestamp, it.layerState.timestamp) }
110         }
111     }
112 }
113