xref: /aosp_15_r20/external/perfetto/ui/src/plugins/dev.perfetto.AndroidNetwork/index.ts (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
1// Copyright (C) 2023 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 {Trace} from '../../public/trace';
16import {PerfettoPlugin} from '../../public/plugin';
17import {addDebugSliceTrack} from '../../components/tracks/debug_tracks';
18
19export default class implements PerfettoPlugin {
20  static readonly id = 'dev.perfetto.AndroidNetwork';
21  // Adds a debug track using the provided query and given columns. The columns
22  // must be start with ts, dur, and a name column. The name column and all
23  // following columns are shown as arguments in slice details.
24  async addSimpleTrack(
25    ctx: Trace,
26    trackName: string,
27    tableOrQuery: string,
28    columns: string[],
29  ): Promise<void> {
30    await addDebugSliceTrack({
31      trace: ctx,
32      data: {
33        sqlSource: `SELECT ${columns.join(',')} FROM ${tableOrQuery}`,
34        columns: columns,
35      },
36      title: trackName,
37      columns: {ts: columns[0], dur: columns[1], name: columns[2]},
38      argColumns: columns.slice(2),
39    });
40  }
41
42  async onTraceLoad(ctx: Trace): Promise<void> {
43    ctx.commands.registerCommand({
44      id: 'dev.perfetto.AndroidNetwork#batteryEvents',
45      name: 'Add track: battery events',
46      callback: async (track) => {
47        if (track === undefined) {
48          track = prompt('Battery Track', '');
49          if (track === null) return;
50        }
51
52        await ctx.engine.query(`SELECT IMPORT('android.battery_stats');`);
53        await this.addSimpleTrack(
54          ctx,
55          track,
56          `(SELECT *
57            FROM android_battery_stats_event_slices
58            WHERE track_name = "${track}")`,
59          ['ts', 'dur', 'str_value', 'int_value'],
60        );
61      },
62    });
63
64    ctx.commands.registerCommand({
65      id: 'dev.perfetto.AndroidNetwork#activityTrack',
66      name: 'Add track: network activity',
67      callback: async (groupby, filter, trackName) => {
68        if (groupby === undefined) {
69          groupby = prompt('Group by', 'package_name');
70          if (groupby === null) return;
71        }
72
73        if (filter === undefined) {
74          filter = prompt('Filter', 'TRUE');
75          if (filter === null) return;
76        }
77
78        const suffix = new Date().getTime();
79        await ctx.engine.query(`
80          SELECT RUN_METRIC(
81            'android/network_activity_template.sql',
82            'view_name', 'android_network_activity_${suffix}',
83            'group_by',  '${groupby}',
84            'filter',    '${filter}',
85            'idle_ns',   '10e9',
86            'quant_ns',  '3e9'
87          );
88        `);
89
90        // The first group column is used for the slice name.
91        const groupCols = groupby.replaceAll(' ', '').split(',');
92        await this.addSimpleTrack(
93          ctx,
94          trackName ?? 'Network Activity',
95          `android_network_activity_${suffix}`,
96          ['ts', 'dur', ...groupCols, 'packet_length', 'packet_count'],
97        );
98      },
99    });
100  }
101}
102