xref: /aosp_15_r20/external/perfetto/ui/src/frontend/trace_converter.ts (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
1// Copyright (C) 2021 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
15import {assetSrc} from '../base/assets';
16import {download} from '../base/clipboard';
17import {defer} from '../base/deferred';
18import {ErrorDetails} from '../base/logging';
19import {utf8Decode} from '../base/string_utils';
20import {time} from '../base/time';
21import {AppImpl} from '../core/app_impl';
22import {maybeShowErrorDialog} from './error_dialog';
23
24type Args =
25  | UpdateStatusArgs
26  | JobCompletedArgs
27  | DownloadFileArgs
28  | OpenTraceInLegacyArgs
29  | ErrorArgs;
30
31interface UpdateStatusArgs {
32  kind: 'updateStatus';
33  status: string;
34}
35
36interface JobCompletedArgs {
37  kind: 'jobCompleted';
38}
39
40interface DownloadFileArgs {
41  kind: 'downloadFile';
42  buffer: Uint8Array;
43  name: string;
44}
45
46interface OpenTraceInLegacyArgs {
47  kind: 'openTraceInLegacy';
48  buffer: Uint8Array;
49}
50
51interface ErrorArgs {
52  kind: 'error';
53  error: ErrorDetails;
54}
55
56type OpenTraceInLegacyCallback = (
57  name: string,
58  data: ArrayBuffer | string,
59  size: number,
60) => void;
61
62async function makeWorkerAndPost(
63  msg: unknown,
64  openTraceInLegacy?: OpenTraceInLegacyCallback,
65) {
66  const promise = defer<void>();
67
68  function handleOnMessage(msg: MessageEvent): void {
69    const args: Args = msg.data;
70    if (args.kind === 'updateStatus') {
71      AppImpl.instance.omnibox.showStatusMessage(args.status);
72    } else if (args.kind === 'jobCompleted') {
73      promise.resolve();
74    } else if (args.kind === 'downloadFile') {
75      download(new File([new Blob([args.buffer])], args.name));
76    } else if (args.kind === 'openTraceInLegacy') {
77      const str = utf8Decode(args.buffer);
78      openTraceInLegacy?.('trace.json', str, 0);
79    } else if (args.kind === 'error') {
80      maybeShowErrorDialog(args.error);
81    } else {
82      throw new Error(`Unhandled message ${JSON.stringify(args)}`);
83    }
84  }
85
86  const worker = new Worker(assetSrc('traceconv_bundle.js'));
87  worker.onmessage = handleOnMessage;
88  worker.postMessage(msg);
89  return promise;
90}
91
92export function convertTraceToJsonAndDownload(trace: Blob): Promise<void> {
93  return makeWorkerAndPost({
94    kind: 'ConvertTraceAndDownload',
95    trace,
96    format: 'json',
97  });
98}
99
100export function convertTraceToSystraceAndDownload(trace: Blob): Promise<void> {
101  return makeWorkerAndPost({
102    kind: 'ConvertTraceAndDownload',
103    trace,
104    format: 'systrace',
105  });
106}
107
108export function convertToJson(
109  trace: Blob,
110  openTraceInLegacy: OpenTraceInLegacyCallback,
111  truncate?: 'start' | 'end',
112): Promise<void> {
113  return makeWorkerAndPost(
114    {
115      kind: 'ConvertTraceAndOpenInLegacy',
116      trace,
117      truncate,
118    },
119    openTraceInLegacy,
120  );
121}
122
123export function convertTraceToPprofAndDownload(
124  trace: Blob,
125  pid: number,
126  ts: time,
127): Promise<void> {
128  return makeWorkerAndPost({
129    kind: 'ConvertTraceToPprof',
130    trace,
131    pid,
132    ts,
133  });
134}
135