blob: 7dfbfa618cc3cf027d8241bff5bee1edd6b9c210 [file] [log] [blame]
/*
* 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};