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 {SetFormatters} from 'parsers/operations/set_formatters'; 20import {TranslateIntDef} from 'parsers/operations/translate_intdef'; 21import {AbstractParser} from 'parsers/perfetto/abstract_parser'; 22import {FakeProtoBuilder} from 'parsers/perfetto/fake_proto_builder'; 23import {FakeProtoTransformer} from 'parsers/perfetto/fake_proto_transformer'; 24import {TamperedMessageType} from 'parsers/tampered_message_type'; 25import root from 'protos/input/latest/json'; 26import {perfetto} from 'protos/input/latest/static'; 27import {TraceFile} from 'trace/trace_file'; 28import {PropertyTreeNode} from 'trace/tree_node/property_tree_node'; 29import {WasmEngineProxy} from 'trace_processor/wasm_engine_proxy'; 30 31export abstract class AbstractInputEventParser extends AbstractParser<PropertyTreeNode> { 32 protected static readonly WrapperProto = TamperedMessageType.tamper( 33 root.lookupType('perfetto.protos.InputEventWrapper'), 34 ); 35 36 private static readonly DispatchEventsField = 37 AbstractInputEventParser.WrapperProto.fields['windowDispatchEvents']; 38 39 private static readonly DISPATCH_EVENT_OPS = [ 40 new SetFormatters(AbstractInputEventParser.DispatchEventsField), 41 new TranslateIntDef(AbstractInputEventParser.DispatchEventsField), 42 ]; 43 44 private static readonly DispatchTableName = 'android_input_event_dispatch'; 45 46 private dispatchEventTransformer: FakeProtoTransformer; 47 48 protected constructor( 49 traceFile: TraceFile, 50 traceProcessor: WasmEngineProxy, 51 timestampConverter: ParserTimestampConverter, 52 ) { 53 super(traceFile, traceProcessor, timestampConverter); 54 55 this.dispatchEventTransformer = new FakeProtoTransformer( 56 assertDefined( 57 AbstractInputEventParser.DispatchEventsField.tamperedMessageType, 58 ), 59 ); 60 } 61 62 protected async getDispatchEvents( 63 eventId: number, 64 ): Promise<perfetto.protos.AndroidWindowInputDispatchEvent[]> { 65 const sql = ` 66 SELECT d.id, 67 args.key, 68 args.value_type, 69 args.int_value, 70 args.string_value, 71 args.real_value 72 FROM ${AbstractInputEventParser.DispatchTableName} AS d 73 INNER JOIN args ON d.arg_set_id = args.arg_set_id 74 WHERE d.event_id = ${eventId} 75 ORDER BY d.id; 76 `; 77 const result = await this.traceProcessor.query(sql).waitAllRows(); 78 79 const dispatchEvents: perfetto.protos.AndroidWindowInputDispatchEvent[] = 80 []; 81 for (const it = result.iter({}); it.valid(); ) { 82 const builder = new FakeProtoBuilder(); 83 const prevId = it.get('id'); 84 while (it.valid() && it.get('id') === prevId) { 85 builder.addArg( 86 it.get('key') as string, 87 it.get('value_type') as string, 88 it.get('int_value') as bigint | undefined, 89 it.get('real_value') as number | undefined, 90 it.get('string_value') as string | undefined, 91 ); 92 it.next(); 93 } 94 dispatchEvents.push(builder.build()); 95 } 96 return dispatchEvents; 97 } 98 99 protected override getStdLibModuleName(): string | undefined { 100 return 'android.input'; 101 } 102 103 protected processDispatchEventsTree(tree: PropertyTreeNode) { 104 AbstractInputEventParser.DISPATCH_EVENT_OPS.forEach((operation) => { 105 operation.apply(tree); 106 }); 107 } 108} 109