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 {assertDefined} from 'common/assert_utils'; 18import {Timestamp} from 'common/time/time'; 19import {AbstractParser} from 'parsers/legacy/abstract_parser'; 20import {AddDefaults} from 'parsers/operations/add_defaults'; 21import {SetFormatters} from 'parsers/operations/set_formatters'; 22import {TamperedMessageType} from 'parsers/tampered_message_type'; 23import {TranslateChanges} from 'parsers/transactions/operations/translate_changes'; 24import root from 'protos/transactions/udc/json'; 25import {android} from 'protos/transactions/udc/static'; 26import { 27 CustomQueryParserResultTypeMap, 28 CustomQueryType, 29 VisitableParserCustomQuery, 30} from 'trace/custom_query'; 31import {EntriesRange} from 'trace/trace'; 32import {TraceType} from 'trace/trace_type'; 33import {PropertyTreeBuilderFromProto} from 'trace/tree_node/property_tree_builder_from_proto'; 34import {PropertyTreeNode} from 'trace/tree_node/property_tree_node'; 35 36type TraceEntryProto = android.surfaceflinger.proto.ITransactionTraceEntry; 37 38class ParserTransactions extends AbstractParser< 39 PropertyTreeNode, 40 TraceEntryProto 41> { 42 private static readonly MAGIC_NUMBER = [ 43 0x09, 0x54, 0x4e, 0x58, 0x54, 0x52, 0x41, 0x43, 0x45, 44 ]; // .TNXTRACE 45 46 private static readonly TransactionsTraceFileProto = 47 TamperedMessageType.tamper( 48 root.lookupType('android.surfaceflinger.TransactionTraceFile'), 49 ); 50 private static readonly TransactionsTraceEntryField = 51 ParserTransactions.TransactionsTraceFileProto.fields['entry']; 52 53 private static readonly OPERATIONS = [ 54 new AddDefaults(ParserTransactions.TransactionsTraceEntryField), 55 new SetFormatters(ParserTransactions.TransactionsTraceEntryField), 56 new TranslateChanges(), 57 ]; 58 59 private realToMonotonicTimeOffsetNs: bigint | undefined; 60 61 override getTraceType(): TraceType { 62 return TraceType.TRANSACTIONS; 63 } 64 65 override getMagicNumber(): number[] { 66 return ParserTransactions.MAGIC_NUMBER; 67 } 68 69 override getRealToBootTimeOffsetNs(): bigint | undefined { 70 return undefined; 71 } 72 73 override getRealToMonotonicTimeOffsetNs(): bigint | undefined { 74 return this.realToMonotonicTimeOffsetNs; 75 } 76 77 override decodeTrace(buffer: Uint8Array): TraceEntryProto[] { 78 const decodedProto = ParserTransactions.TransactionsTraceFileProto.decode( 79 buffer, 80 ) as android.surfaceflinger.proto.ITransactionTraceFile; 81 82 const timeOffset = BigInt( 83 decodedProto.realToElapsedTimeOffsetNanos?.toString() ?? '0', 84 ); 85 this.realToMonotonicTimeOffsetNs = 86 timeOffset !== 0n ? timeOffset : undefined; 87 88 return decodedProto.entry ?? []; 89 } 90 91 protected override getTimestamp(entryProto: TraceEntryProto): Timestamp { 92 return this.timestampConverter.makeTimestampFromMonotonicNs( 93 BigInt(assertDefined(entryProto.elapsedRealtimeNanos).toString()), 94 ); 95 } 96 97 override processDecodedEntry( 98 index: number, 99 entryProto: TraceEntryProto, 100 ): PropertyTreeNode { 101 return this.makePropertiesTree(entryProto); 102 } 103 104 override customQuery<Q extends CustomQueryType>( 105 type: Q, 106 entriesRange: EntriesRange, 107 ): Promise<CustomQueryParserResultTypeMap[Q]> { 108 return new VisitableParserCustomQuery(type) 109 .visit(CustomQueryType.VSYNCID, async () => { 110 return this.decodedEntries 111 .slice(entriesRange.start, entriesRange.end) 112 .map((entry) => { 113 return BigInt(assertDefined(entry.vsyncId?.toString())); // convert Long to bigint 114 }); 115 }) 116 .getResult(); 117 } 118 119 private makePropertiesTree(entryProto: TraceEntryProto): PropertyTreeNode { 120 const tree = new PropertyTreeBuilderFromProto() 121 .setData(entryProto) 122 .setRootId('TransactionsTraceEntry') 123 .setRootName('entry') 124 .build(); 125 126 ParserTransactions.OPERATIONS.forEach((operation) => { 127 operation.apply(tree); 128 }); 129 return tree; 130 } 131} 132 133export {ParserTransactions}; 134