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