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