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