xref: /aosp_15_r20/external/perfetto/ui/src/plugins/dev.perfetto.AndroidStartup/index.ts (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
1// Copyright (C) 2024 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 {LONG} from '../../trace_processor/query_result';
16import {Trace} from '../../public/trace';
17import {PerfettoPlugin} from '../../public/plugin';
18import {createQuerySliceTrack} from '../../components/tracks/query_slice_track';
19import {TrackNode} from '../../public/workspace';
20import {optimizationsTrack} from './optimizations';
21
22export default class implements PerfettoPlugin {
23  static readonly id = 'dev.perfetto.AndroidStartup';
24
25  async onTraceLoad(ctx: Trace): Promise<void> {
26    const e = ctx.engine;
27    await e.query(`
28          include perfetto module android.startup.startups;
29          include perfetto module android.startup.startup_breakdowns;
30         `);
31
32    const cnt = await e.query('select count() cnt from android_startups');
33    if (cnt.firstRow({cnt: LONG}).cnt === 0n) {
34      return;
35    }
36
37    const trackSource = `
38          SELECT l.ts AS ts, l.dur AS dur, l.package AS name
39          FROM android_startups l
40    `;
41    const trackBreakdownSource = `
42        SELECT
43          ts,
44          dur,
45          reason AS name
46          FROM android_startup_opinionated_breakdown
47    `;
48
49    const trackNode = await this.loadStartupTrack(
50      ctx,
51      trackSource,
52      `/android_startups`,
53      'Android App Startups',
54    );
55    const trackBreakdownNode = await this.loadStartupTrack(
56      ctx,
57      trackBreakdownSource,
58      `/android_startups_breakdown`,
59      'Android App Startups Breakdown',
60    );
61    const optimizations = await optimizationsTrack(ctx);
62    ctx.workspace.addChildInOrder(trackNode);
63    trackNode.addChildLast(trackBreakdownNode);
64    if (!!optimizations) {
65      trackNode.addChildLast(optimizations);
66    }
67  }
68
69  private async loadStartupTrack(
70    ctx: Trace,
71    sqlSource: string,
72    uri: string,
73    title: string,
74  ): Promise<TrackNode> {
75    const track = await createQuerySliceTrack({
76      trace: ctx,
77      uri,
78      data: {
79        sqlSource,
80        columns: ['ts', 'dur', 'name'],
81      },
82    });
83    ctx.tracks.registerTrack({
84      uri,
85      title,
86      track,
87    });
88    // Needs a sort order lower than 'Ftrace Events' so that it is prioritized in the UI.
89    return new TrackNode({title, uri, sortOrder: -6});
90  }
91}
92