xref: /aosp_15_r20/external/perfetto/ui/src/assets/index.html (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
1*6dbdd20aSAndroid Build Coastguard Worker<!doctype html>
2*6dbdd20aSAndroid Build Coastguard Worker<html lang="en-us">
3*6dbdd20aSAndroid Build Coastguard Worker<head>
4*6dbdd20aSAndroid Build Coastguard Worker  <meta charset="utf-8">
5*6dbdd20aSAndroid Build Coastguard Worker  <title>Perfetto UI</title>
6*6dbdd20aSAndroid Build Coastguard Worker  <meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" name="viewport" />
7*6dbdd20aSAndroid Build Coastguard Worker  <link rel="shortcut icon" id="favicon" type="image/png" href="data:image/png;base64,iVBORw0KGgo=">
8*6dbdd20aSAndroid Build Coastguard Worker</head>
9*6dbdd20aSAndroid Build Coastguard Worker<body data-perfetto_version='{"filled_by_build_js":"."}'>
10*6dbdd20aSAndroid Build Coastguard Worker  <!--
11*6dbdd20aSAndroid Build Coastguard Worker    Don't add any content here. The whole <body> is replaced by
12*6dbdd20aSAndroid Build Coastguard Worker    frontend/index.ts when bootstrapping. This is only used for very early
13*6dbdd20aSAndroid Build Coastguard Worker    error reporting.
14*6dbdd20aSAndroid Build Coastguard Worker  -->
15*6dbdd20aSAndroid Build Coastguard Worker  <style>
16*6dbdd20aSAndroid Build Coastguard Worker  #app_load_failure {opacity:0;transition:opacity 1s ease;position:absolute;overflow:auto;background:#080082;top:0;left:0;width:100%;height:100%;bottom:0;right:0;margin:0;opacity:0;user-select:text}
17*6dbdd20aSAndroid Build Coastguard Worker  #app_load_failure > pre {color:#fff;position:absolute;margin:auto;white-space:pre-wrap;top:10vh;max-width:90vw;width:880px;left:0;right:0;font-size:16px;line-height:30px;font-weight:700}
18*6dbdd20aSAndroid Build Coastguard Worker  #app_load_failure > pre span {background:#fff;color:#080082;padding:2px}
19*6dbdd20aSAndroid Build Coastguard Worker  #app_load_failure_dbg { overflow-wrap: break-word; font-size: 12px; line-height: 1; font-weight: initial;}
20*6dbdd20aSAndroid Build Coastguard Worker  #app_load_failure a {color:#fff}
21*6dbdd20aSAndroid Build Coastguard Worker  #app_load { position: absolute; top: 0; left: 0; right:0; bottom: 0; background-color: #2c3e50;}
22*6dbdd20aSAndroid Build Coastguard Worker  #app_load_spinner { margin: 30vh auto; width: 150px; height: 150px; border: 3px solid rgba(255,255,255,.3); border-radius: 50%; border-top-color: #fff; animation: app_load_spin 1s ease-in-out infinite; }
23*6dbdd20aSAndroid Build Coastguard Worker  @keyframes app_load_spin { to { transform: rotate(360deg); } }
24*6dbdd20aSAndroid Build Coastguard Worker  </style>
25*6dbdd20aSAndroid Build Coastguard Worker  <div id="app_load"><div id="app_load_spinner"></div></div>
26*6dbdd20aSAndroid Build Coastguard Worker  <div id="app_load_failure">
27*6dbdd20aSAndroid Build Coastguard Worker<pre>
28*6dbdd20aSAndroid Build Coastguard Worker<span>Perfetto UI - An unrecoverable problem occurred</span>
29*6dbdd20aSAndroid Build Coastguard Worker
30*6dbdd20aSAndroid Build Coastguard WorkerIf you are seeing this message, something went wrong while loading the UI.
31*6dbdd20aSAndroid Build Coastguard WorkerIn most cases this is due to very slow or flaky network and it goes away by
32*6dbdd20aSAndroid Build Coastguard Workerdisabling and re-enabling WiFi or trying reloading.
33*6dbdd20aSAndroid Build Coastguard Worker
34*6dbdd20aSAndroid Build Coastguard WorkerIf the problem persists try these remediation steps:
35*6dbdd20aSAndroid Build Coastguard Worker
36*6dbdd20aSAndroid Build Coastguard Worker* Force-reload the page with Ctrl+Shift+R (Mac: Meta+Shift+R) or
37*6dbdd20aSAndroid Build Coastguard Worker  Shift + click on the refresh button.
38*6dbdd20aSAndroid Build Coastguard Worker
39*6dbdd20aSAndroid Build Coastguard Worker* <a href="javascript:clearAllCaches();">Clear all the site storage and caches</a> and reload the page.
40*6dbdd20aSAndroid Build Coastguard Worker
41*6dbdd20aSAndroid Build Coastguard Worker* Clear the site data and caches from devtools, following <a target="_blank" href="https://developers.google.com/web/tools/chrome-devtools/storage/cache#deletecache">these instructions</a>.
42*6dbdd20aSAndroid Build Coastguard Worker
43*6dbdd20aSAndroid Build Coastguard WorkerIf none of this works, file a bug attaching logs and screenshots from devtools.
44*6dbdd20aSAndroid Build Coastguard Worker  Googlers:      <a href="http://go/perfetto-ui-bug" target="_blank">go/perfetto-ui-bug</a>
45*6dbdd20aSAndroid Build Coastguard Worker  Non-googlers:  <a href="https://github.com/google/perfetto/issues/new" target="_blank">github.com/google/perfetto/issues/new</a>
46*6dbdd20aSAndroid Build Coastguard Worker
47*6dbdd20aSAndroid Build Coastguard Worker<div id=app_load_failure_err></div>
48*6dbdd20aSAndroid Build Coastguard WorkerTechnical Information:
49*6dbdd20aSAndroid Build Coastguard Worker<div id=app_load_failure_dbg></div>
50*6dbdd20aSAndroid Build Coastguard Worker</pre>
51*6dbdd20aSAndroid Build Coastguard Worker  </div>
52*6dbdd20aSAndroid Build Coastguard Worker  <script type="text/javascript">
53*6dbdd20aSAndroid Build Coastguard Worker    'use strict';
54*6dbdd20aSAndroid Build Coastguard Worker    (function () {
55*6dbdd20aSAndroid Build Coastguard Worker      const TIMEOUT_MS = 120000;
56*6dbdd20aSAndroid Build Coastguard Worker      let errTimerId = undefined;
57*6dbdd20aSAndroid Build Coastguard Worker
58*6dbdd20aSAndroid Build Coastguard Worker      function errHandler(err) {
59*6dbdd20aSAndroid Build Coastguard Worker        // Note: we deliberately don't clearTimeout(), which means that this
60*6dbdd20aSAndroid Build Coastguard Worker        // handler is called also in the happy case when the UI loads. In that
61*6dbdd20aSAndroid Build Coastguard Worker        // case, though, the onCssLoaded() in frontend/index.ts will empty the
62*6dbdd20aSAndroid Build Coastguard Worker        // <body>, so |div| below will be null and this function becomes a
63*6dbdd20aSAndroid Build Coastguard Worker        // no-op.
64*6dbdd20aSAndroid Build Coastguard Worker        const div = document.getElementById('app_load_failure');
65*6dbdd20aSAndroid Build Coastguard Worker        if (!div) return;
66*6dbdd20aSAndroid Build Coastguard Worker        div.style.opacity ='1';
67*6dbdd20aSAndroid Build Coastguard Worker        const errDom = document.getElementById('app_load_failure_err');
68*6dbdd20aSAndroid Build Coastguard Worker        if (!errDom) return;
69*6dbdd20aSAndroid Build Coastguard Worker        console.error(err);
70*6dbdd20aSAndroid Build Coastguard Worker        errDom.innerText += `${err}\n`;
71*6dbdd20aSAndroid Build Coastguard Worker        const storageJson = JSON.stringify(window.localStorage);
72*6dbdd20aSAndroid Build Coastguard Worker        const dbg = document.getElementById('app_load_failure_dbg');
73*6dbdd20aSAndroid Build Coastguard Worker        if (!dbg) return;
74*6dbdd20aSAndroid Build Coastguard Worker        dbg.innerText = `LocalStorage: ${storageJson}\n`;
75*6dbdd20aSAndroid Build Coastguard Worker        if (errTimerId !== undefined) clearTimeout(errTimerId);
76*6dbdd20aSAndroid Build Coastguard Worker      }
77*6dbdd20aSAndroid Build Coastguard Worker
78*6dbdd20aSAndroid Build Coastguard Worker      // For the 'Click here to clear all caches'.
79*6dbdd20aSAndroid Build Coastguard Worker      window.clearAllCaches = async () => {
80*6dbdd20aSAndroid Build Coastguard Worker        if (window.localStorage) window.localStorage.clear();
81*6dbdd20aSAndroid Build Coastguard Worker        if (window.sessionStorage) window.sessionStorage.clear();
82*6dbdd20aSAndroid Build Coastguard Worker        const promises = [];
83*6dbdd20aSAndroid Build Coastguard Worker        if (window.caches) {
84*6dbdd20aSAndroid Build Coastguard Worker          try {
85*6dbdd20aSAndroid Build Coastguard Worker            const keys = await window.caches.keys();
86*6dbdd20aSAndroid Build Coastguard Worker            keys.forEach(k => promises.push(window.caches.delete(k)));
87*6dbdd20aSAndroid Build Coastguard Worker          } catch (_) {
88*6dbdd20aSAndroid Build Coastguard Worker            // TODO(288483453)
89*6dbdd20aSAndroid Build Coastguard Worker          }
90*6dbdd20aSAndroid Build Coastguard Worker        }
91*6dbdd20aSAndroid Build Coastguard Worker        if (navigator.serviceWorker) {
92*6dbdd20aSAndroid Build Coastguard Worker          const regs = await navigator.serviceWorker.getRegistrations();
93*6dbdd20aSAndroid Build Coastguard Worker          regs.forEach(reg => promises.push(reg.unregister()));
94*6dbdd20aSAndroid Build Coastguard Worker        }
95*6dbdd20aSAndroid Build Coastguard Worker        try {
96*6dbdd20aSAndroid Build Coastguard Worker          await Promise.all(promises);
97*6dbdd20aSAndroid Build Coastguard Worker        } catch (_) {
98*6dbdd20aSAndroid Build Coastguard Worker          // TODO(288483453)
99*6dbdd20aSAndroid Build Coastguard Worker        }
100*6dbdd20aSAndroid Build Coastguard Worker        window.location.reload();
101*6dbdd20aSAndroid Build Coastguard Worker      }
102*6dbdd20aSAndroid Build Coastguard Worker
103*6dbdd20aSAndroid Build Coastguard Worker      // If the frontend doesn't come up, make the error page above visible.
104*6dbdd20aSAndroid Build Coastguard Worker      errTimerId = setTimeout(() => errHandler('Timed out'), TIMEOUT_MS);
105*6dbdd20aSAndroid Build Coastguard Worker      window.onerror = errHandler;
106*6dbdd20aSAndroid Build Coastguard Worker      window.onunhandledrejection = errHandler;
107*6dbdd20aSAndroid Build Coastguard Worker
108*6dbdd20aSAndroid Build Coastguard Worker      const versionStr = document.body.dataset['perfetto_version'] || '{}';
109*6dbdd20aSAndroid Build Coastguard Worker      const versionMap = JSON.parse(versionStr);
110*6dbdd20aSAndroid Build Coastguard Worker      const channel = localStorage.getItem('perfettoUiChannel') || 'stable';
111*6dbdd20aSAndroid Build Coastguard Worker
112*6dbdd20aSAndroid Build Coastguard Worker      // The '.' below is a fallback for the case of opening a pinned version
113*6dbdd20aSAndroid Build Coastguard Worker      // (e.g., ui.perfetto.dev/v1.2.3./). In that case, the index.html has no
114*6dbdd20aSAndroid Build Coastguard Worker      // valid version map; we want to load the frontend from the same
115*6dbdd20aSAndroid Build Coastguard Worker      // sub-directory directory, hence ./frontend_bundle.js.
116*6dbdd20aSAndroid Build Coastguard Worker      const version = versionMap[channel] || versionMap['stable'] || '.';
117*6dbdd20aSAndroid Build Coastguard Worker
118*6dbdd20aSAndroid Build Coastguard Worker      const script = document.createElement('script');
119*6dbdd20aSAndroid Build Coastguard Worker      script.async = true;
120*6dbdd20aSAndroid Build Coastguard Worker      script.src = version + '/frontend_bundle.js';
121*6dbdd20aSAndroid Build Coastguard Worker      script.onerror = () => errHandler(`Failed to load ${script.src}`);
122*6dbdd20aSAndroid Build Coastguard Worker
123*6dbdd20aSAndroid Build Coastguard Worker      document.head.append(script);
124*6dbdd20aSAndroid Build Coastguard Worker    })();
125*6dbdd20aSAndroid Build Coastguard Worker  </script>
126*6dbdd20aSAndroid Build Coastguard Worker</body>
127*6dbdd20aSAndroid Build Coastguard Worker</html>
128