• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright 2017, 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
17/* eslint-disable camelcase */
18/* eslint-disable max-len */
19
20import jsonProtoDefsAccessibility from 'frameworks/base/core/proto/android/server/accessibilitytrace.proto';
21import jsonProtoDefsWm from 'frameworks/base/core/proto/android/server/windowmanagertrace.proto';
22import jsonProtoDefsProtoLog from 'frameworks/base/core/proto/android/internal/protolog.proto';
23import jsonProtoDefsSf from 'frameworks/native/services/surfaceflinger/layerproto/layerstrace.proto';
24import jsonProtoDefsTransaction from 'frameworks/native/services/surfaceflinger/layerproto/transactions.proto';
25import jsonProtoDefsTransactionLegacy from 'frameworks/native/cmds/surfacereplayer/proto/src/trace.proto';
26import jsonProtoDefsWl from 'WaylandSafePath/waylandtrace.proto';
27import jsonProtoDefsSysUi from 'frameworks/base/packages/SystemUI/src/com/android/systemui/tracing/sysui_trace.proto';
28import jsonProtoDefsLauncher from 'packages/apps/Launcher3/protos/launcher_trace_file.proto';
29import jsonProtoDefsIme from 'frameworks/base/core/proto/android/view/inputmethod/inputmethodeditortrace.proto';
30import jsonProtoDefsTags from 'platform_testing/libraries/flicker/src/com/android/server/wm/proto/tags.proto';
31import jsonProtoDefsErrors from 'platform_testing/libraries/flicker/src/com/android/server/wm/proto/errors.proto';
32import protobuf from 'protobufjs';
33import {transform_accessibility_trace} from './transform_accessibility.js';
34import {transform_transaction_trace} from './transform_transaction.js';
35import {transform_transaction_trace_legacy} from './transform_transaction_legacy.js';
36import {transform_wl_outputstate, transform_wayland_trace} from './transform_wl.js';
37import {transformProtolog} from './transform_protolog.js';
38import {transform_sysui_trace} from './transform_sys_ui.js';
39import {transform_launcher_trace} from './transform_launcher.js';
40import {transform_ime_trace_clients, transform_ime_trace_service, transform_ime_trace_managerservice} from './transform_ime.js';
41import {mp4Decoder} from './decodeVideo.js';
42
43import AccessibilityTrace from '@/traces/Accessibility.ts';
44import SurfaceFlingerTrace from '@/traces/SurfaceFlinger.ts';
45import WindowManagerTrace from '@/traces/WindowManager.ts';
46import TransactionsTrace from '@/traces/Transactions.ts';
47import TransactionsTraceLegacy from '@/traces/TransactionsLegacy.ts';
48import ScreenRecordingTrace from '@/traces/ScreenRecording.ts';
49import WaylandTrace from '@/traces/Wayland.ts';
50import ProtoLogTrace from '@/traces/ProtoLog.ts';
51import SystemUITrace from '@/traces/SystemUI.ts';
52import LauncherTrace from '@/traces/Launcher.ts';
53import ImeTraceClients from '@/traces/InputMethodClients.ts';
54import ImeTraceService from '@/traces/InputMethodService.ts';
55import ImeTraceManagerService from '@/traces/InputMethodManagerService.ts';
56
57import SurfaceFlingerDump from '@/dumps/SurfaceFlinger.ts';
58import WindowManagerDump from '@/dumps/WindowManager.ts';
59import WaylandDump from '@/dumps/Wayland.ts';
60
61import TagTrace from '@/traces/TraceTag.ts';
62import ErrorTrace from '@/traces/TraceError.ts';
63
64const AccessibilityTraceMessage = lookup_type(jsonProtoDefsAccessibility, 'com.android.server.accessibility.AccessibilityTraceFileProto');
65const WmTraceMessage = lookup_type(jsonProtoDefsWm, 'com.android.server.wm.WindowManagerTraceFileProto');
66const WmDumpMessage = lookup_type(jsonProtoDefsWm, 'com.android.server.wm.WindowManagerServiceDumpProto');
67const SfTraceMessage = lookup_type(jsonProtoDefsSf, 'android.surfaceflinger.LayersTraceFileProto');
68const SfDumpMessage = lookup_type(jsonProtoDefsSf, 'android.surfaceflinger.LayersProto');
69const SfTransactionTraceMessage = lookup_type(jsonProtoDefsTransaction, 'TransactionTraceFile');
70const SfTransactionTraceMessageLegacy = lookup_type(jsonProtoDefsTransactionLegacy, 'Trace');
71const WaylandTraceMessage = lookup_type(jsonProtoDefsWl, 'org.chromium.arc.wayland_composer.TraceFileProto');
72const WaylandDumpMessage = lookup_type(jsonProtoDefsWl, 'org.chromium.arc.wayland_composer.OutputStateProto');
73const ProtoLogMessage = lookup_type(jsonProtoDefsProtoLog, 'com.android.internal.protolog.ProtoLogFileProto');
74const SystemUiTraceMessage = lookup_type(jsonProtoDefsSysUi, 'com.android.systemui.tracing.SystemUiTraceFileProto');
75const LauncherTraceMessage = lookup_type(jsonProtoDefsLauncher, 'com.android.launcher3.tracing.LauncherTraceFileProto');
76const InputMethodClientsTraceMessage = lookup_type(jsonProtoDefsIme, 'android.view.inputmethod.InputMethodClientsTraceFileProto');
77const InputMethodServiceTraceMessage = lookup_type(jsonProtoDefsIme, 'android.view.inputmethod.InputMethodServiceTraceFileProto');
78const InputMethodManagerServiceTraceMessage = lookup_type(jsonProtoDefsIme, 'android.view.inputmethod.InputMethodManagerServiceTraceFileProto');
79const TagTraceMessage = lookup_type(jsonProtoDefsTags, 'com.android.server.wm.flicker.FlickerTagTraceProto');
80const ErrorTraceMessage = lookup_type(jsonProtoDefsErrors, 'com.android.server.wm.flicker.FlickerErrorTraceProto');
81
82const ACCESSIBILITY_MAGIC_NUMBER = [0x09, 0x41, 0x31, 0x31, 0x59, 0x54, 0x52, 0x41, 0x43]; // .A11YTRAC
83const LAYER_TRACE_MAGIC_NUMBER = [0x09, 0x4c, 0x59, 0x52, 0x54, 0x52, 0x41, 0x43, 0x45]; // .LYRTRACE
84const TRANSACTIONS_TRACE_MAGIC_NUMBER = [0x09, 0x54, 0x4e, 0x58, 0x54, 0x52, 0x41, 0x43, 0x45]; // .TNXTRACE
85const WINDOW_TRACE_MAGIC_NUMBER = [0x09, 0x57, 0x49, 0x4e, 0x54, 0x52, 0x41, 0x43, 0x45]; // .WINTRACE
86const MPEG4_MAGIC_NMBER = [0x00, 0x00, 0x00, 0x18, 0x66, 0x74, 0x79, 0x70, 0x6d, 0x70, 0x34, 0x32]; // ....ftypmp42
87const WAYLAND_TRACE_MAGIC_NUMBER = [0x09, 0x57, 0x59, 0x4c, 0x54, 0x52, 0x41, 0x43, 0x45]; // .WYLTRACE
88const PROTO_LOG_MAGIC_NUMBER = [0x09, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x4c, 0x4f, 0x47]; // .PROTOLOG
89const SYSTEM_UI_MAGIC_NUMBER = [0x09, 0x53, 0x59, 0x53, 0x55, 0x49, 0x54, 0x52, 0x43]; // .SYSUITRC
90const LAUNCHER_MAGIC_NUMBER = [0x09, 0x4C, 0x4E, 0x43, 0x48, 0x52, 0x54, 0x52, 0x43]; // .LNCHRTRC
91const IMC_TRACE_MAGIC_NUMBER = [0x09, 0x49, 0x4d, 0x43, 0x54, 0x52, 0x41, 0x43, 0x45]; // .IMCTRACE
92const IMS_TRACE_MAGIC_NUMBER = [0x09, 0x49, 0x4d, 0x53, 0x54, 0x52, 0x41, 0x43, 0x45]; // .IMSTRACE
93const IMM_TRACE_MAGIC_NUMBER = [0x09, 0x49, 0x4d, 0x4d, 0x54, 0x52, 0x41, 0x43, 0x45]; // .IMMTRACE
94const TAG_TRACE_MAGIC_NUMBER = [0x09, 0x54, 0x41, 0x47, 0x54, 0x52, 0x41, 0x43, 0x45]; //.TAGTRACE
95const ERROR_TRACE_MAGIC_NUMBER = [0x09, 0x45, 0x52, 0x52, 0x54, 0x52, 0x41, 0x43, 0x45]; //.ERRORTRACE
96
97const FILE_TYPES = Object.freeze({
98  ACCESSIBILITY_TRACE: 'AccessibilityTrace',
99  WINDOW_MANAGER_TRACE: 'WindowManagerTrace',
100  SURFACE_FLINGER_TRACE: 'SurfaceFlingerTrace',
101  WINDOW_MANAGER_DUMP: 'WindowManagerDump',
102  SURFACE_FLINGER_DUMP: 'SurfaceFlingerDump',
103  SCREEN_RECORDING: 'ScreenRecording',
104  TRANSACTIONS_TRACE: 'TransactionsTrace',
105  TRANSACTIONS_TRACE_LEGACY: 'TransactionsTraceLegacy',
106  WAYLAND_TRACE: 'WaylandTrace',
107  WAYLAND_DUMP: 'WaylandDump',
108  PROTO_LOG: 'ProtoLog',
109  SYSTEM_UI: 'SystemUI',
110  LAUNCHER: 'Launcher',
111  IME_TRACE_CLIENTS: 'ImeTraceClients',
112  IME_TRACE_SERVICE: 'ImeTrace InputMethodService',
113  IME_TRACE_MANAGERSERVICE: 'ImeTrace InputMethodManagerService',
114  TAG_TRACE: 'TagTrace',
115  ERROR_TRACE: 'ErrorTrace',
116});
117
118const WINDOW_MANAGER_ICON = 'view_compact';
119const SURFACE_FLINGER_ICON = 'filter_none';
120const SCREEN_RECORDING_ICON = 'videocam';
121const TRANSACTION_ICON = 'timeline';
122const WAYLAND_ICON = 'filter_none';
123const PROTO_LOG_ICON = 'notes';
124const SYSTEM_UI_ICON = 'filter_none';
125const LAUNCHER_ICON = 'filter_none';
126const IME_ICON = 'keyboard';
127const ACCESSIBILITY_ICON = 'filter_none';
128const TAG_ICON = 'details';
129const TRACE_ERROR_ICON = 'warning';
130
131const FILE_ICONS = {
132  [FILE_TYPES.ACCESSIBILITY_TRACE]: ACCESSIBILITY_ICON,
133  [FILE_TYPES.WINDOW_MANAGER_TRACE]: WINDOW_MANAGER_ICON,
134  [FILE_TYPES.SURFACE_FLINGER_TRACE]: SURFACE_FLINGER_ICON,
135  [FILE_TYPES.WINDOW_MANAGER_DUMP]: WINDOW_MANAGER_ICON,
136  [FILE_TYPES.SURFACE_FLINGER_DUMP]: SURFACE_FLINGER_ICON,
137  [FILE_TYPES.SCREEN_RECORDING]: SCREEN_RECORDING_ICON,
138  [FILE_TYPES.TRANSACTIONS_TRACE]: TRANSACTION_ICON,
139  [FILE_TYPES.TRANSACTIONS_TRACE_LEGACY]: TRANSACTION_ICON,
140  [FILE_TYPES.WAYLAND_TRACE]: WAYLAND_ICON,
141  [FILE_TYPES.WAYLAND_DUMP]: WAYLAND_ICON,
142  [FILE_TYPES.PROTO_LOG]: PROTO_LOG_ICON,
143  [FILE_TYPES.SYSTEM_UI]: SYSTEM_UI_ICON,
144  [FILE_TYPES.LAUNCHER]: LAUNCHER_ICON,
145  [FILE_TYPES.IME_TRACE_CLIENTS]: IME_ICON,
146  [FILE_TYPES.IME_TRACE_SERVICE]: IME_ICON,
147  [FILE_TYPES.IME_TRACE_MANAGERSERVICE]: IME_ICON,
148  [FILE_TYPES.TAG_TRACE]: TAG_ICON,
149  [FILE_TYPES.ERROR_TRACE]: TRACE_ERROR_ICON,
150};
151
152function oneOf(dataType) {
153  return {oneOf: true, type: dataType};
154}
155
156const TRACE_TYPES = Object.freeze({
157  ACCESSIBILITY: 'AccessibilityTrace',
158  WINDOW_MANAGER: 'WindowManagerTrace',
159  SURFACE_FLINGER: 'SurfaceFlingerTrace',
160  SCREEN_RECORDING: 'ScreenRecording',
161  TRANSACTION: 'Transaction',
162  TRANSACTION_LEGACY: 'Transaction (Legacy)',
163  WAYLAND: 'Wayland',
164  PROTO_LOG: 'ProtoLog',
165  SYSTEM_UI: 'SystemUI',
166  LAUNCHER: 'Launcher',
167  IME_CLIENTS: 'ImeTrace Clients',
168  IME_SERVICE: 'ImeTrace InputMethodService',
169  IME_MANAGERSERVICE: 'ImeTrace InputMethodManagerService',
170  TAG: 'TagTrace',
171  ERROR: 'ErrorTrace',
172});
173
174const TRACE_INFO = {
175  [TRACE_TYPES.ACCESSIBILITY]: {
176    name: 'Accessibility',
177    icon: ACCESSIBILITY_ICON,
178    files: [oneOf(FILE_TYPES.ACCESSIBILITY_TRACE)],
179    constructor: AccessibilityTrace,
180  },
181  [TRACE_TYPES.WINDOW_MANAGER]: {
182    name: 'WindowManager',
183    icon: WINDOW_MANAGER_ICON,
184    files: [oneOf(FILE_TYPES.WINDOW_MANAGER_TRACE)],
185    constructor: WindowManagerTrace,
186  },
187  [TRACE_TYPES.SURFACE_FLINGER]: {
188    name: 'SurfaceFlinger',
189    icon: SURFACE_FLINGER_ICON,
190    files: [oneOf(FILE_TYPES.SURFACE_FLINGER_TRACE)],
191    constructor: SurfaceFlingerTrace,
192  },
193  [TRACE_TYPES.SCREEN_RECORDING]: {
194    name: 'Screen recording',
195    icon: SCREEN_RECORDING_ICON,
196    files: [oneOf(FILE_TYPES.SCREEN_RECORDING)],
197    constructor: ScreenRecordingTrace,
198  },
199  [TRACE_TYPES.TRANSACTION]: {
200    name: 'Transaction',
201    icon: TRANSACTION_ICON,
202    files: [
203      oneOf(FILE_TYPES.TRANSACTIONS_TRACE),
204    ],
205    constructor: TransactionsTrace,
206  },
207  [TRACE_TYPES.TRANSACTION_LEGACY]: {
208    name: 'Transactions (Legacy)',
209    icon: TRANSACTION_ICON,
210    files: [
211      oneOf(FILE_TYPES.TRANSACTIONS_TRACE_LEGACY),
212    ],
213    constructor: TransactionsTraceLegacy,
214  },
215  [TRACE_TYPES.WAYLAND]: {
216    name: 'Wayland',
217    icon: WAYLAND_ICON,
218    files: [oneOf(FILE_TYPES.WAYLAND_TRACE)],
219    constructor: WaylandTrace,
220  },
221  [TRACE_TYPES.PROTO_LOG]: {
222    name: 'ProtoLog',
223    icon: PROTO_LOG_ICON,
224    files: [oneOf(FILE_TYPES.PROTO_LOG)],
225    constructor: ProtoLogTrace,
226  },
227  [TRACE_TYPES.SYSTEM_UI]: {
228    name: 'SystemUI',
229    icon: SYSTEM_UI_ICON,
230    files: [oneOf(FILE_TYPES.SYSTEM_UI)],
231    constructor: SystemUITrace,
232  },
233  [TRACE_TYPES.LAUNCHER]: {
234    name: 'Launcher',
235    icon: LAUNCHER_ICON,
236    files: [oneOf(FILE_TYPES.LAUNCHER)],
237    constructor: LauncherTrace,
238  },
239  [TRACE_TYPES.IME_CLIENTS]: {
240    name: 'InputMethodClients',
241    icon: IME_ICON,
242    files: [oneOf(FILE_TYPES.IME_TRACE_CLIENTS)],
243    constructor: ImeTraceClients,
244  },
245  [TRACE_TYPES.IME_SERVICE]: {
246    name: 'InputMethodService',
247    icon: IME_ICON,
248    files: [oneOf(FILE_TYPES.IME_TRACE_SERVICE)],
249    constructor: ImeTraceService,
250  },
251  [TRACE_TYPES.IME_MANAGERSERVICE]: {
252    name: 'InputMethodManagerService',
253    icon: IME_ICON,
254    files: [oneOf(FILE_TYPES.IME_TRACE_MANAGERSERVICE)],
255    constructor: ImeTraceManagerService,
256  },
257  [TRACE_TYPES.TAG]: {
258    name: 'Tag',
259    icon: TAG_ICON,
260    files: [oneOf(FILE_TYPES.TAG_TRACE)],
261    constructor: TagTrace,
262  },
263  [TRACE_TYPES.ERROR]: {
264    name: 'Error',
265    icon: TRACE_ERROR_ICON,
266    files: [oneOf(FILE_TYPES.ERROR_TRACE)],
267    constructor: ErrorTrace,
268  },
269};
270
271const DUMP_TYPES = Object.freeze({
272  WINDOW_MANAGER: 'WindowManagerDump',
273  SURFACE_FLINGER: 'SurfaceFlingerDump',
274  WAYLAND: 'WaylandDump',
275});
276
277const DUMP_INFO = {
278  [DUMP_TYPES.WINDOW_MANAGER]: {
279    name: 'WindowManager',
280    icon: WINDOW_MANAGER_ICON,
281    files: [oneOf(FILE_TYPES.WINDOW_MANAGER_DUMP)],
282    constructor: WindowManagerDump,
283  },
284  [DUMP_TYPES.SURFACE_FLINGER]: {
285    name: 'SurfaceFlinger',
286    icon: SURFACE_FLINGER_ICON,
287    files: [oneOf(FILE_TYPES.SURFACE_FLINGER_DUMP)],
288    constructor: SurfaceFlingerDump,
289  },
290  [DUMP_TYPES.WAYLAND]: {
291    name: 'Wayland',
292    icon: WAYLAND_ICON,
293    files: [oneOf(FILE_TYPES.WAYLAND_DUMP)],
294    constructor: WaylandDump,
295  },
296};
297
298export const TRACE_ICONS = {
299  [TRACE_TYPES.WINDOW_MANAGER]: WINDOW_MANAGER_ICON,
300  [TRACE_TYPES.SURFACE_FLINGER]: SURFACE_FLINGER_ICON,
301  [TRACE_TYPES.SCREEN_RECORDING]: SCREEN_RECORDING_ICON,
302  [TRACE_TYPES.TRANSACTION]: TRANSACTION_ICON,
303  [TRACE_TYPES.TRANSACTION_LEGACY]: TRANSACTION_ICON,
304  [TRACE_TYPES.WAYLAND]: WAYLAND_ICON,
305  [TRACE_TYPES.PROTO_LOG]: PROTO_LOG_ICON,
306  [TRACE_TYPES.SYSTEM_UI]: SYSTEM_UI_ICON,
307  [TRACE_TYPES.LAUNCHER]: LAUNCHER_ICON,
308  [TRACE_TYPES.IME_CLIENTS]: IME_ICON,
309  [TRACE_TYPES.IME_SERVICE]: IME_ICON,
310  [TRACE_TYPES.IME_MANAGERSERVICE]: IME_ICON,
311  [TRACE_TYPES.TAG_TRACE]: TAG_ICON,
312  [TRACE_TYPES.ERROR_TRACE]: TRACE_ERROR_ICON,
313
314  [DUMP_TYPES.WINDOW_MANAGER]: WINDOW_MANAGER_ICON,
315  [DUMP_TYPES.SURFACE_FLINGER]: SURFACE_FLINGER_ICON,
316  [DUMP_TYPES.WAYLAND]: WAYLAND_ICON,
317};
318
319// TODO: Rename name to defaultName
320const FILE_DECODERS = {
321  [FILE_TYPES.ACCESSIBILITY_TRACE]: {
322    name: 'Accessibility trace',
323    decoder: protoDecoder,
324    decoderParams: {
325      type: FILE_TYPES.ACCESSIBILITY_TRACE,
326      objTypeProto: AccessibilityTraceMessage,
327      transform: transform_accessibility_trace,
328      timeline: true,
329    },
330  },
331  [FILE_TYPES.WINDOW_MANAGER_TRACE]: {
332    name: 'WindowManager trace',
333    decoder: protoDecoder,
334    decoderParams: {
335      type: FILE_TYPES.WINDOW_MANAGER_TRACE,
336      objTypeProto: WmTraceMessage,
337      transform: WindowManagerTrace.fromProto,
338      timeline: true,
339    },
340  },
341  [FILE_TYPES.SURFACE_FLINGER_TRACE]: {
342    name: 'SurfaceFlinger trace',
343    decoder: protoDecoder,
344    decoderParams: {
345      type: FILE_TYPES.SURFACE_FLINGER_TRACE,
346      mime: 'application/octet-stream',
347      objTypeProto: SfTraceMessage,
348      transform: SurfaceFlingerTrace.fromProto,
349      timeline: true,
350    },
351  },
352  [FILE_TYPES.WAYLAND_TRACE]: {
353    name: 'Wayland trace',
354    decoder: protoDecoder,
355    decoderParams: {
356      type: FILE_TYPES.WAYLAND_TRACE,
357      mime: 'application/octet-stream',
358      objTypeProto: WaylandTraceMessage,
359      transform: transform_wayland_trace,
360      timeline: true,
361    },
362  },
363  [FILE_TYPES.SURFACE_FLINGER_DUMP]: {
364    name: 'SurfaceFlinger dump',
365    decoder: protoDecoder,
366    decoderParams: {
367      type: FILE_TYPES.SURFACE_FLINGER_DUMP,
368      mime: 'application/octet-stream',
369      objTypeProto: [SfDumpMessage, SfTraceMessage],
370      transform: [SurfaceFlingerDump.fromProto, SurfaceFlingerTrace.fromProto],
371      timeline: true,
372    },
373  },
374  [FILE_TYPES.WINDOW_MANAGER_DUMP]: {
375    name: 'WindowManager dump',
376    decoder: protoDecoder,
377    decoderParams: {
378      type: FILE_TYPES.WINDOW_MANAGER_DUMP,
379      mime: 'application/octet-stream',
380      objTypeProto: WmDumpMessage,
381      transform: WindowManagerDump.fromProto,
382      timeline: true,
383    },
384  },
385  [FILE_TYPES.WAYLAND_DUMP]: {
386    name: 'Wayland dump',
387    decoder: protoDecoder,
388    decoderParams: {
389      type: FILE_TYPES.WAYLAND_DUMP,
390      mime: 'application/octet-stream',
391      objTypeProto: WaylandDumpMessage,
392      transform: transform_wl_outputstate,
393      timeline: true,
394    },
395  },
396  [FILE_TYPES.SCREEN_RECORDING]: {
397    name: 'Screen recording',
398    decoder: videoDecoder,
399    decoderParams: {
400      type: FILE_TYPES.SCREEN_RECORDING,
401      mime: 'video/mp4',
402      videoDecoder: mp4Decoder,
403    },
404  },
405  [FILE_TYPES.TRANSACTIONS_TRACE]: {
406    name: 'Transaction',
407    decoder: protoDecoder,
408    decoderParams: {
409      type: FILE_TYPES.TRANSACTIONS_TRACE,
410      mime: 'application/octet-stream',
411      objTypeProto: SfTransactionTraceMessage,
412      transform: transform_transaction_trace,
413      timeline: true,
414    },
415  },
416  [FILE_TYPES.TRANSACTIONS_TRACE_LEGACY]: {
417    name: 'Transactions (Legacy)',
418    decoder: protoDecoder,
419    decoderParams: {
420      type: FILE_TYPES.TRANSACTIONS_TRACE_LEGACY,
421      mime: 'application/octet-stream',
422      objTypeProto: SfTransactionTraceMessageLegacy,
423      transform: transform_transaction_trace_legacy,
424      timeline: true,
425    },
426  },
427  [FILE_TYPES.PROTO_LOG]: {
428    name: 'ProtoLog',
429    decoder: protoDecoder,
430    decoderParams: {
431      type: FILE_TYPES.PROTO_LOG,
432      mime: 'application/octet-stream',
433      objTypeProto: ProtoLogMessage,
434      transform: transformProtolog,
435      timeline: true,
436    },
437  },
438  [FILE_TYPES.SYSTEM_UI]: {
439    name: 'SystemUI trace',
440    decoder: protoDecoder,
441    decoderParams: {
442      type: FILE_TYPES.SYSTEM_UI,
443      mime: 'application/octet-stream',
444      objTypeProto: SystemUiTraceMessage,
445      transform: transform_sysui_trace,
446      timeline: true,
447    },
448  },
449  [FILE_TYPES.LAUNCHER]: {
450    name: 'Launcher trace',
451    decoder: protoDecoder,
452    decoderParams: {
453      type: FILE_TYPES.LAUNCHER,
454      mime: 'application/octet-stream',
455      objTypeProto: LauncherTraceMessage,
456      transform: transform_launcher_trace,
457      timeline: true,
458    },
459  },
460  [FILE_TYPES.IME_TRACE_CLIENTS]: {
461    name: 'InputMethodClients trace',
462    decoder: protoDecoder,
463    decoderParams: {
464      type: FILE_TYPES.IME_TRACE_CLIENTS,
465      mime: 'application/octet-stream',
466      objTypeProto: InputMethodClientsTraceMessage,
467      transform: transform_ime_trace_clients,
468      timeline: true,
469    },
470  },
471  [FILE_TYPES.IME_TRACE_SERVICE]: {
472    name: 'InputMethodService trace',
473    decoder: protoDecoder,
474    decoderParams: {
475      type: FILE_TYPES.IME_TRACE_SERVICE,
476      mime: 'application/octet-stream',
477      objTypeProto: InputMethodServiceTraceMessage,
478      transform: transform_ime_trace_service,
479      timeline: true,
480    },
481  },
482  [FILE_TYPES.IME_TRACE_MANAGERSERVICE]: {
483    name: 'InputMethodManagerService trace',
484    decoder: protoDecoder,
485    decoderParams: {
486      type: FILE_TYPES.IME_TRACE_MANAGERSERVICE,
487      mime: 'application/octet-stream',
488      objTypeProto: InputMethodManagerServiceTraceMessage,
489      transform: transform_ime_trace_managerservice,
490      timeline: true,
491    },
492  },
493  [FILE_TYPES.TAG_TRACE]: {
494    name: 'Tag trace',
495    decoder: protoDecoder,
496    decoderParams: {
497      type: FILE_TYPES.TAG_TRACE,
498      objTypeProto: TagTraceMessage,
499      transform: TagTrace.fromProto,
500      timeline: true,
501    },
502  },
503  [FILE_TYPES.ERROR_TRACE]: {
504    name: 'Error trace',
505    decoder: protoDecoder,
506    decoderParams: {
507      type: FILE_TYPES.ERROR_TRACE,
508      objTypeProto: ErrorTraceMessage,
509      transform: ErrorTrace.fromProto,
510      timeline: true,
511    },
512  },
513};
514
515function lookup_type(protoPath, type) {
516  return protobuf.Root.fromJSON(protoPath).lookupType(type);
517}
518
519// Replace enum values with string representation and
520// add default values to the proto objects. This function also handles
521// a special case with TransformProtos where the matrix may be derived
522// from the transform type.
523function modifyProtoFields(protoObj, displayDefaults) {
524  if (!protoObj || protoObj !== Object(protoObj) || !protoObj.$type) {
525    return;
526  }
527
528  for (const fieldName in protoObj.$type.fields) {
529    if (protoObj.$type.fields.hasOwnProperty(fieldName)) {
530      const fieldProperties = protoObj.$type.fields[fieldName];
531      const field = protoObj[fieldName];
532
533      if (Array.isArray(field)) {
534        field.forEach((item, _) => {
535          modifyProtoFields(item, displayDefaults);
536        });
537        continue;
538      }
539
540      if (displayDefaults && !(field)) {
541        protoObj[fieldName] = fieldProperties.defaultValue;
542      }
543
544      if (fieldProperties.resolvedType && fieldProperties.resolvedType.valuesById) {
545        protoObj[fieldName] = fieldProperties.resolvedType.valuesById[protoObj[fieldProperties.name]];
546        continue;
547      }
548      modifyProtoFields(protoObj[fieldName], displayDefaults);
549    }
550  }
551}
552
553function decodeAndTransformProto(buffer, params, displayDefaults) {
554  var objTypesProto = [];
555  var transforms = [];
556  if (!Array.isArray(params.objTypeProto)) {
557    objTypesProto = [params.objTypeProto];
558    transforms = [params.transform];
559  } else {
560    objTypesProto = params.objTypeProto;
561    transforms = params.transform;
562  }
563  // each trace or dump may have different processors, for example, until S, SF dumps
564  // returne a list of layers and winscope built a [LayerTraceEntry] from them.
565  // From S onwards, returns a LayerTrace object, iterating over multiple items allows
566  // winscope to handle both the new and legacy formats
567  // TODO Refactor the decode.js code into a set of decoders to clean up the code
568  let lastError = null;
569  for (var x = 0; x < objTypesProto.length; x++) {
570    const objType = objTypesProto[x];
571    const transform = transforms[x];
572    try {
573      const decoded = objType.decode(buffer);
574      modifyProtoFields(decoded, displayDefaults);
575      const transformed = transform(decoded);
576      return transformed;
577    } catch (e) {
578      lastError = e;
579      // check next parser
580    }
581  }
582
583  if (lastError) {
584    throw lastError;
585  }
586  throw new UndetectableFileType('Unable to parse file');
587}
588
589function protoDecoder(buffer, params, fileName, store) {
590  const transformed = decodeAndTransformProto(buffer, params, store.displayDefaults);
591
592  // add tagGenerationTrace to dataFile for WM/SF traces so tags can be generated
593  var tagGenerationTrace = null;
594  if (params.type === FILE_TYPES.WINDOW_MANAGER_TRACE ||
595    params.type === FILE_TYPES.SURFACE_FLINGER_TRACE) {
596    tagGenerationTrace = transformed;
597  }
598
599  let data;
600  if (params.timeline) {
601    data = transformed.entries ?? transformed.children;
602  } else {
603    data = [transformed];
604  }
605  const blobUrl = URL.createObjectURL(new Blob([buffer], {type: params.mime}));
606
607  return dataFile(
608    fileName,
609    data.map((x) => x.timestamp),
610    data,
611    blobUrl,
612    params.type,
613    tagGenerationTrace
614  );
615}
616
617function videoDecoder(buffer, params, fileName, store) {
618  const [data, timeline] = params.videoDecoder(buffer);
619  const blobUrl = URL.createObjectURL(new Blob([data], {type: params.mime}));
620  return dataFile(fileName, timeline, blobUrl, blobUrl, params.type);
621}
622
623function dataFile(filename, timeline, data, blobUrl, type, tagGenerationTrace = null) {
624  return {
625    filename: filename,
626    // Object is frozen for performance reasons
627    // It will prevent Vue from making it a reactive object which will be very slow as the timeline gets larger.
628    timeline: Object.freeze(timeline),
629    data: data,
630    blobUrl: blobUrl,
631    tagGenerationTrace: tagGenerationTrace,
632    type: type,
633    selectedIndex: 0,
634    destroy() {
635      URL.revokeObjectURL(this.blobUrl);
636    },
637  };
638}
639
640function arrayEquals(a, b) {
641  if (a.length !== b.length) {
642    return false;
643  }
644  for (let i = 0; i < a.length; i++) {
645    if (a[i] != b[i]) {
646      return false;
647    }
648  }
649  return true;
650}
651
652function arrayStartsWith(array, prefix) {
653  return arrayEquals(array.slice(0, prefix.length), prefix);
654}
655
656function decodedFile(fileType, buffer, fileName, store) {
657  const fileDecoder = FILE_DECODERS[fileType];
658  return [fileType, fileDecoder.decoder(buffer, fileDecoder.decoderParams, fileName, store)];
659}
660
661function detectAndDecode(buffer, fileName, store) {
662  if (arrayStartsWith(buffer, LAYER_TRACE_MAGIC_NUMBER)) {
663    return decodedFile(FILE_TYPES.SURFACE_FLINGER_TRACE, buffer, fileName, store);
664  }
665  if (arrayStartsWith(buffer, ACCESSIBILITY_MAGIC_NUMBER)) {
666    return decodedFile(FILE_TYPES.ACCESSIBILITY_TRACE, buffer, fileName, store);
667  }
668  if (arrayStartsWith(buffer, WINDOW_TRACE_MAGIC_NUMBER)) {
669    return decodedFile(FILE_TYPES.WINDOW_MANAGER_TRACE, buffer, fileName, store);
670  }
671  if (arrayStartsWith(buffer, MPEG4_MAGIC_NMBER)) {
672    return decodedFile(FILE_TYPES.SCREEN_RECORDING, buffer, fileName, store);
673  }
674  if (arrayStartsWith(buffer, TRANSACTIONS_TRACE_MAGIC_NUMBER)) {
675    return decodedFile(FILE_TYPES.TRANSACTIONS_TRACE, buffer, fileName, store);
676  }
677  if (arrayStartsWith(buffer, WAYLAND_TRACE_MAGIC_NUMBER)) {
678    return decodedFile(FILE_TYPES.WAYLAND_TRACE, buffer, fileName, store);
679  }
680  if (arrayStartsWith(buffer, PROTO_LOG_MAGIC_NUMBER)) {
681    return decodedFile(FILE_TYPES.PROTO_LOG, buffer, fileName, store);
682  }
683  if (arrayStartsWith(buffer, SYSTEM_UI_MAGIC_NUMBER)) {
684    return decodedFile(FILE_TYPES.SYSTEM_UI, buffer, fileName, store);
685  }
686  if (arrayStartsWith(buffer, LAUNCHER_MAGIC_NUMBER)) {
687    return decodedFile(FILE_TYPES.LAUNCHER, buffer, fileName, store);
688  }
689  if (arrayStartsWith(buffer, IMC_TRACE_MAGIC_NUMBER)) {
690    return decodedFile(FILE_TYPES.IME_TRACE_CLIENTS, buffer, fileName, store);
691  }
692  if (arrayStartsWith(buffer, IMS_TRACE_MAGIC_NUMBER)) {
693    return decodedFile(FILE_TYPES.IME_TRACE_SERVICE, buffer, fileName, store);
694  }
695  if (arrayStartsWith(buffer, IMM_TRACE_MAGIC_NUMBER)) {
696    return decodedFile(FILE_TYPES.IME_TRACE_MANAGERSERVICE, buffer, fileName, store);
697  }
698  if (arrayStartsWith(buffer, TAG_TRACE_MAGIC_NUMBER)) {
699    return decodedFile(FILE_TYPES.TAG_TRACE, buffer, fileName, store);
700  }
701  if (arrayStartsWith(buffer, ERROR_TRACE_MAGIC_NUMBER)) {
702    return decodedFile(FILE_TYPES.ERROR_TRACE, buffer, fileName, store);
703  }
704
705  // TODO(b/169305853): Add magic number at beginning of file for better auto detection
706  for (const [filetype, condition] of [
707    [FILE_TYPES.TRANSACTIONS_TRACE_LEGACY, (file) => file.data.length > 0],
708    [FILE_TYPES.WAYLAND_DUMP, (file) => (file.data.length > 0 && file.data.children[0] > 0) || file.data.length > 1],
709    [FILE_TYPES.WINDOW_MANAGER_DUMP],
710    [FILE_TYPES.SURFACE_FLINGER_DUMP]
711  ]) {
712    try {
713      const [, fileData] = decodedFile(filetype, buffer, fileName, store);
714
715      // A generic file will often wrongly be decoded as an empty wayland dump file
716      if (condition && !condition(fileData)) {
717        // Fall through to next filetype
718        continue;
719      }
720
721      return [filetype, fileData];
722    } catch (ex) {
723      // ignore exception and fall through to next filetype
724    }
725  }
726  throw new UndetectableFileType('Unable to detect file');
727}
728
729/**
730 * Error is raised when detectAndDecode is called but the file can't be
731 * automatically detected as being of a compatible file type.
732 */
733class UndetectableFileType extends Error { }
734
735export {
736  dataFile,
737  detectAndDecode,
738  decodeAndTransformProto,
739  TagTraceMessage,
740  FILE_TYPES,
741  TRACE_INFO,
742  TRACE_TYPES,
743  DUMP_TYPES,
744  DUMP_INFO,
745  FILE_DECODERS,
746  FILE_ICONS,
747  UndetectableFileType
748};
749