• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.traces.events
18 
19 import android.tools.common.Timestamp
20 import android.tools.common.Timestamps
21 import kotlin.js.JsExport
22 import kotlin.js.JsName
23 
24 /**
25  * Represents a CUJ Event from the [EventLog]
26  *
27  * {@inheritDoc}
28  */
29 @JsExport
30 class CujEvent(
31     timestamp: Timestamp,
32     val cuj: CujType,
33     processId: Int,
34     uid: String,
35     threadId: Int,
36     eventTag: String,
37     val cujTag: String?,
38 ) : Event(timestamp, processId, uid, threadId, eventTag) {
39 
40     val type: Type = eventTag.asCujType()
41 
42     override fun toString(): String {
43         return "CujEvent(" +
44             "timestamp=$timestamp, " +
45             "cuj=$cuj, " +
46             "processId=$processId, " +
47             "uid=$uid, " +
48             "threadId=$threadId, " +
49             "tag=$tag" +
50             ")"
51     }
52 
53     companion object {
54         @JsName("fromData")
55         fun fromData(
56             processId: Int,
57             uid: String,
58             threadId: Int,
59             eventTag: String,
60             data: String
61         ): CujEvent {
62             return CujEvent(
63                 Timestamps.from(
64                     elapsedNanos = getElapsedTimestampFromData(data, eventTag.asCujType()),
65                     systemUptimeNanos = getSystemUptimeNanosFromData(data, eventTag.asCujType()),
66                     unixNanos = getUnixTimestampFromData(data, eventTag.asCujType())
67                 ),
68                 getCujMarkerFromData(data, eventTag.asCujType()),
69                 processId,
70                 uid,
71                 threadId,
72                 eventTag,
73                 getCujTagFromData(data, eventTag.asCujType())
74             )
75         }
76 
77         private fun getCujMarkerFromData(data: String, cujType: Type): CujType {
78             val dataEntries = getDataEntries(data, cujType)
79             val eventId = dataEntries[0].toInt()
80             return CujType.from(eventId)
81         }
82 
83         private fun getUnixTimestampFromData(data: String, cujType: Type): Long {
84             val dataEntries = getDataEntries(data, cujType)
85             return dataEntries[1].toLong()
86         }
87 
88         private fun getElapsedTimestampFromData(data: String, cujType: Type): Long {
89             val dataEntries = getDataEntries(data, cujType)
90             return dataEntries[2].toLong()
91         }
92 
93         private fun getSystemUptimeNanosFromData(data: String, cujType: Type): Long {
94             val dataEntries = getDataEntries(data, cujType)
95             return dataEntries[3].toLong()
96         }
97 
98         private fun getCujTagFromData(data: String, cujType: Type): String? {
99             val dataEntries = getDataEntries(data, cujType)
100             return when (cujType) {
101                 Type.START -> dataEntries[4]
102                 else -> null
103             }
104         }
105 
106         private fun isNumeric(toCheck: String): Boolean {
107             return toCheck.all { char -> char.isDigit() }
108         }
109 
110         private fun getDataEntries(data: String, cujType: Type): List<String> {
111             when (cujType) {
112                 Type.START -> {
113                     // (CUJ Type|1|5),(Unix Time Ns|2|3),(Elapsed Time Ns|2|3),(Uptime Time Ns|2|3)
114                     val (cujType, unixNs, elapsedNs, uptimeNs, tag) =
115                         data.replace("[", "").replace("]", "").split(",")
116                     // Not using a Regex because it's not supported by Kotlin/Closure
117                     require(
118                         isNumeric(cujType) &&
119                             isNumeric(unixNs) &&
120                             isNumeric(elapsedNs) &&
121                             isNumeric(uptimeNs)
122                     ) {
123                         "Data \"$data\" didn't match expected format"
124                     }
125                 }
126                 else -> {
127                     // Not using a Regex because it's not supported by Kotlin/Closure
128                     val (cujType, unixNs, elapsedNs, uptimeNs) =
129                         data.replace("[", "").replace("]", "").split(",")
130                     require(
131                         isNumeric(cujType) &&
132                             isNumeric(unixNs) &&
133                             isNumeric(elapsedNs) &&
134                             isNumeric(uptimeNs)
135                     ) {
136                         "Data \"$data\" didn't match expected format"
137                     }
138                 }
139             }
140 
141             return data.slice(1..data.length - 2).split(",")
142         }
143 
144         enum class Type {
145             START,
146             END,
147             CANCEL
148         }
149 
150         const val JANK_CUJ_BEGIN_TAG = "jank_cuj_events_begin_request"
151         const val JANK_CUJ_END_TAG = "jank_cuj_events_end_request"
152         const val JANK_CUJ_CANCEL_TAG = "jank_cuj_events_cancel_request"
153 
154         fun String.asCujType(): Type {
155             return when (this) {
156                 JANK_CUJ_BEGIN_TAG -> Type.START
157                 JANK_CUJ_END_TAG -> Type.END
158                 JANK_CUJ_CANCEL_TAG -> Type.CANCEL
159                 else -> error("Unhandled tag type")
160             }
161         }
162     }
163 }
164