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 {TimeUtils} from 'common/time_utils'; 18import {Timestamp, TimestampType} from 'trace/timestamp'; 19import {TraceFile} from 'trace/trace_file'; 20import {TraceTreeNode} from 'trace/trace_tree_node'; 21import {TraceType} from 'trace/trace_type'; 22import {ImeUtils} from 'viewers/common/ime_utils'; 23import {AbstractParser} from './abstract_parser'; 24import {InputMethodServiceTraceFileProto} from './proto_types'; 25 26class ParserInputMethodService extends AbstractParser { 27 constructor(trace: TraceFile) { 28 super(trace); 29 this.realToElapsedTimeOffsetNs = undefined; 30 } 31 32 getTraceType(): TraceType { 33 return TraceType.INPUT_METHOD_SERVICE; 34 } 35 36 override getMagicNumber(): number[] { 37 return ParserInputMethodService.MAGIC_NUMBER; 38 } 39 40 override decodeTrace(buffer: Uint8Array): any[] { 41 const decoded = InputMethodServiceTraceFileProto.decode(buffer) as any; 42 if (Object.prototype.hasOwnProperty.call(decoded, 'realToElapsedTimeOffsetNanos')) { 43 this.realToElapsedTimeOffsetNs = BigInt(decoded.realToElapsedTimeOffsetNanos); 44 } else { 45 this.realToElapsedTimeOffsetNs = undefined; 46 } 47 return decoded.entry; 48 } 49 50 override getTimestamp(type: TimestampType, entryProto: any): undefined | Timestamp { 51 if (type === TimestampType.ELAPSED) { 52 return new Timestamp(type, BigInt(entryProto.elapsedRealtimeNanos)); 53 } else if (type === TimestampType.REAL && this.realToElapsedTimeOffsetNs !== undefined) { 54 return new Timestamp( 55 type, 56 this.realToElapsedTimeOffsetNs + BigInt(entryProto.elapsedRealtimeNanos) 57 ); 58 } 59 return undefined; 60 } 61 62 override processDecodedEntry( 63 index: number, 64 timestampType: TimestampType, 65 entryProto: TraceTreeNode 66 ): TraceTreeNode { 67 if (entryProto.elapsedRealtimeNanos === undefined) { 68 throw Error('Missing elapsedRealtimeNanos on entry'); 69 } 70 71 let clockTimeNanos: bigint | undefined = undefined; 72 if ( 73 this.realToElapsedTimeOffsetNs !== undefined && 74 entryProto.elapsedRealtimeNanos !== undefined 75 ) { 76 clockTimeNanos = BigInt(entryProto.elapsedRealtimeNanos) + this.realToElapsedTimeOffsetNs; 77 } 78 79 const timestamp = Timestamp.from( 80 timestampType, 81 BigInt(entryProto.elapsedRealtimeNanos), 82 this.realToElapsedTimeOffsetNs 83 ); 84 85 return { 86 name: TimeUtils.format(timestamp) + ' - ' + entryProto.where, 87 kind: 'InputMethodService entry', 88 children: [ 89 { 90 obj: ImeUtils.transformInputConnectionCall(entryProto.inputMethodService), 91 kind: 'InputMethodService', 92 name: '', 93 children: [], 94 stableId: 'service', 95 id: 'service', 96 }, 97 ], 98 obj: entryProto, 99 stableId: 'entry', 100 id: 'entry', 101 elapsedRealtimeNanos: entryProto.elapsedRealtimeNanos, 102 clockTimeNanos, 103 }; 104 } 105 106 private realToElapsedTimeOffsetNs: undefined | bigint; 107 private static readonly MAGIC_NUMBER = [0x09, 0x49, 0x4d, 0x53, 0x54, 0x52, 0x41, 0x43, 0x45]; // .IMSTRACE 108} 109 110export {ParserInputMethodService}; 111