blob: a2be0f4823805206fec34447867944ade85e0047 [file] [log] [blame]
// Copyright (C) 2024 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 {assertTrue} from '../base/logging';
import {App} from '../public/app';
import {TraceContext, TraceImpl} from './trace_impl';
import {CommandManagerImpl} from './command_manager';
import {OmniboxManagerImpl} from './omnibox_manager';
import {raf} from './raf_scheduler';
import {SidebarManagerImpl} from './sidebar_manager';
// The pseudo plugin id used for the core instance of AppImpl.
export const CORE_PLUGIN_ID = '__core__';
/**
* Handles the global state of the ui, for anything that is not related to a
* specific trace. This is always available even before a trace is loaded (in
* contrast to TraceContext, which is bound to the lifetime of a trace).
* There is only one instance in total of this class (see instance()).
* This class is not exposed to anybody. Both core and plugins should access
* this via AppImpl.
*/
export class AppContext {
readonly commandMgr = new CommandManagerImpl();
readonly omniboxMgr = new OmniboxManagerImpl();
readonly sidebarMgr = new SidebarManagerImpl();
// The most recently created trace context. Can be undefined before any trace
// is loaded.
private traceCtx?: TraceContext;
// There is only one global instance, lazily initialized on the first call.
private static _instance: AppContext;
static get instance() {
return (AppContext._instance = AppContext._instance ?? new AppContext());
}
private constructor() {}
get currentTraceCtx(): TraceContext | undefined {
return this.traceCtx;
}
// Called by AppImpl.newTraceInstance().
setActiveTrace(traceCtx: TraceContext | undefined) {
if (this.traceCtx !== undefined) {
// This will trigger the unregistration of trace-scoped commands and
// sidebar menuitems (and few similar things).
this.traceCtx[Symbol.dispose]();
}
this.traceCtx = traceCtx;
}
}
/*
* Every plugin gets its own instance. This is how we keep track
* what each plugin is doing and how we can blame issues on particular
* plugins.
* The instance exists for the whole duration a plugin is active.
*/
export class AppImpl implements App {
private appCtx: AppContext;
readonly pluginId: string;
private currentTrace?: TraceImpl;
private constructor(appCtx: AppContext, pluginId: string) {
this.appCtx = appCtx;
this.pluginId = pluginId;
}
// Gets access to the one instance that the core can use. Note that this is
// NOT the only instance, as other AppImpl instance will be created for each
// plugin.
private static _instance: AppImpl;
static get instance(): AppImpl {
AppImpl._instance =
AppImpl._instance ?? new AppImpl(AppContext.instance, CORE_PLUGIN_ID);
return AppImpl._instance;
}
get commands(): CommandManagerImpl {
return this.appCtx.commandMgr;
}
get sidebar(): SidebarManagerImpl {
return this.appCtx.sidebarMgr;
}
get omnibox(): OmniboxManagerImpl {
return this.appCtx.omniboxMgr;
}
get trace(): TraceImpl | undefined {
return this.currentTrace;
}
closeCurrentTrace() {
this.currentTrace = undefined;
this.appCtx.setActiveTrace(undefined);
}
scheduleRedraw(): void {
raf.scheduleFullRedraw();
}
setActiveTrace(traceImpl: TraceImpl, traceCtx: TraceContext) {
this.appCtx.setActiveTrace(traceCtx);
this.currentTrace = traceImpl;
}
forkForPlugin(pluginId: string): AppImpl {
assertTrue(pluginId != CORE_PLUGIN_ID);
return new AppImpl(this.appCtx, pluginId);
}
}