1/* 2 * Copyright (C) 2022 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 {FunctionUtils, OnProgressUpdateType} from 'common/function_utils'; 18import {Parser} from 'trace/parser'; 19import {TraceFile} from 'trace/trace_file'; 20import {TraceType} from 'trace/trace_type'; 21import {ParserAccessibility} from './parser_accessibility'; 22import {ParserEventLog} from './parser_eventlog'; 23import {ParserInputMethodClients} from './parser_input_method_clients'; 24import {ParserInputMethodManagerService} from './parser_input_method_manager_service'; 25import {ParserInputMethodService} from './parser_input_method_service'; 26import {ParserProtoLog} from './parser_protolog'; 27import {ParserScreenRecording} from './parser_screen_recording'; 28import {ParserScreenRecordingLegacy} from './parser_screen_recording_legacy'; 29import {ParserSurfaceFlinger} from './parser_surface_flinger'; 30import {ParserTransactions} from './parser_transactions'; 31import {ParserTransitionsShell} from './parser_transitions_shell'; 32import {ParserTransitionsWm} from './parser_transitions_wm'; 33import {ParserViewCapture} from './parser_view_capture'; 34import {ParserWindowManager} from './parser_window_manager'; 35import {ParserWindowManagerDump} from './parser_window_manager_dump'; 36 37export class ParserFactory { 38 static readonly PARSERS = [ 39 ParserAccessibility, 40 ParserInputMethodClients, 41 ParserInputMethodManagerService, 42 ParserInputMethodService, 43 ParserProtoLog, 44 ParserScreenRecording, 45 ParserScreenRecordingLegacy, 46 ParserSurfaceFlinger, 47 ParserTransactions, 48 ParserWindowManager, 49 ParserWindowManagerDump, 50 ParserEventLog, 51 ParserTransitionsWm, 52 ParserTransitionsShell, 53 ParserViewCapture, 54 ]; 55 56 private parsers = new Map<TraceType, Parser<object>>(); 57 58 async createParsers( 59 traceFiles: TraceFile[], 60 onProgressUpdate: OnProgressUpdateType = FunctionUtils.DO_NOTHING 61 ): Promise<[Array<{file: TraceFile; parser: Parser<object>}>, ParserError[]]> { 62 const errors: ParserError[] = []; 63 64 const parsers = new Array<{file: TraceFile; parser: Parser<object>}>(); 65 66 if (traceFiles.length === 0) { 67 errors.push(new ParserError(ParserErrorType.NO_INPUT_FILES)); 68 } 69 70 for (const [index, traceFile] of traceFiles.entries()) { 71 let hasFoundParser = false; 72 73 for (const ParserType of ParserFactory.PARSERS) { 74 try { 75 const parser = new ParserType(traceFile); 76 await parser.parse(); 77 hasFoundParser = true; 78 if (this.shouldUseParser(parser, errors)) { 79 this.parsers.set(parser.getTraceType(), parser); 80 parsers.push({file: traceFile, parser}); 81 } 82 break; 83 } catch (error) { 84 // skip current parser 85 } 86 } 87 88 if (!hasFoundParser) { 89 console.log(`Failed to load trace ${traceFile.file.name}`); 90 errors.push(new ParserError(ParserErrorType.UNSUPPORTED_FORMAT, traceFile.getDescriptor())); 91 } 92 93 onProgressUpdate((100 * (index + 1)) / traceFiles.length); 94 } 95 96 return [parsers, errors]; 97 } 98 99 private shouldUseParser(newParser: Parser<object>, errors: ParserError[]): boolean { 100 const oldParser = this.parsers.get(newParser.getTraceType()); 101 if (!oldParser) { 102 console.log( 103 `Loaded trace ${newParser 104 .getDescriptors() 105 .join()} (trace type: ${newParser.getTraceType()})` 106 ); 107 return true; 108 } 109 110 if (newParser.getLengthEntries() > oldParser.getLengthEntries()) { 111 console.log( 112 `Loaded trace ${newParser 113 .getDescriptors() 114 .join()} (trace type: ${newParser.getTraceType()}).` + 115 ` Replace trace ${oldParser.getDescriptors().join()}` 116 ); 117 errors.push( 118 new ParserError( 119 ParserErrorType.OVERRIDE, 120 oldParser.getDescriptors().join(), 121 oldParser.getTraceType() 122 ) 123 ); 124 return true; 125 } 126 127 console.log( 128 `Skipping trace ${newParser 129 .getDescriptors() 130 .join()} (trace type: ${newParser.getTraceType()}).` + 131 ` Keep trace ${oldParser.getDescriptors().join()}` 132 ); 133 errors.push( 134 new ParserError( 135 ParserErrorType.OVERRIDE, 136 newParser.getDescriptors().join(), 137 newParser.getTraceType() 138 ) 139 ); 140 return false; 141 } 142} 143 144export enum ParserErrorType { 145 NO_INPUT_FILES, 146 UNSUPPORTED_FORMAT, 147 OVERRIDE, 148} 149 150export class ParserError { 151 constructor( 152 public type: ParserErrorType, 153 public trace: string | undefined = undefined, 154 public traceType: TraceType | undefined = undefined 155 ) {} 156} 157