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