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