1/* 2 * Copyright (C) 2022 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 {FormattedLogMessage, LogMessage, UnformattedLogMessage} from 'trace/protolog'; 18import {Timestamp, TimestampType} from 'trace/timestamp'; 19import {TraceFile} from 'trace/trace_file'; 20import {TraceType} from 'trace/trace_type'; 21import configJson from '../../../../../frameworks/base/data/etc/services.core.protolog.json'; 22import {AbstractParser} from './abstract_parser'; 23import {ProtoLogFileProto} from './proto_types'; 24 25class ParserProtoLog extends AbstractParser { 26 constructor(trace: TraceFile) { 27 super(trace); 28 } 29 30 override getTraceType(): TraceType { 31 return TraceType.PROTO_LOG; 32 } 33 34 override getMagicNumber(): number[] { 35 return ParserProtoLog.MAGIC_NUMBER; 36 } 37 38 override decodeTrace(buffer: Uint8Array): any[] { 39 const fileProto: any = ProtoLogFileProto.decode(buffer); 40 41 if (fileProto.version !== ParserProtoLog.PROTOLOG_VERSION) { 42 const message = 'Unsupported ProtoLog trace version'; 43 console.log(message); 44 throw new TypeError(message); 45 } 46 47 if (configJson.version !== ParserProtoLog.PROTOLOG_VERSION) { 48 const message = 'Unsupported ProtoLog JSON config version'; 49 console.log(message); 50 throw new TypeError(message); 51 } 52 53 this.realToElapsedTimeOffsetNs = BigInt(fileProto.realTimeToElapsedTimeOffsetMillis) * 1000000n; 54 55 fileProto.log.sort((a: any, b: any) => { 56 return Number(a.elapsedRealtimeNanos) - Number(b.elapsedRealtimeNanos); 57 }); 58 59 return fileProto.log; 60 } 61 62 override getTimestamp(type: TimestampType, entryProto: any): undefined | Timestamp { 63 if (type === TimestampType.ELAPSED) { 64 return new Timestamp(type, BigInt(entryProto.elapsedRealtimeNanos)); 65 } 66 if (type === TimestampType.REAL && this.realToElapsedTimeOffsetNs !== undefined) { 67 return new Timestamp( 68 type, 69 BigInt(entryProto.elapsedRealtimeNanos) + this.realToElapsedTimeOffsetNs 70 ); 71 } 72 return undefined; 73 } 74 75 override processDecodedEntry( 76 index: number, 77 timestampType: TimestampType, 78 entryProto: object 79 ): LogMessage { 80 const message = (configJson as any).messages[(entryProto as any).messageHash]; 81 if (!message) { 82 return new FormattedLogMessage(entryProto, timestampType, this.realToElapsedTimeOffsetNs); 83 } 84 85 try { 86 return new UnformattedLogMessage( 87 entryProto, 88 timestampType, 89 this.realToElapsedTimeOffsetNs, 90 message 91 ); 92 } catch (error) { 93 if (error instanceof FormatStringMismatchError) { 94 return new FormattedLogMessage(entryProto, timestampType, this.realToElapsedTimeOffsetNs); 95 } 96 throw error; 97 } 98 } 99 100 private realToElapsedTimeOffsetNs: undefined | bigint = undefined; 101 private static readonly MAGIC_NUMBER = [0x09, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x4c, 0x4f, 0x47]; // .PROTOLOG 102 private static readonly PROTOLOG_VERSION = '1.0.0'; 103} 104 105class FormatStringMismatchError extends Error { 106 constructor(message: string) { 107 super(message); 108 } 109} 110 111export {ParserProtoLog}; 112