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