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 {ParserTimestampConverter} from 'common/timestamp_converter';
19import {AbstractInputEventParser} from 'parsers/input/perfetto/abstract_input_event_parser';
20import {SetFormatters} from 'parsers/operations/set_formatters';
21import {TranslateIntDef} from 'parsers/operations/translate_intdef';
22import {FakeProtoTransformer} from 'parsers/perfetto/fake_proto_transformer';
23import {Utils} from 'parsers/perfetto/utils';
24import {perfetto} from 'protos/input/latest/static';
25import {TraceFile} from 'trace/trace_file';
26import {TraceType} from 'trace/trace_type';
27import {PropertyTreeBuilderFromProto} from 'trace/tree_node/property_tree_builder_from_proto';
28import {PropertyTreeNode} from 'trace/tree_node/property_tree_node';
29import {WasmEngineProxy} from 'trace_processor/wasm_engine_proxy';
30
31export class ParserMotionEvent extends AbstractInputEventParser {
32  private static readonly MotionEventField =
33    AbstractInputEventParser.WrapperProto.fields['motionEvent'];
34
35  private static readonly MOTION_EVENT_OPS = [
36    new SetFormatters(ParserMotionEvent.MotionEventField),
37    new TranslateIntDef(ParserMotionEvent.MotionEventField),
38  ];
39
40  private motionEventTransformer: FakeProtoTransformer;
41
42  constructor(
43    traceFile: TraceFile,
44    traceProcessor: WasmEngineProxy,
45    timestampConverter: ParserTimestampConverter,
46  ) {
47    super(traceFile, traceProcessor, timestampConverter);
48
49    this.motionEventTransformer = new FakeProtoTransformer(
50      assertDefined(ParserMotionEvent.MotionEventField.tamperedMessageType),
51    );
52  }
53
54  override getTraceType(): TraceType {
55    return TraceType.INPUT_MOTION_EVENT;
56  }
57
58  override async getEntry(index: number): Promise<PropertyTreeNode> {
59    const motionEvent = await this.getMotionEventProto(index);
60    const events = perfetto.protos.InputEventWrapper.create({
61      motionEvent,
62      windowDispatchEvents: await this.getDispatchEvents(motionEvent.eventId),
63    });
64    return this.makeMotionPropertiesTree(events);
65  }
66
67  private async getMotionEventProto(
68    index: number,
69  ): Promise<perfetto.protos.AndroidMotionEvent> {
70    let motionEventProto = await Utils.queryEntry(
71      this.traceProcessor,
72      this.getTableName(),
73      this.entryIndexToRowIdMap,
74      index,
75    );
76
77    motionEventProto = this.motionEventTransformer.transform(motionEventProto);
78    return motionEventProto;
79  }
80
81  protected override getTableName(): string {
82    return 'android_motion_events';
83  }
84
85  protected override getStdLibModuleName(): string | undefined {
86    return 'android.input';
87  }
88
89  private makeMotionPropertiesTree(
90    entryProto: perfetto.protos.InputEventWrapper,
91  ): PropertyTreeNode {
92    const tree = new PropertyTreeBuilderFromProto()
93      .setData(entryProto)
94      .setRootId('AndroidMotionEvent')
95      .setRootName('entry')
96      .build();
97
98    ParserMotionEvent.MOTION_EVENT_OPS.forEach((operation) => {
99      operation.apply(assertDefined(tree.getChildByName('motionEvent')));
100    });
101
102    this.processDispatchEventsTree(
103      assertDefined(tree.getChildByName('windowDispatchEvents')),
104    );
105
106    return tree;
107  }
108}
109