xref: /aosp_15_r20/external/perfetto/tools/java_heap_dump (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
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