blob: 4918dd5032a9c04f2bbfec133eac520030e68d22 [file] [log] [blame]
Primiano Tuccic2d4c6d2021-01-15 11:37:30 +01001#!/usr/bin/env python3
Primiano Tucci35e311e2021-05-21 20:31:55 +01002# Copyright (C) 2021 The Android Open Source Project
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
Primiano Tuccic2d4c6d2021-01-15 11:37:30 +010015
16import atexit
17import argparse
18import datetime
Primiano Tucci35e311e2021-05-21 20:31:55 +010019import hashlib
Primiano Tuccic2d4c6d2021-01-15 11:37:30 +010020import http.server
21import os
Primiano Tucci59f08d52021-10-19 17:28:36 +010022import re
Primiano Tuccic2d4c6d2021-01-15 11:37:30 +010023import shutil
24import socketserver
25import subprocess
26import sys
Primiano Tucci35e311e2021-05-21 20:31:55 +010027import tempfile
Primiano Tuccic2d4c6d2021-01-15 11:37:30 +010028import time
29import webbrowser
30
31ROOT_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
32
33# This is not required. It's only used as a fallback if no adb is found on the
34# PATH. It's fine if it doesn't exist so this script can be copied elsewhere.
35HERMETIC_ADB_PATH = ROOT_DIR + '/buildtools/android_sdk/platform-tools/adb'
36
Primiano Tucci35e311e2021-05-21 20:31:55 +010037# Translates the Android ro.product.cpu.abi into the GN's target_cpu.
38ABI_TO_ARCH = {
39 'armeabi-v7a': 'arm',
40 'arm64-v8a': 'arm64',
41 'x86': 'x86',
42 'x86_64': 'x64',
43}
44
Primiano Tucci8e3e1bb2021-06-01 20:05:38 +010045MAX_ADB_FAILURES = 15 # 2 seconds between retries, 30 seconds total.
46
Primiano Tuccic2d4c6d2021-01-15 11:37:30 +010047devnull = open(os.devnull, 'rb')
48adb_path = None
49procs = []
50
51
52class ANSI:
53 END = '\033[0m'
54 BOLD = '\033[1m'
55 RED = '\033[91m'
56 BLACK = '\033[30m'
57 BLUE = '\033[94m'
58 BG_YELLOW = '\033[43m'
59 BG_BLUE = '\033[44m'
60
61
62# HTTP Server used to open the trace in the browser.
63class HttpHandler(http.server.SimpleHTTPRequestHandler):
64
65 def end_headers(self):
66 self.send_header('Access-Control-Allow-Origin', '*')
67 return super().end_headers()
68
69 def do_GET(self):
70 self.server.last_request = self.path
71 return super().do_GET()
72
73 def do_POST(self):
74 self.send_error(404, "File not found")
75
76
77def main():
78 atexit.register(kill_all_subprocs_on_exit)
79 default_out_dir_str = '~/traces/'
80 default_out_dir = os.path.expanduser(default_out_dir_str)
81
82 examples = '\n'.join([
Primiano Tucciddf91652021-05-21 22:59:41 +010083 ANSI.BOLD + 'Examples' + ANSI.END, ' -t 10s -b 32mb sched gfx wm -a*',
Primiano Tuccic2d4c6d2021-01-15 11:37:30 +010084 ' -t 5s sched/sched_switch raw_syscalls/sys_enter raw_syscalls/sys_exit',
85 ' -c /path/to/full-textual-trace.config', '',
86 ANSI.BOLD + 'Long traces' + ANSI.END,
87 'If you want to record a hours long trace and stream it into a file ',
88 'you need to pass a full trace config and set write_into_file = true.',
89 'See https://perfetto.dev/docs/concepts/config#long-traces .'
90 ])
91 parser = argparse.ArgumentParser(
92 epilog=examples, formatter_class=argparse.RawTextHelpFormatter)
93
94 help = 'Output file or directory (default: %s)' % default_out_dir_str
95 parser.add_argument('-o', '--out', default=default_out_dir, help=help)
96
97 help = 'Don\'t open in the browser'
98 parser.add_argument('-n', '--no-open', action='store_true', help=help)
99
Primiano Tucci35e311e2021-05-21 20:31:55 +0100100 help = 'Force the use of the sideloaded binaries rather than system daemons'
101 parser.add_argument('--sideload', action='store_true', help=help)
102
Hector Dearman762c18f2021-05-24 11:10:52 +0100103 help = ('Sideload the given binary rather than downloading it. ' +
Primiano Tucciddf91652021-05-21 22:59:41 +0100104 'Implies --sideload')
105 parser.add_argument('--sideload-path', default=None, help=help)
106
Primiano Tucci35e311e2021-05-21 20:31:55 +0100107 help = 'Don\'t run `adb root` run as user (only when sideloading)'
108 parser.add_argument('-u', '--user', action='store_true', help=help)
109
Primiano Tuccic2d4c6d2021-01-15 11:37:30 +0100110 grp = parser.add_argument_group(
111 'Short options: (only when not using -c/--config)')
112
113 help = 'Trace duration N[s,m,h] (default: trace until stopped)'
114 grp.add_argument('-t', '--time', default='0s', help=help)
115
116 help = 'Ring buffer size N[mb,gb] (default: 32mb)'
117 grp.add_argument('-b', '--buffer', default='32mb', help=help)
118
Primiano Tucciddf91652021-05-21 22:59:41 +0100119 help = ('Android (atrace) app names. Can be specified multiple times.\n-a*' +
120 'for all apps (without space between a and * or bash will expand it)')
Lalit Maganti484b6742021-05-04 13:38:35 +0100121 grp.add_argument(
122 '-a',
123 '--app',
Primiano Tucciddf91652021-05-21 22:59:41 +0100124 metavar='com.myapp',
Lalit Maganti484b6742021-05-04 13:38:35 +0100125 action='append',
126 default=[],
127 help=help)
128
Primiano Tuccic2d4c6d2021-01-15 11:37:30 +0100129 help = 'sched, gfx, am, wm (see --list)'
130 grp.add_argument('events', metavar='Atrace events', nargs='*', help=help)
131
132 help = 'sched/sched_switch kmem/kmem (see --list-ftrace)'
133 grp.add_argument('_', metavar='Ftrace events', nargs='*', help=help)
134
135 help = 'Lists all the categories available'
136 grp.add_argument('--list', action='store_true', help=help)
137
138 help = 'Lists all the ftrace events available'
139 grp.add_argument('--list-ftrace', action='store_true', help=help)
140
141 section = ('Full trace config (only when not using short options)')
142 grp = parser.add_argument_group(section)
143
144 help = 'Can be generated with https://ui.perfetto.dev/#!/record'
145 grp.add_argument('-c', '--config', default=None, help=help)
Johnd8fa2bd2021-06-24 11:13:10 +0800146
147 help = 'Specify the ADB device serial'
148 grp.add_argument('--serial', '-s', default=None, help=help)
149
Primiano Tuccic2d4c6d2021-01-15 11:37:30 +0100150 args = parser.parse_args()
Primiano Tucciddf91652021-05-21 22:59:41 +0100151 args.sideload = args.sideload or args.sideload_path is not None
Primiano Tuccic2d4c6d2021-01-15 11:37:30 +0100152
Johnd8fa2bd2021-06-24 11:13:10 +0800153 if args.serial:
154 os.environ["ANDROID_SERIAL"] = args.serial
155
Primiano Tuccic2d4c6d2021-01-15 11:37:30 +0100156 find_adb()
157
158 if args.list:
159 adb('shell', 'atrace', '--list_categories').wait()
160 sys.exit(0)
161
162 if args.list_ftrace:
163 adb('shell', 'cat /d/tracing/available_events | tr : /').wait()
164 sys.exit(0)
165
166 if args.config is not None and not os.path.exists(args.config):
167 prt('Config file not found: %s' % args.config, ANSI.RED)
168 sys.exit(1)
169
170 if len(args.events) == 0 and args.config is None:
171 prt('Must either pass short options (e.g. -t 10s sched) or a --config file',
172 ANSI.RED)
173 parser.print_help()
174 sys.exit(1)
175
176 if args.config is None and args.events and os.path.exists(args.events[0]):
177 prt(('The passed event name "%s" is a local file. ' % args.events[0] +
178 'Did you mean to pass -c / --config ?'), ANSI.RED)
179 sys.exit(1)
180
Primiano Tucci35e311e2021-05-21 20:31:55 +0100181 perfetto_cmd = 'perfetto'
182 device_dir = '/data/misc/perfetto-traces/'
183
184 # Check the version of android. If too old (< Q) sideload tracebox. Also use
185 # use /data/local/tmp as /data/misc/perfetto-traces was introduced only later.
186 probe_cmd = 'getprop ro.build.version.sdk; getprop ro.product.cpu.abi; whoami'
187 probe = adb('shell', probe_cmd, stdout=subprocess.PIPE)
188 lines = probe.communicate()[0].decode().strip().split('\n')
189 lines = [x.strip() for x in lines] # To strip \r(s) on Windows.
190 if probe.returncode != 0:
191 prt('ADB connection failed', ANSI.RED)
192 sys.exit(1)
193 api_level = int(lines[0])
194 abi = lines[1]
195 arch = ABI_TO_ARCH.get(abi)
196 if arch is None:
197 prt('Unsupported ABI: ' + abi)
198 sys.exit(1)
199 shell_user = lines[2]
200 if api_level < 29 or args.sideload: # 29: Android Q.
Primiano Tuccid3e40bd2021-08-03 10:52:39 +0100201 tracebox_bin = args.sideload_path
202 if tracebox_bin is None:
203 tracebox_bin = get_perfetto_prebuilt('tracebox', arch='android-' + arch)
Primiano Tucci35e311e2021-05-21 20:31:55 +0100204 perfetto_cmd = '/data/local/tmp/tracebox'
205 exit_code = adb('push', '--sync', tracebox_bin, perfetto_cmd).wait()
206 exit_code |= adb('shell', 'chmod 755 ' + perfetto_cmd).wait()
207 if exit_code != 0:
208 prt('ADB push failed', ANSI.RED)
209 sys.exit(1)
210 device_dir = '/data/local/tmp/'
211 if shell_user != 'root' and not args.user:
212 # Run as root if possible as that will give access to more tracing
213 # capabilities. Non-root still works, but some ftrace events might not be
214 # available.
215 adb('root').wait()
216
217 tstamp = datetime.datetime.now().strftime('%Y-%m-%d_%H-%M')
218 fname = '%s-%s.pftrace' % (tstamp, os.urandom(3).hex())
219 device_file = device_dir + fname
220
221 cmd = [perfetto_cmd, '--background', '--txt', '-o', device_file]
Primiano Tuccic2d4c6d2021-01-15 11:37:30 +0100222 if args.config is not None:
223 cmd += ['-c', '-']
224 else:
Lalit Maganti484b6742021-05-04 13:38:35 +0100225 cmd += ['-t', args.time, '-b', args.buffer]
226 for app in args.app:
Primiano Tucciddf91652021-05-21 22:59:41 +0100227 cmd += ['--app', '\'' + app + '\'']
Lalit Maganti484b6742021-05-04 13:38:35 +0100228 cmd += args.events
Primiano Tuccic2d4c6d2021-01-15 11:37:30 +0100229
230 # Perfetto will error out with a proper message if both a config file and
231 # short options are specified. No need to replicate that logic.
232
233 # Work out the output file or directory.
234 if args.out.endswith('/') or os.path.isdir(args.out):
235 host_dir = args.out
236 host_file = os.path.join(args.out, fname)
237 else:
238 host_file = args.out
239 host_dir = os.path.dirname(host_file)
Primiano Tucci7c70b692021-02-16 13:58:39 +0100240 if host_dir == '':
241 host_dir = '.'
242 host_file = './' + host_file
Primiano Tuccic2d4c6d2021-01-15 11:37:30 +0100243 if not os.path.exists(host_dir):
244 shutil.os.makedirs(host_dir)
245
246 with open(args.config or os.devnull, 'rb') as f:
247 print('Running ' + ' '.join(cmd))
248 proc = adb('shell', *cmd, stdin=f, stdout=subprocess.PIPE)
Primiano Tucci59f08d52021-10-19 17:28:36 +0100249 proc_out = proc.communicate()[0].decode().strip()
250 # On older versions of Android (x86_64 emulator running API 22) the output
251 # looks like:
252 # WARNING: linker: /data/local/tmp/tracebox: unused DT entry: ...
253 # WARNING: ... (other 2 WARNING: linker: lines)
254 # 1234 <-- The actual pid we want.
255 match = re.search(r'^(\d+)$', proc_out, re.M)
256 if match is None:
257 prt('Failed to read the pid from perfetto --background', ANSI.RED)
258 prt(proc_out)
259 sys.exit(1)
260 bg_pid = match.group(1)
Primiano Tuccic2d4c6d2021-01-15 11:37:30 +0100261 exit_code = proc.wait()
262
263 if exit_code != 0:
264 prt('Perfetto invocation failed', ANSI.RED)
265 sys.exit(1)
266
267 prt('Trace started. Press CTRL+C to stop', ANSI.BLACK + ANSI.BG_BLUE)
268 logcat = adb('logcat', '-v', 'brief', '-s', 'perfetto', '-b', 'main', '-T',
269 '1')
270
271 ctrl_c_count = 0
Primiano Tucci8e3e1bb2021-06-01 20:05:38 +0100272 adb_failure_count = 0
Primiano Tuccic2d4c6d2021-01-15 11:37:30 +0100273 while ctrl_c_count < 2:
274 try:
Primiano Tucci59f08d52021-10-19 17:28:36 +0100275 # On older Android devices adbd doesn't propagate the exit code. Hence
276 # the RUN/TERM parts.
277 poll = adb(
278 'shell',
279 'test -d /proc/%s && echo RUN || echo TERM' % bg_pid,
280 stdout=subprocess.PIPE)
281 poll_res = poll.communicate()[0].decode().strip()
282 if poll_res == 'TERM':
Primiano Tucci8e3e1bb2021-06-01 20:05:38 +0100283 break # Process terminated
Primiano Tucci59f08d52021-10-19 17:28:36 +0100284 if poll_res == 'RUN':
Primiano Tucci8e3e1bb2021-06-01 20:05:38 +0100285 # The 'perfetto' cmdline client is still running. If previously we had
286 # an ADB error, tell the user now it's all right again.
287 if adb_failure_count > 0:
288 adb_failure_count = 0
289 prt('ADB connection re-established, the trace is still ongoing',
290 ANSI.BLUE)
291 time.sleep(0.5)
292 continue
293 # Some ADB error happened. This can happen when tracing soon after boot,
294 # before logging in, when adb gets restarted.
295 adb_failure_count += 1
296 if adb_failure_count >= MAX_ADB_FAILURES:
297 prt('Too many unrecoverable ADB failures, bailing out', ANSI.RED)
298 sys.exit(1)
299 time.sleep(2)
Primiano Tuccic2d4c6d2021-01-15 11:37:30 +0100300 except KeyboardInterrupt:
301 sig = 'TERM' if ctrl_c_count == 0 else 'KILL'
302 ctrl_c_count += 1
303 prt('Stopping the trace (SIG%s)' % sig, ANSI.BLACK + ANSI.BG_YELLOW)
Primiano Tucci8e3e1bb2021-06-01 20:05:38 +0100304 adb('shell', 'kill -%s %s' % (sig, bg_pid)).wait()
Primiano Tuccic2d4c6d2021-01-15 11:37:30 +0100305
306 logcat.kill()
307 logcat.wait()
308
309 prt('\n')
310 prt('Pulling into %s' % host_file, ANSI.BOLD)
311 adb('pull', device_file, host_file).wait()
Primiano Tucci407f4072021-06-22 10:00:44 +0100312 adb('shell', 'rm -f ' + device_file).wait()
Primiano Tuccic2d4c6d2021-01-15 11:37:30 +0100313
314 if not args.no_open:
315 prt('\n')
Primiano Tucci7c70b692021-02-16 13:58:39 +0100316 prt('Opening the trace (%s) in the browser' % host_file)
Primiano Tuccic2d4c6d2021-01-15 11:37:30 +0100317 open_trace_in_browser(host_file)
318
319
320def prt(msg, colors=ANSI.END):
321 print(colors + msg + ANSI.END)
322
323
324def find_adb():
325 """ Locate the "right" adb path
326
327 If adb is in the PATH use that (likely what the user wants) otherwise use the
328 hermetic one in our SDK copy.
329 """
330 global adb_path
331 for path in ['adb', HERMETIC_ADB_PATH]:
332 try:
333 subprocess.call([path, '--version'], stdout=devnull, stderr=devnull)
334 adb_path = path
335 break
336 except OSError:
337 continue
338 if adb_path is None:
Primiano Tuccifb43b842021-02-17 08:52:01 +0100339 sdk_url = 'https://developer.android.com/studio/releases/platform-tools'
340 prt('Could not find a suitable adb binary in the PATH. ', ANSI.RED)
341 prt('You can download adb from %s' % sdk_url, ANSI.RED)
Primiano Tuccic2d4c6d2021-01-15 11:37:30 +0100342 sys.exit(1)
343
344
345def open_trace_in_browser(path):
346 # We reuse the HTTP+RPC port because it's the only one allowed by the CSP.
347 PORT = 9001
348 os.chdir(os.path.dirname(path))
349 fname = os.path.basename(path)
350 socketserver.TCPServer.allow_reuse_address = True
351 with socketserver.TCPServer(('127.0.0.1', PORT), HttpHandler) as httpd:
352 webbrowser.open_new_tab(
Primiano Tucci35e311e2021-05-21 20:31:55 +0100353 'https://ui.perfetto.dev/#!/?url=http://127.0.0.1:%d/%s' %
Primiano Tuccic2d4c6d2021-01-15 11:37:30 +0100354 (PORT, fname))
355 while httpd.__dict__.get('last_request') != '/' + fname:
356 httpd.handle_request()
357
358
359def adb(*args, stdin=devnull, stdout=None):
360 cmd = [adb_path, *args]
Primiano Tuccifb43b842021-02-17 08:52:01 +0100361 setpgrp = None
362 if os.name != 'nt':
363 # On Linux/Mac, start a new process group so all child processes are killed
364 # on exit. Unsupported on Windows.
365 setpgrp = lambda: os.setpgrp()
366 proc = subprocess.Popen(cmd, stdin=stdin, stdout=stdout, preexec_fn=setpgrp)
Primiano Tuccic2d4c6d2021-01-15 11:37:30 +0100367 procs.append(proc)
368 return proc
369
370
371def kill_all_subprocs_on_exit():
372 for p in [p for p in procs if p.poll() is None]:
373 p.kill()
374
375
Primiano Tucci35e311e2021-05-21 20:31:55 +0100376def check_hash(file_name, sha_value):
377 with open(file_name, 'rb') as fd:
378 file_hash = hashlib.sha1(fd.read()).hexdigest()
379 return file_hash == sha_value
380
381
Primiano Tuccid3e40bd2021-08-03 10:52:39 +0100382# BEGIN_SECTION_GENERATED_BY(roll-prebuilts)
Primiano Tucci45646b62021-11-04 11:18:03 +0000383# Revision: v21.0
Primiano Tuccid3e40bd2021-08-03 10:52:39 +0100384PERFETTO_PREBUILT_MANIFEST = [{
385 'tool':
386 'tracebox',
387 'arch':
388 'android-arm',
389 'file_name':
390 'tracebox',
391 'file_size':
Primiano Tucci45646b62021-11-04 11:18:03 +0000392 993356,
Primiano Tuccid3e40bd2021-08-03 10:52:39 +0100393 'url':
Primiano Tucci45646b62021-11-04 11:18:03 +0000394 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v21.0/android-arm/tracebox',
Primiano Tuccid3e40bd2021-08-03 10:52:39 +0100395 'sha256':
Primiano Tucci45646b62021-11-04 11:18:03 +0000396 '86df4b8f210fc7fba88881db340182ecebbdecb9418a36a6c21d62863a77c1f6'
Primiano Tuccid3e40bd2021-08-03 10:52:39 +0100397}, {
398 'tool':
399 'tracebox',
400 'arch':
401 'android-arm64',
402 'file_name':
403 'tracebox',
404 'file_size':
Primiano Tucci45646b62021-11-04 11:18:03 +0000405 1522496,
Primiano Tuccid3e40bd2021-08-03 10:52:39 +0100406 'url':
Primiano Tucci45646b62021-11-04 11:18:03 +0000407 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v21.0/android-arm64/tracebox',
Primiano Tuccid3e40bd2021-08-03 10:52:39 +0100408 'sha256':
Primiano Tucci45646b62021-11-04 11:18:03 +0000409 '22f9a3c750c0ef60281a18a7bc7966427322f3a7d4bb8226bd2c8e37f22100e1'
Primiano Tuccid3e40bd2021-08-03 10:52:39 +0100410}, {
411 'tool':
412 'tracebox',
413 'arch':
414 'android-x86',
415 'file_name':
416 'tracebox',
417 'file_size':
Primiano Tucci45646b62021-11-04 11:18:03 +0000418 1542172,
Primiano Tuccid3e40bd2021-08-03 10:52:39 +0100419 'url':
Primiano Tucci45646b62021-11-04 11:18:03 +0000420 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v21.0/android-x86/tracebox',
Primiano Tuccid3e40bd2021-08-03 10:52:39 +0100421 'sha256':
Primiano Tucci45646b62021-11-04 11:18:03 +0000422 'cbb1073c515848753d36d8bda81ce4ed97384c4cca90d6d84a294031d83724e5'
Primiano Tuccid3e40bd2021-08-03 10:52:39 +0100423}, {
424 'tool':
425 'tracebox',
426 'arch':
427 'android-x64',
428 'file_name':
429 'tracebox',
430 'file_size':
Primiano Tucci45646b62021-11-04 11:18:03 +0000431 1780544,
Primiano Tuccid3e40bd2021-08-03 10:52:39 +0100432 'url':
Primiano Tucci45646b62021-11-04 11:18:03 +0000433 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v21.0/android-x64/tracebox',
Primiano Tuccid3e40bd2021-08-03 10:52:39 +0100434 'sha256':
Primiano Tucci45646b62021-11-04 11:18:03 +0000435 'f01656ea00156e64a8cd2aa65c1a8814eebecea6280dc3eb14cfc7b7eefda776'
Primiano Tuccid3e40bd2021-08-03 10:52:39 +0100436}]
Primiano Tucci35e311e2021-05-21 20:31:55 +0100437
438
Primiano Tuccid3e40bd2021-08-03 10:52:39 +0100439# DO NOT EDIT. If you wish to make edits to this code, you need to change only
440# //tools/get_perfetto_prebuilt.py and run /tools/roll-prebuilts to regenerate
441# all the others scripts this is embedded into.
442def get_perfetto_prebuilt(tool_name, soft_fail=False, arch=None):
443 """ Downloads the prebuilt, if necessary, and returns its path on disk. """
444
445 # The first time this is invoked, it downloads the |url| and caches it into
446 # ~/.perfetto/prebuilts/$tool_name. On subsequent invocations it just runs the
447 # cached version.
448 def download_or_get_cached(file_name, url, sha256):
449 import os, hashlib, subprocess
450 dir = os.path.join(
451 os.path.expanduser('~'), '.local', 'share', 'perfetto', 'prebuilts')
452 os.makedirs(dir, exist_ok=True)
453 bin_path = os.path.join(dir, file_name)
454 sha256_path = os.path.join(dir, file_name + '.sha256')
455 needs_download = True
456
457 # Avoid recomputing the SHA-256 on each invocation. The SHA-256 of the last
458 # download is cached into file_name.sha256, just check if that matches.
459 if os.path.exists(bin_path) and os.path.exists(sha256_path):
460 with open(sha256_path, 'rb') as f:
461 digest = f.read().decode()
462 if digest == sha256:
463 needs_download = False
464
465 if needs_download:
466 # Either the filed doesn't exist or the SHA256 doesn't match.
467 tmp_path = bin_path + '.tmp'
468 print('Downloading ' + url)
469 subprocess.check_call(['curl', '-f', '-L', '-#', '-o', tmp_path, url])
470 with open(tmp_path, 'rb') as fd:
471 actual_sha256 = hashlib.sha256(fd.read()).hexdigest()
472 if actual_sha256 != sha256:
473 raise Exception('Checksum mismatch for %s (actual: %s, expected: %s)' %
474 (url, actual_sha256, sha256))
475 os.chmod(tmp_path, 0o755)
476 os.rename(tmp_path, bin_path)
477 with open(sha256_path, 'w') as f:
478 f.write(sha256)
479 return bin_path
480 # --- end of download_or_get_cached() ---
481
482 # --- get_perfetto_prebuilt() function starts here. ---
483 import os, platform, sys
484 plat = sys.platform.lower()
485 machine = platform.machine().lower()
486 manifest_entry = None
487 for entry in PERFETTO_PREBUILT_MANIFEST:
488 # If the caller overrides the arch, just match that (for Android prebuilts).
489 if arch and entry.get('arch') == arch:
490 manifest_entry = entry
491 break
492 # Otherwise guess the local machine arch.
493 if entry.get('tool') == tool_name and entry.get(
494 'platform') == plat and machine in entry.get('machine', []):
495 manifest_entry = entry
496 break
497 if manifest_entry is None:
498 if soft_fail:
499 return None
500 raise Exception(
501 ('No prebuilts available for %s-%s\n' % (plat, machine)) +
502 'See https://perfetto.dev/docs/contributing/build-instructions')
503
504 return download_or_get_cached(
505 file_name=manifest_entry['file_name'],
506 url=manifest_entry['url'],
507 sha256=manifest_entry['sha256'])
508
509
510# END_SECTION_GENERATED_BY(roll-prebuilts)
511
Primiano Tuccic2d4c6d2021-01-15 11:37:30 +0100512if __name__ == '__main__':
513 sys.exit(main())