blob: 48449ca9f09c42c3b110319cc6d41bc3ce96ee3b [file] [log] [blame]
Morten Krogh-Jespersen45abed92021-01-18 22:07:41 +01001#!/usr/bin/env python3
Mads Ager418d1ca2017-05-22 09:35:49 +02002# Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
3# for details. All rights reserved. Use of this source code is governed by a
4# BSD-style license that can be found in the LICENSE file.
5
Tamas Kenezfc34cd82017-07-13 12:43:57 +02006from __future__ import print_function
Tamas Kenez02bff032017-07-18 12:13:58 +02007from glob import glob
Rico Windb57bbc12018-09-20 19:23:32 +02008import copy
Mads Ager418d1ca2017-05-22 09:35:49 +02009import optparse
10import os
Søren Gjesse80e00482021-04-06 13:17:35 +020011import shutil
Mads Ager418d1ca2017-05-22 09:35:49 +020012import sys
Tamas Kenezf2ee2a32017-06-21 10:30:20 +020013import time
Mads Ager418d1ca2017-05-22 09:35:49 +020014
Christoffer Quist Adamsen870fa462020-12-15 10:50:54 +010015import archive
Morten Krogh-Jespersen89e19012021-10-05 09:55:01 +020016import gradle
Søren Gjesse5ecb04a2017-06-13 09:44:32 +020017import gmail_data
Christoffer Quist Adamsena2a58772018-10-03 09:47:46 +020018import nest_data
Søren Gjesse889e09d2019-11-07 16:33:51 +010019from sanitize_libraries import SanitizeLibraries, SanitizeLibrariesInPgconf
Christoffer Quist Adamsen65ef2982023-08-24 08:45:39 +020020import thread_utils
21from thread_utils import print_thread
Mathias Ravdd6a6de2018-05-18 10:18:33 +020022import toolhelper
Christoffer Quist Adamsen870fa462020-12-15 10:50:54 +010023import update_prebuilds_in_android
Ian Zerny877c1862017-07-06 11:12:26 +020024import utils
25import youtube_data
Rico Wind86bfc832018-09-18 07:48:21 +020026import chrome_data
Mads Ager418d1ca2017-05-22 09:35:49 +020027
28TYPES = ['dex', 'deploy', 'proguarded']
Christoffer Quist Adamsenca2cc7d2023-08-24 09:14:43 +020029APPS = ['nest', 'youtube', 'gmail', 'chrome']
Tamas Kenez63a51d02019-01-07 15:53:02 +010030COMPILERS = ['d8', 'r8']
31COMPILER_BUILDS = ['full', 'lib']
32
Rico Wind5fdec152018-12-17 09:16:14 +010033# We use this magic exit code to signal that the program OOM'ed
34OOM_EXIT_CODE = 42
Jinseong Jeon158a3f12019-02-08 01:40:59 -080035# According to Popen.returncode doc:
36# A negative value -N indicates that the child was terminated by signal N.
37TIMEOUT_KILL_CODE = -9
Mads Ager418d1ca2017-05-22 09:35:49 +020038
Morten Krogh-Jespersen0981b722019-10-09 10:00:33 +020039# Log file names
40FIND_MIN_XMX_FILE = 'find_min_xmx_results'
41FIND_MIN_XMX_DIR = 'find_min_xmx'
42
Tamas Kenez5b1c5852017-07-21 13:38:33 +020043def ParseOptions(argv):
Mads Ager418d1ca2017-05-22 09:35:49 +020044 result = optparse.OptionParser()
Søren Gjesse932881f2017-06-13 10:43:36 +020045 result.add_option('--compiler',
Rico Windb57bbc12018-09-20 19:23:32 +020046 help='The compiler to use',
Tamas Kenez5b1c5852017-07-21 13:38:33 +020047 choices=COMPILERS)
Tamas Kenez63a51d02019-01-07 15:53:02 +010048 result.add_option('--compiler-build',
49 help='Compiler build to use',
50 choices=COMPILER_BUILDS,
51 default='lib')
Christoffer Quist Adamsen65ef2982023-08-24 08:45:39 +020052 result.add_option('--no-fail-fast',
53 help='Whether run_on_app.py should report all failures '
54 'and not just the first one',
55 default=False,
56 action='store_true')
Christoffer Quist Adamsen870fa462020-12-15 10:50:54 +010057 result.add_option('--hash',
58 help='The version of D8/R8 to use')
Mads Ager418d1ca2017-05-22 09:35:49 +020059 result.add_option('--app',
Rico Windb57bbc12018-09-20 19:23:32 +020060 help='What app to run on',
Mads Ager418d1ca2017-05-22 09:35:49 +020061 choices=APPS)
Rico Windb57bbc12018-09-20 19:23:32 +020062 result.add_option('--run-all',
63 help='Compile all possible combinations',
64 default=False,
65 action='store_true')
Morten Krogh-Jespersenb7e1a182019-10-09 13:04:54 +020066 result.add_option('--expect-oom',
67 help='Expect that compilation will fail with an OOM',
68 default=False,
69 action='store_true')
Mads Ager418d1ca2017-05-22 09:35:49 +020070 result.add_option('--type',
Tamas Kenez3fdaabd2017-06-15 13:05:12 +020071 help='Default for R8: deploy, for D8: proguarded',
Mads Ager418d1ca2017-05-22 09:35:49 +020072 choices=TYPES)
73 result.add_option('--out',
Rico Windb57bbc12018-09-20 19:23:32 +020074 help='Where to place the output',
Rico Winde9485ba2018-10-01 07:04:16 +020075 default=utils.BUILD)
Mads Ager418d1ca2017-05-22 09:35:49 +020076 result.add_option('--no-build',
Rico Windb57bbc12018-09-20 19:23:32 +020077 help='Run without building first',
Mads Ager418d1ca2017-05-22 09:35:49 +020078 default=False,
79 action='store_true')
Morten Krogh-Jespersen322c2f12019-10-08 10:41:21 +020080 result.add_option('--max-memory',
81 help='The maximum memory in MB to run with',
82 type='int')
Rico Wind5fdec152018-12-17 09:16:14 +010083 result.add_option('--find-min-xmx',
84 help='Find the minimum amount of memory we can run in',
85 default=False,
86 action='store_true')
Morten Krogh-Jespersen04c7c302019-10-01 15:04:33 +020087 result.add_option('--find-min-xmx-min-memory',
88 help='Setting the minimum memory baseline to run in',
89 type='int')
90 result.add_option('--find-min-xmx-max-memory',
91 help='Setting the maximum memory baseline to run in',
92 type='int')
93 result.add_option('--find-min-xmx-range-size',
94 help='Setting the size of the acceptable memory range',
95 type='int',
96 default=32)
Morten Krogh-Jespersen0981b722019-10-09 10:00:33 +020097 result.add_option('--find-min-xmx-archive',
98 help='Archive find-min-xmx results on GCS',
99 default=False,
100 action='store_true')
Christoffer Quist Adamsen3bbb50e2020-05-19 15:00:00 +0200101 result.add_option('--no-extra-pgconf', '--no_extra_pgconf',
102 help='Build without the following extra rules: ' +
103 '-printconfiguration, -printmapping, -printseeds, ' +
104 '-printusage',
105 default=False,
106 action='store_true')
Jinseong Jeon158a3f12019-02-08 01:40:59 -0800107 result.add_option('--timeout',
Morten Krogh-Jespersen0981b722019-10-09 10:00:33 +0200108 type='int',
Jinseong Jeon158a3f12019-02-08 01:40:59 -0800109 default=0,
110 help='Set timeout instead of waiting for OOM.')
Rico Wind139eece2018-09-25 09:42:09 +0200111 result.add_option('--ignore-java-version',
112 help='Do not check java version',
113 default=False,
114 action='store_true')
Mads Ager418d1ca2017-05-22 09:35:49 +0200115 result.add_option('--no-libraries',
Rico Windb57bbc12018-09-20 19:23:32 +0200116 help='Do not pass in libraries, even if they exist in conf',
Mads Ager418d1ca2017-05-22 09:35:49 +0200117 default=False,
118 action='store_true')
119 result.add_option('--no-debug',
120 help='Run without debug asserts.',
121 default=False,
122 action='store_true')
Ian Zerny016d6f62020-03-19 08:58:21 +0100123 result.add_option('--debug-agent',
124 help='Run with debug agent.',
125 default=False,
126 action='store_true')
Mads Ager418d1ca2017-05-22 09:35:49 +0200127 result.add_option('--version',
Rico Windb57bbc12018-09-20 19:23:32 +0200128 help='The version of the app to run')
Mads Ager418d1ca2017-05-22 09:35:49 +0200129 result.add_option('-k',
130 help='Override the default ProGuard keep rules')
Tamas Kenez139acc12017-06-14 17:14:58 +0200131 result.add_option('--compiler-flags',
132 help='Additional option(s) for the compiler. ' +
133 'If passing several options use a quoted string.')
Mads Ager418d1ca2017-05-22 09:35:49 +0200134 result.add_option('--r8-flags',
Tamas Kenez139acc12017-06-14 17:14:58 +0200135 help='Additional option(s) for the compiler. ' +
Tamas Kenezfc34cd82017-07-13 12:43:57 +0200136 'Same as --compiler-flags, keeping it for backward'
137 ' compatibility. ' +
Mads Ager418d1ca2017-05-22 09:35:49 +0200138 'If passing several options use a quoted string.')
139 result.add_option('--track-memory-to-file',
140 help='Track how much memory the jvm is using while ' +
141 ' compiling. Output to the specified file.')
142 result.add_option('--profile',
143 help='Profile R8 run.',
144 default=False,
145 action='store_true')
146 result.add_option('--dump-args-file',
147 help='Dump a file with the arguments for the specified ' +
148 'configuration. For use as a @<file> argument to perform ' +
149 'the run.')
Tamas Kenezf2ee2a32017-06-21 10:30:20 +0200150 result.add_option('--print-runtimeraw',
151 metavar='BENCHMARKNAME',
Tamas Kenez02bff032017-07-18 12:13:58 +0200152 help='Print the line \'<BENCHMARKNAME>(RunTimeRaw):' +
153 ' <elapsed> ms\' at the end where <elapsed> is' +
154 ' the elapsed time in milliseconds.')
Tamas Kenezfc34cd82017-07-13 12:43:57 +0200155 result.add_option('--print-memoryuse',
156 metavar='BENCHMARKNAME',
Tamas Kenez02bff032017-07-18 12:13:58 +0200157 help='Print the line \'<BENCHMARKNAME>(MemoryUse):' +
158 ' <mem>\' at the end where <mem> is the peak' +
159 ' peak resident set size (VmHWM) in bytes.')
160 result.add_option('--print-dexsegments',
161 metavar='BENCHMARKNAME',
162 help='Print the sizes of individual dex segments as ' +
163 '\'<BENCHMARKNAME>-<segment>(CodeSize): <bytes>\'')
Morten Krogh-Jespersenae9557c2019-10-23 15:14:02 +0200164 result.add_option('--track-time-in-memory',
165 help='Plot the times taken from memory starting point to '
166 'end-point with defined memory increment',
167 default=False,
168 action='store_true')
169 result.add_option('--track-time-in-memory-max',
170 help='Setting the maximum memory baseline to run in',
171 type='int')
172 result.add_option('--track-time-in-memory-min',
173 help='Setting the minimum memory baseline to run in',
174 type='int')
175 result.add_option('--track-time-in-memory-increment',
176 help='Setting the increment',
177 type='int',
178 default=32)
Søren Gjesse04a94332020-01-27 15:35:42 +0100179 result.add_option('--print-times',
180 help='Include timing',
181 default=False,
182 action='store_true')
Søren Gjesse943389f2020-03-13 10:40:25 +0100183 result.add_option('--cpu-list',
184 help='Run under \'taskset\' with these CPUs. See '
185 'the \'taskset\' -c option for the format')
Christoffer Quist Adamsend61d2a32020-06-02 07:41:10 +0200186 result.add_option('--quiet',
187 help='Disable compiler logging',
188 default=False,
189 action='store_true')
Christoffer Quist Adamsen65ef2982023-08-24 08:45:39 +0200190 result.add_option('--workers',
191 help='Number of workers to use',
192 default=1,
193 type=int)
Christoffer Quist Adamsen870fa462020-12-15 10:50:54 +0100194 (options, args) = result.parse_args(argv)
195 assert not options.hash or options.no_build, (
196 'Argument --no-build is required when using --hash')
197 assert not options.hash or options.compiler_build == 'full', (
198 'Compiler build lib not yet supported with --hash')
199 return (options, args)
Mads Ager418d1ca2017-05-22 09:35:49 +0200200
Man Cao29b9ef12019-03-25 11:19:35 -0700201# Most apps have -printmapping, -printseeds, -printusage and
202# -printconfiguration in the Proguard configuration. However we don't
203# want to write these files in the locations specified.
204# Instead generate an auxiliary Proguard configuration placing these
205# output files together with the dex output.
Søren Gjesse3a5aed92017-06-14 15:36:02 +0200206def GenerateAdditionalProguardConfiguration(temp, outdir):
207 name = "output.config"
Tamas Kenezfc34cd82017-07-13 12:43:57 +0200208 with open(os.path.join(temp, name), 'w') as f:
209 f.write('-printmapping ' + os.path.join(outdir, 'proguard.map') + "\n")
210 f.write('-printseeds ' + os.path.join(outdir, 'proguard.seeds') + "\n")
Søren Gjesse59459582018-04-06 10:12:45 +0200211 f.write('-printusage ' + os.path.join(outdir, 'proguard.usage') + "\n")
Man Cao29b9ef12019-03-25 11:19:35 -0700212 f.write('-printconfiguration ' + os.path.join(outdir, 'proguard.config') + "\n")
Tamas Kenezfc34cd82017-07-13 12:43:57 +0200213 return os.path.abspath(f.name)
Søren Gjesse3a5aed92017-06-14 15:36:02 +0200214
Rico Wind3f9302b2018-09-21 08:53:09 +0200215# Please add bug number for disabled permutations and please explicitly
216# do Bug: #BUG in the commit message of disabling to ensure re-enabling
217DISABLED_PERMUTATIONS = [
Christoffer Quist Adamsen130394c2021-01-19 08:55:57 +0100218 # (app, version, type), e.g., ('gmail', '180826.15', 'deploy')
Rico Wind3f9302b2018-09-21 08:53:09 +0200219]
220
Rico Windb57bbc12018-09-20 19:23:32 +0200221def get_permutations():
222 data_providers = {
Christoffer Quist Adamsena2a58772018-10-03 09:47:46 +0200223 'nest': nest_data,
Rico Windb57bbc12018-09-20 19:23:32 +0200224 'youtube': youtube_data,
225 'chrome': chrome_data,
Morten Krogh-Jespersen04c7c302019-10-01 15:04:33 +0200226 'gmail': gmail_data,
Rico Windb57bbc12018-09-20 19:23:32 +0200227 }
228 # Check to ensure that we add all variants here.
229 assert len(APPS) == len(data_providers)
Christoffer Quist Adamsen147342c2021-01-20 11:50:17 +0100230 for app, data in data_providers.items():
Rico Windb57bbc12018-09-20 19:23:32 +0200231 for version in data.VERSIONS:
232 for type in data.VERSIONS[version]:
Rico Wind3f9302b2018-09-21 08:53:09 +0200233 if (app, version, type) not in DISABLED_PERMUTATIONS:
Rico Wind6ddf2ce2023-08-23 08:46:29 +0200234 # Only run with R8 lib to reduce cycle times.
235 for use_r8lib in [True]:
Tamas Keneza730a7e2018-12-10 15:02:28 +0100236 yield app, version, type, use_r8lib
Rico Windb57bbc12018-09-20 19:23:32 +0200237
238def run_all(options, args):
Christoffer Quist Adamsen65ef2982023-08-24 08:45:39 +0200239 # Build first so that each job won't.
240 if should_build(options):
241 gradle.RunGradle(['r8lib'])
242 options.no_build = True
243 assert not should_build(options)
244
Rico Windb57bbc12018-09-20 19:23:32 +0200245 # Args will be destroyed
246 assert len(args) == 0
Christoffer Quist Adamsen65ef2982023-08-24 08:45:39 +0200247 jobs = []
Tamas Keneza730a7e2018-12-10 15:02:28 +0100248 for name, version, type, use_r8lib in get_permutations():
Rico Windb57bbc12018-09-20 19:23:32 +0200249 compiler = 'r8' if type == 'deploy' else 'd8'
Tamas Kenez63a51d02019-01-07 15:53:02 +0100250 compiler_build = 'lib' if use_r8lib else 'full'
Rico Windb57bbc12018-09-20 19:23:32 +0200251 fixed_options = copy.copy(options)
252 fixed_options.app = name
253 fixed_options.version = version
254 fixed_options.compiler = compiler
Tamas Kenez63a51d02019-01-07 15:53:02 +0100255 fixed_options.compiler_build = compiler_build
Rico Windb57bbc12018-09-20 19:23:32 +0200256 fixed_options.type = type
Christoffer Quist Adamsen65ef2982023-08-24 08:45:39 +0200257 jobs.append(
258 create_job(
259 compiler, compiler_build, name, fixed_options, type, version))
260 exit_code = thread_utils.run_in_parallel(
261 jobs,
262 number_of_workers=options.workers,
263 stop_on_first_failure=not options.no_fail_fast)
264 exit(exit_code)
265
266def create_job(compiler, compiler_build, name, options, type, version):
267 return lambda worker_id: run_job(
268 compiler, compiler_build, name, options, type, version, worker_id)
269
270def run_job(
271 compiler, compiler_build, name, options, type, version, worker_id):
272 print_thread(
273 'Executing %s/%s with %s %s %s'
274 % (compiler, compiler_build, name, version, type),
275 worker_id)
276 if worker_id is not None:
277 options.out = os.path.join(options.out, str(worker_id))
278 os.makedirs(options.out, exist_ok=True)
279 exit_code = run_with_options(options, [], worker_id=worker_id)
280 if exit_code:
281 print_thread(
282 'Failed %s %s %s with %s/%s'
283 % (name, version, type, compiler, compiler_build),
284 worker_id)
285 return exit_code
Rico Windb57bbc12018-09-20 19:23:32 +0200286
Rico Wind5fdec152018-12-17 09:16:14 +0100287def find_min_xmx(options, args):
288 # Args will be destroyed
289 assert len(args) == 0
290 # If we can run in 128 MB then we are good (which we can for small examples
291 # or D8 on medium sized examples)
Morten Krogh-Jespersen04c7c302019-10-01 15:04:33 +0200292 if options.find_min_xmx_min_memory:
293 not_working = options.find_min_xmx_min_memory
294 elif options.compiler == 'd8':
295 not_working = 128
296 else:
297 not_working = 1024
298 if options.find_min_xmx_max_memory:
299 working = options.find_min_xmx_max_memory
300 else:
301 working = 1024 * 8
Rico Wind5fdec152018-12-17 09:16:14 +0100302 exit_code = 0
Morten Krogh-Jespersen70432842021-01-19 17:07:58 +0100303 range = int(options.find_min_xmx_range_size)
Morten Krogh-Jespersen04c7c302019-10-01 15:04:33 +0200304 while working - not_working > range:
Morten Krogh-Jespersen70432842021-01-19 17:07:58 +0100305 next_candidate = int(working - ((working - not_working)/2))
Rico Wind5fdec152018-12-17 09:16:14 +0100306 print('working: %s, non_working: %s, next_candidate: %s' %
307 (working, not_working, next_candidate))
308 extra_args = ['-Xmx%sM' % next_candidate]
Rico Wind5fdec152018-12-17 09:16:14 +0100309 t0 = time.time()
310 exit_code = run_with_options(options, [], extra_args)
311 t1 = time.time()
312 print('Running took: %s ms' % (1000.0 * (t1 - t0)))
Jinseong Jeon158a3f12019-02-08 01:40:59 -0800313 if exit_code != 0:
314 if exit_code not in [OOM_EXIT_CODE, TIMEOUT_KILL_CODE]:
315 print('Non OOM/Timeout error executing, exiting')
316 return 2
Rico Wind5fdec152018-12-17 09:16:14 +0100317 if exit_code == 0:
318 working = next_candidate
Jinseong Jeon158a3f12019-02-08 01:40:59 -0800319 elif exit_code == TIMEOUT_KILL_CODE:
320 print('Timeout. Continue to the next candidate.')
321 not_working = next_candidate
Rico Wind5fdec152018-12-17 09:16:14 +0100322 else:
323 assert exit_code == OOM_EXIT_CODE
324 not_working = next_candidate
325
Morten Krogh-Jespersen04c7c302019-10-01 15:04:33 +0200326 assert working - not_working <= range
Morten Krogh-Jespersen0981b722019-10-09 10:00:33 +0200327 found_range = 'Found range: %s - %s' % (not_working, working)
328 print(found_range)
329
330 if options.find_min_xmx_archive:
331 sha = utils.get_HEAD_sha1()
332 (version, _) = get_version_and_data(options)
333 destination = os.path.join(
334 utils.R8_TEST_RESULTS_BUCKET,
335 FIND_MIN_XMX_DIR,
336 sha,
337 options.compiler,
338 options.compiler_build,
339 options.app,
340 version,
341 get_type(options))
342 gs_destination = 'gs://%s' % destination
343 utils.archive_value(FIND_MIN_XMX_FILE, gs_destination, found_range + '\n')
344
Rico Wind5fdec152018-12-17 09:16:14 +0100345 return 0
346
Morten Krogh-Jespersenf2412302019-10-22 10:18:04 +0200347def print_min_xmx_ranges_for_hash(hash, compiler, compiler_build):
348 app_directory = os.path.join(
349 utils.R8_TEST_RESULTS_BUCKET,
350 FIND_MIN_XMX_DIR,
351 hash,
352 compiler,
353 compiler_build)
354 gs_base = 'gs://%s' % app_directory
355 for app in utils.ls_files_on_cloud_storage(gs_base).strip().split('\n'):
356 for version in utils.ls_files_on_cloud_storage(app).strip().split('\n'):
357 for type in utils.ls_files_on_cloud_storage(version).strip().split('\n'):
358 gs_location = '%s%s' % (type, FIND_MIN_XMX_FILE)
359 value = utils.cat_file_on_cloud_storage(gs_location, ignore_errors=True)
360 print('%s\n' % value)
361
Morten Krogh-Jespersenae9557c2019-10-23 15:14:02 +0200362def track_time_in_memory(options, args):
363 # Args will be destroyed
364 assert len(args) == 0
365 if not options.track_time_in_memory_min:
366 raise Exception(
367 'You have to specify --track_time_in_memory_min when running with '
368 '--track-time-in-memory')
369 if not options.track_time_in_memory_max:
370 raise Exception(
371 'You have to specify --track_time_in_memory_max when running with '
372 '--track-time-in-memory')
373 if not options.track_time_in_memory_increment:
374 raise Exception(
375 'You have to specify --track_time_in_memory_increment when running '
376 'with --track-time-in-memory')
377 current = options.track_time_in_memory_min
378 print('Memory (KB)\tTime (ms)')
379 with utils.TempDir() as temp:
380 stdout = os.path.join(temp, 'stdout')
381 stdout_fd = open(stdout, 'w')
382 while current <= options.track_time_in_memory_max:
383 extra_args = ['-Xmx%sM' % current]
384 t0 = time.time()
385 exit_code = run_with_options(options, [], extra_args, stdout_fd, quiet=True)
386 t1 = time.time()
387 total = (1000.0 * (t1 - t0)) if exit_code == 0 else -1
388 print('%s\t%s' % (current, total))
389 current += options.track_time_in_memory_increment
390
391 return 0
392
Tamas Kenez5b1c5852017-07-21 13:38:33 +0200393def main(argv):
Tamas Kenez5b1c5852017-07-21 13:38:33 +0200394 (options, args) = ParseOptions(argv)
Morten Krogh-Jespersenb7e1a182019-10-09 13:04:54 +0200395 if options.expect_oom and not options.max_memory:
396 raise Exception(
397 'You should only use --expect-oom if also specifying --max-memory')
398 if options.expect_oom and options.timeout:
399 raise Exception(
400 'You should not use --timeout when also specifying --expect-oom')
Morten Krogh-Jespersenae9557c2019-10-23 15:14:02 +0200401 if options.find_min_xmx and options.track_time_in_memory:
402 raise Exception(
403 'You cannot both find the min xmx and track time at the same time')
Rico Windb57bbc12018-09-20 19:23:32 +0200404 if options.run_all:
405 return run_all(options, args)
Rico Wind5fdec152018-12-17 09:16:14 +0100406 if options.find_min_xmx:
407 return find_min_xmx(options, args)
Morten Krogh-Jespersenae9557c2019-10-23 15:14:02 +0200408 if options.track_time_in_memory:
409 return track_time_in_memory(options, args)
Christoffer Quist Adamsend61d2a32020-06-02 07:41:10 +0200410 exit_code = run_with_options(options, args, quiet=options.quiet)
Morten Krogh-Jespersenb7e1a182019-10-09 13:04:54 +0200411 if options.expect_oom:
412 exit_code = 0 if exit_code == OOM_EXIT_CODE else 1
413 return exit_code
Rico Windb57bbc12018-09-20 19:23:32 +0200414
Morten Krogh-Jespersen0981b722019-10-09 10:00:33 +0200415def get_version_and_data(options):
Christoffer Quist Adamsenca2cc7d2023-08-24 09:14:43 +0200416 if options.app == 'nest':
Morten Krogh-Jespersen0981b722019-10-09 10:00:33 +0200417 version = options.version or '20180926'
418 data = nest_data
419 elif options.app == 'youtube':
Christoffer Quist Adamsen4380de32021-04-23 06:24:31 +0200420 version = options.version or youtube_data.LATEST_VERSION
Morten Krogh-Jespersen0981b722019-10-09 10:00:33 +0200421 data = youtube_data
422 elif options.app == 'chrome':
423 version = options.version or '180917'
424 data = chrome_data
425 elif options.app == 'gmail':
426 version = options.version or '170604.16'
427 data = gmail_data
Morten Krogh-Jespersen0981b722019-10-09 10:00:33 +0200428 else:
429 raise Exception("You need to specify '--app={}'".format('|'.join(APPS)))
430 return version, data
431
432def get_type(options):
433 if not options.type:
434 return 'deploy' if options.compiler == 'r8' else 'proguarded'
435 return options.type
436
Søren Gjesse94793ca2019-11-08 13:53:08 +0100437def has_injars_and_libraryjars(pgconfs):
438 # Check if there are -injars and -libraryjars in the configuration.
439 has_injars = False
440 has_libraryjars = False
441 for pgconf in pgconfs:
442 pgconf_dirname = os.path.abspath(os.path.dirname(pgconf))
443 with open(pgconf) as pgconf_file:
444 for line in pgconf_file:
445 trimmed = line.strip()
446 if trimmed.startswith('-injars'):
447 has_injars = True
448 elif trimmed.startswith('-libraryjars'):
449 has_libraryjars = True
450 if has_injars and has_libraryjars:
451 return True
452 return False
453
Søren Gjesse889e09d2019-11-07 16:33:51 +0100454def check_no_injars_and_no_libraryjars(pgconfs):
455 # Ensure that there are no -injars or -libraryjars in the configuration.
456 for pgconf in pgconfs:
457 pgconf_dirname = os.path.abspath(os.path.dirname(pgconf))
458 with open(pgconf) as pgconf_file:
459 for line in pgconf_file:
460 trimmed = line.strip()
461 if trimmed.startswith('-injars'):
462 raise Exception("Unexpected -injars found in " + pgconf)
463 elif trimmed.startswith('-libraryjars'):
464 raise Exception("Unexpected -libraryjars found in " + pgconf)
465
Søren Gjesse80e00482021-04-06 13:17:35 +0200466def should_build(options):
Morten Krogh-Jespersen254805e2022-06-03 09:32:42 +0200467 return not options.no_build
Søren Gjesse80e00482021-04-06 13:17:35 +0200468
Christoffer Quist Adamsen7ff14092021-04-15 11:48:12 +0200469def build_desugared_library_dex(
470 options,
471 quiet,
472 temp,
473 android_java8_libs,
474 desugared_lib_pg_conf,
475 inputs,
476 outdir):
477 if not inputs:
478 raise Exception(
479 "If 'android_java8_libs' is specified the inputs must be explicit"
480 + "(not defined using '-injars' in Proguard configuration files)")
Søren Gjesse80e00482021-04-06 13:17:35 +0200481 if outdir.endswith('.zip') or outdir.endswith('.jar'):
Christoffer Quist Adamsen7ff14092021-04-15 11:48:12 +0200482 raise Exception(
483 "If 'android_java8_libs' is specified the output must be a directory")
Søren Gjesse80e00482021-04-06 13:17:35 +0200484
485 jar = None
486 main = None
487 if options.hash:
488 jar = os.path.join(utils.LIBS, 'r8-' + options.hash + '.jar')
Christoffer Quist Adamsen7ff14092021-04-15 11:48:12 +0200489 main = 'com.android.tools.r8.R8'
Søren Gjesse80e00482021-04-06 13:17:35 +0200490
Christoffer Quist Adamsen7ff14092021-04-15 11:48:12 +0200491 # Determine the l8 tool.
Søren Gjesse80e00482021-04-06 13:17:35 +0200492 assert(options.compiler_build in ['full', 'lib'])
493 lib_prefix = 'r8lib-' if options.compiler_build == 'lib' else ''
Christoffer Quist Adamsen7ff14092021-04-15 11:48:12 +0200494 tool = lib_prefix + 'l8'
Søren Gjesse80e00482021-04-06 13:17:35 +0200495
Christoffer Quist Adamsen7ff14092021-04-15 11:48:12 +0200496 # Prepare out directory.
Søren Gjesse80e00482021-04-06 13:17:35 +0200497 android_java8_libs_output = os.path.join(temp, 'android_java8_libs')
498 os.makedirs(android_java8_libs_output)
Christoffer Quist Adamsen7ff14092021-04-15 11:48:12 +0200499
500 # Prepare arguments for L8.
Søren Gjesse80e00482021-04-06 13:17:35 +0200501 args = [
Christoffer Quist Adamsen7ff14092021-04-15 11:48:12 +0200502 '--desugared-lib', android_java8_libs['config'],
503 '--lib', android_java8_libs['library'],
Søren Gjesse80e00482021-04-06 13:17:35 +0200504 '--output', android_java8_libs_output,
Christoffer Quist Adamsen7ff14092021-04-15 11:48:12 +0200505 '--pg-conf', desugared_lib_pg_conf,
506 '--release',
Søren Gjesse80e00482021-04-06 13:17:35 +0200507 ]
Christoffer Quist Adamsen7ff14092021-04-15 11:48:12 +0200508 if 'pgconf' in android_java8_libs:
509 for pgconf in android_java8_libs['pgconf']:
510 args.extend(['--pg-conf', pgconf])
511 args.extend(android_java8_libs['program'])
512
513 # Run L8.
514 exit_code = toolhelper.run(
515 tool, args,
Søren Gjesse80e00482021-04-06 13:17:35 +0200516 build=should_build(options),
517 debug=not options.no_debug,
518 quiet=quiet,
519 jar=jar,
520 main=main)
Christoffer Quist Adamsen7ff14092021-04-15 11:48:12 +0200521
Søren Gjesse80e00482021-04-06 13:17:35 +0200522 # Copy the desugared library DEX to the output.
Christoffer Quist Adamsen7ff14092021-04-15 11:48:12 +0200523 dex_file_name = (
524 'classes' + str(len(glob(os.path.join(outdir, '*.dex'))) + 1) + '.dex')
Søren Gjesse80e00482021-04-06 13:17:35 +0200525 shutil.copyfile(
526 os.path.join(android_java8_libs_output, 'classes.dex'),
527 os.path.join(outdir, dex_file_name))
528
Christoffer Quist Adamsen65ef2982023-08-24 08:45:39 +0200529def run_with_options(
530 options, args, extra_args=None, stdout=None, quiet=False, worker_id=None):
Morten Krogh-Jespersen94a9b102019-11-01 09:45:44 +0000531 if extra_args is None:
532 extra_args = []
Rico Windb57bbc12018-09-20 19:23:32 +0200533 app_provided_pg_conf = False;
Rico Windadd08132018-12-14 14:17:15 +0100534 # todo(121018500): remove when memory is under control
Rico Wind20602b72019-01-09 09:17:13 +0100535 if not any('-Xmx' in arg for arg in extra_args):
Morten Krogh-Jespersen322c2f12019-10-08 10:41:21 +0200536 if options.max_memory:
537 extra_args.append('-Xmx%sM' % options.max_memory)
538 else:
539 extra_args.append('-Xmx8G')
Rico Windafdbbfd2019-02-22 09:32:07 +0100540 if not options.ignore_java_version:
541 utils.check_java_version()
542
Søren Gjesse04a94332020-01-27 15:35:42 +0100543 if options.print_times:
544 extra_args.append('-Dcom.android.tools.r8.printtimes=1')
545
Morten Krogh-Jespersena565f012021-07-13 13:27:41 +0200546 if not options.no_debug:
547 extra_args.append('-Dcom.android.tools.r8.enableTestAssertions=1')
548
Mads Ager418d1ca2017-05-22 09:35:49 +0200549 outdir = options.out
Morten Krogh-Jespersen0981b722019-10-09 10:00:33 +0200550 (version_id, data) = get_version_and_data(options)
551
Tamas Kenez5b1c5852017-07-21 13:38:33 +0200552 if options.compiler not in COMPILERS:
553 raise Exception("You need to specify '--compiler={}'"
554 .format('|'.join(COMPILERS)))
Mads Ager418d1ca2017-05-22 09:35:49 +0200555
Tamas Kenez63a51d02019-01-07 15:53:02 +0100556 if options.compiler_build not in COMPILER_BUILDS:
557 raise Exception("You need to specify '--compiler-build={}'"
558 .format('|'.join(COMPILER_BUILDS)))
559
Morten Krogh-Jespersen0981b722019-10-09 10:00:33 +0200560 if not version_id in data.VERSIONS.keys():
Tamas Kenezfc34cd82017-07-13 12:43:57 +0200561 print('No version {} for application {}'
Morten Krogh-Jespersen0981b722019-10-09 10:00:33 +0200562 .format(version_id, options.app))
Tamas Kenezfc34cd82017-07-13 12:43:57 +0200563 print('Valid versions are {}'.format(data.VERSIONS.keys()))
Mads Ager418d1ca2017-05-22 09:35:49 +0200564 return 1
565
Morten Krogh-Jespersen0981b722019-10-09 10:00:33 +0200566 version = data.VERSIONS[version_id]
Mads Ager418d1ca2017-05-22 09:35:49 +0200567
Morten Krogh-Jespersen0981b722019-10-09 10:00:33 +0200568 type = get_type(options)
Tamas Kenez3fdaabd2017-06-15 13:05:12 +0200569
Morten Krogh-Jespersen0981b722019-10-09 10:00:33 +0200570 if type not in version:
571 print('No type {} for version {}'.format(type, version))
Tamas Kenezfc34cd82017-07-13 12:43:57 +0200572 print('Valid types are {}'.format(version.keys()))
Mads Ager418d1ca2017-05-22 09:35:49 +0200573 return 1
Morten Krogh-Jespersen0981b722019-10-09 10:00:33 +0200574 values = version[type]
Mads Ager418d1ca2017-05-22 09:35:49 +0200575
576 args.extend(['--output', outdir])
Ian Zerny877c1862017-07-06 11:12:26 +0200577 if 'min-api' in values:
578 args.extend(['--min-api', values['min-api']])
Søren Gjesse932881f2017-06-13 10:43:36 +0200579
Søren Gjesse8ae55eb2018-09-28 11:11:36 +0200580 if 'main-dex-list' in values:
581 args.extend(['--main-dex-list', values['main-dex-list']])
582
Christoffer Quist Adamsene7273022021-04-12 07:42:07 +0200583 inputs = values['inputs']
Søren Gjesse94793ca2019-11-08 13:53:08 +0100584 libraries = values['libraries'] if 'libraries' in values else []
Christoffer Quist Adamsene7273022021-04-12 07:42:07 +0200585
Tamas Kenez63a51d02019-01-07 15:53:02 +0100586 if options.compiler == 'r8':
Søren Gjesse932881f2017-06-13 10:43:36 +0200587 if 'pgconf' in values and not options.k:
Christoffer Quist Adamsen65ef2982023-08-24 08:45:39 +0200588 sanitized_lib_path = os.path.join(
589 os.path.abspath(outdir), 'sanitized_lib.jar')
Søren Gjesse94793ca2019-11-08 13:53:08 +0100590 if has_injars_and_libraryjars(values['pgconf']):
Søren Gjesse889e09d2019-11-07 16:33:51 +0100591 sanitized_pgconf_path = os.path.join(
592 os.path.abspath(outdir), 'sanitized.config')
593 SanitizeLibrariesInPgconf(
594 sanitized_lib_path, sanitized_pgconf_path, values['pgconf'])
Søren Gjesse94793ca2019-11-08 13:53:08 +0100595 libraries = [sanitized_lib_path]
Søren Gjesse889e09d2019-11-07 16:33:51 +0100596 args.extend(['--pg-conf', sanitized_pgconf_path])
Christoffer Quist Adamsene7273022021-04-12 07:42:07 +0200597 inputs = []
Søren Gjesse94793ca2019-11-08 13:53:08 +0100598 else:
599 # -injars without -libraryjars or vice versa is not supported.
600 check_no_injars_and_no_libraryjars(values['pgconf'])
601 for pgconf in values['pgconf']:
602 args.extend(['--pg-conf', pgconf])
603 if 'sanitize_libraries' in values and values['sanitize_libraries']:
Søren Gjesse94793ca2019-11-08 13:53:08 +0100604 SanitizeLibraries(
605 sanitized_lib_path, values['libraries'], values['inputs'])
606 libraries = [sanitized_lib_path]
Søren Gjessecbeae782019-05-21 14:14:25 +0200607 app_provided_pg_conf = True
Rico Wind51f0bb22021-09-09 09:57:42 +0200608 if 'pgconf_extra' in values:
609 extra_conf = os.path.join(os.path.abspath(outdir), 'pgconf_extra')
610 with open(extra_conf, 'w') as extra_f:
611 extra_f.write(values['pgconf_extra'])
612 args.extend(['--pg-conf', extra_conf])
Søren Gjesse932881f2017-06-13 10:43:36 +0200613 if options.k:
614 args.extend(['--pg-conf', options.k])
Søren Gjessec801ecc2017-08-03 13:40:06 +0200615 if 'maindexrules' in values:
616 for rules in values['maindexrules']:
617 args.extend(['--main-dex-rules', rules])
Rico Wind79e4eb52018-12-13 13:00:49 +0100618 if 'allow-type-errors' in values:
619 extra_args.append('-Dcom.android.tools.r8.allowTypeErrors=1')
Christoffer Quist Adamsen57254f02020-05-18 15:43:58 +0200620 extra_args.append(
621 '-Dcom.android.tools.r8.disallowClassInlinerGracefulExit=1')
Christoffer Quist Adamsen62fcc152022-06-03 14:01:35 +0200622 if 'system-properties' in values:
623 for system_property in values['system-properties']:
624 extra_args.append(system_property)
Søren Gjesse932881f2017-06-13 10:43:36 +0200625
Ian Zerny016d6f62020-03-19 08:58:21 +0100626 if options.debug_agent:
627 if not options.compiler_build == 'full':
628 print('WARNING: Running debugging agent on r8lib is questionable...')
629 extra_args.append(
630 '-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=*:5005')
631
Søren Gjesse94793ca2019-11-08 13:53:08 +0100632 if not options.no_libraries:
633 for lib in libraries:
Mads Ager418d1ca2017-05-22 09:35:49 +0200634 args.extend(['--lib', lib])
635
Tamas Kenezfc34cd82017-07-13 12:43:57 +0200636 if not outdir.endswith('.zip') and not outdir.endswith('.jar') \
637 and not os.path.exists(outdir):
Mads Ager418d1ca2017-05-22 09:35:49 +0200638 os.makedirs(outdir)
639
Christoffer Quist Adamsen870fa462020-12-15 10:50:54 +0100640 if options.hash:
641 # Download r8-<hash>.jar from
642 # https://storage.googleapis.com/r8-releases/raw/<hash>/.
643 download_path = archive.GetUploadDestination(options.hash, 'r8.jar', True)
644 assert utils.file_exists_on_cloud_storage(download_path), (
645 'Could not find r8.jar file from provided hash: %s' % options.hash)
646 destination = os.path.join(utils.LIBS, 'r8-' + options.hash + '.jar')
647 utils.download_file_from_cloud_storage(
648 download_path, destination, quiet=quiet)
649
Søren Gjesse8ae55eb2018-09-28 11:11:36 +0200650 # Additional flags for the compiler from the configuration file.
651 if 'flags' in values:
652 args.extend(values['flags'].split(' '))
Tamas Kenez63a51d02019-01-07 15:53:02 +0100653 if options.compiler == 'r8':
Søren Gjesse932881f2017-06-13 10:43:36 +0200654 if 'r8-flags' in values:
655 args.extend(values['r8-flags'].split(' '))
Tamas Kenez139acc12017-06-14 17:14:58 +0200656
Søren Gjesse8ae55eb2018-09-28 11:11:36 +0200657 # Additional flags for the compiler from the command line.
Tamas Kenez139acc12017-06-14 17:14:58 +0200658 if options.compiler_flags:
659 args.extend(options.compiler_flags.split(' '))
660 if options.r8_flags:
661 args.extend(options.r8_flags.split(' '))
Mads Ager418d1ca2017-05-22 09:35:49 +0200662
Christoffer Quist Adamsen287c1862020-05-20 15:51:12 +0200663 # Feature jars.
664 features = values['features'] if 'features' in values else []
665 for i, feature in enumerate(features, start=1):
666 feature_out = os.path.join(outdir, 'feature-%d.zip' % i)
667 for feature_jar in feature['inputs']:
668 args.extend(['--feature', feature_jar, feature_out])
669
Søren Gjesse94793ca2019-11-08 13:53:08 +0100670 args.extend(inputs)
Mads Ager418d1ca2017-05-22 09:35:49 +0200671
Morten Krogh-Jespersen89e19012021-10-05 09:55:01 +0200672 t0 = None
Mads Ager418d1ca2017-05-22 09:35:49 +0200673 if options.dump_args_file:
674 with open(options.dump_args_file, 'w') as args_file:
675 args_file.writelines([arg + os.linesep for arg in args])
676 else:
Tamas Kenezfc34cd82017-07-13 12:43:57 +0200677 with utils.TempDir() as temp:
678 if options.print_memoryuse and not options.track_memory_to_file:
679 options.track_memory_to_file = os.path.join(temp,
680 utils.MEMORY_USE_TMP_FILE)
Tamas Kenez63a51d02019-01-07 15:53:02 +0100681 if options.compiler == 'r8' and app_provided_pg_conf:
Mathias Ravdd6a6de2018-05-18 10:18:33 +0200682 # Ensure that output of -printmapping and -printseeds go to the output
683 # location and not where the app Proguard configuration places them.
684 if outdir.endswith('.zip') or outdir.endswith('.jar'):
685 pg_outdir = os.path.dirname(outdir)
686 else:
687 pg_outdir = outdir
Christoffer Quist Adamsen3bbb50e2020-05-19 15:00:00 +0200688 if not options.no_extra_pgconf:
689 additional_pg_conf = GenerateAdditionalProguardConfiguration(
690 temp, os.path.abspath(pg_outdir))
691 args.extend(['--pg-conf', additional_pg_conf])
Christoffer Quist Adamsen7ff14092021-04-15 11:48:12 +0200692
693 android_java8_libs = values.get('android_java8_libs')
694 if android_java8_libs:
695 desugared_lib_pg_conf = os.path.join(
696 temp, 'desugared-lib-pg-conf.txt')
697 args.extend(['--desugared-lib', android_java8_libs['config']])
698 args.extend(
699 ['--desugared-lib-pg-conf-output', desugared_lib_pg_conf])
700
Rico Wind5fdec152018-12-17 09:16:14 +0100701 stderr_path = os.path.join(temp, 'stderr')
702 with open(stderr_path, 'w') as stderr:
Christoffer Quist Adamsen870fa462020-12-15 10:50:54 +0100703 jar = None
704 main = None
Tamas Kenez63a51d02019-01-07 15:53:02 +0100705 if options.compiler_build == 'full':
706 tool = options.compiler
707 else:
708 assert(options.compiler_build == 'lib')
709 tool = 'r8lib-' + options.compiler
Christoffer Quist Adamsen870fa462020-12-15 10:50:54 +0100710 if options.hash:
711 jar = os.path.join(utils.LIBS, 'r8-' + options.hash + '.jar')
712 main = 'com.android.tools.r8.' + options.compiler.upper()
Morten Krogh-Jespersen89e19012021-10-05 09:55:01 +0200713 if should_build(options):
714 gradle.RunGradle(['r8lib' if tool.startswith('r8lib') else 'r8'])
715 t0 = time.time()
Tamas Kenez63a51d02019-01-07 15:53:02 +0100716 exit_code = toolhelper.run(tool, args,
Morten Krogh-Jespersen89e19012021-10-05 09:55:01 +0200717 build=False,
Rico Wind5fdec152018-12-17 09:16:14 +0100718 debug=not options.no_debug,
719 profile=options.profile,
720 track_memory_file=options.track_memory_to_file,
Jinseong Jeon158a3f12019-02-08 01:40:59 -0800721 extra_args=extra_args,
Morten Krogh-Jespersenae9557c2019-10-23 15:14:02 +0200722 stdout=stdout,
Jinseong Jeon158a3f12019-02-08 01:40:59 -0800723 stderr=stderr,
Morten Krogh-Jespersenae9557c2019-10-23 15:14:02 +0200724 timeout=options.timeout,
Søren Gjesse943389f2020-03-13 10:40:25 +0100725 quiet=quiet,
Morten Krogh-Jespersen0e4d7e22020-03-14 00:56:32 +0100726 cmd_prefix=[
Christoffer Quist Adamsen870fa462020-12-15 10:50:54 +0100727 'taskset', '-c', options.cpu_list] if options.cpu_list else [],
728 jar=jar,
Christoffer Quist Adamsen65ef2982023-08-24 08:45:39 +0200729 main=main,
730 worker_id=worker_id)
Christoffer Quist Adamsen21c66602018-08-09 16:22:54 +0200731 if exit_code != 0:
Rico Wind5fdec152018-12-17 09:16:14 +0100732 with open(stderr_path) as stderr:
733 stderr_text = stderr.read()
Morten Krogh-Jespersenae9557c2019-10-23 15:14:02 +0200734 if not quiet:
735 print(stderr_text)
Rico Wind5fdec152018-12-17 09:16:14 +0100736 if 'java.lang.OutOfMemoryError' in stderr_text:
Morten Krogh-Jespersenae9557c2019-10-23 15:14:02 +0200737 if not quiet:
738 print('Failure was OOM')
Rico Wind5fdec152018-12-17 09:16:14 +0100739 return OOM_EXIT_CODE
740 return exit_code
Christoffer Quist Adamsen21c66602018-08-09 16:22:54 +0200741
Tamas Kenezfc34cd82017-07-13 12:43:57 +0200742 if options.print_memoryuse:
743 print('{}(MemoryUse): {}'
744 .format(options.print_memoryuse,
745 utils.grep_memoryuse(options.track_memory_to_file)))
Mads Ager418d1ca2017-05-22 09:35:49 +0200746
Christoffer Quist Adamsen7ff14092021-04-15 11:48:12 +0200747 if android_java8_libs:
748 build_desugared_library_dex(
749 options, quiet, temp, android_java8_libs,
750 desugared_lib_pg_conf, inputs, outdir)
Søren Gjesse80e00482021-04-06 13:17:35 +0200751
752
Tamas Kenezf2ee2a32017-06-21 10:30:20 +0200753 if options.print_runtimeraw:
754 print('{}(RunTimeRaw): {} ms'
755 .format(options.print_runtimeraw, 1000.0 * (time.time() - t0)))
756
Tamas Kenez02bff032017-07-18 12:13:58 +0200757 if options.print_dexsegments:
758 dex_files = glob(os.path.join(outdir, '*.dex'))
759 utils.print_dexsegments(options.print_dexsegments, dex_files)
Morten Krogh-Jespersen254805e2022-06-03 09:32:42 +0200760 print('{}-Total(CodeSize): {}'.format(
761 options.print_dexsegments, compute_size_of_dex_files(dex_files)))
Rico Windb57bbc12018-09-20 19:23:32 +0200762 return 0
Tamas Kenez02bff032017-07-18 12:13:58 +0200763
Morten Krogh-Jespersenf4a8f762021-12-22 12:31:21 +0100764def compute_size_of_dex_files(dex_files):
765 dex_size = 0
766 for dex_file in dex_files:
767 dex_size += os.path.getsize(dex_file)
768 return dex_size
769
Mads Ager418d1ca2017-05-22 09:35:49 +0200770if __name__ == '__main__':
Tamas Kenez5b1c5852017-07-21 13:38:33 +0200771 sys.exit(main(sys.argv[1:]))