xref: /aosp_15_r20/development/tools/winscope/src/parsers/surface_flinger/legacy/parser_surface_flinger.ts (revision 90c8c64db3049935a07c6143d7fd006e26f8ecca)
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 {TranslateIntDef} from 'parsers/operations/translate_intdef';
23import {DENYLIST_PROPERTIES} from 'parsers/surface_flinger/denylist_properties';
24import {EAGER_PROPERTIES} from 'parsers/surface_flinger/eager_properties';
25import {EntryHierarchyTreeFactory} from 'parsers/surface_flinger/entry_hierarchy_tree_factory';
26import {TamperedMessageType} from 'parsers/tampered_message_type';
27import root from 'protos/surfaceflinger/udc/json';
28import {android} from 'protos/surfaceflinger/udc/static';
29import {
30  CustomQueryParserResultTypeMap,
31  CustomQueryType,
32  VisitableParserCustomQuery,
33} from 'trace/custom_query';
34import {EntriesRange} from 'trace/trace';
35import {TraceType} from 'trace/trace_type';
36import {EnumFormatter, LAYER_ID_FORMATTER} from 'trace/tree_node/formatters';
37import {HierarchyTreeNode} from 'trace/tree_node/hierarchy_tree_node';
38
39class ParserSurfaceFlinger extends AbstractParser<HierarchyTreeNode> {
40  private static readonly MAGIC_NUMBER = [
41    0x09, 0x4c, 0x59, 0x52, 0x54, 0x52, 0x41, 0x43, 0x45,
42  ]; // .LYRTRACE
43  private static readonly CUSTOM_FORMATTERS = new Map([
44    ['cropLayerId', LAYER_ID_FORMATTER],
45    ['zOrderRelativeOf', LAYER_ID_FORMATTER],
46    [
47      'hwcCompositionType',
48      new EnumFormatter(android.surfaceflinger.HwcCompositionType),
49    ],
50  ]);
51
52  private static readonly LayersTraceFileProto = TamperedMessageType.tamper(
53    root.lookupType('android.surfaceflinger.LayersTraceFileProto'),
54  );
55  private static readonly entryField =
56    ParserSurfaceFlinger.LayersTraceFileProto.fields['entry'];
57  private static readonly layerField = assertDefined(
58    ParserSurfaceFlinger.entryField.tamperedMessageType?.fields['layers']
59      .tamperedMessageType,
60  ).fields['layers'];
61
62  static readonly Operations = {
63    SetFormattersLayer: new SetFormatters(
64      ParserSurfaceFlinger.layerField,
65      ParserSurfaceFlinger.CUSTOM_FORMATTERS,
66    ),
67    TranslateIntDefLayer: new TranslateIntDef(ParserSurfaceFlinger.layerField),
68    AddDefaultsLayerEager: new AddDefaults(
69      ParserSurfaceFlinger.layerField,
70      EAGER_PROPERTIES,
71    ),
72    AddDefaultsLayerLazy: new AddDefaults(
73      ParserSurfaceFlinger.layerField,
74      undefined,
75      EAGER_PROPERTIES.concat(DENYLIST_PROPERTIES),
76    ),
77    SetFormattersEntry: new SetFormatters(
78      ParserSurfaceFlinger.entryField,
79      ParserSurfaceFlinger.CUSTOM_FORMATTERS,
80    ),
81    TranslateIntDefEntry: new TranslateIntDef(ParserSurfaceFlinger.entryField),
82    AddDefaultsEntryEager: new AddDefaults(ParserSurfaceFlinger.entryField, [
83      'displays',
84    ]),
85    AddDefaultsEntryLazy: new AddDefaults(
86      ParserSurfaceFlinger.entryField,
87      undefined,
88      DENYLIST_PROPERTIES,
89    ),
90  };
91
92  private readonly factory = new EntryHierarchyTreeFactory();
93  private realToMonotonicTimeOffsetNs: bigint | undefined;
94  private isDump = false;
95
96  override getTraceType(): TraceType {
97    return TraceType.SURFACE_FLINGER;
98  }
99
100  override getMagicNumber(): number[] {
101    return ParserSurfaceFlinger.MAGIC_NUMBER;
102  }
103
104  override getRealToBootTimeOffsetNs(): bigint | undefined {
105    return undefined;
106  }
107
108  override getRealToMonotonicTimeOffsetNs(): bigint | undefined {
109    return this.realToMonotonicTimeOffsetNs;
110  }
111
112  override decodeTrace(
113    buffer: Uint8Array,
114  ): android.surfaceflinger.ILayersTraceProto[] {
115    const decoded = ParserSurfaceFlinger.LayersTraceFileProto.decode(
116      buffer,
117    ) as android.surfaceflinger.ILayersTraceFileProto;
118    const timeOffset = BigInt(
119      decoded.realToElapsedTimeOffsetNanos?.toString() ?? '0',
120    );
121    this.realToMonotonicTimeOffsetNs =
122      timeOffset !== 0n ? timeOffset : undefined;
123    this.isDump =
124      decoded.entry?.length === 1 &&
125      !Object.prototype.hasOwnProperty.call(
126        decoded.entry[0],
127        'elapsedRealtimeNanos',
128      );
129    return decoded.entry ?? [];
130  }
131
132  protected override getTimestamp(
133    entry: android.surfaceflinger.ILayersTraceProto,
134  ): Timestamp {
135    if (this.isDump) {
136      return this.timestampConverter.makeZeroTimestamp();
137    }
138    return this.timestampConverter.makeTimestampFromMonotonicNs(
139      BigInt(assertDefined(entry.elapsedRealtimeNanos).toString()),
140    );
141  }
142
143  override processDecodedEntry(
144    index: number,
145    entry: android.surfaceflinger.ILayersTraceProto,
146  ): HierarchyTreeNode {
147    return this.factory.makeEntryHierarchyTree(
148      entry,
149      assertDefined(entry.layers?.layers),
150      ParserSurfaceFlinger,
151    );
152  }
153
154  override customQuery<Q extends CustomQueryType>(
155    type: Q,
156    entriesRange: EntriesRange,
157  ): Promise<CustomQueryParserResultTypeMap[Q]> {
158    return new VisitableParserCustomQuery(type)
159      .visit(CustomQueryType.VSYNCID, () => {
160        const result = this.decodedEntries
161          .slice(entriesRange.start, entriesRange.end)
162          .map((entry) => {
163            return BigInt(entry.vsyncId.toString()); // convert Long to bigint
164          });
165        return Promise.resolve(result);
166      })
167      .visit(CustomQueryType.SF_LAYERS_ID_AND_NAME, () => {
168        const result: Array<{id: number; name: string}> = [];
169        this.decodedEntries
170          .slice(entriesRange.start, entriesRange.end)
171          .forEach((entry: android.surfaceflinger.ILayersTraceProto) => {
172            entry.layers?.layers?.forEach(
173              (layer: android.surfaceflinger.ILayerProto) => {
174                result.push({
175                  id: assertDefined(layer.id),
176                  name: assertDefined(layer.name),
177                });
178              },
179            );
180          });
181        return Promise.resolve(result);
182      })
183      .getResult();
184  }
185}
186
187export {ParserSurfaceFlinger};
188