xref: /aosp_15_r20/external/perfetto/ui/src/plugins/dev.perfetto.AndroidLog/index.ts (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
1// Copyright (C) 2021 The Android Open Source Project
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//      http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15import m from 'mithril';
16import {LogFilteringCriteria, LogPanel} from './logs_panel';
17import {ANDROID_LOGS_TRACK_KIND} from '../../public/track_kinds';
18import {Trace} from '../../public/trace';
19import {PerfettoPlugin} from '../../public/plugin';
20import {NUM} from '../../trace_processor/query_result';
21import {AndroidLogTrack} from './logs_track';
22import {exists} from '../../base/utils';
23import {TrackNode} from '../../public/workspace';
24
25const VERSION = 1;
26
27const DEFAULT_STATE: AndroidLogPluginState = {
28  version: VERSION,
29  filter: {
30    // The first two log priorities are ignored.
31    minimumLevel: 2,
32    tags: [],
33    textEntry: '',
34    hideNonMatching: true,
35  },
36};
37
38interface AndroidLogPluginState {
39  version: number;
40  filter: LogFilteringCriteria;
41}
42
43export default class implements PerfettoPlugin {
44  static readonly id = 'dev.perfetto.AndroidLog';
45  async onTraceLoad(ctx: Trace): Promise<void> {
46    const store = ctx.mountStore<AndroidLogPluginState>((init) => {
47      return exists(init) && (init as {version: unknown}).version === VERSION
48        ? (init as AndroidLogPluginState)
49        : DEFAULT_STATE;
50    });
51
52    const result = await ctx.engine.query(
53      `select count(1) as cnt from android_logs`,
54    );
55    const logCount = result.firstRow({cnt: NUM}).cnt;
56    const uri = 'perfetto.AndroidLog';
57    const title = 'Android logs';
58    if (logCount > 0) {
59      ctx.tracks.registerTrack({
60        uri,
61        title,
62        tags: {kind: ANDROID_LOGS_TRACK_KIND},
63        track: new AndroidLogTrack(ctx.engine),
64      });
65      const track = new TrackNode({title, uri});
66      ctx.workspace.addChildInOrder(track);
67    }
68
69    const androidLogsTabUri = 'perfetto.AndroidLog#tab';
70
71    // Eternal tabs should always be available even if there is nothing to show
72    const filterStore = store.createSubStore(
73      ['filter'],
74      (x) => x as LogFilteringCriteria,
75    );
76
77    ctx.tabs.registerTab({
78      isEphemeral: false,
79      uri: androidLogsTabUri,
80      content: {
81        render: () => m(LogPanel, {filterStore: filterStore, trace: ctx}),
82        getTitle: () => 'Android Logs',
83      },
84    });
85
86    if (logCount > 0) {
87      ctx.tabs.addDefaultTab(androidLogsTabUri);
88    }
89
90    ctx.commands.registerCommand({
91      id: 'perfetto.AndroidLog#ShowLogsTab',
92      name: 'Show android logs tab',
93      callback: () => {
94        ctx.tabs.showTab(androidLogsTabUri);
95      },
96    });
97  }
98}
99