1*6dbdd20aSAndroid Build Coastguard Worker// Copyright (C) 2023 The Android Open Source Project 2*6dbdd20aSAndroid Build Coastguard Worker// 3*6dbdd20aSAndroid Build Coastguard Worker// Licensed under the Apache License, Version 2.0 (the "License"); 4*6dbdd20aSAndroid Build Coastguard Worker// you may not use this file except in compliance with the License. 5*6dbdd20aSAndroid Build Coastguard Worker// You may obtain a copy of the License at 6*6dbdd20aSAndroid Build Coastguard Worker// 7*6dbdd20aSAndroid Build Coastguard Worker// http://www.apache.org/licenses/LICENSE-2.0 8*6dbdd20aSAndroid Build Coastguard Worker// 9*6dbdd20aSAndroid Build Coastguard Worker// Unless required by applicable law or agreed to in writing, software 10*6dbdd20aSAndroid Build Coastguard Worker// distributed under the License is distributed on an "AS IS" BASIS, 11*6dbdd20aSAndroid Build Coastguard Worker// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*6dbdd20aSAndroid Build Coastguard Worker// See the License for the specific language governing permissions and 13*6dbdd20aSAndroid Build Coastguard Worker// limitations under the License. 14*6dbdd20aSAndroid Build Coastguard Worker 15*6dbdd20aSAndroid Build Coastguard Worker// Keep this import first. 16*6dbdd20aSAndroid Build Coastguard Workerimport '../base/static_initializers'; 17*6dbdd20aSAndroid Build Coastguard Workerimport m from 'mithril'; 18*6dbdd20aSAndroid Build Coastguard Workerimport {defer} from '../base/deferred'; 19*6dbdd20aSAndroid Build Coastguard Workerimport {reportError, addErrorHandler, ErrorDetails} from '../base/logging'; 20*6dbdd20aSAndroid Build Coastguard Workerimport {initLiveReloadIfLocalhost} from '../core/live_reload'; 21*6dbdd20aSAndroid Build Coastguard Workerimport {raf} from '../core/raf_scheduler'; 22*6dbdd20aSAndroid Build Coastguard Workerimport {setScheduleFullRedraw} from '../widgets/raf'; 23*6dbdd20aSAndroid Build Coastguard Worker 24*6dbdd20aSAndroid Build Coastguard Workerfunction getRoot() { 25*6dbdd20aSAndroid Build Coastguard Worker // Works out the root directory where the content should be served from 26*6dbdd20aSAndroid Build Coastguard Worker // e.g. `http://origin/v1.2.3/`. 27*6dbdd20aSAndroid Build Coastguard Worker const script = document.currentScript as HTMLScriptElement; 28*6dbdd20aSAndroid Build Coastguard Worker 29*6dbdd20aSAndroid Build Coastguard Worker // Needed for DOM tests, that do not have script element. 30*6dbdd20aSAndroid Build Coastguard Worker if (script === null) { 31*6dbdd20aSAndroid Build Coastguard Worker return ''; 32*6dbdd20aSAndroid Build Coastguard Worker } 33*6dbdd20aSAndroid Build Coastguard Worker 34*6dbdd20aSAndroid Build Coastguard Worker let root = script.src; 35*6dbdd20aSAndroid Build Coastguard Worker root = root.substr(0, root.lastIndexOf('/') + 1); 36*6dbdd20aSAndroid Build Coastguard Worker return root; 37*6dbdd20aSAndroid Build Coastguard Worker} 38*6dbdd20aSAndroid Build Coastguard Worker 39*6dbdd20aSAndroid Build Coastguard Workerfunction setupContentSecurityPolicy() { 40*6dbdd20aSAndroid Build Coastguard Worker // Note: self and sha-xxx must be quoted, urls data: and blob: must not. 41*6dbdd20aSAndroid Build Coastguard Worker const policy = { 42*6dbdd20aSAndroid Build Coastguard Worker 'default-src': [ 43*6dbdd20aSAndroid Build Coastguard Worker `'self'`, 44*6dbdd20aSAndroid Build Coastguard Worker ], 45*6dbdd20aSAndroid Build Coastguard Worker 'script-src': [ 46*6dbdd20aSAndroid Build Coastguard Worker `'self'`, 47*6dbdd20aSAndroid Build Coastguard Worker ], 48*6dbdd20aSAndroid Build Coastguard Worker 'object-src': ['none'], 49*6dbdd20aSAndroid Build Coastguard Worker 'connect-src': [ 50*6dbdd20aSAndroid Build Coastguard Worker `'self'`, 51*6dbdd20aSAndroid Build Coastguard Worker ], 52*6dbdd20aSAndroid Build Coastguard Worker 'img-src': [ 53*6dbdd20aSAndroid Build Coastguard Worker `'self'`, 54*6dbdd20aSAndroid Build Coastguard Worker 'data:', 55*6dbdd20aSAndroid Build Coastguard Worker 'blob:', 56*6dbdd20aSAndroid Build Coastguard Worker ], 57*6dbdd20aSAndroid Build Coastguard Worker 'style-src': [ 58*6dbdd20aSAndroid Build Coastguard Worker `'self'`, 59*6dbdd20aSAndroid Build Coastguard Worker ], 60*6dbdd20aSAndroid Build Coastguard Worker 'navigate-to': ['https://*.perfetto.dev', 'self'], 61*6dbdd20aSAndroid Build Coastguard Worker }; 62*6dbdd20aSAndroid Build Coastguard Worker const meta = document.createElement('meta'); 63*6dbdd20aSAndroid Build Coastguard Worker meta.httpEquiv = 'Content-Security-Policy'; 64*6dbdd20aSAndroid Build Coastguard Worker let policyStr = ''; 65*6dbdd20aSAndroid Build Coastguard Worker for (const [key, list] of Object.entries(policy)) { 66*6dbdd20aSAndroid Build Coastguard Worker policyStr += `${key} ${list.join(' ')}; `; 67*6dbdd20aSAndroid Build Coastguard Worker } 68*6dbdd20aSAndroid Build Coastguard Worker meta.content = policyStr; 69*6dbdd20aSAndroid Build Coastguard Worker document.head.appendChild(meta); 70*6dbdd20aSAndroid Build Coastguard Worker} 71*6dbdd20aSAndroid Build Coastguard Worker 72*6dbdd20aSAndroid Build Coastguard Workerfunction main() { 73*6dbdd20aSAndroid Build Coastguard Worker // Wire up raf for widgets. 74*6dbdd20aSAndroid Build Coastguard Worker setScheduleFullRedraw(() => raf.scheduleFullRedraw()); 75*6dbdd20aSAndroid Build Coastguard Worker 76*6dbdd20aSAndroid Build Coastguard Worker setupContentSecurityPolicy(); 77*6dbdd20aSAndroid Build Coastguard Worker 78*6dbdd20aSAndroid Build Coastguard Worker // Load the css. The load is asynchronous and the CSS is not ready by the time 79*6dbdd20aSAndroid Build Coastguard Worker // appendChild returns. 80*6dbdd20aSAndroid Build Coastguard Worker const root = getRoot(); 81*6dbdd20aSAndroid Build Coastguard Worker const cssLoadPromise = defer<void>(); 82*6dbdd20aSAndroid Build Coastguard Worker const css = document.createElement('link'); 83*6dbdd20aSAndroid Build Coastguard Worker css.rel = 'stylesheet'; 84*6dbdd20aSAndroid Build Coastguard Worker css.href = root + 'perfetto.css'; 85*6dbdd20aSAndroid Build Coastguard Worker css.onload = () => cssLoadPromise.resolve(); 86*6dbdd20aSAndroid Build Coastguard Worker css.onerror = (err) => cssLoadPromise.reject(err); 87*6dbdd20aSAndroid Build Coastguard Worker const favicon = document.head.querySelector('#favicon') as HTMLLinkElement; 88*6dbdd20aSAndroid Build Coastguard Worker if (favicon) favicon.href = root + 'assets/favicon.png'; 89*6dbdd20aSAndroid Build Coastguard Worker 90*6dbdd20aSAndroid Build Coastguard Worker document.head.append(css); 91*6dbdd20aSAndroid Build Coastguard Worker 92*6dbdd20aSAndroid Build Coastguard Worker // Add Error handlers for JS error and for uncaught exceptions in promises. 93*6dbdd20aSAndroid Build Coastguard Worker addErrorHandler((err: ErrorDetails) => console.log(err.message, err.stack)); 94*6dbdd20aSAndroid Build Coastguard Worker window.addEventListener('error', (e) => reportError(e)); 95*6dbdd20aSAndroid Build Coastguard Worker window.addEventListener('unhandledrejection', (e) => reportError(e)); 96*6dbdd20aSAndroid Build Coastguard Worker 97*6dbdd20aSAndroid Build Coastguard Worker // Prevent pinch zoom. 98*6dbdd20aSAndroid Build Coastguard Worker document.body.addEventListener('wheel', (e: MouseEvent) => { 99*6dbdd20aSAndroid Build Coastguard Worker if (e.ctrlKey) e.preventDefault(); 100*6dbdd20aSAndroid Build Coastguard Worker }, {passive: false}); 101*6dbdd20aSAndroid Build Coastguard Worker 102*6dbdd20aSAndroid Build Coastguard Worker cssLoadPromise.then(() => onCssLoaded()); 103*6dbdd20aSAndroid Build Coastguard Worker} 104*6dbdd20aSAndroid Build Coastguard Worker 105*6dbdd20aSAndroid Build Coastguard Workerfunction onCssLoaded() { 106*6dbdd20aSAndroid Build Coastguard Worker // Clear all the contents of the initial page (e.g. the <pre> error message) 107*6dbdd20aSAndroid Build Coastguard Worker // And replace it with the root <main> element which will be used by mithril. 108*6dbdd20aSAndroid Build Coastguard Worker document.body.innerHTML = ''; 109*6dbdd20aSAndroid Build Coastguard Worker 110*6dbdd20aSAndroid Build Coastguard Worker raf.domRedraw = () => { 111*6dbdd20aSAndroid Build Coastguard Worker m.render(document.body, m('div')); 112*6dbdd20aSAndroid Build Coastguard Worker }; 113*6dbdd20aSAndroid Build Coastguard Worker 114*6dbdd20aSAndroid Build Coastguard Worker initLiveReloadIfLocalhost(false); 115*6dbdd20aSAndroid Build Coastguard Worker} 116*6dbdd20aSAndroid Build Coastguard Worker 117*6dbdd20aSAndroid Build Coastguard Workermain(); 118