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 {RectsComputation} from 'parsers/surface_flinger/computations/rects_computation';
24import {VisibilityPropertiesComputation} from 'parsers/surface_flinger/computations/visibility_properties_computation';
25import {ZOrderPathsComputation} from 'parsers/surface_flinger/computations/z_order_paths_computation';
26import {HierarchyTreeBuilderSf} from 'parsers/surface_flinger/hierarchy_tree_builder_sf';
27import {ParserSfUtils} from 'parsers/surface_flinger/parser_surface_flinger_utils';
28import {TamperedMessageType} from 'parsers/tampered_message_type';
29import root from 'protos/surfaceflinger/udc/json';
30import {android} from 'protos/surfaceflinger/udc/static';
31import {
32  CustomQueryParserResultTypeMap,
33  CustomQueryType,
34  VisitableParserCustomQuery,
35} from 'trace/custom_query';
36import {EntriesRange} from 'trace/trace';
37import {TraceType} from 'trace/trace_type';
38import {EnumFormatter, LAYER_ID_FORMATTER} from 'trace/tree_node/formatters';
39import {HierarchyTreeNode} from 'trace/tree_node/hierarchy_tree_node';
40import {PropertiesProvider} from 'trace/tree_node/properties_provider';
41import {PropertiesProviderBuilder} from 'trace/tree_node/properties_provider_builder';
42
43class ParserSurfaceFlinger extends AbstractParser<HierarchyTreeNode> {
44  private static readonly MAGIC_NUMBER = [
45    0x09, 0x4c, 0x59, 0x52, 0x54, 0x52, 0x41, 0x43, 0x45,
46  ]; // .LYRTRACE
47  private static readonly CUSTOM_FORMATTERS = new Map([
48    ['cropLayerId', LAYER_ID_FORMATTER],
49    ['zOrderRelativeOf', LAYER_ID_FORMATTER],
50    [
51      'hwcCompositionType',
52      new EnumFormatter(android.surfaceflinger.HwcCompositionType),
53    ],
54  ]);
55
56  private static readonly LayersTraceFileProto = TamperedMessageType.tamper(
57    root.lookupType('android.surfaceflinger.LayersTraceFileProto'),
58  );
59  private static readonly entryField =
60    ParserSurfaceFlinger.LayersTraceFileProto.fields['entry'];
61  private static readonly layerField = assertDefined(
62    ParserSurfaceFlinger.entryField.tamperedMessageType?.fields['layers']
63      .tamperedMessageType,
64  ).fields['layers'];
65
66  private static readonly Operations = {
67    SetFormattersLayer: new SetFormatters(
68      ParserSurfaceFlinger.layerField,
69      ParserSurfaceFlinger.CUSTOM_FORMATTERS,
70    ),
71    TranslateIntDefLayer: new TranslateIntDef(ParserSurfaceFlinger.layerField),
72    AddDefaultsLayerEager: new AddDefaults(
73      ParserSurfaceFlinger.layerField,
74      ParserSfUtils.EAGER_PROPERTIES,
75    ),
76    AddDefaultsLayerLazy: new AddDefaults(
77      ParserSurfaceFlinger.layerField,
78      undefined,
79      ParserSfUtils.EAGER_PROPERTIES.concat(ParserSfUtils.DENYLIST_PROPERTIES),
80    ),
81    SetFormattersEntry: new SetFormatters(
82      ParserSurfaceFlinger.entryField,
83      ParserSurfaceFlinger.CUSTOM_FORMATTERS,
84    ),
85    TranslateIntDefEntry: new TranslateIntDef(ParserSurfaceFlinger.entryField),
86    AddDefaultsEntryEager: new AddDefaults(ParserSurfaceFlinger.entryField, [
87      'displays',
88    ]),
89    AddDefaultsEntryLazy: new AddDefaults(
90      ParserSurfaceFlinger.entryField,
91      undefined,
92      ParserSfUtils.DENYLIST_PROPERTIES,
93    ),
94  };
95
96  private realToMonotonicTimeOffsetNs: bigint | undefined;
97  private isDump = false;
98
99  override getTraceType(): TraceType {
100    return TraceType.SURFACE_FLINGER;
101  }
102
103  override getMagicNumber(): number[] {
104    return ParserSurfaceFlinger.MAGIC_NUMBER;
105  }
106
107  override getRealToBootTimeOffsetNs(): bigint | undefined {
108    return undefined;
109  }
110
111  override getRealToMonotonicTimeOffsetNs(): bigint | undefined {
112    return this.realToMonotonicTimeOffsetNs;
113  }
114
115  override decodeTrace(
116    buffer: Uint8Array,
117  ): android.surfaceflinger.ILayersTraceProto[] {
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(
136    entry: android.surfaceflinger.ILayersTraceProto,
137  ): Timestamp {
138    if (this.isDump) {
139      return this.timestampConverter.makeZeroTimestamp();
140    }
141    return this.timestampConverter.makeTimestampFromMonotonicNs(
142      BigInt(assertDefined(entry.elapsedRealtimeNanos).toString()),
143    );
144  }
145
146  override processDecodedEntry(
147    index: number,
148    entry: android.surfaceflinger.ILayersTraceProto,
149  ): HierarchyTreeNode {
150    return this.makeHierarchyTree(entry);
151  }
152
153  override customQuery<Q extends CustomQueryType>(
154    type: Q,
155    entriesRange: EntriesRange,
156  ): Promise<CustomQueryParserResultTypeMap[Q]> {
157    return new VisitableParserCustomQuery(type)
158      .visit(CustomQueryType.VSYNCID, () => {
159        const result = this.decodedEntries
160          .slice(entriesRange.start, entriesRange.end)
161          .map((entry) => {
162            return BigInt(entry.vsyncId.toString()); // convert Long to bigint
163          });
164        return Promise.resolve(result);
165      })
166      .visit(CustomQueryType.SF_LAYERS_ID_AND_NAME, () => {
167        const result: Array<{id: number; name: string}> = [];
168        this.decodedEntries
169          .slice(entriesRange.start, entriesRange.end)
170          .forEach((entry: android.surfaceflinger.ILayersTraceProto) => {
171            entry.layers?.layers?.forEach(
172              (layer: android.surfaceflinger.ILayerProto) => {
173                result.push({
174                  id: assertDefined(layer.id),
175                  name: assertDefined(layer.name),
176                });
177              },
178            );
179          });
180        return Promise.resolve(result);
181      })
182      .getResult();
183  }
184
185  private makeHierarchyTree(
186    entryProto: android.surfaceflinger.ILayersTraceProto,
187  ): HierarchyTreeNode {
188    const excludesCompositionState =
189      entryProto?.excludesCompositionState ?? false;
190    const addExcludesCompositionState = excludesCompositionState
191      ? ParserSfUtils.OPERATIONS.AddExcludesCompositionStateTrue
192      : ParserSfUtils.OPERATIONS.AddExcludesCompositionStateFalse;
193
194    const processed = new Map<number, number>();
195
196    const layers: PropertiesProvider[] = assertDefined(
197      entryProto.layers?.layers,
198    ).map((layer: android.surfaceflinger.ILayerProto) => {
199      const duplicateCount = processed.get(assertDefined(layer.id)) ?? 0;
200      processed.set(assertDefined(layer.id), duplicateCount + 1);
201      const eagerProperties = ParserSfUtils.makeEagerPropertiesTree(
202        layer,
203        duplicateCount,
204      );
205      const lazyPropertiesStrategy =
206        ParserSfUtils.makeLayerLazyPropertiesStrategy(layer, duplicateCount);
207
208      const layerProps = new PropertiesProviderBuilder()
209        .setEagerProperties(eagerProperties)
210        .setLazyPropertiesStrategy(lazyPropertiesStrategy)
211        .setCommonOperations([
212          ParserSurfaceFlinger.Operations.SetFormattersLayer,
213          ParserSurfaceFlinger.Operations.TranslateIntDefLayer,
214        ])
215        .setEagerOperations([
216          ParserSurfaceFlinger.Operations.AddDefaultsLayerEager,
217          ParserSfUtils.OPERATIONS.AddCompositionType,
218          ParserSfUtils.OPERATIONS.UpdateTransforms,
219          ParserSfUtils.OPERATIONS.AddVerboseFlags,
220          addExcludesCompositionState,
221        ])
222        .setLazyOperations([
223          ParserSurfaceFlinger.Operations.AddDefaultsLayerLazy,
224        ])
225        .build();
226      return layerProps;
227    });
228
229    const entry = new PropertiesProviderBuilder()
230      .setEagerProperties(
231        ParserSfUtils.makeEntryEagerPropertiesTree(entryProto),
232      )
233      .setLazyPropertiesStrategy(
234        ParserSfUtils.makeEntryLazyPropertiesStrategy(entryProto),
235      )
236      .setCommonOperations([
237        ParserSurfaceFlinger.Operations.SetFormattersEntry,
238        ParserSurfaceFlinger.Operations.TranslateIntDefEntry,
239      ])
240      .setEagerOperations([
241        ParserSurfaceFlinger.Operations.AddDefaultsEntryEager,
242      ])
243      .setLazyOperations([
244        ParserSurfaceFlinger.Operations.AddDefaultsEntryLazy,
245        ParserSfUtils.OPERATIONS.AddDisplayProperties,
246      ])
247      .build();
248
249    return new HierarchyTreeBuilderSf()
250      .setRoot(entry)
251      .setChildren(layers)
252      .setComputations([
253        new ZOrderPathsComputation(),
254        new VisibilityPropertiesComputation(),
255        new RectsComputation(),
256      ])
257      .build();
258  }
259}
260
261export {ParserSurfaceFlinger};
262