Merge "Docs: add docs to explain window.open() / deep links"
diff --git a/docs/toc.md b/docs/toc.md
index 15c1cae..a27779d 100644
--- a/docs/toc.md
+++ b/docs/toc.md
@@ -40,6 +40,7 @@
 * [Trace visualization](#)
   * [Perfetto UI](visualization/perfetto-ui.md)
   * [Visualising large traces](visualization/large-traces.md)
+  * [Deep linking to Perfetto UI](visualization/deep-linking-to-perfetto-ui.md)
 
 * [Core concepts](#)
   * [Trace configuration](concepts/config.md)
diff --git a/docs/visualization/deep-linking-to-perfetto-ui.md b/docs/visualization/deep-linking-to-perfetto-ui.md
new file mode 100644
index 0000000..f6a9225
--- /dev/null
+++ b/docs/visualization/deep-linking-to-perfetto-ui.md
@@ -0,0 +1,142 @@
+# Deep linking to the Perfetto UI
+
+This document describes how to open traces hosted on external servers with the
+Perfetto UI. This can help integrating the Perfetto UI with custom dashboards
+and implement _'Open with Perfetto UI'_-like features.
+
+## Using window.open and postMessage
+
+The supported way of doing this is to _inject_ the trace as an ArrayBuffer
+via `window.open('https://ui.perfetto.dev')` and `postMessage()`.
+In order to do this you need some minimal JavaScript code running on some
+hosting infrastructure you control which can access the trace file. In most
+cases this is some dashboard which you want to deep-link to the Perfetto UI.
+
+#### Open ui.perfetto.dev via window.open
+
+The source dashboard, the one that knows how to locate a trace and deal with
+ACL checking / oauth authentication and the like, creates a new tab by doing
+
+```js
+var handle = window.open('https://ui.perfetto.dev');
+```
+
+The window handle allows bidirectional communication using `postMessage()`
+between the source dashboard and the Perfetto UI.
+
+#### Wait for the UI to be ready via PING/PONG
+
+Wait for the UI to be ready. The `window.open()` message channel is not
+buffered. If you send a message before the opened page has registered an
+`onmessage` listener the messagge will be dropped on the floor.
+In order to avoid this race, you can use a very basic PING/PONG protocol: keep
+sending a 'PING' message until the opened window replies with a 'PONG'.
+When this happens, that is the signal that the Perfetto UI is ready to open
+traces.
+
+#### Post a message the following JavaScript object
+
+```js
+  {
+    'perfetto': {
+      buffer: ArrayBuffer;
+      title: string;
+      fileName?: string;  // Optional
+      url?: string;       // Optional
+    }
+  }
+```
+
+`buffer` is the ArrayBuffer with the actual trace file content. This is
+typically something that you obtain by doing a `fetch()` on your backend
+storage.
+
+`title` is the human friendly trace title that will be shown in the
+sidebar. This can help people to disambiguate traces from several tabs.
+
+`fileName` will be used if the user clicks on "Download". A generic name will
+be used if omitted.
+
+`url` is used if the user clicks on the "Share" link in the sidebar. This should
+print to a URL owned by you that would cause your dashboard to re-open the
+current trace, by re-kicking-off the window.open() process herein described.
+If omitted traces won't be shareable.
+
+### Code samples
+
+See https://jsfiddle.net/primiano/1hd0a4wj/68/ (also mirrored on
+[this GitHub gist](https://gist.github.com/primiano/e164868b617844ef8fa4770eb3b323b9)
+)
+
+Googlers: take a look at the
+[existing examples in the internal codesearch](http://go/perfetto-ui-deeplink-cs)
+
+### Common pitfalls
+
+Many browsers sometimes block window.open() requests prompting the user to allow
+popups for the site. This usually happens if:
+
+- The window.open() is NOT initiated by a user gesture.
+- Too much time is passed from the user gesture to the window.open()
+
+If the trace file is big enough, the fetch() might take long time and pass the
+user gesture threshold. This can be detected by observing that the window.open()
+returned `null`. When this happens the best option is to show another clickable
+element and bind the fetched trace ArrayBuffer to the new onclick handler, like
+the code in the example above does.
+
+Some browser can have a variable time threshold for the user gesture timeout
+which depends on the website engagement score (how much the user has visited
+the page that does the window.open() before). It's quite common when testing
+this code to see a popup blocker the first time the new feature is used and
+then not see it again.
+
+### Where does the posted trace go?
+
+The Perfetto UI is client-only and doesn't require any server-side interaction.
+Traces pushed via postMessage() are kept only in the browser memory/cache and
+are not sent to any server.
+
+## Why can't I just pass a URL?
+
+_"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?"_
+
+The answer to this is manifold and boils down to security.
+
+#### Cross origin requests blocking
+
+If ui.perfetto.dev had to do a `fetch('https://yourwebsite.com/trace')` that
+would be a cross-origin request. Browsers disallow by default cross-origin
+fetch requests.
+In order for this to work, the web server that hosts yourwebsite.com would have
+to expose a custom HTTP response header
+ (`Access-Control-Allow-Origin: https://ui.perfetto.dev`) to allow the fetch.
+In most cases customizing the HTTP response headers is outside of dashboard's
+owners control.
+
+You can learn more about CORS at
+https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
+
+#### Content Security Policy
+
+Perfetto UI uses a strict Content Security Policy which disallows foreign
+fetches and subresources, as a security mitigation about common attacks.
+Even assuming that CORS headers are properly set and your trace files are
+publicly accessible, fetching the trace from the Perfetto UI would require
+allow-listing your origin in our CSP policy. This is not scalable.
+
+You can learn more about CSP at
+https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP
+
+#### Dealing with OAuth2 or other authentication mechanisms
+
+Even ignoring CORS, the Perfetto UI would have to deal with OAuth2 or other
+authentication mechanisms to fetch the trace file. Even if all the dashboards
+out there used OAuth2, that would still mean that Perfetto UI would have to know
+about all the possible OAuth2 scopes, one for each dashboard. This is not
+scalable.
+
+## Source links
+
+The source code that deals with the postMessage() in the Perfetto UI is
+[`post_message_handler.ts`](/ui/src/frontend/post_message_handler.ts)