// Copyright (C) 2021 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 {Actions} from '../common/actions'; import {AggregateData, isEmptyData} from '../common/aggregation_data'; import {ConversionJobStatusUpdate} from '../common/conversion_jobs'; import { LogBoundsKey, LogEntriesKey, LogExists, LogExistsKey } from '../common/logs'; import {MetricResult} from '../common/metric_data'; import {CurrentSearchResults, SearchSummary} from '../common/search_data'; import { CounterDetails, CpuProfileDetails, FlamegraphDetails, Flow, globals, QuantizedLoad, SliceDetails, ThreadDesc, ThreadStateDetails } from './globals'; import {findCurrentSelection} from './keyboard_event_handler'; import {PivotTableHelper} from './pivot_table_helper'; export function publishOverviewData( data: {[key: string]: QuantizedLoad|QuantizedLoad[]}) { for (const [key, value] of Object.entries(data)) { if (!globals.overviewStore.has(key)) { globals.overviewStore.set(key, []); } if (value instanceof Array) { globals.overviewStore.get(key)!.push(...value); } else { globals.overviewStore.get(key)!.push(value); } } globals.rafScheduler.scheduleRedraw(); } export function publishTrackData(args: {id: string, data: {}}) { globals.setTrackData(args.id, args.data); if ([LogExistsKey, LogBoundsKey, LogEntriesKey].includes(args.id)) { const data = globals.trackDataStore.get(LogExistsKey) as LogExists; if (data && data.exists) globals.rafScheduler.scheduleFullRedraw(); } else { globals.rafScheduler.scheduleRedraw(); } } export function publishMetricResult(metricResult: MetricResult) { globals.setMetricResult(metricResult); globals.publishRedraw(); } export function publishSelectedFlows(selectedFlows: Flow[]) { globals.selectedFlows = selectedFlows; globals.publishRedraw(); } export function publishCounterDetails(click: CounterDetails) { globals.counterDetails = click; globals.publishRedraw(); } export function publishFlamegraphDetails(click: FlamegraphDetails) { globals.flamegraphDetails = click; globals.publishRedraw(); } export function publishCpuProfileDetails(details: CpuProfileDetails) { globals.cpuProfileDetails = details; globals.publishRedraw(); } export function publishHasFtrace(hasFtrace: boolean) { globals.hasFtrace = hasFtrace; globals.publishRedraw(); } export function publishConversionJobStatusUpdate( job: ConversionJobStatusUpdate) { globals.setConversionJobStatus(job.jobName, job.jobStatus); globals.publishRedraw(); } export function publishLoading(numQueuedQueries: number) { globals.numQueuedQueries = numQueuedQueries; // TODO(hjd): Clean up loadingAnimation given that this now causes a full // redraw anyways. Also this should probably just go via the global state. globals.rafScheduler.scheduleFullRedraw(); } export function publishBufferUsage(args: {percentage: number}) { globals.setBufferUsage(args.percentage); globals.publishRedraw(); } export function publishSearch(args: SearchSummary) { globals.searchSummary = args; globals.publishRedraw(); } export function publishSearchResult(args: CurrentSearchResults) { globals.currentSearchResults = args; globals.publishRedraw(); } export function publishRecordingLog(args: {logs: string}) { globals.setRecordingLog(args.logs); globals.publishRedraw(); } export function publishTraceErrors(numErrors: number) { globals.setTraceErrors(numErrors); globals.publishRedraw(); } export function publishMetricError(error: string) { globals.setMetricError(error); globals.logging.logError(error, false); globals.publishRedraw(); } export function publishAggregateData( args: {data: AggregateData, kind: string}) { globals.setAggregateData(args.kind, args.data); if (!isEmptyData(args.data)) { globals.dispatch(Actions.setCurrentTab({tab: args.data.tabName})); } globals.publishRedraw(); } export function publishQueryResult(args: {id: string, data?: {}}) { globals.queryResults.set(args.id, args.data); globals.dispatch(Actions.setCurrentTab({tab: 'query_result'})); globals.publishRedraw(); } export function publishPivotTableHelper( args: {id: string, data: PivotTableHelper}) { globals.pivotTableHelper.set(args.id, args.data); globals.publishRedraw(); } export function publishThreads(data: ThreadDesc[]) { globals.threads.clear(); data.forEach(thread => { globals.threads.set(thread.utid, thread); }); globals.publishRedraw(); } export function publishSliceDetails(click: SliceDetails) { globals.sliceDetails = click; const id = click.id; if (id !== undefined && id === globals.state.pendingScrollId) { findCurrentSelection(); globals.dispatch(Actions.clearPendingScrollId({id: undefined})); } globals.publishRedraw(); } export function publishThreadStateDetails(click: ThreadStateDetails) { globals.threadStateDetails = click; globals.publishRedraw(); } export function publishConnectedFlows(connectedFlows: Flow[]) { globals.connectedFlows = connectedFlows; // If a chrome slice is selected and we have any flows in connectedFlows // we will find the flows on the right and left of that slice to set a default // focus. In all other cases the focusedFlowId(Left|Right) will be set to -1. globals.dispatch(Actions.setHighlightedFlowLeftId({flowId: -1})); globals.dispatch(Actions.setHighlightedFlowRightId({flowId: -1})); if (globals.state.currentSelection?.kind === 'CHROME_SLICE') { const sliceId = globals.state.currentSelection.id; for (const flow of globals.connectedFlows) { if (flow.begin.sliceId === sliceId) { globals.dispatch(Actions.setHighlightedFlowRightId({flowId: flow.id})); } if (flow.end.sliceId === sliceId) { globals.dispatch(Actions.setHighlightedFlowLeftId({flowId: flow.id})); } } } globals.publishRedraw(); }