1/* 2 * Copyright (C) 2023 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 {ParserTimestampConverter} from 'common/timestamp_converter'; 18import {UserNotifier} from 'common/user_notifier'; 19import {ProgressListener} from 'messaging/progress_listener'; 20import {InvalidPerfettoTrace} from 'messaging/user_warnings'; 21import {ParserKeyEvent} from 'parsers/input/perfetto/parser_key_event'; 22import {ParserMotionEvent} from 'parsers/input/perfetto/parser_motion_event'; 23import {ParserInputMethodClients} from 'parsers/input_method/perfetto/parser_input_method_clients'; 24import {ParserInputMethodManagerService} from 'parsers/input_method/perfetto/parser_input_method_manager_service'; 25import {ParserInputMethodService} from 'parsers/input_method/perfetto/parser_input_method_service'; 26import {ParserProtolog} from 'parsers/protolog/perfetto/parser_protolog'; 27import {ParserSurfaceFlinger} from 'parsers/surface_flinger/perfetto/parser_surface_flinger'; 28import {ParserTransactions} from 'parsers/transactions/perfetto/parser_transactions'; 29import {ParserTransitions} from 'parsers/transitions/perfetto/parser_transitions'; 30import {ParserViewCapture} from 'parsers/view_capture/perfetto/parser_view_capture'; 31import {ParserWindowManager} from 'parsers/window_manager/perfetto/parser_window_manager'; 32import {Parser} from 'trace/parser'; 33import {TraceFile} from 'trace/trace_file'; 34import {TraceProcessorFactory} from 'trace_processor/trace_processor_factory'; 35import {WasmEngineProxy} from 'trace_processor/wasm_engine_proxy'; 36 37export class ParserFactory { 38 private static readonly PARSERS = [ 39 ParserInputMethodClients, 40 ParserInputMethodManagerService, 41 ParserInputMethodService, 42 ParserProtolog, 43 ParserSurfaceFlinger, 44 ParserTransactions, 45 ParserTransitions, 46 ParserViewCapture, 47 ParserWindowManager, 48 ParserMotionEvent, 49 ParserKeyEvent, 50 ]; 51 private static readonly CHUNK_SIZE_BYTES = 50 * 1024 * 1024; 52 53 async createParsers( 54 traceFile: TraceFile, 55 timestampConverter: ParserTimestampConverter, 56 progressListener?: ProgressListener, 57 ): Promise<Array<Parser<object>>> { 58 const traceProcessor = await this.initializeTraceProcessor(); 59 for ( 60 let chunkStart = 0; 61 chunkStart < traceFile.file.size; 62 chunkStart += ParserFactory.CHUNK_SIZE_BYTES 63 ) { 64 progressListener?.onProgressUpdate( 65 'Loading perfetto trace...', 66 (chunkStart / traceFile.file.size) * 100, 67 ); 68 const chunkEnd = chunkStart + ParserFactory.CHUNK_SIZE_BYTES; 69 const data = await traceFile.file 70 .slice(chunkStart, chunkEnd) 71 .arrayBuffer(); 72 try { 73 await traceProcessor.parse(new Uint8Array(data)); 74 } catch (e) { 75 console.error('Trace processor failed to parse data:', e); 76 return []; 77 } 78 } 79 await traceProcessor.notifyEof(); 80 81 progressListener?.onProgressUpdate( 82 'Reading from trace processor...', 83 undefined, 84 ); 85 const parsers: Array<Parser<object>> = []; 86 87 let hasFoundParser = false; 88 89 const errors: string[] = []; 90 for (const ParserType of ParserFactory.PARSERS) { 91 try { 92 const parser = new ParserType( 93 traceFile, 94 traceProcessor, 95 timestampConverter, 96 ); 97 await parser.parse(); 98 if (parser instanceof ParserViewCapture) { 99 parsers.push(...parser.getWindowParsers()); 100 } else { 101 parsers.push(parser); 102 } 103 hasFoundParser = true; 104 } catch (error) { 105 // skip current parser 106 errors.push((error as Error).message); 107 } 108 } 109 110 if (!hasFoundParser) { 111 UserNotifier.add( 112 new InvalidPerfettoTrace(traceFile.getDescriptor(), errors), 113 ); 114 } 115 116 return parsers; 117 } 118 119 private async initializeTraceProcessor(): Promise<WasmEngineProxy> { 120 const traceProcessor = await TraceProcessorFactory.getSingleInstance(); 121 122 await traceProcessor.resetTraceProcessor({ 123 cropTrackEvents: false, 124 ingestFtraceInRawTable: false, 125 analyzeTraceProtoContent: false, 126 }); 127 128 return traceProcessor; 129 } 130} 131