1*795d594fSAndroid Build Coastguard Worker#! /usr/bin/env python3 2*795d594fSAndroid Build Coastguard Worker# 3*795d594fSAndroid Build Coastguard Worker# Copyright 2023, The Android Open Source Project 4*795d594fSAndroid Build Coastguard Worker# 5*795d594fSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License"); 6*795d594fSAndroid Build Coastguard Worker# you may not use this file except in compliance with the License. 7*795d594fSAndroid Build Coastguard Worker# You may obtain a copy of the License at 8*795d594fSAndroid Build Coastguard Worker# 9*795d594fSAndroid Build Coastguard Worker# http://www.apache.org/licenses/LICENSE-2.0 10*795d594fSAndroid Build Coastguard Worker# 11*795d594fSAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software 12*795d594fSAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS, 13*795d594fSAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14*795d594fSAndroid Build Coastguard Worker# See the License for the specific language governing permissions and 15*795d594fSAndroid Build Coastguard Worker# limitations under the License. 16*795d594fSAndroid Build Coastguard Worker 17*795d594fSAndroid Build Coastguard Workerimport argparse 18*795d594fSAndroid Build Coastguard Workerfrom collections import namedtuple 19*795d594fSAndroid Build Coastguard Workerimport subprocess 20*795d594fSAndroid Build Coastguard Worker 21*795d594fSAndroid Build Coastguard Workertry: 22*795d594fSAndroid Build Coastguard Worker from tqdm import tqdm 23*795d594fSAndroid Build Coastguard Workerexcept: 24*795d594fSAndroid Build Coastguard Worker 25*795d594fSAndroid Build Coastguard Worker def tqdm(x): 26*795d594fSAndroid Build Coastguard Worker return x 27*795d594fSAndroid Build Coastguard Worker 28*795d594fSAndroid Build Coastguard Worker 29*795d594fSAndroid Build Coastguard WorkerProcEntry = namedtuple('ProcEntry', 'pid, ppid, cmd, name, etc_args') 30*795d594fSAndroid Build Coastguard Worker 31*795d594fSAndroid Build Coastguard Worker 32*795d594fSAndroid Build Coastguard Workerdef get_mem_stats( 33*795d594fSAndroid Build Coastguard Worker zygote_pid, 34*795d594fSAndroid Build Coastguard Worker target_pid, 35*795d594fSAndroid Build Coastguard Worker target_name, 36*795d594fSAndroid Build Coastguard Worker imgdiag_path, 37*795d594fSAndroid Build Coastguard Worker boot_image, 38*795d594fSAndroid Build Coastguard Worker device_out_dir, 39*795d594fSAndroid Build Coastguard Worker host_out_dir, 40*795d594fSAndroid Build Coastguard Worker): 41*795d594fSAndroid Build Coastguard Worker imgdiag_output_path = ( 42*795d594fSAndroid Build Coastguard Worker f'{device_out_dir}/imgdiag_{target_name}_{target_pid}.txt' 43*795d594fSAndroid Build Coastguard Worker ) 44*795d594fSAndroid Build Coastguard Worker cmd_collect = ( 45*795d594fSAndroid Build Coastguard Worker 'adb shell ' 46*795d594fSAndroid Build Coastguard Worker f'"{imgdiag_path} --zygote-diff-pid={zygote_pid} --image-diff-pid={target_pid} ' 47*795d594fSAndroid Build Coastguard Worker f'--output={imgdiag_output_path} --boot-image={boot_image} --dump-dirty-objects"' 48*795d594fSAndroid Build Coastguard Worker ) 49*795d594fSAndroid Build Coastguard Worker 50*795d594fSAndroid Build Coastguard Worker try: 51*795d594fSAndroid Build Coastguard Worker subprocess.run(cmd_collect, shell=True, check=True) 52*795d594fSAndroid Build Coastguard Worker except: 53*795d594fSAndroid Build Coastguard Worker print('imgdiag call failed on:', target_pid, target_name) 54*795d594fSAndroid Build Coastguard Worker return 55*795d594fSAndroid Build Coastguard Worker 56*795d594fSAndroid Build Coastguard Worker cmd_pull = f'adb pull {imgdiag_output_path} {host_out_dir}' 57*795d594fSAndroid Build Coastguard Worker subprocess.run(cmd_pull, shell=True, check=True, capture_output=True) 58*795d594fSAndroid Build Coastguard Worker 59*795d594fSAndroid Build Coastguard Worker 60*795d594fSAndroid Build Coastguard Workerdef main(): 61*795d594fSAndroid Build Coastguard Worker parser = argparse.ArgumentParser( 62*795d594fSAndroid Build Coastguard Worker description=( 63*795d594fSAndroid Build Coastguard Worker 'Run imgdiag on selected processes and pull results from the device.' 64*795d594fSAndroid Build Coastguard Worker ), 65*795d594fSAndroid Build Coastguard Worker formatter_class=argparse.ArgumentDefaultsHelpFormatter, 66*795d594fSAndroid Build Coastguard Worker ) 67*795d594fSAndroid Build Coastguard Worker parser.add_argument( 68*795d594fSAndroid Build Coastguard Worker 'process_names', 69*795d594fSAndroid Build Coastguard Worker nargs='*', 70*795d594fSAndroid Build Coastguard Worker help='Process names to use. If none - dump all zygote children.', 71*795d594fSAndroid Build Coastguard Worker ) 72*795d594fSAndroid Build Coastguard Worker parser.add_argument( 73*795d594fSAndroid Build Coastguard Worker '--boot-image', 74*795d594fSAndroid Build Coastguard Worker dest='boot_image', 75*795d594fSAndroid Build Coastguard Worker default='/data/misc/apexdata/com.android.art/dalvik-cache/boot.art', 76*795d594fSAndroid Build Coastguard Worker help='Path to boot.art', 77*795d594fSAndroid Build Coastguard Worker ) 78*795d594fSAndroid Build Coastguard Worker parser.add_argument( 79*795d594fSAndroid Build Coastguard Worker '--zygote', 80*795d594fSAndroid Build Coastguard Worker default='zygote64', 81*795d594fSAndroid Build Coastguard Worker help='Zygote process name', 82*795d594fSAndroid Build Coastguard Worker ) 83*795d594fSAndroid Build Coastguard Worker parser.add_argument( 84*795d594fSAndroid Build Coastguard Worker '--imgdiag', 85*795d594fSAndroid Build Coastguard Worker default='/apex/com.android.art/bin/imgdiag64', 86*795d594fSAndroid Build Coastguard Worker help='Path to imgdiag binary.', 87*795d594fSAndroid Build Coastguard Worker ) 88*795d594fSAndroid Build Coastguard Worker parser.add_argument( 89*795d594fSAndroid Build Coastguard Worker '--device-out-dir', 90*795d594fSAndroid Build Coastguard Worker default='/data/local/tmp/imgdiag_out', 91*795d594fSAndroid Build Coastguard Worker help='Directory for imgdiag output files on the device.', 92*795d594fSAndroid Build Coastguard Worker ) 93*795d594fSAndroid Build Coastguard Worker parser.add_argument( 94*795d594fSAndroid Build Coastguard Worker '--host-out-dir', 95*795d594fSAndroid Build Coastguard Worker default='./', 96*795d594fSAndroid Build Coastguard Worker help='Directory for imgdiag output files on the host.', 97*795d594fSAndroid Build Coastguard Worker ) 98*795d594fSAndroid Build Coastguard Worker 99*795d594fSAndroid Build Coastguard Worker args = parser.parse_args() 100*795d594fSAndroid Build Coastguard Worker 101*795d594fSAndroid Build Coastguard Worker res = subprocess.run( 102*795d594fSAndroid Build Coastguard Worker args='adb shell ps -o pid:1,ppid:1,cmd:1,args:1', 103*795d594fSAndroid Build Coastguard Worker capture_output=True, 104*795d594fSAndroid Build Coastguard Worker shell=True, 105*795d594fSAndroid Build Coastguard Worker check=True, 106*795d594fSAndroid Build Coastguard Worker text=True, 107*795d594fSAndroid Build Coastguard Worker ) 108*795d594fSAndroid Build Coastguard Worker 109*795d594fSAndroid Build Coastguard Worker proc_entries = [] 110*795d594fSAndroid Build Coastguard Worker for line in res.stdout.splitlines()[1:]: # skip header 111*795d594fSAndroid Build Coastguard Worker pid, ppid, cmd, name, *etc_args = line.split(' ') 112*795d594fSAndroid Build Coastguard Worker entry = ProcEntry(int(pid), int(ppid), cmd, name, etc_args) 113*795d594fSAndroid Build Coastguard Worker proc_entries.append(entry) 114*795d594fSAndroid Build Coastguard Worker 115*795d594fSAndroid Build Coastguard Worker zygote_entry = next(e for e in proc_entries if e.name == args.zygote) 116*795d594fSAndroid Build Coastguard Worker zygote_children = [e for e in proc_entries if e.ppid == zygote_entry.pid] 117*795d594fSAndroid Build Coastguard Worker 118*795d594fSAndroid Build Coastguard Worker if args.process_names: 119*795d594fSAndroid Build Coastguard Worker zygote_children = [e for e in proc_entries if e.name in args.process_names] 120*795d594fSAndroid Build Coastguard Worker 121*795d594fSAndroid Build Coastguard Worker print('\n'.join(str(e.pid) + ' ' + e.name for e in zygote_children)) 122*795d594fSAndroid Build Coastguard Worker 123*795d594fSAndroid Build Coastguard Worker subprocess.run( 124*795d594fSAndroid Build Coastguard Worker args=f'adb shell "mkdir -p {args.device_out_dir}"', check=True, shell=True 125*795d594fSAndroid Build Coastguard Worker ) 126*795d594fSAndroid Build Coastguard Worker subprocess.run(args=f'mkdir -p {args.host_out_dir}', check=True, shell=True) 127*795d594fSAndroid Build Coastguard Worker 128*795d594fSAndroid Build Coastguard Worker for entry in tqdm(zygote_children): 129*795d594fSAndroid Build Coastguard Worker get_mem_stats( 130*795d594fSAndroid Build Coastguard Worker zygote_pid=entry.ppid, 131*795d594fSAndroid Build Coastguard Worker target_pid=entry.pid, 132*795d594fSAndroid Build Coastguard Worker target_name=entry.name, 133*795d594fSAndroid Build Coastguard Worker imgdiag_path=args.imgdiag, 134*795d594fSAndroid Build Coastguard Worker boot_image=args.boot_image, 135*795d594fSAndroid Build Coastguard Worker device_out_dir=args.device_out_dir, 136*795d594fSAndroid Build Coastguard Worker host_out_dir=args.host_out_dir, 137*795d594fSAndroid Build Coastguard Worker ) 138*795d594fSAndroid Build Coastguard Worker 139*795d594fSAndroid Build Coastguard Worker 140*795d594fSAndroid Build Coastguard Workerif __name__ == '__main__': 141*795d594fSAndroid Build Coastguard Worker main() 142