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 {HierarchyTreeBuilderInputMethod} from 'parsers/input_method/hierarchy_tree_builder_input_method'; 18import {AddDefaults} from 'parsers/operations/add_defaults'; 19import {SetFormatters} from 'parsers/operations/set_formatters'; 20import {TranslateIntDef} from 'parsers/operations/translate_intdef'; 21import {TamperedProtoField} from 'parsers/tampered_message_type'; 22import {perfetto} from 'protos/ime/latest/static'; 23import {android} from 'protos/ime/udc/static'; 24import {HierarchyTreeNode} from 'trace/tree_node/hierarchy_tree_node'; 25import {LazyPropertiesStrategyType} 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'; 29 30export class HierarchyTreeServiceFactory { 31 private static readonly ENTRY_DENYLIST_PROPERTIES = ['inputMethodService']; 32 private static readonly ENTRY_EAGER_PROPERTIES = ['where']; 33 private static readonly SERVICE_EAGER_PROPERTIES = [ 34 'windowVisible', 35 'decorViewVisible', 36 'inputEditorInfo', 37 ]; 38 39 private SetFormattersService: SetFormatters; 40 private TranslateIntDefService: TranslateIntDef; 41 private AddDefaultsServiceEager: AddDefaults; 42 private AddDefaultsServiceLazy: AddDefaults; 43 private SetFormattersEntry: SetFormatters; 44 private AddDefaultsEntryEager: AddDefaults; 45 private AddDefaultsEntryLazy: AddDefaults; 46 47 constructor( 48 entryField: TamperedProtoField, 49 serviceField: TamperedProtoField, 50 ) { 51 this.SetFormattersService = new SetFormatters(serviceField); 52 this.TranslateIntDefService = new TranslateIntDef(serviceField); 53 this.AddDefaultsServiceEager = new AddDefaults( 54 serviceField, 55 HierarchyTreeServiceFactory.SERVICE_EAGER_PROPERTIES, 56 ); 57 this.AddDefaultsServiceLazy = new AddDefaults( 58 serviceField, 59 undefined, 60 HierarchyTreeServiceFactory.SERVICE_EAGER_PROPERTIES, 61 ); 62 this.SetFormattersEntry = new SetFormatters(entryField); 63 this.AddDefaultsEntryEager = new AddDefaults( 64 entryField, 65 HierarchyTreeServiceFactory.ENTRY_EAGER_PROPERTIES, 66 ); 67 this.AddDefaultsEntryLazy = new AddDefaults( 68 entryField, 69 undefined, 70 HierarchyTreeServiceFactory.ENTRY_EAGER_PROPERTIES.concat( 71 HierarchyTreeServiceFactory.ENTRY_DENYLIST_PROPERTIES, 72 ), 73 ); 74 } 75 76 makeHierarchyTree( 77 entryProto: 78 | android.view.inputmethod.IInputMethodServiceTraceProto 79 | perfetto.protos.IInputMethodServiceTraceProto, 80 ): HierarchyTreeNode { 81 const entry = new PropertiesProviderBuilder() 82 .setEagerProperties(this.makeEntryEagerPropertiesTree(entryProto)) 83 .setLazyPropertiesStrategy( 84 this.makeEntryLazyPropertiesStrategy(entryProto), 85 ) 86 .setEagerOperations([this.AddDefaultsEntryEager]) 87 .setCommonOperations([this.SetFormattersEntry]) 88 .setLazyOperations([this.AddDefaultsEntryLazy]) 89 .build(); 90 91 const inputMethodService = entryProto.inputMethodService 92 ? new PropertiesProviderBuilder() 93 .setEagerProperties( 94 this.makeServiceEagerPropertiesTree(entryProto.inputMethodService), 95 ) 96 .setLazyPropertiesStrategy( 97 this.makeServiceLazyPropertiesStrategy( 98 entryProto.inputMethodService, 99 ), 100 ) 101 .setEagerOperations([this.AddDefaultsServiceEager]) 102 .setCommonOperations([ 103 this.SetFormattersService, 104 this.TranslateIntDefService, 105 ]) 106 .setLazyOperations([this.AddDefaultsServiceLazy]) 107 .build() 108 : undefined; 109 110 return new HierarchyTreeBuilderInputMethod() 111 .setRoot(entry) 112 .setChildren(inputMethodService ? [inputMethodService] : []) 113 .build(); 114 } 115 116 private makeEntryEagerPropertiesTree( 117 entryProto: 118 | android.view.inputmethod.IInputMethodServiceTraceProto 119 | perfetto.protos.IInputMethodServiceTraceProto, 120 ): PropertyTreeNode { 121 const denyList: string[] = []; 122 Object.getOwnPropertyNames(entryProto).forEach((it) => { 123 if (!HierarchyTreeServiceFactory.ENTRY_EAGER_PROPERTIES.includes(it)) { 124 denyList.push(it); 125 } 126 }); 127 128 return new PropertyTreeBuilderFromProto() 129 .setData(entryProto) 130 .setRootId('InputMethodService') 131 .setRootName('entry') 132 .setDenyList(denyList) 133 .build(); 134 } 135 136 private makeEntryLazyPropertiesStrategy( 137 entryProto: 138 | android.view.inputmethod.IInputMethodServiceTraceProto 139 | perfetto.protos.IInputMethodServiceTraceProto, 140 ): LazyPropertiesStrategyType { 141 return async () => { 142 return new PropertyTreeBuilderFromProto() 143 .setData(entryProto) 144 .setRootId('InputMethodService') 145 .setRootName('entry') 146 .setDenyList( 147 HierarchyTreeServiceFactory.ENTRY_EAGER_PROPERTIES.concat( 148 HierarchyTreeServiceFactory.ENTRY_DENYLIST_PROPERTIES, 149 ), 150 ) 151 .build(); 152 }; 153 } 154 155 private makeServiceEagerPropertiesTree( 156 serviceProto: 157 | android.inputmethodservice.IInputMethodServiceProto 158 | perfetto.protos.IInputMethodServiceProto, 159 ): PropertyTreeNode { 160 const denyList: string[] = []; 161 let data: any = serviceProto; 162 if (serviceProto) { 163 Object.getOwnPropertyNames(serviceProto).forEach((it) => { 164 if ( 165 !HierarchyTreeServiceFactory.SERVICE_EAGER_PROPERTIES.includes(it) 166 ) { 167 denyList.push(it); 168 } 169 }); 170 } else { 171 data = {inputMethodService: null}; 172 } 173 return new PropertyTreeBuilderFromProto() 174 .setData(serviceProto) 175 .setRootId('InputMethodService') 176 .setRootName('inputMethodService') 177 .setDenyList(denyList) 178 .setVisitPrototype(false) 179 .build(); 180 } 181 182 private makeServiceLazyPropertiesStrategy( 183 serviceProto: 184 | android.inputmethodservice.IInputMethodServiceProto 185 | perfetto.protos.IInputMethodServiceProto, 186 ): LazyPropertiesStrategyType { 187 return async () => { 188 return new PropertyTreeBuilderFromProto() 189 .setData(serviceProto ?? {inputMethodService: null}) 190 .setRootId('InputMethodService') 191 .setRootName('inputMethodService') 192 .setDenyList(HierarchyTreeServiceFactory.SERVICE_EAGER_PROPERTIES) 193 .setVisitPrototype(false) 194 .build(); 195 }; 196 } 197} 198