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