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