• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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