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 { 16 expandProcessName, 17 BlockingCallMetricData, 18 MetricHandler, 19} from './metricUtils'; 20import {Trace} from '../../../public/trace'; 21import {addJankCUJDebugTrack} from '../../dev.perfetto.AndroidCujs'; 22import {addDebugSliceTrack} from '../../../components/tracks/debug_tracks'; 23 24class BlockingCallMetricHandler implements MetricHandler { 25 /** 26 * Match metric key & return parsed data if successful. 27 * 28 * @param {string} metricKey The metric key to match. 29 * @returns {BlockingCallMetricData | undefined} Parsed data or undefined if no match. 30 */ 31 public match(metricKey: string): BlockingCallMetricData | undefined { 32 const matcher = 33 /perfetto_android_blocking_call-cuj-name-(?<process>.*)-name-(?<cujName>.*)-blocking_calls-name-(?<blockingCallName>([^\-]*))-(?<aggregation>.*)/; 34 const match = matcher.exec(metricKey); 35 if (!match?.groups) { 36 return undefined; 37 } 38 const metricData: BlockingCallMetricData = { 39 process: expandProcessName(match.groups.process), 40 cujName: match.groups.cujName, 41 blockingCallName: match.groups.blockingCallName, 42 aggregation: match.groups.aggregation, 43 }; 44 return metricData; 45 } 46 47 /** 48 * Adds the debug tracks for Blocking Call metrics 49 * 50 * @param {BlockingCallMetricData} metricData Parsed metric data for the cuj scoped jank 51 * @param {Trace} ctx PluginContextTrace for trace related properties and methods 52 * @returns {void} Adds one track for Jank CUJ slice and one for Janky CUJ frames 53 */ 54 public addMetricTrack(metricData: BlockingCallMetricData, ctx: Trace): void { 55 this.pinSingleCuj(ctx, metricData); 56 const config = this.blockingCallTrackConfig(metricData); 57 addDebugSliceTrack({trace: ctx, ...config}); 58 } 59 60 private pinSingleCuj(ctx: Trace, metricData: BlockingCallMetricData) { 61 const trackName = `Jank CUJ: ${metricData.cujName}`; 62 addJankCUJDebugTrack(ctx, trackName, metricData.cujName); 63 } 64 65 private blockingCallTrackConfig(metricData: BlockingCallMetricData) { 66 const cuj = metricData.cujName; 67 const processName = metricData.process; 68 const blockingCallName = metricData.blockingCallName; 69 70 // TODO: b/296349525 - Migrate jank tables from run metrics to stdlib 71 const blockingCallDuringCujQuery = ` 72 SELECT name, ts, dur 73 FROM main_thread_slices_scoped_to_cujs 74 WHERE process_name = "${processName}" 75 AND cuj_name = "${cuj}" 76 AND name = "${blockingCallName}" 77 `; 78 79 const trackName = 'Blocking calls in ' + processName; 80 return { 81 data: { 82 sqlSource: blockingCallDuringCujQuery, 83 columns: ['name', 'ts', 'dur'], 84 }, 85 columns: {ts: 'ts', dur: 'dur', name: 'name'}, 86 argColumns: ['name', 'ts', 'dur'], 87 trackName, 88 }; 89 } 90} 91 92export const pinBlockingCallHandlerInstance = new BlockingCallMetricHandler(); 93