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 17import {StringUtils} from 'common/string_utils'; 18import {Timestamp} from 'common/time'; 19import {AbstractParser} from 'parsers/legacy/abstract_parser'; 20import {TraceType} from 'trace/trace_type'; 21import {PropertyTreeBuilderFromProto} from 'trace/tree_node/property_tree_builder_from_proto'; 22import {PropertyTreeNode} from 'trace/tree_node/property_tree_node'; 23 24class ParserEventLog extends AbstractParser<PropertyTreeNode> { 25 private static readonly MAGIC_NUMBER_STRING = 'EventLog'; 26 private static readonly MAGIC_NUMBER: number[] = Array.from( 27 new TextEncoder().encode(ParserEventLog.MAGIC_NUMBER_STRING), 28 ); 29 30 override getTraceType(): TraceType { 31 return TraceType.EVENT_LOG; 32 } 33 34 override getMagicNumber(): number[] { 35 return ParserEventLog.MAGIC_NUMBER; 36 } 37 38 override getRealToMonotonicTimeOffsetNs(): bigint | undefined { 39 return undefined; 40 } 41 42 override getRealToBootTimeOffsetNs(): bigint | undefined { 43 return undefined; 44 } 45 46 override decodeTrace(buffer: Uint8Array): Event[] { 47 const decodedLogs = this.decodeByteArray(buffer); 48 const events = this.parseLogs(decodedLogs); 49 return events.sort((a: Event, b: Event) => { 50 return a.eventTimestamp < b.eventTimestamp ? -1 : 1; 51 }); 52 } 53 54 protected override getTimestamp(entry: Event): Timestamp { 55 return this.timestampConverter.makeTimestampFromRealNs( 56 entry.eventTimestamp, 57 ); 58 } 59 60 override processDecodedEntry(index: number, entry: Event): PropertyTreeNode { 61 return new PropertyTreeBuilderFromProto() 62 .setData(entry) 63 .setRootId('EventLogTrace') 64 .setRootName('event') 65 .build(); 66 } 67 68 private decodeByteArray(bytes: Uint8Array): string[] { 69 const allLogsString = new TextDecoder().decode(bytes); 70 const splitLogs = allLogsString.split('\n'); 71 72 const firstIndexOfEventLogTrace = splitLogs.findIndex((substring) => { 73 return ( 74 !substring.includes(ParserEventLog.MAGIC_NUMBER_STRING) && 75 !substring.includes('beginning of events') && 76 !StringUtils.isBlank(substring) 77 ); 78 }); 79 80 const lastIndexOfEventLogTrace = splitLogs.findIndex((substring, index) => { 81 return ( 82 index > firstIndexOfEventLogTrace && StringUtils.isBlank(substring) 83 ); 84 }); 85 86 if (lastIndexOfEventLogTrace === -1) { 87 return splitLogs.slice(firstIndexOfEventLogTrace); 88 } 89 return splitLogs.slice(firstIndexOfEventLogTrace, lastIndexOfEventLogTrace); 90 } 91 92 private parseLogs(input: string[]): Event[] { 93 return input.map((log) => { 94 const [metaData, eventData] = log 95 .split(':', 2) 96 .map((string) => string.trim()); 97 const [rawTimestamp, uid, pid, tid, priority, tag] = metaData 98 .split(' ') 99 .filter((substring) => substring.length > 0); 100 const timestampNs = BigInt(rawTimestamp.replace('.', '')); 101 return { 102 eventTimestamp: timestampNs, 103 pid: Number(pid), 104 uid: Number(uid), 105 tid: Number(tid), 106 tag, 107 eventData, 108 }; 109 }); 110 } 111} 112 113interface Event { 114 eventTimestamp: bigint; 115 pid: number; 116 uid: number; 117 tid: number; 118 tag: string; 119 eventData: string; 120} 121 122export {ParserEventLog}; 123