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.parsers
18 
19 import android.tools.Cache
20 import android.tools.Timestamp
21 import android.tools.Timestamps
22 import android.tools.withTracing
23 
24 /** Base trace parser class */
25 abstract class AbstractTraceParser<
26     InputTypeTrace, InputTypeEntry, OutputTypeEntry, OutputTypeTrace> :
27     AbstractParser<InputTypeTrace, OutputTypeTrace>() {
onBeforeParsenull28     protected open fun onBeforeParse(input: InputTypeTrace) {}
getEntriesnull29     protected abstract fun getEntries(input: InputTypeTrace): Collection<InputTypeEntry>
30     protected abstract fun getTimestamp(entry: InputTypeEntry): Timestamp
31     protected abstract fun doParseEntry(entry: InputTypeEntry): OutputTypeEntry
32     protected abstract fun createTrace(entries: Collection<OutputTypeEntry>): OutputTypeTrace
33 
34     open fun shouldParseEntry(entry: InputTypeEntry) = true
35 
36     final override fun parse(bytes: ByteArray, clearCache: Boolean): OutputTypeTrace {
37         return parse(
38             bytes,
39             from = Timestamps.min(),
40             to = Timestamps.max(),
41             addInitialEntry = true,
42             clearCache = clearCache
43         )
44     }
45 
parsenull46     final override fun parse(input: InputTypeTrace, clearCache: Boolean): OutputTypeTrace {
47         return parse(
48             input,
49             from = Timestamps.min(),
50             to = Timestamps.max(),
51             addInitialEntry = true,
52             clearCache = clearCache
53         )
54     }
55 
doParsenull56     final override fun doParse(input: InputTypeTrace): OutputTypeTrace {
57         return doParse(
58             input,
59             from = Timestamps.min(),
60             to = Timestamps.max(),
61             addInitialEntry = true
62         )
63     }
64 
65     /**
66      * Uses [InputTypeTrace] to generates a trace
67      *
68      * @param input Parsed proto data
69      * @param from Initial timestamp to be parsed
70      * @param to Final timestamp to be parsed
71      * @param addInitialEntry If the last entry smaller than [from] should be included as well
72      */
doParsenull73     protected open fun doParse(
74         input: InputTypeTrace,
75         from: Timestamp,
76         to: Timestamp,
77         addInitialEntry: Boolean
78     ): OutputTypeTrace {
79         onBeforeParse(input)
80         val parsedEntries = mutableListOf<OutputTypeEntry>()
81         val rawEntries = getEntries(input)
82         val allInputTimestamps = rawEntries.map { getTimestamp(it) }
83         val selectedInputTimestamps =
84             getTimestampsInRange(allInputTimestamps, from, to, addInitialEntry)
85         for (rawEntry in rawEntries) {
86             val currTimestamp = getTimestamp(rawEntry)
87             if (!selectedInputTimestamps.contains(currTimestamp) || !shouldParseEntry(rawEntry)) {
88                 continue
89             }
90             val parsedEntry = withTracing("doParseEntry") { doParseEntry(rawEntry) }
91             parsedEntries.add(parsedEntry)
92         }
93         return createTrace(parsedEntries)
94     }
95 
96     /**
97      * Uses [InputTypeTrace] to generates a trace
98      *
99      * @param input Parsed proto data
100      * @param from Initial timestamp to be parsed
101      * @param to Final timestamp to be parsed
102      * @param addInitialEntry If the last entry smaller than [from] should be included as well
103      * @param clearCache If the caching used while parsing the object should be cleared
104      */
parsenull105     fun parse(
106         input: InputTypeTrace,
107         from: Timestamp,
108         to: Timestamp,
109         addInitialEntry: Boolean = true,
110         clearCache: Boolean = true
111     ): OutputTypeTrace {
112         return withTracing("${this::class.simpleName}#parse") {
113             try {
114                 doParse(input, from, to, addInitialEntry)
115             } finally {
116                 if (clearCache) {
117                     Cache.clear()
118                 }
119             }
120         }
121     }
122 
123     /**
124      * Uses a [ByteArray] to generates a trace
125      *
126      * @param bytes Parsed proto data
127      * @param from Initial timestamp to be parsed
128      * @param to Final timestamp to be parsed
129      * @param addInitialEntry If the last entry smaller than [from] should be included as well
130      * @param clearCache If the caching used while parsing the object should be cleared
131      */
parsenull132     fun parse(
133         bytes: ByteArray,
134         from: Timestamp,
135         to: Timestamp,
136         addInitialEntry: Boolean = true,
137         clearCache: Boolean = true
138     ): OutputTypeTrace {
139         val input = decodeByteArray(bytes)
140         return parse(input, from, to, addInitialEntry, clearCache)
141     }
142 }
143