• 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 {MakeTimestampStrategyType, Timestamp} from 'common/time/time';
19import {ParserTimestampConverter} from 'common/time/timestamp_converter';
20import {AddDefaults} from 'parsers/operations/add_defaults';
21import {SetFormatters} from 'parsers/operations/set_formatters';
22import {TransformToTimestamp} from 'parsers/operations/transform_to_timestamp';
23import {TranslateIntDef} from 'parsers/operations/translate_intdef';
24import {TamperedMessageType} from 'parsers/tampered_message_type';
25import {perfetto} from 'protos/transitions/latest/static';
26import root from 'protos/transitions/udc/json';
27import {com} from 'protos/transitions/udc/static';
28import {
29  EnumFormatter,
30  PropertyFormatter,
31  TIMESTAMP_NODE_FORMATTER,
32} from 'trace/tree_node/formatters';
33import {PropertyTreeBuilderFromProto} from 'trace/tree_node/property_tree_builder_from_proto';
34import {PropertyTreeNode} from 'trace/tree_node/property_tree_node';
35import {AddDuration} from './operations/add_duration';
36import {AddRealToBootTimeOffsetTimestamp} from './operations/add_real_to_elapsed_time_offset_timestamp';
37import {AddRootProperties} from './operations/add_root_properties';
38import {AddStatus} from './operations/add_status';
39import {UpdateAbortTimeNodes} from './operations/update_abort_time_nodes';
40import {TransitionType} from './transition_type';
41
42interface TransitionInfo {
43  entry:
44    | com.android.server.wm.shell.ITransition
45    | com.android.wm.shell.ITransition
46    | perfetto.protos.IShellTransition;
47  realToBootTimeOffsetNs: bigint | undefined;
48  timestampConverter: ParserTimestampConverter;
49  handlerMapping?: {[key: number]: string};
50}
51
52export class EntryPropertiesTreeFactory {
53  static readonly TRANSITION_OPERATIONS = [
54    new AddDuration(),
55    new AddStatus(),
56    new AddRootProperties(),
57  ];
58
59  private static readonly TransitionTraceProto = TamperedMessageType.tamper(
60    root.lookupType('com.android.server.wm.shell.TransitionTraceProto'),
61  );
62  private static readonly TransitionField =
63    EntryPropertiesTreeFactory.TransitionTraceProto.fields['transitions'];
64  private static readonly WM_ADD_DEFAULTS_OPERATION = new AddDefaults(
65    EntryPropertiesTreeFactory.TransitionField,
66    ['type', 'targets'],
67  );
68  private static WM_INTDEF_OPERATION = new TranslateIntDef(
69    EntryPropertiesTreeFactory.TransitionField,
70  );
71  private static readonly SET_FORMATTERS_OPERATION = new SetFormatters();
72  private static readonly PERFETTO_TRANSITION_OPERATIONS = [
73    new UpdateAbortTimeNodes(),
74  ];
75  private static readonly TRANSITION_TYPE_FORMATTER = new EnumFormatter(
76    TransitionType,
77  );
78
79  static makeTransitionPropertiesTree(
80    shellEntryTree: PropertyTreeNode,
81    wmEntryTree: PropertyTreeNode,
82  ): PropertyTreeNode {
83    const transitionTree = new PropertyTreeNode(
84      wmEntryTree.id,
85      wmEntryTree.name,
86      wmEntryTree.source,
87      undefined,
88    );
89
90    transitionTree.addOrReplaceChild(
91      assertDefined(shellEntryTree.getChildByName('shellData')),
92    );
93    transitionTree.addOrReplaceChild(
94      assertDefined(wmEntryTree.getChildByName('wmData')),
95    );
96    EntryPropertiesTreeFactory.TRANSITION_OPERATIONS.forEach((operation) =>
97      operation.apply(transitionTree),
98    );
99    return transitionTree;
100  }
101
102  static makeWmPropertiesTree(
103    info?: TransitionInfo,
104    denylistProperties: string[] = [],
105  ): PropertyTreeNode {
106    const tree = new PropertyTreeBuilderFromProto()
107      .setData({wmData: info?.entry ?? null})
108      .setRootId('TransitionTraceEntry')
109      .setRootName('Selected Transition')
110      .setDenyList(denylistProperties)
111      .setVisitPrototype(false)
112      .build();
113
114    if (!info) {
115      EntryPropertiesTreeFactory.SET_FORMATTERS_OPERATION.apply(tree);
116      return tree;
117    }
118
119    if (denylistProperties.length > 0) {
120      EntryPropertiesTreeFactory.PERFETTO_TRANSITION_OPERATIONS.forEach(
121        (operation) => operation.apply(tree),
122      );
123    }
124
125    let realToBootTimeOffsetTimestamp: Timestamp | undefined;
126
127    if (info.realToBootTimeOffsetNs !== undefined) {
128      realToBootTimeOffsetTimestamp =
129        info.timestampConverter.makeTimestampFromRealNs(
130          info.realToBootTimeOffsetNs,
131        );
132    }
133
134    const wmDataNode = assertDefined(tree.getChildByName('wmData'));
135    new AddRealToBootTimeOffsetTimestamp(realToBootTimeOffsetTimestamp).apply(
136      wmDataNode,
137    );
138    EntryPropertiesTreeFactory.WM_ADD_DEFAULTS_OPERATION.apply(wmDataNode);
139    new TransformToTimestamp(
140      [
141        'abortTimeNs',
142        'createTimeNs',
143        'sendTimeNs',
144        'finishTimeNs',
145        'startingWindowRemoveTimeNs',
146      ],
147      EntryPropertiesTreeFactory.makeTimestampStrategy(info.timestampConverter),
148    ).apply(wmDataNode);
149
150    const customFormatters = new Map<string, PropertyFormatter>([
151      ['type', EntryPropertiesTreeFactory.TRANSITION_TYPE_FORMATTER],
152      ['mode', EntryPropertiesTreeFactory.TRANSITION_TYPE_FORMATTER],
153      ['abortTimeNs', TIMESTAMP_NODE_FORMATTER],
154      ['createTimeNs', TIMESTAMP_NODE_FORMATTER],
155      ['sendTimeNs', TIMESTAMP_NODE_FORMATTER],
156      ['finishTimeNs', TIMESTAMP_NODE_FORMATTER],
157      ['startingWindowRemoveTimeNs', TIMESTAMP_NODE_FORMATTER],
158    ]);
159
160    new SetFormatters(undefined, customFormatters).apply(tree);
161
162    EntryPropertiesTreeFactory.WM_INTDEF_OPERATION.apply(tree);
163    return tree;
164  }
165
166  static makeShellPropertiesTree(
167    info?: TransitionInfo,
168    denylistProperties: string[] = [],
169  ): PropertyTreeNode {
170    const tree = new PropertyTreeBuilderFromProto()
171      .setData({shellData: info?.entry ?? null})
172      .setRootId('TransitionTraceEntry')
173      .setRootName('Selected Transition')
174      .setDenyList(denylistProperties)
175      .setVisitPrototype(false)
176      .build();
177
178    if (!info) {
179      EntryPropertiesTreeFactory.SET_FORMATTERS_OPERATION.apply(tree);
180      return tree;
181    }
182
183    if (denylistProperties.length > 0) {
184      EntryPropertiesTreeFactory.PERFETTO_TRANSITION_OPERATIONS.forEach(
185        (operation) => operation.apply(tree),
186      );
187    }
188
189    let realToBootTimeOffsetTimestamp: Timestamp | undefined;
190    if (info.realToBootTimeOffsetNs !== undefined) {
191      realToBootTimeOffsetTimestamp =
192        info.timestampConverter.makeTimestampFromRealNs(
193          info.realToBootTimeOffsetNs,
194        );
195    }
196
197    const shellDataNode = assertDefined(tree.getChildByName('shellData'));
198    new AddRealToBootTimeOffsetTimestamp(realToBootTimeOffsetTimestamp).apply(
199      shellDataNode,
200    );
201    new TransformToTimestamp(
202      ['dispatchTimeNs', 'mergeRequestTimeNs', 'mergeTimeNs', 'abortTimeNs'],
203      EntryPropertiesTreeFactory.makeTimestampStrategy(info.timestampConverter),
204    ).apply(shellDataNode);
205
206    const customFormatters = new Map<string, PropertyFormatter>([
207      ['type', EntryPropertiesTreeFactory.TRANSITION_TYPE_FORMATTER],
208      ['mode', EntryPropertiesTreeFactory.TRANSITION_TYPE_FORMATTER],
209      ['dispatchTimeNs', TIMESTAMP_NODE_FORMATTER],
210      ['mergeRequestTimeNs', TIMESTAMP_NODE_FORMATTER],
211      ['mergeTimeNs', TIMESTAMP_NODE_FORMATTER],
212      ['abortTimeNs', TIMESTAMP_NODE_FORMATTER],
213    ]);
214
215    if (info.handlerMapping) {
216      customFormatters.set('handler', new EnumFormatter(info.handlerMapping));
217    }
218
219    new SetFormatters(undefined, customFormatters).apply(tree);
220
221    return tree;
222  }
223
224  private static makeTimestampStrategy(
225    timestampConverter: ParserTimestampConverter,
226  ): MakeTimestampStrategyType {
227    return (valueNs: bigint) => {
228      return timestampConverter.makeTimestampFromBootTimeNs(valueNs);
229    };
230  }
231}
232