xref: /aosp_15_r20/external/perfetto/docs/visualization/deep-linking-to-perfetto-ui.md (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
1*6dbdd20aSAndroid Build Coastguard Worker# Deep linking to the Perfetto UI
2*6dbdd20aSAndroid Build Coastguard Worker
3*6dbdd20aSAndroid Build Coastguard WorkerThis document describes how to open traces hosted on external servers with the
4*6dbdd20aSAndroid Build Coastguard WorkerPerfetto UI. This can help integrating the Perfetto UI with custom dashboards
5*6dbdd20aSAndroid Build Coastguard Workerand implement _'Open with Perfetto UI'_-like features.
6*6dbdd20aSAndroid Build Coastguard Worker
7*6dbdd20aSAndroid Build Coastguard Worker## Using window.open and postMessage
8*6dbdd20aSAndroid Build Coastguard Worker
9*6dbdd20aSAndroid Build Coastguard WorkerThe supported way of doing this is to _inject_ the trace as an ArrayBuffer
10*6dbdd20aSAndroid Build Coastguard Workervia `window.open('https://ui.perfetto.dev')` and `postMessage()`.
11*6dbdd20aSAndroid Build Coastguard WorkerIn order to do this you need some minimal JavaScript code running on some
12*6dbdd20aSAndroid Build Coastguard Workerhosting infrastructure you control which can access the trace file. In most
13*6dbdd20aSAndroid Build Coastguard Workercases this is some dashboard which you want to deep-link to the Perfetto UI.
14*6dbdd20aSAndroid Build Coastguard Worker
15*6dbdd20aSAndroid Build Coastguard Worker#### Open ui.perfetto.dev via window.open
16*6dbdd20aSAndroid Build Coastguard Worker
17*6dbdd20aSAndroid Build Coastguard WorkerThe source dashboard, the one that knows how to locate a trace and deal with
18*6dbdd20aSAndroid Build Coastguard WorkerACL checking / oauth authentication and the like, creates a new tab by doing
19*6dbdd20aSAndroid Build Coastguard Worker
20*6dbdd20aSAndroid Build Coastguard Worker```js
21*6dbdd20aSAndroid Build Coastguard Workervar handle = window.open('https://ui.perfetto.dev');
22*6dbdd20aSAndroid Build Coastguard Worker```
23*6dbdd20aSAndroid Build Coastguard Worker
24*6dbdd20aSAndroid Build Coastguard WorkerThe window handle allows bidirectional communication using `postMessage()`
25*6dbdd20aSAndroid Build Coastguard Workerbetween the source dashboard and the Perfetto UI.
26*6dbdd20aSAndroid Build Coastguard Worker
27*6dbdd20aSAndroid Build Coastguard Worker#### Wait for the UI to be ready via PING/PONG
28*6dbdd20aSAndroid Build Coastguard Worker
29*6dbdd20aSAndroid Build Coastguard WorkerWait for the UI to be ready. The `window.open()` message channel is not
30*6dbdd20aSAndroid Build Coastguard Workerbuffered. If you send a message before the opened page has registered an
31*6dbdd20aSAndroid Build Coastguard Worker`onmessage` listener the messagge will be dropped on the floor.
32*6dbdd20aSAndroid Build Coastguard WorkerIn order to avoid this race, you can use a very basic PING/PONG protocol: keep
33*6dbdd20aSAndroid Build Coastguard Workersending a 'PING' message until the opened window replies with a 'PONG'.
34*6dbdd20aSAndroid Build Coastguard WorkerWhen this happens, that is the signal that the Perfetto UI is ready to open
35*6dbdd20aSAndroid Build Coastguard Workertraces.
36*6dbdd20aSAndroid Build Coastguard Worker
37*6dbdd20aSAndroid Build Coastguard Worker#### Post a message the following JavaScript object
38*6dbdd20aSAndroid Build Coastguard Worker
39*6dbdd20aSAndroid Build Coastguard Worker```js
40*6dbdd20aSAndroid Build Coastguard Worker  {
41*6dbdd20aSAndroid Build Coastguard Worker    'perfetto': {
42*6dbdd20aSAndroid Build Coastguard Worker      buffer: ArrayBuffer;
43*6dbdd20aSAndroid Build Coastguard Worker      title: string;
44*6dbdd20aSAndroid Build Coastguard Worker      fileName?: string;  // Optional
45*6dbdd20aSAndroid Build Coastguard Worker      url?: string;       // Optional
46*6dbdd20aSAndroid Build Coastguard Worker    }
47*6dbdd20aSAndroid Build Coastguard Worker  }
48*6dbdd20aSAndroid Build Coastguard Worker```
49*6dbdd20aSAndroid Build Coastguard Worker
50*6dbdd20aSAndroid Build Coastguard Worker`buffer` is the ArrayBuffer with the actual trace file content. This is
51*6dbdd20aSAndroid Build Coastguard Workertypically something that you obtain by doing a `fetch()` on your backend
52*6dbdd20aSAndroid Build Coastguard Workerstorage.
53*6dbdd20aSAndroid Build Coastguard Worker
54*6dbdd20aSAndroid Build Coastguard Worker`title` is the human friendly trace title that will be shown in the
55*6dbdd20aSAndroid Build Coastguard Workersidebar. This can help people to disambiguate traces from several tabs.
56*6dbdd20aSAndroid Build Coastguard Worker
57*6dbdd20aSAndroid Build Coastguard Worker`fileName` will be used if the user clicks on "Download". A generic name will
58*6dbdd20aSAndroid Build Coastguard Workerbe used if omitted.
59*6dbdd20aSAndroid Build Coastguard Worker
60*6dbdd20aSAndroid Build Coastguard Worker`url` is used if the user clicks on the "Share" link in the sidebar. This should
61*6dbdd20aSAndroid Build Coastguard Workerprint to a URL owned by you that would cause your dashboard to re-open the
62*6dbdd20aSAndroid Build Coastguard Workercurrent trace, by re-kicking-off the window.open() process herein described.
63*6dbdd20aSAndroid Build Coastguard WorkerIf omitted traces won't be shareable.
64*6dbdd20aSAndroid Build Coastguard Worker
65*6dbdd20aSAndroid Build Coastguard Worker### Code samples
66*6dbdd20aSAndroid Build Coastguard Worker
67*6dbdd20aSAndroid Build Coastguard WorkerSee [this example caller](https://bl.ocks.org/chromy/170c11ce30d9084957d7f3aa065e89f8),
68*6dbdd20aSAndroid Build Coastguard Workerfor which the code is in
69*6dbdd20aSAndroid Build Coastguard Worker[this GitHub gist](https://gist.github.com/chromy/170c11ce30d9084957d7f3aa065e89f8).
70*6dbdd20aSAndroid Build Coastguard Worker
71*6dbdd20aSAndroid Build Coastguard WorkerGooglers: take a look at the
72*6dbdd20aSAndroid Build Coastguard Worker[existing examples in the internal codesearch](http://go/perfetto-ui-deeplink-cs)
73*6dbdd20aSAndroid Build Coastguard Worker
74*6dbdd20aSAndroid Build Coastguard Worker### Common pitfalls
75*6dbdd20aSAndroid Build Coastguard Worker
76*6dbdd20aSAndroid Build Coastguard WorkerMany browsers sometimes block window.open() requests prompting the user to allow
77*6dbdd20aSAndroid Build Coastguard Workerpopups for the site. This usually happens if:
78*6dbdd20aSAndroid Build Coastguard Worker
79*6dbdd20aSAndroid Build Coastguard Worker- The window.open() is NOT initiated by a user gesture.
80*6dbdd20aSAndroid Build Coastguard Worker- Too much time is passed from the user gesture to the window.open()
81*6dbdd20aSAndroid Build Coastguard Worker
82*6dbdd20aSAndroid Build Coastguard WorkerIf the trace file is big enough, the fetch() might take long time and pass the
83*6dbdd20aSAndroid Build Coastguard Workeruser gesture threshold. This can be detected by observing that the window.open()
84*6dbdd20aSAndroid Build Coastguard Workerreturned `null`. When this happens the best option is to show another clickable
85*6dbdd20aSAndroid Build Coastguard Workerelement and bind the fetched trace ArrayBuffer to the new onclick handler, like
86*6dbdd20aSAndroid Build Coastguard Workerthe code in the example above does.
87*6dbdd20aSAndroid Build Coastguard Worker
88*6dbdd20aSAndroid Build Coastguard WorkerSome browser can have a variable time threshold for the user gesture timeout
89*6dbdd20aSAndroid Build Coastguard Workerwhich depends on the website engagement score (how much the user has visited
90*6dbdd20aSAndroid Build Coastguard Workerthe page that does the window.open() before). It's quite common when testing
91*6dbdd20aSAndroid Build Coastguard Workerthis code to see a popup blocker the first time the new feature is used and
92*6dbdd20aSAndroid Build Coastguard Workerthen not see it again.
93*6dbdd20aSAndroid Build Coastguard Worker
94*6dbdd20aSAndroid Build Coastguard WorkerThis scheme will not work from a `file://` based URL.
95*6dbdd20aSAndroid Build Coastguard WorkerThis is due to browser security context for `file://` URLs.
96*6dbdd20aSAndroid Build Coastguard Worker
97*6dbdd20aSAndroid Build Coastguard WorkerThe source website must not be served with the
98*6dbdd20aSAndroid Build Coastguard Worker`Cross-Origin-Opener-Policy: same-origin` header.
99*6dbdd20aSAndroid Build Coastguard WorkerFor example see
100*6dbdd20aSAndroid Build Coastguard Worker[this issue](https://github.com/google/perfetto/issues/525#issuecomment-1625055986).
101*6dbdd20aSAndroid Build Coastguard Worker
102*6dbdd20aSAndroid Build Coastguard Worker### Where does the posted trace go?
103*6dbdd20aSAndroid Build Coastguard Worker
104*6dbdd20aSAndroid Build Coastguard WorkerThe Perfetto UI is client-only and doesn't require any server-side interaction.
105*6dbdd20aSAndroid Build Coastguard WorkerTraces pushed via postMessage() are kept only in the browser memory/cache and
106*6dbdd20aSAndroid Build Coastguard Workerare not sent to any server.
107*6dbdd20aSAndroid Build Coastguard Worker
108*6dbdd20aSAndroid Build Coastguard Worker## Why can't I just pass a URL?
109*6dbdd20aSAndroid Build Coastguard Worker
110*6dbdd20aSAndroid Build Coastguard Worker_"Why you don't let me just pass a URL to the Perfetto UI (e.g. ui.perfetto.dev?url=...) and you deal with all this?"_
111*6dbdd20aSAndroid Build Coastguard Worker
112*6dbdd20aSAndroid Build Coastguard WorkerThe answer to this is manifold and boils down to security.
113*6dbdd20aSAndroid Build Coastguard Worker
114*6dbdd20aSAndroid Build Coastguard Worker#### Cross origin requests blocking
115*6dbdd20aSAndroid Build Coastguard Worker
116*6dbdd20aSAndroid Build Coastguard WorkerIf ui.perfetto.dev had to do a `fetch('https://yourwebsite.com/trace')` that
117*6dbdd20aSAndroid Build Coastguard Workerwould be a cross-origin request. Browsers disallow by default cross-origin
118*6dbdd20aSAndroid Build Coastguard Workerfetch requests.
119*6dbdd20aSAndroid Build Coastguard WorkerIn order for this to work, the web server that hosts yourwebsite.com would have
120*6dbdd20aSAndroid Build Coastguard Workerto expose a custom HTTP response header
121*6dbdd20aSAndroid Build Coastguard Worker (`Access-Control-Allow-Origin: https://ui.perfetto.dev`) to allow the fetch.
122*6dbdd20aSAndroid Build Coastguard WorkerIn most cases customizing the HTTP response headers is outside of dashboard's
123*6dbdd20aSAndroid Build Coastguard Workerowners control.
124*6dbdd20aSAndroid Build Coastguard Worker
125*6dbdd20aSAndroid Build Coastguard WorkerYou can learn more about CORS at
126*6dbdd20aSAndroid Build Coastguard Workerhttps://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
127*6dbdd20aSAndroid Build Coastguard Worker
128*6dbdd20aSAndroid Build Coastguard Worker#### Content Security Policy
129*6dbdd20aSAndroid Build Coastguard Worker
130*6dbdd20aSAndroid Build Coastguard WorkerPerfetto UI uses a strict Content Security Policy which disallows foreign
131*6dbdd20aSAndroid Build Coastguard Workerfetches and subresources, as a security mitigation about common attacks.
132*6dbdd20aSAndroid Build Coastguard WorkerEven assuming that CORS headers are properly set and your trace files are
133*6dbdd20aSAndroid Build Coastguard Workerpublicly accessible, fetching the trace from the Perfetto UI would require
134*6dbdd20aSAndroid Build Coastguard Workerallow-listing your origin in our CSP policy. This is not scalable.
135*6dbdd20aSAndroid Build Coastguard Worker
136*6dbdd20aSAndroid Build Coastguard WorkerYou can learn more about CSP at
137*6dbdd20aSAndroid Build Coastguard Workerhttps://developer.mozilla.org/en-US/docs/Web/HTTP/CSP
138*6dbdd20aSAndroid Build Coastguard Worker
139*6dbdd20aSAndroid Build Coastguard Worker#### Dealing with OAuth2 or other authentication mechanisms
140*6dbdd20aSAndroid Build Coastguard Worker
141*6dbdd20aSAndroid Build Coastguard WorkerEven ignoring CORS, the Perfetto UI would have to deal with OAuth2 or other
142*6dbdd20aSAndroid Build Coastguard Workerauthentication mechanisms to fetch the trace file. Even if all the dashboards
143*6dbdd20aSAndroid Build Coastguard Workerout there used OAuth2, that would still mean that Perfetto UI would have to know
144*6dbdd20aSAndroid Build Coastguard Workerabout all the possible OAuth2 scopes, one for each dashboard. This is not
145*6dbdd20aSAndroid Build Coastguard Workerscalable.
146*6dbdd20aSAndroid Build Coastguard Worker
147*6dbdd20aSAndroid Build Coastguard Worker## Opening the trace at a specific event or time
148*6dbdd20aSAndroid Build Coastguard Worker
149*6dbdd20aSAndroid Build Coastguard WorkerUsing the fragment query string allows for more control over the UI after
150*6dbdd20aSAndroid Build Coastguard Workerthe trace opens. For example this URL:
151*6dbdd20aSAndroid Build Coastguard Worker
152*6dbdd20aSAndroid Build Coastguard Worker```
153*6dbdd20aSAndroid Build Coastguard Workerhttps://ui.perfetto.dev/#!/?visStart=261191575272856&visEnd=261191675272856
154*6dbdd20aSAndroid Build Coastguard Worker```
155*6dbdd20aSAndroid Build Coastguard Worker
156*6dbdd20aSAndroid Build Coastguard WorkerWill open the pushed trace at 261191575272856ns (~261192s) and the
157*6dbdd20aSAndroid Build Coastguard Workerviewing window will be 261191675272856ns -261191575272856ns = 100ms wide.
158*6dbdd20aSAndroid Build Coastguard Worker
159*6dbdd20aSAndroid Build Coastguard Worker**Selecting a slice on load**:
160*6dbdd20aSAndroid Build Coastguard Worker
161*6dbdd20aSAndroid Build Coastguard WorkerYou can pass the following parameters: `ts`, `dur`, `pid`, `tid`.
162*6dbdd20aSAndroid Build Coastguard WorkerThe UI will query the slice table and find a slice that matches the parameters
163*6dbdd20aSAndroid Build Coastguard Workerpassed. If a slice is found it's highlighted.
164*6dbdd20aSAndroid Build Coastguard WorkerYou don't have to provide all the parameters.
165*6dbdd20aSAndroid Build Coastguard WorkerUsually `ts` and `dur` suffice to uniquely identifying a slice.
166*6dbdd20aSAndroid Build Coastguard Worker
167*6dbdd20aSAndroid Build Coastguard WorkerWe deliberately do NOT support linking by slice id. This is because slice IDs
168*6dbdd20aSAndroid Build Coastguard Workerare not stable across perfetto versions. Instead you can link a slice by passing
169*6dbdd20aSAndroid Build Coastguard Workerthe exact start and duration (`ts` and `dur`), as you see them by issuing a
170*6dbdd20aSAndroid Build Coastguard Workerquery `SELECT ts, dur FROM slices WHERE id=...`.
171*6dbdd20aSAndroid Build Coastguard Worker
172*6dbdd20aSAndroid Build Coastguard Worker**Zooming into a region of the trace on load**:
173*6dbdd20aSAndroid Build Coastguard Worker
174*6dbdd20aSAndroid Build Coastguard WorkerPass `visStart`, `visEnd`. These values are the raw values in `ns` as seen in
175*6dbdd20aSAndroid Build Coastguard Workerthe sql tables.
176*6dbdd20aSAndroid Build Coastguard Worker
177*6dbdd20aSAndroid Build Coastguard Worker**Issuing a query on load**:
178*6dbdd20aSAndroid Build Coastguard Worker
179*6dbdd20aSAndroid Build Coastguard WorkerPass the query in the `query` parameter.
180*6dbdd20aSAndroid Build Coastguard Worker
181*6dbdd20aSAndroid Build Coastguard Worker
182*6dbdd20aSAndroid Build Coastguard WorkerTry the following examples:
183*6dbdd20aSAndroid Build Coastguard Worker- [visStart & visEnd](https://ui.perfetto.dev/#!/?url=https%3A%2F%2Fstorage.googleapis.com%2Fperfetto-misc%2Fexample_android_trace_15s&visStart=261191575272856&visEnd=261191675272856)
184*6dbdd20aSAndroid Build Coastguard Worker- [ts & dur](https://ui.perfetto.dev/#!/?url=https%3A%2F%2Fstorage.googleapis.com%2Fperfetto-misc%2Fexample_android_trace_15s&ts=261192482777530&dur=1667500)
185*6dbdd20aSAndroid Build Coastguard Worker- [query](https://ui.perfetto.dev/#!/?url=https%3A%2F%2Fstorage.googleapis.com%2Fperfetto-misc%2Fexample_android_trace_15s&query=select%20'Hello%2C%20world!'%20as%20msg)
186*6dbdd20aSAndroid Build Coastguard Worker
187*6dbdd20aSAndroid Build Coastguard WorkerYou must take care to correctly escape strings where needed.
188*6dbdd20aSAndroid Build Coastguard Worker
189*6dbdd20aSAndroid Build Coastguard Worker## Source links
190*6dbdd20aSAndroid Build Coastguard Worker
191*6dbdd20aSAndroid Build Coastguard WorkerThe source code that deals with the postMessage() in the Perfetto UI is
192*6dbdd20aSAndroid Build Coastguard Worker[`post_message_handler.ts`](/ui/src/frontend/post_message_handler.ts).
193