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.parsers.events 18 19 import android.tools.Timestamp 20 import android.tools.Timestamps 21 import android.tools.parsers.AbstractParser 22 import android.tools.traces.events.CujEvent 23 import android.tools.traces.events.Event 24 import android.tools.traces.events.EventLog 25 import android.tools.traces.events.EventLog.Companion.MAGIC_NUMBER 26 import android.tools.traces.events.FocusEvent 27 28 operator fun <T> List<T>.component6(): T = get(5) 29 30 class EventLogParser : AbstractParser<Collection<String>, EventLog>() { 31 override val traceName: String = "Event Log" 32 33 override fun doDecodeByteArray(bytes: ByteArray): Collection<String> { 34 val logsString = bytes.decodeToString() 35 return logsString 36 .split("\n") 37 .dropWhile { 38 it.contains(MAGIC_NUMBER) || it.contains("beginning of events") || it.isBlank() 39 } 40 .dropLastWhile { it.isBlank() } 41 } 42 43 override fun doParse(input: Collection<String>): EventLog { 44 val events = 45 input 46 .map { log -> 47 val (metaData, eventData) = log.split(":", limit = 2).map { it.trim() } 48 val (rawTimestamp, uid, pid, tid, priority, tag) = 49 metaData.split(" ").filter { it.isNotEmpty() } 50 51 val timestamp = 52 Timestamps.from(unixNanos = rawTimestamp.replace(".", "").toLong()) 53 parseEvent(timestamp, pid.toInt(), uid, tid.toInt(), tag, eventData) 54 } 55 .sortedBy { it.timestamp.unixNanos } 56 57 return EventLog(events) 58 } 59 60 private fun parseEvent( 61 timestamp: Timestamp, 62 pid: Int, 63 uid: String, 64 tid: Int, 65 tag: String, 66 eventData: String 67 ): Event { 68 return when (tag) { 69 INPUT_FOCUS_TAG -> { 70 FocusEvent.from(timestamp, pid, uid, tid, parseData(eventData)) 71 } 72 JANK_CUJ_BEGIN_TAG -> { 73 CujEvent.fromData(pid, uid, tid, tag, eventData) 74 } 75 JANK_CUJ_END_TAG -> { 76 CujEvent.fromData(pid, uid, tid, tag, eventData) 77 } 78 JANK_CUJ_CANCEL_TAG -> { 79 CujEvent.fromData(pid, uid, tid, tag, eventData) 80 } 81 else -> { 82 Event(timestamp, pid, uid, tid, tag) 83 } 84 } 85 } 86 87 private fun parseData(data: String): Collection<String> { 88 require(data.first() == '[') 89 require(data.last() == ']') 90 return data.drop(1).dropLast(1).split(",") 91 } 92 93 fun parseSlice(bytes: ByteArray, from: Timestamp, to: Timestamp): EventLog { 94 require(from.unixNanos < to.unixNanos) { "'to' needs to be greater than 'from'" } 95 require(from.hasUnixTimestamp && to.hasUnixTimestamp) { "Missing required timestamp type" } 96 return doParse( 97 this.doDecodeByteArray(bytes) 98 .sortedBy { getTimestampFromRawEntry(it).unixNanos } 99 .dropWhile { getTimestampFromRawEntry(it).unixNanos < from.unixNanos } 100 .dropLastWhile { getTimestampFromRawEntry(it).unixNanos > to.unixNanos } 101 ) 102 } 103 104 private fun getTimestampFromRawEntry(entry: String): Timestamp { 105 val (metaData, _) = entry.split(":", limit = 2).map { it.trim() } 106 val (rawTimestamp, _, _, _, _, _) = metaData.split(" ").filter { it.isNotEmpty() } 107 return Timestamps.from(unixNanos = rawTimestamp.replace(".", "").toLong()) 108 } 109 110 companion object { 111 const val EVENT_LOG_INPUT_FOCUS_TAG = 62001 112 113 const val WM_JANK_CUJ_EVENTS_BEGIN_REQUEST = 37001 114 const val WM_JANK_CUJ_EVENTS_END_REQUEST = 37002 115 const val WM_JANK_CUJ_EVENTS_CANCEL_REQUEST = 37003 116 117 const val INPUT_FOCUS_TAG = "input_focus" 118 const val JANK_CUJ_BEGIN_TAG = "jank_cuj_events_begin_request" 119 const val JANK_CUJ_END_TAG = "jank_cuj_events_end_request" 120 const val JANK_CUJ_CANCEL_TAG = "jank_cuj_events_cancel_request" 121 } 122 } 123