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 m from 'mithril'; 16import {copyToClipboard} from '../../base/clipboard'; 17import {Icons} from '../../base/semantic_icons'; 18import {exists} from '../../base/utils'; 19import {addEphemeralTab} from '../details/add_ephemeral_tab'; 20import {Upid} from '../sql_utils/core_types'; 21import { 22 getProcessInfo, 23 getProcessName, 24 ProcessInfo, 25} from '../sql_utils/process'; 26import {Anchor} from '../../widgets/anchor'; 27import {MenuItem, PopupMenu2} from '../../widgets/menu'; 28import {ProcessDetailsTab} from '../details/process_details_tab'; 29import { 30 createSqlIdRefRenderer, 31 sqlIdRegistry, 32} from '../widgets/sql/details/sql_ref_renderer_registry'; 33import {asUpid} from '../sql_utils/core_types'; 34import {AppImpl} from '../../core/app_impl'; 35 36export function showProcessDetailsMenuItem( 37 upid: Upid, 38 pid?: number, 39): m.Children { 40 return m(MenuItem, { 41 icon: Icons.ExternalLink, 42 label: 'Show process details', 43 onclick: () => { 44 // TODO(primiano): `trace` should be injected, but doing so would require 45 // an invasive refactoring of most classes in frontend/widgets/sql/*. 46 const trace = AppImpl.instance.trace; 47 if (trace === undefined) return; 48 addEphemeralTab( 49 'processDetails', 50 new ProcessDetailsTab({ 51 trace, 52 upid, 53 pid, 54 }), 55 ); 56 }, 57 }); 58} 59 60export function processRefMenuItems(info: { 61 upid: Upid; 62 name?: string; 63 pid?: number; 64}): m.Children { 65 // We capture a copy to be able to pass it across async boundary to `onclick`. 66 const name = info.name; 67 return [ 68 exists(name) && 69 m(MenuItem, { 70 icon: Icons.Copy, 71 label: 'Copy process name', 72 onclick: () => copyToClipboard(name), 73 }), 74 exists(info.pid) && 75 m(MenuItem, { 76 icon: Icons.Copy, 77 label: 'Copy pid', 78 onclick: () => copyToClipboard(`${info.pid}`), 79 }), 80 m(MenuItem, { 81 icon: Icons.Copy, 82 label: 'Copy upid', 83 onclick: () => copyToClipboard(`${info.upid}`), 84 }), 85 showProcessDetailsMenuItem(info.upid, info.pid), 86 ]; 87} 88 89export function renderProcessRef(info: ProcessInfo): m.Children { 90 return m( 91 PopupMenu2, 92 { 93 trigger: m(Anchor, getProcessName(info)), 94 }, 95 processRefMenuItems(info), 96 ); 97} 98 99sqlIdRegistry['process'] = createSqlIdRefRenderer<ProcessInfo>( 100 async (engine, id) => await getProcessInfo(engine, asUpid(Number(id))), 101 (data: ProcessInfo) => ({ 102 value: renderProcessRef(data), 103 }), 104); 105