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