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