xref: /aosp_15_r20/development/tools/winscope/src/parsers/surface_flinger/entry_hierarchy_tree_factory.ts (revision 90c8c64db3049935a07c6143d7fd006e26f8ecca)
1/*
2 * Copyright (C) 2024 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 {UserNotifier} from 'common/user_notifier';
19import {DuplicateLayerIds, MissingLayerIds} from 'messaging/user_warnings';
20import {perfetto} from 'protos/surfaceflinger/latest/static';
21import {android} from 'protos/surfaceflinger/udc/static';
22import {HierarchyTreeNode} from 'trace/tree_node/hierarchy_tree_node';
23import {
24  LazyPropertiesStrategyType,
25  PropertiesProvider,
26} from 'trace/tree_node/properties_provider';
27import {PropertiesProviderBuilder} from 'trace/tree_node/properties_provider_builder';
28import {PropertyTreeBuilderFromProto} from 'trace/tree_node/property_tree_builder_from_proto';
29import {PropertyTreeNode} from 'trace/tree_node/property_tree_node';
30import {COMMON_OPERATIONS} from './common_operations';
31import {RectsComputation} from './computations/rects_computation';
32import {VisibilityPropertiesComputation} from './computations/visibility_properties_computation';
33import {ZOrderPathsComputation} from './computations/z_order_paths_computation';
34import {DENYLIST_PROPERTIES} from './denylist_properties';
35import {EAGER_PROPERTIES} from './eager_properties';
36import {HierarchyTreeBuilderSf} from './hierarchy_tree_builder_sf';
37import {ParserSurfaceFlinger as LegacyParserSurfaceFlinger} from './legacy/parser_surface_flinger';
38import {ParserSurfaceFlinger as PerfettoParserSurfaceFlinger} from './perfetto/parser_surface_flinger';
39
40export class EntryHierarchyTreeFactory {
41  makeEntryHierarchyTree(
42    entryProto: EntryType,
43    layerProtos: LayerType[],
44    ParserSurfaceFlinger: ParserSurfaceFlinger,
45  ): HierarchyTreeNode {
46    const excludesCompositionState =
47      entryProto?.excludesCompositionState ?? false;
48    const addExcludesCompositionState = excludesCompositionState
49      ? COMMON_OPERATIONS.AddExcludesCompositionStateTrue
50      : COMMON_OPERATIONS.AddExcludesCompositionStateFalse;
51
52    const processed = new Map<number, number>();
53    let missingLayerIds = false;
54
55    const layers = layerProtos.reduce(
56      (allLayerProps: PropertiesProvider[], layer: LayerType) => {
57        if (layer.id === null || layer.id === undefined) {
58          missingLayerIds = true;
59          return allLayerProps;
60        }
61        const duplicateCount = processed.get(assertDefined(layer.id)) ?? 0;
62        processed.set(assertDefined(layer.id), duplicateCount + 1);
63        const eagerProperties = this.makeEagerPropertiesTree(
64          layer,
65          duplicateCount,
66        );
67        const lazyPropertiesStrategy = this.makeLayerLazyPropertiesStrategy(
68          layer,
69          duplicateCount,
70        );
71
72        const layerProps = new PropertiesProviderBuilder()
73          .setEagerProperties(eagerProperties)
74          .setLazyPropertiesStrategy(lazyPropertiesStrategy)
75          .setCommonOperations([
76            ParserSurfaceFlinger.Operations.SetFormattersLayer,
77            ParserSurfaceFlinger.Operations.TranslateIntDefLayer,
78          ])
79          .setEagerOperations([
80            ParserSurfaceFlinger.Operations.AddDefaultsLayerEager,
81            COMMON_OPERATIONS.AddCompositionType,
82            COMMON_OPERATIONS.UpdateTransforms,
83            COMMON_OPERATIONS.AddVerboseFlags,
84            addExcludesCompositionState,
85          ])
86          .setLazyOperations([
87            ParserSurfaceFlinger.Operations.AddDefaultsLayerLazy,
88          ])
89          .build();
90        allLayerProps.push(layerProps);
91        return allLayerProps;
92      },
93      [] as PropertiesProvider[],
94    );
95
96    if (missingLayerIds) {
97      UserNotifier.add(new MissingLayerIds());
98    }
99
100    const entry = new PropertiesProviderBuilder()
101      .setEagerProperties(this.makeEntryEagerPropertiesTree(entryProto))
102      .setLazyPropertiesStrategy(
103        this.makeEntryLazyPropertiesStrategy(entryProto),
104      )
105      .setCommonOperations([
106        COMMON_OPERATIONS.AddDisplayProperties,
107        ParserSurfaceFlinger.Operations.SetFormattersEntry,
108        ParserSurfaceFlinger.Operations.TranslateIntDefEntry,
109      ])
110      .setEagerOperations([
111        ParserSurfaceFlinger.Operations.AddDefaultsEntryEager,
112      ])
113      .setLazyOperations([ParserSurfaceFlinger.Operations.AddDefaultsEntryLazy])
114      .build();
115
116    const tree = new HierarchyTreeBuilderSf()
117      .setRoot(entry)
118      .setChildren(layers)
119      .setComputations([
120        new ZOrderPathsComputation(),
121        new VisibilityPropertiesComputation(),
122        new RectsComputation(),
123      ])
124      .build();
125
126    if (missingLayerIds) {
127      tree.addWarning(new MissingLayerIds());
128    }
129    const duplicateIds = Array.from(processed.keys()).filter(
130      (layerId) => assertDefined(processed.get(layerId)) > 1,
131    );
132    if (duplicateIds.length > 0) {
133      tree.addWarning(new DuplicateLayerIds(duplicateIds));
134    }
135
136    return tree;
137  }
138
139  private makeEagerPropertiesTree(
140    layer: LayerType,
141    duplicateCount: number,
142  ): PropertyTreeNode {
143    const denyList: string[] = [];
144    let obj = layer;
145    do {
146      Object.getOwnPropertyNames(obj).forEach((it) => {
147        if (!EAGER_PROPERTIES.includes(it)) denyList.push(it);
148      });
149      obj = Object.getPrototypeOf(obj);
150    } while (obj);
151
152    return new PropertyTreeBuilderFromProto()
153      .setData(layer)
154      .setRootId(assertDefined(layer.id))
155      .setRootName(assertDefined(layer.name))
156      .setDenyList(denyList)
157      .setDuplicateCount(duplicateCount)
158      .build();
159  }
160
161  private makeEntryEagerPropertiesTree(entry: EntryType): PropertyTreeNode {
162    const denyList: string[] = [];
163    let obj = entry;
164    do {
165      Object.getOwnPropertyNames(obj).forEach((it) => {
166        if (it !== 'displays') denyList.push(it);
167      });
168      obj = Object.getPrototypeOf(obj);
169    } while (obj);
170
171    return new PropertyTreeBuilderFromProto()
172      .setData(entry)
173      .setRootId('LayerTraceEntry')
174      .setRootName('root')
175      .setDenyList(denyList)
176      .build();
177  }
178
179  private makeLayerLazyPropertiesStrategy(
180    layer: LayerType,
181    duplicateCount: number,
182  ): LazyPropertiesStrategyType {
183    return async () => {
184      return new PropertyTreeBuilderFromProto()
185        .setData(layer)
186        .setRootId(assertDefined(layer.id))
187        .setRootName(assertDefined(layer.name))
188        .setDenyList(EAGER_PROPERTIES.concat(DENYLIST_PROPERTIES))
189        .setDuplicateCount(duplicateCount)
190        .build();
191    };
192  }
193
194  private makeEntryLazyPropertiesStrategy(
195    entry: EntryType,
196  ): LazyPropertiesStrategyType {
197    return async () => {
198      return new PropertyTreeBuilderFromProto()
199        .setData(entry)
200        .setRootId('LayerTraceEntry')
201        .setRootName('root')
202        .setDenyList(DENYLIST_PROPERTIES)
203        .build();
204    };
205  }
206}
207
208type EntryType =
209  | android.surfaceflinger.ILayersTraceProto
210  | perfetto.protos.ILayersSnapshotProto;
211
212type LayerType =
213  | android.surfaceflinger.ILayerProto
214  | perfetto.protos.ILayerProto;
215
216type ParserSurfaceFlinger =
217  | typeof PerfettoParserSurfaceFlinger
218  | typeof LegacyParserSurfaceFlinger;
219