blob: e6e3b666dac8ef629551785ad97cea9c5609985b [file] [log] [blame]
// Copyright (C) 2018 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import '../tracks/all_frontend';
import * as m from 'mithril';
import {forwardRemoteCalls} from '../base/remote';
import {loadPermalink, navigate} from '../common/actions';
import {State} from '../common/state';
import {TimeSpan} from '../common/time';
import {
takeWasmEngineWorkerPort,
warmupWasmEngineWorker,
} from '../controller/wasm_engine_proxy';
import {globals, QuantizedLoad, ThreadDesc} from './globals';
import {HomePage} from './home_page';
import {ViewerPage} from './viewer_page';
/**
* The API the main thread exposes to the controller.
*/
class FrontendApi {
updateState(state: State) {
globals.state = state;
// If the visible time in the global state has been updated more recently
// than the visible time handled by the frontend @ 60fps, update it. This
// typically happens when restoring the state from a permalink.
const vizTraceTime = globals.state.visibleTraceTime;
if (vizTraceTime.lastUpdate >
globals.frontendLocalState.visibleTimeLastUpdate) {
globals.frontendLocalState.updateVisibleTime(
new TimeSpan(vizTraceTime.startSec, vizTraceTime.endSec));
}
this.redraw();
}
// TODO: we can't have a publish method for each batch of data that we don't
// want to keep in the global state. Figure out a more generic and type-safe
// mechanism to achieve this.
publishOverviewData(data: {[key: string]: QuantizedLoad}) {
for (const key of Object.keys(data)) {
if (!globals.overviewStore.has(key)) {
globals.overviewStore.set(key, []);
}
globals.overviewStore.get(key)!.push(data[key]);
}
globals.rafScheduler.scheduleOneRedraw();
}
publishTrackData(args: {id: string, data: {}}) {
globals.trackDataStore.set(args.id, args.data);
globals.rafScheduler.scheduleOneRedraw();
}
publishQueryResult(args: {id: string, data: {}}) {
globals.queryResults.set(args.id, args.data);
this.redraw();
}
publishThreads(data: ThreadDesc[]) {
globals.threads.clear();
data.forEach(thread => {
globals.threads.set(thread.utid, thread);
});
this.redraw();
}
/**
* Creates a new trace processor wasm engine (backed by a worker running
* engine_bundle.js) and returns a MessagePort for talking to it.
* This indirection is due to workers not being able create workers in
* Chrome which is tracked at: crbug.com/31666
* TODO(hjd): Remove this once the fix has landed.
*/
createWasmEnginePort(): MessagePort {
return takeWasmEngineWorkerPort();
}
private redraw(): void {
if (globals.state.route && globals.state.route !== m.route.get()) {
m.route.set(globals.state.route);
} else {
m.redraw();
}
}
}
function main() {
const controller = new Worker('controller_bundle.js');
controller.onerror = e => {
console.error(e);
};
const channel = new MessageChannel();
forwardRemoteCalls(channel.port2, new FrontendApi());
controller.postMessage(channel.port1, [channel.port1]);
globals.initialize(controller.postMessage.bind(controller));
warmupWasmEngineWorker();
m.route(document.body, '/', {
'/': HomePage,
'/viewer': ViewerPage,
});
// Put these variables in the global scope for better debugging.
(window as {} as {m: {}}).m = m;
(window as {} as {globals: {}}).globals = globals;
// /?s=xxxx for permalinks.
const stateHash = m.route.param('s');
if (stateHash) {
globals.dispatch(loadPermalink(stateHash));
}
// Prevent pinch zoom.
document.body.addEventListener('wheel', (e: MouseEvent) => {
if (e.ctrlKey) e.preventDefault();
});
globals.dispatch(navigate(m.route.get()));
}
main();