/* * Copyright 2017, The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* eslint-disable camelcase */ /* eslint-disable max-len */ import jsonProtoDefsWm from 'frameworks/base/core/proto/android/server/windowmanagertrace.proto'; import jsonProtoDefsProtoLog from 'frameworks/base/core/proto/android/internal/protolog.proto'; import jsonProtoDefsSf from 'frameworks/native/services/surfaceflinger/layerproto/layerstrace.proto'; import jsonProtoDefsTransaction from 'frameworks/native/cmds/surfacereplayer/proto/src/trace.proto'; import jsonProtoDefsWl from 'WaylandSafePath/waylandtrace.proto'; import jsonProtoDefsSysUi from 'frameworks/base/packages/SystemUI/src/com/android/systemui/tracing/sysui_trace.proto'; import jsonProtoDefsLauncher from 'packages/apps/Launcher3/protos/launcher_trace_file.proto'; import jsonProtoDefsIme from 'frameworks/base/core/proto/android/view/inputmethod/inputmethodeditortrace.proto'; import protobuf from 'protobufjs'; import {transformLayers, transformLayersTrace} from './transform_sf.js'; import {transform_transaction_trace} from './transform_transaction.js'; import {transform_wl_outputstate, transform_wayland_trace} from './transform_wl.js'; import {transformProtolog} from './transform_protolog.js'; import {transform_sysui_trace} from './transform_sys_ui.js'; import {transform_launcher_trace} from './transform_launcher.js'; import {transform_ime_trace_clients, transform_ime_trace_service, transform_ime_trace_managerservice} from './transform_ime.js'; import {fill_transform_data} from './matrix_utils.js'; import {mp4Decoder} from './decodeVideo.js'; import SurfaceFlingerTrace from '@/traces/SurfaceFlinger.ts'; import WindowManagerTrace from '@/traces/WindowManager.ts'; import TransactionsTrace from '@/traces/Transactions.ts'; import ScreenRecordingTrace from '@/traces/ScreenRecording.ts'; import WaylandTrace from '@/traces/Wayland.ts'; import ProtoLogTrace from '@/traces/ProtoLog.ts'; import SystemUITrace from '@/traces/SystemUI.ts'; import LauncherTrace from '@/traces/Launcher.ts'; import ImeTraceClients from '@/traces/InputMethodClients.ts'; import ImeTraceService from '@/traces/InputMethodService.ts'; import ImeTraceManagerService from '@/traces/InputMethodManagerService.ts'; import SurfaceFlingerDump from '@/dumps/SurfaceFlinger.ts'; import WindowManagerDump from '@/dumps/WindowManager.ts'; import WaylandDump from '@/dumps/Wayland.ts'; const WmTraceMessage = lookup_type(jsonProtoDefsWm, 'com.android.server.wm.WindowManagerTraceFileProto'); const WmDumpMessage = lookup_type(jsonProtoDefsWm, 'com.android.server.wm.WindowManagerServiceDumpProto'); const SfTraceMessage = lookup_type(jsonProtoDefsSf, 'android.surfaceflinger.LayersTraceFileProto'); const SfDumpMessage = lookup_type(jsonProtoDefsSf, 'android.surfaceflinger.LayersProto'); const SfTransactionTraceMessage = lookup_type(jsonProtoDefsTransaction, 'Trace'); const WaylandTraceMessage = lookup_type(jsonProtoDefsWl, 'org.chromium.arc.wayland_composer.TraceFileProto'); const WaylandDumpMessage = lookup_type(jsonProtoDefsWl, 'org.chromium.arc.wayland_composer.OutputStateProto'); const ProtoLogMessage = lookup_type(jsonProtoDefsProtoLog, 'com.android.internal.protolog.ProtoLogFileProto'); const SystemUiTraceMessage = lookup_type(jsonProtoDefsSysUi, 'com.android.systemui.tracing.SystemUiTraceFileProto'); const LauncherTraceMessage = lookup_type(jsonProtoDefsLauncher, 'com.android.launcher3.tracing.LauncherTraceFileProto'); const InputMethodClientsTraceMessage = lookup_type(jsonProtoDefsIme, "android.view.inputmethod.InputMethodClientsTraceFileProto"); const InputMethodServiceTraceMessage = lookup_type(jsonProtoDefsIme, "android.view.inputmethod.InputMethodServiceTraceFileProto"); const InputMethodManagerServiceTraceMessage = lookup_type(jsonProtoDefsIme, "android.view.inputmethod.InputMethodManagerServiceTraceFileProto"); const LAYER_TRACE_MAGIC_NUMBER = [0x09, 0x4c, 0x59, 0x52, 0x54, 0x52, 0x41, 0x43, 0x45]; // .LYRTRACE const WINDOW_TRACE_MAGIC_NUMBER = [0x09, 0x57, 0x49, 0x4e, 0x54, 0x52, 0x41, 0x43, 0x45]; // .WINTRACE const MPEG4_MAGIC_NMBER = [0x00, 0x00, 0x00, 0x18, 0x66, 0x74, 0x79, 0x70, 0x6d, 0x70, 0x34, 0x32]; // ....ftypmp42 const WAYLAND_TRACE_MAGIC_NUMBER = [0x09, 0x57, 0x59, 0x4c, 0x54, 0x52, 0x41, 0x43, 0x45]; // .WYLTRACE const PROTO_LOG_MAGIC_NUMBER = [0x09, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x4c, 0x4f, 0x47]; // .PROTOLOG const SYSTEM_UI_MAGIC_NUMBER = [0x09, 0x53, 0x59, 0x53, 0x55, 0x49, 0x54, 0x52, 0x43]; // .SYSUITRC const LAUNCHER_MAGIC_NUMBER = [0x09, 0x4C, 0x4E, 0x43, 0x48, 0x52, 0x54, 0x52, 0x43]; // .LNCHRTRC const IMC_TRACE_MAGIC_NUMBER = [0x09, 0x49, 0x4d, 0x43, 0x54, 0x52, 0x41, 0x43, 0x45] //.IMCTRACE const IMS_TRACE_MAGIC_NUMBER = [0x09, 0x49, 0x4d, 0x53, 0x54, 0x52, 0x41, 0x43, 0x45] //.IMSTRACE const IMM_TRACE_MAGIC_NUMBER = [0x09, 0x49, 0x4d, 0x4d, 0x54, 0x52, 0x41, 0x43, 0x45] //.IMMTRACE const FILE_TYPES = Object.freeze({ WINDOW_MANAGER_TRACE: 'WindowManagerTrace', SURFACE_FLINGER_TRACE: 'SurfaceFlingerTrace', WINDOW_MANAGER_DUMP: 'WindowManagerDump', SURFACE_FLINGER_DUMP: 'SurfaceFlingerDump', SCREEN_RECORDING: 'ScreenRecording', TRANSACTIONS_TRACE: 'TransactionsTrace', WAYLAND_TRACE: 'WaylandTrace', WAYLAND_DUMP: 'WaylandDump', PROTO_LOG: 'ProtoLog', SYSTEM_UI: 'SystemUI', LAUNCHER: 'Launcher', IME_TRACE_CLIENTS: 'ImeTraceClients', IME_TRACE_SERVICE: 'ImeTrace InputMethodService', IME_TRACE_MANAGERSERVICE: 'ImeTrace InputMethodManagerService', }); const WINDOW_MANAGER_ICON = 'view_compact'; const SURFACE_FLINGER_ICON = 'filter_none'; const SCREEN_RECORDING_ICON = 'videocam'; const TRANSACTION_ICON = 'timeline'; const WAYLAND_ICON = 'filter_none'; const PROTO_LOG_ICON = 'notes'; const SYSTEM_UI_ICON = 'filter_none'; const LAUNCHER_ICON = 'filter_none'; const IME_ICON = 'keyboard'; const FILE_ICONS = { [FILE_TYPES.WINDOW_MANAGER_TRACE]: WINDOW_MANAGER_ICON, [FILE_TYPES.SURFACE_FLINGER_TRACE]: SURFACE_FLINGER_ICON, [FILE_TYPES.WINDOW_MANAGER_DUMP]: WINDOW_MANAGER_ICON, [FILE_TYPES.SURFACE_FLINGER_DUMP]: SURFACE_FLINGER_ICON, [FILE_TYPES.SCREEN_RECORDING]: SCREEN_RECORDING_ICON, [FILE_TYPES.TRANSACTIONS_TRACE]: TRANSACTION_ICON, [FILE_TYPES.WAYLAND_TRACE]: WAYLAND_ICON, [FILE_TYPES.WAYLAND_DUMP]: WAYLAND_ICON, [FILE_TYPES.PROTO_LOG]: PROTO_LOG_ICON, [FILE_TYPES.SYSTEM_UI]: SYSTEM_UI_ICON, [FILE_TYPES.LAUNCHER]: LAUNCHER_ICON, [FILE_TYPES.IME_TRACE_CLIENTS]: IME_ICON, [FILE_TYPES.IME_TRACE_SERVICE]: IME_ICON, [FILE_TYPES.IME_TRACE_MANAGERSERVICE]: IME_ICON, }; function oneOf(dataType) { return {oneOf: true, type: dataType}; } function manyOf(dataType, fold = null) { return {manyOf: true, type: dataType, fold}; } const TRACE_TYPES = Object.freeze({ WINDOW_MANAGER: 'WindowManagerTrace', SURFACE_FLINGER: 'SurfaceFlingerTrace', SCREEN_RECORDING: 'ScreenRecording', TRANSACTION: 'Transaction', WAYLAND: 'Wayland', PROTO_LOG: 'ProtoLog', SYSTEM_UI: 'SystemUI', LAUNCHER: 'Launcher', IME_CLIENTS: 'ImeTrace Clients', IME_SERVICE: 'ImeTrace InputMethodService', IME_MANAGERSERVICE: 'ImeTrace InputMethodManagerService', }); const TRACE_INFO = { [TRACE_TYPES.WINDOW_MANAGER]: { name: 'WindowManager', icon: WINDOW_MANAGER_ICON, files: [oneOf(FILE_TYPES.WINDOW_MANAGER_TRACE)], constructor: WindowManagerTrace, }, [TRACE_TYPES.SURFACE_FLINGER]: { name: 'SurfaceFlinger', icon: SURFACE_FLINGER_ICON, files: [oneOf(FILE_TYPES.SURFACE_FLINGER_TRACE)], constructor: SurfaceFlingerTrace, }, [TRACE_TYPES.SCREEN_RECORDING]: { name: 'Screen recording', icon: SCREEN_RECORDING_ICON, files: [oneOf(FILE_TYPES.SCREEN_RECORDING)], constructor: ScreenRecordingTrace, }, [TRACE_TYPES.TRANSACTION]: { name: 'Transaction', icon: TRANSACTION_ICON, files: [ oneOf(FILE_TYPES.TRANSACTIONS_TRACE), ], constructor: TransactionsTrace, }, [TRACE_TYPES.WAYLAND]: { name: 'Wayland', icon: WAYLAND_ICON, files: [oneOf(FILE_TYPES.WAYLAND_TRACE)], constructor: WaylandTrace, }, [TRACE_TYPES.PROTO_LOG]: { name: 'ProtoLog', icon: PROTO_LOG_ICON, files: [oneOf(FILE_TYPES.PROTO_LOG)], constructor: ProtoLogTrace, }, [TRACE_TYPES.SYSTEM_UI]: { name: 'SystemUI', icon: SYSTEM_UI_ICON, files: [oneOf(FILE_TYPES.SYSTEM_UI)], constructor: SystemUITrace, }, [TRACE_TYPES.LAUNCHER]: { name: 'Launcher', icon: LAUNCHER_ICON, files: [oneOf(FILE_TYPES.LAUNCHER)], constructor: LauncherTrace, }, [TRACE_TYPES.IME_CLIENTS]: { name: 'InputMethodClients', icon: IME_ICON, files: [oneOf(FILE_TYPES.IME_TRACE_CLIENTS)], constructor: ImeTraceClients, }, [TRACE_TYPES.IME_SERVICE]: { name: 'InputMethodService', icon: IME_ICON, files: [oneOf(FILE_TYPES.IME_TRACE_SERVICE)], constructor: ImeTraceService, }, [TRACE_TYPES.IME_MANAGERSERVICE]: { name: 'InputMethodManagerService', icon: IME_ICON, files: [oneOf(FILE_TYPES.IME_TRACE_MANAGERSERVICE)], constructor: ImeTraceManagerService, }, }; const DUMP_TYPES = Object.freeze({ WINDOW_MANAGER: 'WindowManagerDump', SURFACE_FLINGER: 'SurfaceFlingerDump', WAYLAND: 'WaylandDump', }); const DUMP_INFO = { [DUMP_TYPES.WINDOW_MANAGER]: { name: 'WindowManager', icon: WINDOW_MANAGER_ICON, files: [oneOf(FILE_TYPES.WINDOW_MANAGER_DUMP)], constructor: WindowManagerDump, }, [DUMP_TYPES.SURFACE_FLINGER]: { name: 'SurfaceFlinger', icon: SURFACE_FLINGER_ICON, files: [oneOf(FILE_TYPES.SURFACE_FLINGER_DUMP)], constructor: SurfaceFlingerDump, }, [DUMP_TYPES.WAYLAND]: { name: 'Wayland', icon: WAYLAND_ICON, files: [oneOf(FILE_TYPES.WAYLAND_DUMP)], constructor: WaylandDump, }, }; export const TRACE_ICONS = { [TRACE_TYPES.WINDOW_MANAGER]: WINDOW_MANAGER_ICON, [TRACE_TYPES.SURFACE_FLINGER]: SURFACE_FLINGER_ICON, [TRACE_TYPES.SCREEN_RECORDING]: SCREEN_RECORDING_ICON, [TRACE_TYPES.TRANSACTION]: TRANSACTION_ICON, [TRACE_TYPES.WAYLAND]: WAYLAND_ICON, [TRACE_TYPES.PROTO_LOG]: PROTO_LOG_ICON, [TRACE_TYPES.SYSTEM_UI]: SYSTEM_UI_ICON, [TRACE_TYPES.LAUNCHER]: LAUNCHER_ICON, [TRACE_TYPES.IME_CLIENTS]: IME_ICON, [TRACE_TYPES.IME_SERVICE]: IME_ICON, [TRACE_TYPES.IME_MANAGERSERVICE]: IME_ICON, [DUMP_TYPES.WINDOW_MANAGER]: WINDOW_MANAGER_ICON, [DUMP_TYPES.SURFACE_FLINGER]: SURFACE_FLINGER_ICON, [DUMP_TYPES.WAYLAND]: WAYLAND_ICON, }; // TODO: Rename name to defaultName const FILE_DECODERS = { [FILE_TYPES.WINDOW_MANAGER_TRACE]: { name: 'WindowManager trace', decoder: protoDecoder, decoderParams: { type: FILE_TYPES.WINDOW_MANAGER_TRACE, protoType: WmTraceMessage, transform: WindowManagerTrace.fromProto, timeline: true, }, }, [FILE_TYPES.SURFACE_FLINGER_TRACE]: { name: 'SurfaceFlinger trace', decoder: protoDecoder, decoderParams: { type: FILE_TYPES.SURFACE_FLINGER_TRACE, mime: 'application/octet-stream', protoType: SfTraceMessage, transform: transformLayersTrace, timeline: true, }, }, [FILE_TYPES.WAYLAND_TRACE]: { name: 'Wayland trace', decoder: protoDecoder, decoderParams: { type: FILE_TYPES.WAYLAND_TRACE, mime: 'application/octet-stream', protoType: WaylandTraceMessage, transform: transform_wayland_trace, timeline: true, }, }, [FILE_TYPES.SURFACE_FLINGER_DUMP]: { name: 'SurfaceFlinger dump', decoder: protoDecoder, decoderParams: { type: FILE_TYPES.SURFACE_FLINGER_DUMP, mime: 'application/octet-stream', protoType: SfDumpMessage, transform: (decoded) => transformLayers(true /* includesCompositionState*/, decoded), timeline: false, }, }, [FILE_TYPES.WINDOW_MANAGER_DUMP]: { name: 'WindowManager dump', decoder: protoDecoder, decoderParams: { type: FILE_TYPES.WINDOW_MANAGER_DUMP, mime: 'application/octet-stream', protoType: WmDumpMessage, transform: WindowManagerDump.fromProto, timeline: false, }, }, [FILE_TYPES.WAYLAND_DUMP]: { name: 'Wayland dump', decoder: protoDecoder, decoderParams: { type: FILE_TYPES.WAYLAND_DUMP, mime: 'application/octet-stream', protoType: WaylandDumpMessage, transform: transform_wl_outputstate, timeline: false, }, }, [FILE_TYPES.SCREEN_RECORDING]: { name: 'Screen recording', decoder: videoDecoder, decoderParams: { type: FILE_TYPES.SCREEN_RECORDING, mime: 'video/mp4', videoDecoder: mp4Decoder, }, }, [FILE_TYPES.TRANSACTIONS_TRACE]: { name: 'Transaction', decoder: protoDecoder, decoderParams: { type: FILE_TYPES.TRANSACTIONS_TRACE, mime: 'application/octet-stream', protoType: SfTransactionTraceMessage, transform: transform_transaction_trace, timeline: true, }, }, [FILE_TYPES.PROTO_LOG]: { name: 'ProtoLog', decoder: protoDecoder, decoderParams: { type: FILE_TYPES.PROTO_LOG, mime: 'application/octet-stream', protoType: ProtoLogMessage, transform: transformProtolog, timeline: true, }, }, [FILE_TYPES.SYSTEM_UI]: { name: 'SystemUI trace', decoder: protoDecoder, decoderParams: { type: FILE_TYPES.SYSTEM_UI, mime: 'application/octet-stream', protoType: SystemUiTraceMessage, transform: transform_sysui_trace, timeline: true, }, }, [FILE_TYPES.LAUNCHER]: { name: 'Launcher trace', decoder: protoDecoder, decoderParams: { type: FILE_TYPES.LAUNCHER, mime: 'application/octet-stream', protoType: LauncherTraceMessage, transform: transform_launcher_trace, timeline: true, }, }, [FILE_TYPES.IME_TRACE_CLIENTS]: { name: 'InputMethodClients trace', decoder: protoDecoder, decoderParams: { type: FILE_TYPES.IME_TRACE_CLIENTS, mime: 'application/octet-stream', protoType: InputMethodClientsTraceMessage, transform: transform_ime_trace_clients, timeline: true, }, }, [FILE_TYPES.IME_TRACE_SERVICE]: { name: 'InputMethodService trace', decoder: protoDecoder, decoderParams: { type: FILE_TYPES.IME_TRACE_SERVICE, mime: 'application/octet-stream', protoType: InputMethodServiceTraceMessage, transform: transform_ime_trace_service, timeline: true, }, }, [FILE_TYPES.IME_TRACE_MANAGERSERVICE]: { name: 'InputMethodManagerService trace', decoder: protoDecoder, decoderParams: { type: FILE_TYPES.IME_TRACE_MANAGERSERVICE, mime: 'application/octet-stream', protoType: InputMethodManagerServiceTraceMessage, transform: transform_ime_trace_managerservice, timeline: true, }, }, }; function lookup_type(protoPath, type) { return protobuf.Root.fromJSON(protoPath).lookupType(type); } // Replace enum values with string representation and // add default values to the proto objects. This function also handles // a special case with TransformProtos where the matrix may be derived // from the transform type. function modifyProtoFields(protoObj, displayDefaults) { if (!protoObj || protoObj !== Object(protoObj) || !protoObj.$type) { return; } for (const fieldName in protoObj.$type.fields) { if (protoObj.$type.fields.hasOwnProperty(fieldName)) { const fieldProperties = protoObj.$type.fields[fieldName]; const field = protoObj[fieldName]; if (Array.isArray(field)) { field.forEach((item, _) => { modifyProtoFields(item, displayDefaults); }); continue; } if (displayDefaults && !(field)) { protoObj[fieldName] = fieldProperties.defaultValue; } if (fieldProperties.type === 'TransformProto') { fill_transform_data(protoObj[fieldName]); continue; } if (fieldProperties.resolvedType && fieldProperties.resolvedType.valuesById) { protoObj[fieldName] = fieldProperties.resolvedType.valuesById[protoObj[fieldProperties.name]]; continue; } modifyProtoFields(protoObj[fieldName], displayDefaults); } } } function decodeAndTransformProto(buffer, params, displayDefaults) { const decoded = params.protoType.decode(buffer); modifyProtoFields(decoded, displayDefaults); const transformed = params.transform(decoded); return transformed; } function protoDecoder(buffer, params, fileName, store) { const transformed = decodeAndTransformProto(buffer, params, store.displayDefaults); let data; if (params.timeline) { data = transformed.entries ?? transformed.children; } else { data = [transformed]; } const blobUrl = URL.createObjectURL(new Blob([buffer], {type: params.mime})); return dataFile(fileName, data.map((x) => x.timestamp), data, blobUrl, params.type); } function videoDecoder(buffer, params, fileName, store) { const [data, timeline] = params.videoDecoder(buffer); const blobUrl = URL.createObjectURL(new Blob([data], {type: params.mime})); return dataFile(fileName, timeline, blobUrl, blobUrl, params.type); } function dataFile(filename, timeline, data, blobUrl, type) { return { filename: filename, // Object is frozen for performance reasons // It will prevent Vue from making it a reactive object which will be very slow as the timeline gets larger. timeline: Object.freeze(timeline), data: data, blobUrl: blobUrl, type: type, selectedIndex: 0, destroy() { URL.revokeObjectURL(this.blobUrl); }, }; } function arrayEquals(a, b) { if (a.length !== b.length) { return false; } for (let i = 0; i < a.length; i++) { if (a[i] != b[i]) { return false; } } return true; } function arrayStartsWith(array, prefix) { return arrayEquals(array.slice(0, prefix.length), prefix); } function decodedFile(fileType, buffer, fileName, store) { const fileDecoder = FILE_DECODERS[fileType]; return [fileType, fileDecoder.decoder(buffer, fileDecoder.decoderParams, fileName, store)]; } function detectAndDecode(buffer, fileName, store) { if (arrayStartsWith(buffer, LAYER_TRACE_MAGIC_NUMBER)) { return decodedFile(FILE_TYPES.SURFACE_FLINGER_TRACE, buffer, fileName, store); } if (arrayStartsWith(buffer, WINDOW_TRACE_MAGIC_NUMBER)) { return decodedFile(FILE_TYPES.WINDOW_MANAGER_TRACE, buffer, fileName, store); } if (arrayStartsWith(buffer, MPEG4_MAGIC_NMBER)) { return decodedFile(FILE_TYPES.SCREEN_RECORDING, buffer, fileName, store); } if (arrayStartsWith(buffer, WAYLAND_TRACE_MAGIC_NUMBER)) { return decodedFile(FILE_TYPES.WAYLAND_TRACE, buffer, fileName, store); } if (arrayStartsWith(buffer, PROTO_LOG_MAGIC_NUMBER)) { return decodedFile(FILE_TYPES.PROTO_LOG, buffer, fileName, store); } if (arrayStartsWith(buffer, SYSTEM_UI_MAGIC_NUMBER)) { return decodedFile(FILE_TYPES.SYSTEM_UI, buffer, fileName, store); } if (arrayStartsWith(buffer, LAUNCHER_MAGIC_NUMBER)) { return decodedFile(FILE_TYPES.LAUNCHER, buffer, fileName, store); } if (arrayStartsWith(buffer, IMC_TRACE_MAGIC_NUMBER)) { return decodedFile(FILE_TYPES.IME_TRACE_CLIENTS, buffer, fileName, store); } if (arrayStartsWith(buffer, IMS_TRACE_MAGIC_NUMBER)) { return decodedFile(FILE_TYPES.IME_TRACE_SERVICE, buffer, fileName, store); } if (arrayStartsWith(buffer, IMM_TRACE_MAGIC_NUMBER)) { return decodedFile(FILE_TYPES.IME_TRACE_MANAGERSERVICE, buffer, fileName, store); } // TODO(b/169305853): Add magic number at beginning of file for better auto detection for (const [filetype, condition] of [ [FILE_TYPES.TRANSACTIONS_TRACE, (file) => file.data.length > 0], [FILE_TYPES.WAYLAND_DUMP, (file) => (file.data.length > 0 && file.data.children[0] > 0) || file.data.length > 1], [FILE_TYPES.WINDOW_MANAGER_DUMP], [FILE_TYPES.SURFACE_FLINGER_DUMP], ]) { try { const [, fileData] = decodedFile(filetype, buffer, fileName, store); // A generic file will often wrongly be decoded as an empty wayland dump file if (condition && !condition(fileData)) { // Fall through to next filetype continue; } return [filetype, fileData]; } catch (ex) { // ignore exception and fall through to next filetype } } throw new UndetectableFileType('Unable to detect file'); } /** * Error is raised when detectAndDecode is called but the file can't be * automatically detected as being of a compatible file type. */ class UndetectableFileType extends Error { } export {detectAndDecode, decodeAndTransformProto, FILE_TYPES, TRACE_INFO, TRACE_TYPES, DUMP_TYPES, DUMP_INFO, FILE_DECODERS, FILE_ICONS, UndetectableFileType};