• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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