| // Copyright (C) 2023 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 type {Trace} from '../../public/trace'; | |
| import type {PerfettoPlugin} from '../../public/plugin'; | |
| import {addDebugSliceTrack} from '../../components/tracks/debug_tracks'; | |
| export default class implements PerfettoPlugin { | |
| static readonly id = 'com.android.AndroidNetwork'; | |
| // Adds a debug track using the provided query and given columns. The columns | |
| // must be start with ts, dur, and a name column. The name column and all | |
| // following columns are shown as arguments in slice details. | |
| async addSimpleTrack( | |
| ctx: Trace, | |
| trackName: string, | |
| tableOrQuery: string, | |
| columns: string[], | |
| ): Promise<void> { | |
| await addDebugSliceTrack({ | |
| trace: ctx, | |
| data: { | |
| sqlSource: `SELECT ${columns.join(',')} FROM ${tableOrQuery}`, | |
| columns: columns, | |
| }, | |
| title: trackName, | |
| columns: {ts: columns[0], dur: columns[1], name: columns[2]}, | |
| rawColumns: columns.slice(2), | |
| }); | |
| } | |
| async onTraceLoad(ctx: Trace): Promise<void> { | |
| ctx.commands.registerCommand({ | |
| id: 'com.android.AddBatteryEventsTrack', | |
| name: 'Add track: battery events', | |
| callback: async (trackNameArg) => { | |
| const trackName = | |
| typeof trackNameArg === 'string' | |
| ? trackNameArg | |
| : await ctx.omnibox.prompt('Battery Track'); | |
| if (!trackName) return; | |
| await ctx.engine.query(`SELECT IMPORT('android.battery_stats');`); | |
| await this.addSimpleTrack( | |
| ctx, | |
| trackName, | |
| `(SELECT * | |
| FROM android_battery_stats_event_slices | |
| WHERE track_name = "${trackName}")`, | |
| ['ts', 'dur', 'str_value', 'int_value'], | |
| ); | |
| }, | |
| }); | |
| ctx.commands.registerCommand({ | |
| id: 'com.android.AddNetworkActivityTrack', | |
| name: 'Add track: network activity', | |
| callback: async (groupByArg, filterArg, trackNameArg) => { | |
| const groupby = | |
| typeof groupByArg === 'string' | |
| ? groupByArg | |
| : await ctx.omnibox.prompt('Group by', 'package_name'); | |
| if (groupby === undefined) return; | |
| const filter = | |
| typeof filterArg === 'string' | |
| ? filterArg | |
| : await ctx.omnibox.prompt('Filter', 'TRUE'); | |
| if (filter === undefined) return; | |
| const trackName = | |
| typeof trackNameArg === 'string' ? trackNameArg : 'Network Activity'; | |
| const suffix = new Date().getTime(); | |
| await ctx.engine.query(` | |
| SELECT RUN_METRIC( | |
| 'android/network_activity_template.sql', | |
| 'view_name', 'android_network_activity_${suffix}', | |
| 'group_by', '${groupby}', | |
| 'filter', '${filter}', | |
| 'idle_ns', '10e9', | |
| 'quant_ns', '3e9' | |
| ); | |
| `); | |
| // The first group column is used for the slice name. | |
| const groupCols = groupby.replaceAll(' ', '').split(','); | |
| await this.addSimpleTrack( | |
| ctx, | |
| trackName, | |
| `android_network_activity_${suffix}`, | |
| ['ts', 'dur', ...groupCols, 'packet_length', 'packet_count'], | |
| ); | |
| }, | |
| }); | |
| } | |
| } |