xref: /aosp_15_r20/development/tools/winscope/src/parsers/input_method/hierarchy_tree_service_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 {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