1*6dbdd20aSAndroid Build Coastguard Worker#!/usr/bin/env python3 2*6dbdd20aSAndroid Build Coastguard Worker 3*6dbdd20aSAndroid Build Coastguard Worker# Copyright (C) 2020 The Android Open Source Project 4*6dbdd20aSAndroid Build Coastguard Worker# 5*6dbdd20aSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License"); 6*6dbdd20aSAndroid Build Coastguard Worker# you may not use this file except in compliance with the License. 7*6dbdd20aSAndroid Build Coastguard Worker# You may obtain a copy of the License at 8*6dbdd20aSAndroid Build Coastguard Worker# 9*6dbdd20aSAndroid Build Coastguard Worker# http://www.apache.org/licenses/LICENSE-2.0 10*6dbdd20aSAndroid Build Coastguard Worker# 11*6dbdd20aSAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software 12*6dbdd20aSAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS, 13*6dbdd20aSAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14*6dbdd20aSAndroid Build Coastguard Worker# See the License for the specific language governing permissions and 15*6dbdd20aSAndroid Build Coastguard Worker# limitations under the License. 16*6dbdd20aSAndroid Build Coastguard Worker 17*6dbdd20aSAndroid Build Coastguard Workerfrom __future__ import absolute_import 18*6dbdd20aSAndroid Build Coastguard Workerfrom __future__ import division 19*6dbdd20aSAndroid Build Coastguard Workerfrom __future__ import print_function 20*6dbdd20aSAndroid Build Coastguard Worker 21*6dbdd20aSAndroid Build Coastguard Workerimport argparse 22*6dbdd20aSAndroid Build Coastguard Workerimport os 23*6dbdd20aSAndroid Build Coastguard Workerimport subprocess 24*6dbdd20aSAndroid Build Coastguard Workerimport sys 25*6dbdd20aSAndroid Build Coastguard Workerimport tempfile 26*6dbdd20aSAndroid Build Coastguard Workerimport time 27*6dbdd20aSAndroid Build Coastguard Workerimport uuid 28*6dbdd20aSAndroid Build Coastguard Worker 29*6dbdd20aSAndroid Build Coastguard WorkerNULL = open(os.devnull) 30*6dbdd20aSAndroid Build Coastguard Worker 31*6dbdd20aSAndroid Build Coastguard WorkerPACKAGES_LIST_CFG = '''data_sources { 32*6dbdd20aSAndroid Build Coastguard Worker config { 33*6dbdd20aSAndroid Build Coastguard Worker name: "android.packages_list" 34*6dbdd20aSAndroid Build Coastguard Worker } 35*6dbdd20aSAndroid Build Coastguard Worker} 36*6dbdd20aSAndroid Build Coastguard Worker''' 37*6dbdd20aSAndroid Build Coastguard Worker 38*6dbdd20aSAndroid Build Coastguard WorkerCFG_INDENT = ' ' 39*6dbdd20aSAndroid Build Coastguard WorkerCFG = '''buffers {{ 40*6dbdd20aSAndroid Build Coastguard Worker size_kb: {size_kb} 41*6dbdd20aSAndroid Build Coastguard Worker fill_policy: DISCARD 42*6dbdd20aSAndroid Build Coastguard Worker}} 43*6dbdd20aSAndroid Build Coastguard Worker 44*6dbdd20aSAndroid Build Coastguard Workerdata_sources {{ 45*6dbdd20aSAndroid Build Coastguard Worker config {{ 46*6dbdd20aSAndroid Build Coastguard Worker name: "android.java_hprof" 47*6dbdd20aSAndroid Build Coastguard Worker java_hprof_config {{ 48*6dbdd20aSAndroid Build Coastguard Worker{target_cfg} 49*6dbdd20aSAndroid Build Coastguard Worker{continuous_dump_config} 50*6dbdd20aSAndroid Build Coastguard Worker }} 51*6dbdd20aSAndroid Build Coastguard Worker }} 52*6dbdd20aSAndroid Build Coastguard Worker}} 53*6dbdd20aSAndroid Build Coastguard Worker 54*6dbdd20aSAndroid Build Coastguard Workerdata_source_stop_timeout_ms: {data_source_stop_timeout_ms} 55*6dbdd20aSAndroid Build Coastguard Workerduration_ms: {duration_ms} 56*6dbdd20aSAndroid Build Coastguard Worker''' 57*6dbdd20aSAndroid Build Coastguard Worker 58*6dbdd20aSAndroid Build Coastguard WorkerOOM_CFG = '''buffers: {{ 59*6dbdd20aSAndroid Build Coastguard Worker size_kb: {size_kb} 60*6dbdd20aSAndroid Build Coastguard Worker fill_policy: DISCARD 61*6dbdd20aSAndroid Build Coastguard Worker}} 62*6dbdd20aSAndroid Build Coastguard Worker 63*6dbdd20aSAndroid Build Coastguard Workerdata_sources: {{ 64*6dbdd20aSAndroid Build Coastguard Worker config {{ 65*6dbdd20aSAndroid Build Coastguard Worker name: "android.java_hprof.oom" 66*6dbdd20aSAndroid Build Coastguard Worker java_hprof_config {{ 67*6dbdd20aSAndroid Build Coastguard Worker{process_cfg} 68*6dbdd20aSAndroid Build Coastguard Worker }} 69*6dbdd20aSAndroid Build Coastguard Worker }} 70*6dbdd20aSAndroid Build Coastguard Worker}} 71*6dbdd20aSAndroid Build Coastguard Worker 72*6dbdd20aSAndroid Build Coastguard Workerdata_source_stop_timeout_ms: 100000 73*6dbdd20aSAndroid Build Coastguard Worker 74*6dbdd20aSAndroid Build Coastguard Workertrigger_config {{ 75*6dbdd20aSAndroid Build Coastguard Worker trigger_mode: START_TRACING 76*6dbdd20aSAndroid Build Coastguard Worker trigger_timeout_ms: {wait_duration_ms} 77*6dbdd20aSAndroid Build Coastguard Worker triggers {{ 78*6dbdd20aSAndroid Build Coastguard Worker name: "com.android.telemetry.art-outofmemory" 79*6dbdd20aSAndroid Build Coastguard Worker stop_delay_ms: 500 80*6dbdd20aSAndroid Build Coastguard Worker }} 81*6dbdd20aSAndroid Build Coastguard Worker}} 82*6dbdd20aSAndroid Build Coastguard Worker''' 83*6dbdd20aSAndroid Build Coastguard Worker 84*6dbdd20aSAndroid Build Coastguard WorkerCONTINUOUS_DUMP = """ 85*6dbdd20aSAndroid Build Coastguard Worker continuous_dump_config {{ 86*6dbdd20aSAndroid Build Coastguard Worker dump_phase_ms: 0 87*6dbdd20aSAndroid Build Coastguard Worker dump_interval_ms: {dump_interval} 88*6dbdd20aSAndroid Build Coastguard Worker }} 89*6dbdd20aSAndroid Build Coastguard Worker""" 90*6dbdd20aSAndroid Build Coastguard Worker 91*6dbdd20aSAndroid Build Coastguard WorkerUUID = str(uuid.uuid4())[-6:] 92*6dbdd20aSAndroid Build Coastguard WorkerPROFILE_PATH = '/data/misc/perfetto-traces/java-profile-' + UUID 93*6dbdd20aSAndroid Build Coastguard Worker 94*6dbdd20aSAndroid Build Coastguard WorkerPERFETTO_CMD = ('CFG=\'{cfg}\'; echo ${{CFG}} | ' 95*6dbdd20aSAndroid Build Coastguard Worker 'perfetto --txt -c - -o ' + PROFILE_PATH + ' -d') 96*6dbdd20aSAndroid Build Coastguard Worker 97*6dbdd20aSAndroid Build Coastguard WorkerSDK = { 98*6dbdd20aSAndroid Build Coastguard Worker 'S': 31, 99*6dbdd20aSAndroid Build Coastguard Worker 'UpsideDownCake': 34, 100*6dbdd20aSAndroid Build Coastguard Worker} 101*6dbdd20aSAndroid Build Coastguard Worker 102*6dbdd20aSAndroid Build Coastguard Worker 103*6dbdd20aSAndroid Build Coastguard Workerdef release_or_newer(release): 104*6dbdd20aSAndroid Build Coastguard Worker sdk = int( 105*6dbdd20aSAndroid Build Coastguard Worker subprocess.check_output( 106*6dbdd20aSAndroid Build Coastguard Worker ['adb', 'shell', 'getprop', 107*6dbdd20aSAndroid Build Coastguard Worker 'ro.system.build.version.sdk']).decode('utf-8').strip()) 108*6dbdd20aSAndroid Build Coastguard Worker if sdk >= SDK[release]: 109*6dbdd20aSAndroid Build Coastguard Worker return True 110*6dbdd20aSAndroid Build Coastguard Worker codename = subprocess.check_output( 111*6dbdd20aSAndroid Build Coastguard Worker ['adb', 'shell', 'getprop', 112*6dbdd20aSAndroid Build Coastguard Worker 'ro.build.version.codename']).decode('utf-8').strip() 113*6dbdd20aSAndroid Build Coastguard Worker return codename == release 114*6dbdd20aSAndroid Build Coastguard Worker 115*6dbdd20aSAndroid Build Coastguard Workerdef convert_size_to_kb(size): 116*6dbdd20aSAndroid Build Coastguard Worker if size.endswith("kb"): 117*6dbdd20aSAndroid Build Coastguard Worker return int(size[:-2]) 118*6dbdd20aSAndroid Build Coastguard Worker elif size.endswith("mb"): 119*6dbdd20aSAndroid Build Coastguard Worker return int(size[:-2]) * 1024 120*6dbdd20aSAndroid Build Coastguard Worker elif size.endswith("gb"): 121*6dbdd20aSAndroid Build Coastguard Worker return int(size[:-2]) * 1024 * 1024 122*6dbdd20aSAndroid Build Coastguard Worker else: 123*6dbdd20aSAndroid Build Coastguard Worker return int(size) 124*6dbdd20aSAndroid Build Coastguard Worker 125*6dbdd20aSAndroid Build Coastguard Workerdef generate_heap_dump_config(args): 126*6dbdd20aSAndroid Build Coastguard Worker fail = False 127*6dbdd20aSAndroid Build Coastguard Worker if args.pid is None and args.name is None: 128*6dbdd20aSAndroid Build Coastguard Worker print("FATAL: Neither PID nor NAME given.", file=sys.stderr) 129*6dbdd20aSAndroid Build Coastguard Worker fail = True 130*6dbdd20aSAndroid Build Coastguard Worker 131*6dbdd20aSAndroid Build Coastguard Worker target_cfg = "" 132*6dbdd20aSAndroid Build Coastguard Worker if args.pid: 133*6dbdd20aSAndroid Build Coastguard Worker for pid in args.pid.split(','): 134*6dbdd20aSAndroid Build Coastguard Worker try: 135*6dbdd20aSAndroid Build Coastguard Worker pid = int(pid) 136*6dbdd20aSAndroid Build Coastguard Worker except ValueError: 137*6dbdd20aSAndroid Build Coastguard Worker print("FATAL: invalid PID %s" % pid, file=sys.stderr) 138*6dbdd20aSAndroid Build Coastguard Worker fail = True 139*6dbdd20aSAndroid Build Coastguard Worker target_cfg += '{}pid: {}\n'.format(CFG_INDENT, pid) 140*6dbdd20aSAndroid Build Coastguard Worker if args.name: 141*6dbdd20aSAndroid Build Coastguard Worker for name in args.name.split(','): 142*6dbdd20aSAndroid Build Coastguard Worker target_cfg += '{}process_cmdline: "{}"\n'.format(CFG_INDENT, name) 143*6dbdd20aSAndroid Build Coastguard Worker if args.dump_smaps: 144*6dbdd20aSAndroid Build Coastguard Worker target_cfg += '{}dump_smaps: true\n'.format(CFG_INDENT) 145*6dbdd20aSAndroid Build Coastguard Worker 146*6dbdd20aSAndroid Build Coastguard Worker if fail: 147*6dbdd20aSAndroid Build Coastguard Worker return None 148*6dbdd20aSAndroid Build Coastguard Worker 149*6dbdd20aSAndroid Build Coastguard Worker continuous_dump_cfg = "" 150*6dbdd20aSAndroid Build Coastguard Worker if args.continuous_dump: 151*6dbdd20aSAndroid Build Coastguard Worker continuous_dump_cfg = CONTINUOUS_DUMP.format( 152*6dbdd20aSAndroid Build Coastguard Worker dump_interval=args.continuous_dump) 153*6dbdd20aSAndroid Build Coastguard Worker 154*6dbdd20aSAndroid Build Coastguard Worker if args.continuous_dump: 155*6dbdd20aSAndroid Build Coastguard Worker # Unlimited trace duration 156*6dbdd20aSAndroid Build Coastguard Worker duration_ms = 0 157*6dbdd20aSAndroid Build Coastguard Worker elif args.stop_when_done: 158*6dbdd20aSAndroid Build Coastguard Worker # Oneshot heapdump and the system supports data_source_stop_timeout_ms, we 159*6dbdd20aSAndroid Build Coastguard Worker # can use a short duration. 160*6dbdd20aSAndroid Build Coastguard Worker duration_ms = 1000 161*6dbdd20aSAndroid Build Coastguard Worker else: 162*6dbdd20aSAndroid Build Coastguard Worker # Oneshot heapdump, but the system doesn't supports 163*6dbdd20aSAndroid Build Coastguard Worker # data_source_stop_timeout_ms, we have to use a longer duration in the hope 164*6dbdd20aSAndroid Build Coastguard Worker # of giving enough time to capture the whole dump. 165*6dbdd20aSAndroid Build Coastguard Worker duration_ms = 20000 166*6dbdd20aSAndroid Build Coastguard Worker 167*6dbdd20aSAndroid Build Coastguard Worker if args.stop_when_done: 168*6dbdd20aSAndroid Build Coastguard Worker data_source_stop_timeout_ms = 100000 169*6dbdd20aSAndroid Build Coastguard Worker else: 170*6dbdd20aSAndroid Build Coastguard Worker data_source_stop_timeout_ms = 0 171*6dbdd20aSAndroid Build Coastguard Worker 172*6dbdd20aSAndroid Build Coastguard Worker return CFG.format( 173*6dbdd20aSAndroid Build Coastguard Worker size_kb=convert_size_to_kb(args.buffer_size), 174*6dbdd20aSAndroid Build Coastguard Worker target_cfg=target_cfg, 175*6dbdd20aSAndroid Build Coastguard Worker continuous_dump_config=continuous_dump_cfg, 176*6dbdd20aSAndroid Build Coastguard Worker duration_ms=duration_ms, 177*6dbdd20aSAndroid Build Coastguard Worker data_source_stop_timeout_ms=data_source_stop_timeout_ms) 178*6dbdd20aSAndroid Build Coastguard Worker 179*6dbdd20aSAndroid Build Coastguard Workerdef generate_oom_config(args): 180*6dbdd20aSAndroid Build Coastguard Worker if not release_or_newer('UpsideDownCake'): 181*6dbdd20aSAndroid Build Coastguard Worker print("FATAL: OOM mode not supported for this android version", 182*6dbdd20aSAndroid Build Coastguard Worker file=sys.stderr) 183*6dbdd20aSAndroid Build Coastguard Worker return None 184*6dbdd20aSAndroid Build Coastguard Worker 185*6dbdd20aSAndroid Build Coastguard Worker if args.pid: 186*6dbdd20aSAndroid Build Coastguard Worker print("FATAL: Specifying pid not supported in OOM mode", 187*6dbdd20aSAndroid Build Coastguard Worker file=sys.stderr) 188*6dbdd20aSAndroid Build Coastguard Worker return None 189*6dbdd20aSAndroid Build Coastguard Worker 190*6dbdd20aSAndroid Build Coastguard Worker if not args.name: 191*6dbdd20aSAndroid Build Coastguard Worker print("FATAL: Must specify process in OOM mode (use --name '*' to match all)", 192*6dbdd20aSAndroid Build Coastguard Worker file=sys.stderr) 193*6dbdd20aSAndroid Build Coastguard Worker return None 194*6dbdd20aSAndroid Build Coastguard Worker 195*6dbdd20aSAndroid Build Coastguard Worker if args.continuous_dump: 196*6dbdd20aSAndroid Build Coastguard Worker print("FATAL: Specifying continuous dump not supported in OOM mode", 197*6dbdd20aSAndroid Build Coastguard Worker file=sys.stderr) 198*6dbdd20aSAndroid Build Coastguard Worker return None 199*6dbdd20aSAndroid Build Coastguard Worker 200*6dbdd20aSAndroid Build Coastguard Worker if args.dump_smaps: 201*6dbdd20aSAndroid Build Coastguard Worker print("FATAL: Dumping smaps not supported in OOM mode", 202*6dbdd20aSAndroid Build Coastguard Worker file=sys.stderr) 203*6dbdd20aSAndroid Build Coastguard Worker return None 204*6dbdd20aSAndroid Build Coastguard Worker 205*6dbdd20aSAndroid Build Coastguard Worker process_cfg = '' 206*6dbdd20aSAndroid Build Coastguard Worker for name in args.name.split(','): 207*6dbdd20aSAndroid Build Coastguard Worker process_cfg += '{}process_cmdline: "{}"\n'.format(CFG_INDENT, name) 208*6dbdd20aSAndroid Build Coastguard Worker 209*6dbdd20aSAndroid Build Coastguard Worker return OOM_CFG.format( 210*6dbdd20aSAndroid Build Coastguard Worker size_kb=convert_size_to_kb(args.buffer_size), 211*6dbdd20aSAndroid Build Coastguard Worker wait_duration_ms=args.oom_wait_seconds * 1000, 212*6dbdd20aSAndroid Build Coastguard Worker process_cfg=process_cfg) 213*6dbdd20aSAndroid Build Coastguard Worker 214*6dbdd20aSAndroid Build Coastguard Worker 215*6dbdd20aSAndroid Build Coastguard Workerdef main(argv): 216*6dbdd20aSAndroid Build Coastguard Worker parser = argparse.ArgumentParser() 217*6dbdd20aSAndroid Build Coastguard Worker parser.add_argument( 218*6dbdd20aSAndroid Build Coastguard Worker "-o", 219*6dbdd20aSAndroid Build Coastguard Worker "--output", 220*6dbdd20aSAndroid Build Coastguard Worker help="Filename to save profile to.", 221*6dbdd20aSAndroid Build Coastguard Worker metavar="FILE", 222*6dbdd20aSAndroid Build Coastguard Worker default=None) 223*6dbdd20aSAndroid Build Coastguard Worker parser.add_argument( 224*6dbdd20aSAndroid Build Coastguard Worker "-p", 225*6dbdd20aSAndroid Build Coastguard Worker "--pid", 226*6dbdd20aSAndroid Build Coastguard Worker help="Comma-separated list of PIDs to " 227*6dbdd20aSAndroid Build Coastguard Worker "profile.", 228*6dbdd20aSAndroid Build Coastguard Worker metavar="PIDS") 229*6dbdd20aSAndroid Build Coastguard Worker parser.add_argument( 230*6dbdd20aSAndroid Build Coastguard Worker "-n", 231*6dbdd20aSAndroid Build Coastguard Worker "--name", 232*6dbdd20aSAndroid Build Coastguard Worker help="Comma-separated list of process " 233*6dbdd20aSAndroid Build Coastguard Worker "names to profile.", 234*6dbdd20aSAndroid Build Coastguard Worker metavar="NAMES") 235*6dbdd20aSAndroid Build Coastguard Worker parser.add_argument( 236*6dbdd20aSAndroid Build Coastguard Worker "-b", 237*6dbdd20aSAndroid Build Coastguard Worker "--buffer-size", 238*6dbdd20aSAndroid Build Coastguard Worker help="Buffer size in memory that store the whole java heap graph. N(kb|mb|gb)", 239*6dbdd20aSAndroid Build Coastguard Worker type=str, 240*6dbdd20aSAndroid Build Coastguard Worker default="256mb") 241*6dbdd20aSAndroid Build Coastguard Worker parser.add_argument( 242*6dbdd20aSAndroid Build Coastguard Worker "-c", 243*6dbdd20aSAndroid Build Coastguard Worker "--continuous-dump", 244*6dbdd20aSAndroid Build Coastguard Worker help="Dump interval in ms. 0 to disable continuous dump. When continuous " 245*6dbdd20aSAndroid Build Coastguard Worker "dump is enabled, use CTRL+C to stop", 246*6dbdd20aSAndroid Build Coastguard Worker type=int, 247*6dbdd20aSAndroid Build Coastguard Worker default=0) 248*6dbdd20aSAndroid Build Coastguard Worker parser.add_argument( 249*6dbdd20aSAndroid Build Coastguard Worker "--no-versions", 250*6dbdd20aSAndroid Build Coastguard Worker action="store_true", 251*6dbdd20aSAndroid Build Coastguard Worker help="Do not get version information about APKs.") 252*6dbdd20aSAndroid Build Coastguard Worker parser.add_argument( 253*6dbdd20aSAndroid Build Coastguard Worker "--dump-smaps", 254*6dbdd20aSAndroid Build Coastguard Worker action="store_true", 255*6dbdd20aSAndroid Build Coastguard Worker help="Get information about /proc/$PID/smaps of target.") 256*6dbdd20aSAndroid Build Coastguard Worker parser.add_argument( 257*6dbdd20aSAndroid Build Coastguard Worker "--print-config", 258*6dbdd20aSAndroid Build Coastguard Worker action="store_true", 259*6dbdd20aSAndroid Build Coastguard Worker help="Print config instead of running. For debugging.") 260*6dbdd20aSAndroid Build Coastguard Worker parser.add_argument( 261*6dbdd20aSAndroid Build Coastguard Worker "--stop-when-done", 262*6dbdd20aSAndroid Build Coastguard Worker action="store_true", 263*6dbdd20aSAndroid Build Coastguard Worker default=None, 264*6dbdd20aSAndroid Build Coastguard Worker help="Use a new method to stop the profile when the dump is done. " 265*6dbdd20aSAndroid Build Coastguard Worker "Previously, we would hardcode a duration. Available and default on S.") 266*6dbdd20aSAndroid Build Coastguard Worker parser.add_argument( 267*6dbdd20aSAndroid Build Coastguard Worker "--no-stop-when-done", 268*6dbdd20aSAndroid Build Coastguard Worker action="store_false", 269*6dbdd20aSAndroid Build Coastguard Worker dest='stop_when_done', 270*6dbdd20aSAndroid Build Coastguard Worker help="Do not use a new method to stop the profile when the dump is done.") 271*6dbdd20aSAndroid Build Coastguard Worker parser.add_argument( 272*6dbdd20aSAndroid Build Coastguard Worker "--wait-for-oom", 273*6dbdd20aSAndroid Build Coastguard Worker action="store_true", 274*6dbdd20aSAndroid Build Coastguard Worker dest='wait_for_oom', 275*6dbdd20aSAndroid Build Coastguard Worker help="Starts a tracing session waiting for an OutOfMemoryError to be " 276*6dbdd20aSAndroid Build Coastguard Worker "thrown. Available on U.") 277*6dbdd20aSAndroid Build Coastguard Worker parser.add_argument( 278*6dbdd20aSAndroid Build Coastguard Worker "--oom-wait-seconds", 279*6dbdd20aSAndroid Build Coastguard Worker type=int, 280*6dbdd20aSAndroid Build Coastguard Worker default=60, 281*6dbdd20aSAndroid Build Coastguard Worker help="Seconds to wait for an OutOfMemoryError to be thrown. " 282*6dbdd20aSAndroid Build Coastguard Worker "Defaults to 60.") 283*6dbdd20aSAndroid Build Coastguard Worker 284*6dbdd20aSAndroid Build Coastguard Worker args = parser.parse_args() 285*6dbdd20aSAndroid Build Coastguard Worker 286*6dbdd20aSAndroid Build Coastguard Worker if args.stop_when_done is None: 287*6dbdd20aSAndroid Build Coastguard Worker args.stop_when_done = release_or_newer('S') 288*6dbdd20aSAndroid Build Coastguard Worker 289*6dbdd20aSAndroid Build Coastguard Worker cfg = None 290*6dbdd20aSAndroid Build Coastguard Worker if args.wait_for_oom: 291*6dbdd20aSAndroid Build Coastguard Worker cfg = generate_oom_config(args) 292*6dbdd20aSAndroid Build Coastguard Worker else: 293*6dbdd20aSAndroid Build Coastguard Worker cfg = generate_heap_dump_config(args) 294*6dbdd20aSAndroid Build Coastguard Worker 295*6dbdd20aSAndroid Build Coastguard Worker if not cfg: 296*6dbdd20aSAndroid Build Coastguard Worker parser.print_help() 297*6dbdd20aSAndroid Build Coastguard Worker return 1 298*6dbdd20aSAndroid Build Coastguard Worker 299*6dbdd20aSAndroid Build Coastguard Worker if not args.no_versions: 300*6dbdd20aSAndroid Build Coastguard Worker cfg += PACKAGES_LIST_CFG 301*6dbdd20aSAndroid Build Coastguard Worker 302*6dbdd20aSAndroid Build Coastguard Worker if args.print_config: 303*6dbdd20aSAndroid Build Coastguard Worker print(cfg) 304*6dbdd20aSAndroid Build Coastguard Worker return 0 305*6dbdd20aSAndroid Build Coastguard Worker 306*6dbdd20aSAndroid Build Coastguard Worker output_file = args.output 307*6dbdd20aSAndroid Build Coastguard Worker if output_file is None: 308*6dbdd20aSAndroid Build Coastguard Worker fd, name = tempfile.mkstemp('profile') 309*6dbdd20aSAndroid Build Coastguard Worker os.close(fd) 310*6dbdd20aSAndroid Build Coastguard Worker output_file = name 311*6dbdd20aSAndroid Build Coastguard Worker 312*6dbdd20aSAndroid Build Coastguard Worker user = subprocess.check_output(['adb', 'shell', 313*6dbdd20aSAndroid Build Coastguard Worker 'whoami']).strip().decode('utf8') 314*6dbdd20aSAndroid Build Coastguard Worker perfetto_pid = subprocess.check_output( 315*6dbdd20aSAndroid Build Coastguard Worker ['adb', 'exec-out', 316*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_CMD.format(cfg=cfg, user=user)]).strip().decode('utf8') 317*6dbdd20aSAndroid Build Coastguard Worker try: 318*6dbdd20aSAndroid Build Coastguard Worker int(perfetto_pid.strip()) 319*6dbdd20aSAndroid Build Coastguard Worker except ValueError: 320*6dbdd20aSAndroid Build Coastguard Worker print("Failed to invoke perfetto: {}".format(perfetto_pid), file=sys.stderr) 321*6dbdd20aSAndroid Build Coastguard Worker return 1 322*6dbdd20aSAndroid Build Coastguard Worker 323*6dbdd20aSAndroid Build Coastguard Worker if args.wait_for_oom: 324*6dbdd20aSAndroid Build Coastguard Worker print("Waiting for OutOfMemoryError") 325*6dbdd20aSAndroid Build Coastguard Worker else: 326*6dbdd20aSAndroid Build Coastguard Worker print("Dumping Java Heap.") 327*6dbdd20aSAndroid Build Coastguard Worker 328*6dbdd20aSAndroid Build Coastguard Worker exists = True 329*6dbdd20aSAndroid Build Coastguard Worker ctrl_c_count = 0 330*6dbdd20aSAndroid Build Coastguard Worker # Wait for perfetto cmd to return. 331*6dbdd20aSAndroid Build Coastguard Worker while exists: 332*6dbdd20aSAndroid Build Coastguard Worker try: 333*6dbdd20aSAndroid Build Coastguard Worker exists = subprocess.call( 334*6dbdd20aSAndroid Build Coastguard Worker ['adb', 'shell', '[ -d /proc/{} ]'.format(perfetto_pid)]) == 0 335*6dbdd20aSAndroid Build Coastguard Worker time.sleep(1) 336*6dbdd20aSAndroid Build Coastguard Worker except KeyboardInterrupt as e: 337*6dbdd20aSAndroid Build Coastguard Worker ctrl_c_count += 1 338*6dbdd20aSAndroid Build Coastguard Worker subprocess.check_call( 339*6dbdd20aSAndroid Build Coastguard Worker ['adb', 'shell', 'kill -TERM {}'.format(perfetto_pid)]) 340*6dbdd20aSAndroid Build Coastguard Worker if ctrl_c_count == 1: 341*6dbdd20aSAndroid Build Coastguard Worker print("Stopping perfetto and waiting for data...") 342*6dbdd20aSAndroid Build Coastguard Worker else: 343*6dbdd20aSAndroid Build Coastguard Worker raise e 344*6dbdd20aSAndroid Build Coastguard Worker 345*6dbdd20aSAndroid Build Coastguard Worker subprocess.check_call(['adb', 'pull', PROFILE_PATH, output_file], stdout=NULL) 346*6dbdd20aSAndroid Build Coastguard Worker 347*6dbdd20aSAndroid Build Coastguard Worker subprocess.check_call(['adb', 'shell', 'rm', '-f', PROFILE_PATH], stdout=NULL) 348*6dbdd20aSAndroid Build Coastguard Worker 349*6dbdd20aSAndroid Build Coastguard Worker print("Wrote profile to {}".format(output_file)) 350*6dbdd20aSAndroid Build Coastguard Worker print("This can be viewed using https://ui.perfetto.dev.") 351*6dbdd20aSAndroid Build Coastguard Worker 352*6dbdd20aSAndroid Build Coastguard Worker 353*6dbdd20aSAndroid Build Coastguard Workerif __name__ == '__main__': 354*6dbdd20aSAndroid Build Coastguard Worker sys.exit(main(sys.argv)) 355