1// Copyright (C) 2018 The Android Open Source Project 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15/** 16 * A plain js object, holding objects of type |Class| keyed by string id. 17 * We use this instead of using |Map| object since it is simpler and faster to 18 * serialize for use in postMessage. 19 */ 20export interface ObjectById<Class extends{id: string}> { [id: string]: Class; } 21 22export type Timestamped<T> = { 23 [P in keyof T]: T[P]; 24}&{lastUpdate: number}; 25 26export type OmniboxState = 27 Timestamped<{omnibox: string; mode: 'SEARCH' | 'COMMAND'}>; 28 29export type VisibleState = 30 Timestamped<{startSec: number; endSec: number; resolution: number;}>; 31 32export type TimestampedAreaSelection = Timestamped<AreaSelection>; 33export interface AreaSelection { 34 area?: Area; 35} 36export interface Area { 37 startSec: number; 38 endSec: number; 39 tracks: string[]; 40} 41 42export const MAX_TIME = 180; 43 44export const SCROLLING_TRACK_GROUP = 'ScrollingTracks'; 45 46 47export type EngineMode = 'WASM'|'HTTP_RPC'; 48 49export type NewEngineMode = 'USE_HTTP_RPC_IF_AVAILABLE'|'FORCE_BUILTIN_WASM'; 50 51export type HeapProfileFlamegraphViewingOption = 52 'SPACE'|'ALLOC_SPACE'|'OBJECTS'|'ALLOC_OBJECTS'; 53 54export interface CallsiteInfo { 55 id: number; 56 parentId: number; 57 depth: number; 58 name?: string; 59 totalSize: number; 60 selfSize: number; 61 mapping: string; 62 merged: boolean; 63} 64 65export interface TraceFileSource { 66 type: 'FILE'; 67 file: File; 68} 69 70export interface TraceArrayBufferSource { 71 type: 'ARRAY_BUFFER'; 72 title: string; 73 url?: string; 74 buffer: ArrayBuffer; 75} 76 77export interface TraceUrlSource { 78 type: 'URL'; 79 url: string; 80} 81 82export interface TraceHttpRpcSource { 83 type: 'HTTP_RPC'; 84} 85 86export type TraceSource = 87 TraceFileSource|TraceArrayBufferSource|TraceUrlSource|TraceHttpRpcSource; 88 89export interface TrackState { 90 id: string; 91 engineId: string; 92 kind: string; 93 name: string; 94 trackGroup?: string; 95 config: {}; 96} 97 98export interface TrackGroupState { 99 id: string; 100 engineId: string; 101 name: string; 102 collapsed: boolean; 103 tracks: string[]; // Child track ids. 104 summaryTrackId: string; 105} 106 107export interface EngineConfig { 108 id: string; 109 mode?: EngineMode; // Is undefined until |ready| is true. 110 ready: boolean; 111 failed?: string; // If defined the engine has crashed with the given message. 112 source: TraceSource; 113} 114 115export interface QueryConfig { 116 id: string; 117 engineId: string; 118 query: string; 119} 120 121export interface PermalinkConfig { 122 requestId?: string; // Set by the frontend to request a new permalink. 123 hash?: string; // Set by the controller when the link has been created. 124} 125 126export interface TraceTime { 127 startSec: number; 128 endSec: number; 129} 130 131export interface FrontendLocalState { 132 omniboxState: OmniboxState; 133 visibleState: VisibleState; 134 selectedArea: TimestampedAreaSelection; 135} 136 137export interface Status { 138 msg: string; 139 timestamp: number; // Epoch in seconds (Date.now() / 1000). 140} 141 142export interface Note { 143 noteType: 'DEFAULT'|'MOVIE'; 144 id: string; 145 timestamp: number; 146 color: string; 147 text: string; 148} 149 150export interface AreaNote { 151 noteType: 'AREA'; 152 id: string; 153 timestamp: number; 154 area: Area; 155 color: string; 156 text: string; 157} 158 159export interface NoteSelection { 160 kind: 'NOTE'; 161 id: string; 162} 163 164export interface SliceSelection { 165 kind: 'SLICE'; 166 id: number; 167} 168 169export interface CounterSelection { 170 kind: 'COUNTER'; 171 leftTs: number; 172 rightTs: number; 173 id: number; 174} 175 176export interface HeapProfileSelection { 177 kind: 'HEAP_PROFILE'; 178 id: number; 179 upid: number; 180 ts: number; 181 type: string; 182} 183 184export interface HeapProfileFlamegraph { 185 kind: 'HEAP_PROFILE_FLAMEGRAPH'; 186 id: number; 187 upid: number; 188 ts: number; 189 type: string; 190 viewingOption: HeapProfileFlamegraphViewingOption; 191 focusRegex: string; 192 expandedCallsite?: CallsiteInfo; 193} 194 195export interface CpuProfileSampleSelection { 196 kind: 'CPU_PROFILE_SAMPLE'; 197 id: number; 198 utid: number; 199 ts: number; 200} 201 202export interface ChromeSliceSelection { 203 kind: 'CHROME_SLICE'; 204 id: number; 205 table: string; 206} 207 208export interface ThreadStateSelection { 209 kind: 'THREAD_STATE'; 210 utid: number; 211 ts: number; 212 dur: number; 213 state: string; 214 cpu: number; 215} 216 217type Selection = (NoteSelection|SliceSelection|CounterSelection| 218 HeapProfileSelection|CpuProfileSampleSelection| 219 ChromeSliceSelection|ThreadStateSelection)&{trackId?: string}; 220 221export interface LogsPagination { 222 offset: number; 223 count: number; 224} 225 226export interface RecordingTarget { 227 name: string; 228 os: TargetOs; 229} 230 231export interface AdbRecordingTarget extends RecordingTarget { 232 serial: string; 233} 234 235export interface Sorting { 236 column: string; 237 direction: 'DESC'|'ASC'; 238} 239 240export interface AggregationState { 241 id: string; 242 sorting?: Sorting; 243} 244 245export interface State { 246 // tslint:disable-next-line:no-any 247 [key: string]: any; 248 route: string|null; 249 nextId: number; 250 251 /** 252 * State of the ConfigEditor. 253 */ 254 recordConfig: RecordConfig; 255 displayConfigAsPbtxt: boolean; 256 257 /** 258 * Open traces. 259 */ 260 newEngineMode: NewEngineMode; 261 engines: ObjectById<EngineConfig>; 262 traceTime: TraceTime; 263 trackGroups: ObjectById<TrackGroupState>; 264 tracks: ObjectById<TrackState>; 265 aggregatePreferences: ObjectById<AggregationState>; 266 visibleTracks: string[]; 267 scrollingTracks: string[]; 268 pinnedTracks: string[]; 269 queries: ObjectById<QueryConfig>; 270 permalink: PermalinkConfig; 271 notes: ObjectById<Note|AreaNote>; 272 status: Status; 273 currentSelection: Selection|null; 274 currentHeapProfileFlamegraph: HeapProfileFlamegraph|null; 275 logsPagination: LogsPagination; 276 277 /** 278 * This state is updated on the frontend at 60Hz and eventually syncronised to 279 * the controller at 10Hz. When the controller sends state updates to the 280 * frontend the frontend has special logic to pick whichever version of this 281 * key is most up to date. 282 */ 283 frontendLocalState: FrontendLocalState; 284 285 video: string | null; 286 videoEnabled: boolean; 287 videoOffset: number; 288 videoNoteIds: string[]; 289 scrubbingEnabled: boolean; 290 flagPauseEnabled: boolean; 291 292 /** 293 * Trace recording 294 */ 295 recordingInProgress: boolean; 296 recordingCancelled: boolean; 297 extensionInstalled: boolean; 298 recordingTarget: RecordingTarget; 299 availableAdbDevices: AdbRecordingTarget[]; 300 lastRecordingError?: string; 301 recordingStatus?: string; 302 303 chromeCategories: string[]|undefined; 304 analyzePageQuery?: string; 305} 306 307export const defaultTraceTime = { 308 startSec: 0, 309 endSec: 10, 310}; 311 312export declare type RecordMode = 313 'STOP_WHEN_FULL' | 'RING_BUFFER' | 'LONG_TRACE'; 314 315// 'Q','P','O' for Android, 'L' for Linux, 'C' for Chrome. 316export declare type TargetOs = 'Q' | 'P' | 'O' | 'C' | 'L'; 317 318export function isAndroidP(target: RecordingTarget) { 319 return target.os === 'P'; 320} 321 322export function isAndroidTarget(target: RecordingTarget) { 323 return ['Q', 'P', 'O'].includes(target.os); 324} 325 326export function isChromeTarget(target: RecordingTarget) { 327 return target.os === 'C'; 328} 329 330export function isLinuxTarget(target: RecordingTarget) { 331 return target.os === 'L'; 332} 333 334export function isAdbTarget(target: RecordingTarget): 335 target is AdbRecordingTarget { 336 if ((target as AdbRecordingTarget).serial) return true; 337 return false; 338} 339 340export interface RecordConfig { 341 [key: string]: null|number|boolean|string|string[]; 342 343 // Global settings 344 mode: RecordMode; 345 durationMs: number; 346 bufferSizeMb: number; 347 maxFileSizeMb: number; // Only for mode == 'LONG_TRACE'. 348 fileWritePeriodMs: number; // Only for mode == 'LONG_TRACE'. 349 350 cpuSched: boolean; 351 cpuLatency: boolean; 352 cpuFreq: boolean; 353 cpuCoarse: boolean; 354 cpuCoarsePollMs: number; 355 cpuSyscall: boolean; 356 357 screenRecord: boolean; 358 359 gpuFreq: boolean; 360 361 ftrace: boolean; 362 atrace: boolean; 363 ftraceEvents: string[]; 364 ftraceExtraEvents: string; 365 atraceCats: string[]; 366 atraceApps: string; 367 ftraceBufferSizeKb: number; 368 ftraceDrainPeriodMs: number; 369 androidLogs: boolean; 370 androidLogBuffers: string[]; 371 372 batteryDrain: boolean; 373 batteryDrainPollMs: number; 374 375 boardSensors: boolean; 376 377 memHiFreq: boolean; 378 memLmk: boolean; 379 meminfo: boolean; 380 meminfoPeriodMs: number; 381 meminfoCounters: string[]; 382 vmstat: boolean; 383 vmstatPeriodMs: number; 384 vmstatCounters: string[]; 385 386 heapProfiling: boolean; 387 hpSamplingIntervalBytes: number; 388 hpProcesses: string; 389 hpContinuousDumpsPhase: number; 390 hpContinuousDumpsInterval: number; 391 hpSharedMemoryBuffer: number; 392 393 javaHeapDump: boolean; 394 jpProcesses: string; 395 jpContinuousDumpsPhase: number; 396 jpContinuousDumpsInterval: number; 397 398 procStats: boolean; 399 procStatsPeriodMs: number; 400 401 chromeCategoriesSelected: string[]; 402} 403 404export function createEmptyRecordConfig(): RecordConfig { 405 return { 406 mode: 'STOP_WHEN_FULL', 407 durationMs: 10000.0, 408 maxFileSizeMb: 100, 409 fileWritePeriodMs: 2500, 410 bufferSizeMb: 10.0, 411 412 cpuSched: false, 413 cpuLatency: false, 414 cpuFreq: false, 415 cpuSyscall: false, 416 417 screenRecord: false, 418 419 gpuFreq: false, 420 421 ftrace: false, 422 atrace: false, 423 ftraceEvents: [], 424 ftraceExtraEvents: '', 425 atraceCats: [], 426 atraceApps: '', 427 ftraceBufferSizeKb: 2 * 1024, 428 ftraceDrainPeriodMs: 250, 429 androidLogs: false, 430 androidLogBuffers: [], 431 432 cpuCoarse: false, 433 cpuCoarsePollMs: 1000, 434 435 batteryDrain: false, 436 batteryDrainPollMs: 1000, 437 438 boardSensors: false, 439 440 memHiFreq: false, 441 meminfo: false, 442 meminfoPeriodMs: 1000, 443 meminfoCounters: [], 444 445 vmstat: false, 446 vmstatPeriodMs: 1000, 447 vmstatCounters: [], 448 449 heapProfiling: false, 450 hpSamplingIntervalBytes: 4096, 451 hpProcesses: '', 452 hpContinuousDumpsPhase: 0, 453 hpContinuousDumpsInterval: 0, 454 hpSharedMemoryBuffer: 8 * 1048576, 455 456 javaHeapDump: false, 457 jpProcesses: '', 458 jpContinuousDumpsPhase: 0, 459 jpContinuousDumpsInterval: 0, 460 461 memLmk: false, 462 procStats: false, 463 procStatsPeriodMs: 1000, 464 465 chromeCategoriesSelected: [], 466 }; 467} 468 469export function getDefaultRecordingTargets(): RecordingTarget[] { 470 return [ 471 {os: 'Q', name: 'Android Q+'}, 472 {os: 'P', name: 'Android P'}, 473 {os: 'O', name: 'Android O-'}, 474 {os: 'C', name: 'Chrome'}, 475 {os: 'L', name: 'Linux desktop'} 476 ]; 477} 478 479export function getBuiltinChromeCategoryList(): string[] { 480 // List of static Chrome categories, last updated at Chromium 81.0.4021.0 from 481 // Chromium's //base/trace_event/builtin_categories.h. 482 return [ 483 'accessibility', 484 'AccountFetcherService', 485 'android_webview', 486 'audio', 487 'base', 488 'benchmark', 489 'blink', 490 'blink.animations', 491 'blink.console', 492 'blink_gc', 493 'blink.net', 494 'blink_style', 495 'blink.user_timing', 496 'blink.worker', 497 'Blob', 498 'browser', 499 'browsing_data', 500 'CacheStorage', 501 'camera', 502 'cast_perf_test', 503 'cast.stream', 504 'cc', 505 'cc.debug', 506 'cdp.perf', 507 'chromeos', 508 'cma', 509 'compositor', 510 'content', 511 'content_capture', 512 'devtools', 513 'devtools.timeline', 514 'devtools.timeline.async', 515 'download', 516 'download_service', 517 'drm', 518 'drmcursor', 519 'dwrite', 520 'DXVA Decoding', 521 'EarlyJava', 522 'evdev', 523 'event', 524 'exo', 525 'explore_sites', 526 'FileSystem', 527 'file_system_provider', 528 'fonts', 529 'GAMEPAD', 530 'gpu', 531 'gpu.capture', 532 'headless', 533 'hwoverlays', 534 'identity', 535 'IndexedDB', 536 'input', 537 'io', 538 'ipc', 539 'Java', 540 'jni', 541 'jpeg', 542 'latency', 543 'latencyInfo', 544 'leveldb', 545 'loading', 546 'log', 547 'login', 548 'media', 549 'media_router', 550 'memory', 551 'midi', 552 'mojom', 553 'mus', 554 'native', 555 'navigation', 556 'net', 557 'netlog', 558 'offline_pages', 559 'omnibox', 560 'oobe', 561 'ozone', 562 'passwords', 563 'p2p', 564 'page-serialization', 565 'pepper', 566 'ppapi', 567 'ppapi proxy', 568 'rail', 569 'renderer', 570 'renderer_host', 571 'renderer.scheduler', 572 'RLZ', 573 'safe_browsing', 574 'screenlock_monitor', 575 'sequence_manager', 576 'service_manager', 577 'ServiceWorker', 578 'shell', 579 'shortcut_viewer', 580 'shutdown', 581 'SiteEngagement', 582 'skia', 583 'startup', 584 'sync', 585 'sync_lock_contention', 586 'thread_pool', 587 'test_gpu', 588 'test_tracing', 589 'toplevel', 590 'ui', 591 'v8', 592 'v8.execute', 593 'ValueStoreFrontend::Backend', 594 'views', 595 'views.frame', 596 'viz', 597 'vk', 598 'wayland', 599 'webaudio', 600 'weblayer', 601 'WebCore', 602 'webrtc', 603 'xr', 604 'disabled-by-default-animation-worklet', 605 'disabled-by-default-audio-worklet', 606 'disabled-by-default-blink.debug', 607 'disabled-by-default-blink.debug.display_lock', 608 'disabled-by-default-blink.debug.layout', 609 'disabled-by-default-blink.debug.layout.trees', 610 'disabled-by-default-blink.feature_usage', 611 'disabled-by-default-blink_gc', 612 'disabled-by-default-blink.image_decoding', 613 'disabled-by-default-blink.invalidation', 614 'disabled-by-default-cc', 615 'disabled-by-default-cc.debug', 616 'disabled-by-default-cc.debug.cdp-perf', 617 'disabled-by-default-cc.debug.display_items', 618 'disabled-by-default-cc.debug.picture', 619 'disabled-by-default-cc.debug.scheduler', 620 'disabled-by-default-cc.debug.scheduler.frames', 621 'disabled-by-default-cc.debug.scheduler.now', 622 'disabled-by-default-cpu_profiler', 623 'disabled-by-default-cpu_profiler.debug', 624 'disabled-by-default-devtools.screenshot', 625 'disabled-by-default-devtools.timeline', 626 'disabled-by-default-devtools.timeline.frame', 627 'disabled-by-default-devtools.timeline.inputs', 628 'disabled-by-default-devtools.timeline.invalidationTracking', 629 'disabled-by-default-devtools.timeline.layers', 630 'disabled-by-default-devtools.timeline.picture', 631 'disabled-by-default-file', 632 'disabled-by-default-fonts', 633 'disabled-by-default-gpu_cmd_queue', 634 'disabled-by-default-gpu.dawn', 635 'disabled-by-default-gpu.debug', 636 'disabled-by-default-gpu_decoder', 637 'disabled-by-default-gpu.device', 638 'disabled-by-default-gpu.service', 639 'disabled-by-default-histogram_samples', 640 'disabled-by-default-ipc.flow', 641 'disabled-by-default-java-heap-profiler', 642 'disabled-by-default-layer-element', 643 'disabled-by-default-lifecycles', 644 'disabled-by-default-loading', 645 'disabled-by-default-memory-infra', 646 'disabled-by-default-memory-infra.v8.code_stats', 647 'disabled-by-default-net', 648 'disabled-by-default-network', 649 'disabled-by-default-paint-worklet', 650 'disabled-by-default-power', 651 'disabled-by-default-renderer.scheduler', 652 'disabled-by-default-renderer.scheduler.debug', 653 'disabled-by-default-sequence_manager', 654 'disabled-by-default-sequence_manager.debug', 655 'disabled-by-default-sequence_manager.verbose_snapshots', 656 'disabled-by-default-skia', 657 'disabled-by-default-skia.gpu', 658 'disabled-by-default-skia.gpu.cache', 659 'disabled-by-default-SyncFileSystem', 660 'disabled-by-default-system_stats', 661 'disabled-by-default-thread_pool_diagnostics', 662 'disabled-by-default-toplevel.flow', 663 'disabled-by-default-toplevel.ipc', 664 'disabled-by-default-v8.compile', 665 'disabled-by-default-v8.cpu_profiler', 666 'disabled-by-default-v8.cpu_profiler.hires', 667 'disabled-by-default-v8.gc', 668 'disabled-by-default-v8.gc_stats', 669 'disabled-by-default-v8.ic_stats', 670 'disabled-by-default-v8.runtime', 671 'disabled-by-default-v8.runtime_stats', 672 'disabled-by-default-v8.runtime_stats_sampling', 673 'disabled-by-default-v8.turbofan', 674 'disabled-by-default-v8.wasm', 675 'disabled-by-default-video_and_image_capture', 676 'disabled-by-default-viz.debug.overlay_planes', 677 'disabled-by-default-viz.hit_testing_flow', 678 'disabled-by-default-viz.overdraw', 679 'disabled-by-default-viz.quads', 680 'disabled-by-default-viz.surface_id_flow', 681 'disabled-by-default-viz.surface_lifetime', 682 'disabled-by-default-viz.triangles', 683 'disabled-by-default-worker.scheduler', 684 ]; 685} 686 687export function createEmptyState(): State { 688 return { 689 route: null, 690 nextId: 0, 691 newEngineMode: 'USE_HTTP_RPC_IF_AVAILABLE', 692 engines: {}, 693 traceTime: {...defaultTraceTime}, 694 tracks: {}, 695 aggregatePreferences: {}, 696 trackGroups: {}, 697 visibleTracks: [], 698 pinnedTracks: [], 699 scrollingTracks: [], 700 queries: {}, 701 permalink: {}, 702 notes: {}, 703 704 recordConfig: createEmptyRecordConfig(), 705 displayConfigAsPbtxt: false, 706 707 frontendLocalState: { 708 omniboxState: { 709 lastUpdate: 0, 710 omnibox: '', 711 mode: 'SEARCH', 712 }, 713 714 visibleState: { 715 ...defaultTraceTime, 716 lastUpdate: 0, 717 resolution: 0, 718 }, 719 selectedArea: { 720 lastUpdate: 0, 721 } 722 }, 723 724 logsPagination: { 725 offset: 0, 726 count: 0, 727 }, 728 729 status: {msg: '', timestamp: 0}, 730 currentSelection: null, 731 currentHeapProfileFlamegraph: null, 732 733 video: null, 734 videoEnabled: false, 735 videoOffset: 0, 736 videoNoteIds: [], 737 scrubbingEnabled: false, 738 flagPauseEnabled: false, 739 recordingInProgress: false, 740 recordingCancelled: false, 741 extensionInstalled: false, 742 recordingTarget: getDefaultRecordingTargets()[0], 743 availableAdbDevices: [], 744 745 chromeCategories: undefined, 746 }; 747} 748 749export function getContainingTrackId(state: State, trackId: string): null| 750 string { 751 const track = state.tracks[trackId]; 752 if (!track) { 753 return null; 754 } 755 const parentId = track.trackGroup; 756 if (!parentId) { 757 return null; 758 } 759 return parentId; 760} 761