| #!/usr/bin/env python3 | 
 | # Copyright (c) 2020, the R8 project authors. Please see the AUTHORS file | 
 | # for details. All rights reserved. Use of this source code is governed by a | 
 | # BSD-style license that can be found in the LICENSE file. | 
 |  | 
 | import argparse | 
 | import os | 
 | import shutil | 
 | import subprocess | 
 | import sys | 
 | import time | 
 | import zipfile | 
 |  | 
 | import archive | 
 | import gradle | 
 | import jdk | 
 | import retrace | 
 | import utils | 
 |  | 
 |  | 
 | def make_parser(): | 
 |     parser = argparse.ArgumentParser(description='Compile a dump artifact.') | 
 |     parser.add_argument('--summary', | 
 |                         help='List a summary of the contents of the dumps.', | 
 |                         default=False, | 
 |                         action='store_true') | 
 |     parser.add_argument('-d', | 
 |                         '--dump', | 
 |                         help='Dump file or directory to compile', | 
 |                         default=None) | 
 |     parser.add_argument('-o', | 
 |                         '--output', | 
 |                         help='File to output (defaults to out.jar in temp)', | 
 |                         default=None) | 
 |     parser.add_argument( | 
 |         '--temp', | 
 |         help= | 
 |         'Temp directory to extract the dump to, allows you to rerun the command' | 
 |         ' more easily in the terminal with changes', | 
 |         default=None) | 
 |     parser.add_argument('-c', | 
 |                         '--compiler', | 
 |                         help='Compiler to use', | 
 |                         default=None) | 
 |     parser.add_argument('--minify', | 
 |                         help='Force enable/disable minification' | 
 |                         ' (defaults to app proguard config)', | 
 |                         choices=['default', 'force-enable', 'force-disable'], | 
 |                         default='default') | 
 |     parser.add_argument('--optimize', | 
 |                         help='Force enable/disable optimizations' | 
 |                         ' (defaults to app proguard config)', | 
 |                         choices=['default', 'force-enable', 'force-disable'], | 
 |                         default='default') | 
 |     parser.add_argument('--shrink', | 
 |                         help='Force enable/disable shrinking' | 
 |                         ' (defaults to app proguard config)', | 
 |                         choices=['default', 'force-enable', 'force-disable'], | 
 |                         default='default') | 
 |     parser.add_argument( | 
 |         '-v', | 
 |         '--version', | 
 |         help='Compiler version to use (default read from dump version file).' | 
 |         'Valid arguments are:' | 
 |         '  "main" to run from your own tree,' | 
 |         '  "source" to run from build classes directly,' | 
 |         '  "X.Y.Z" to run a specific version, or' | 
 |         '  <hash> to run that hash from main.', | 
 |         default=None) | 
 |     parser.add_argument('--r8-jar', help='Path to an R8 jar.', default=None) | 
 |     parser.add_argument('--r8-flags', | 
 |                         '--r8_flags', | 
 |                         help='Additional option(s) for the compiler.') | 
 |     parser.add_argument('--pg-conf', | 
 |                         '--pg_conf', | 
 |                         help='Keep rule file(s).', | 
 |                         action='append') | 
 |     parser.add_argument('--override', | 
 |                         help='Do not override any extracted dump in temp-dir', | 
 |                         default=False, | 
 |                         action='store_true') | 
 |     parser.add_argument( | 
 |         '--nolib', | 
 |         help='Use the non-lib distribution (default uses the lib distribution)', | 
 |         default=False, | 
 |         action='store_true') | 
 |     parser.add_argument('--print-times', | 
 |                         help='Print timing information from r8', | 
 |                         default=False, | 
 |                         action='store_true') | 
 |     parser.add_argument( | 
 |         '--disable-assertions', | 
 |         '--disable_assertions', | 
 |         '-da', | 
 |         help= | 
 |         'Disable Java assertions when running the compiler (default enabled)', | 
 |         default=False, | 
 |         action='store_true') | 
 |     parser.add_argument( | 
 |         '--enable-test-assertions', | 
 |         '--enable_test_assertions', | 
 |         help= | 
 |         'Enable additional test assertions when running the compiler (default disabled)', | 
 |         default=False, | 
 |         action='store_true') | 
 |     parser.add_argument('--java-opts', | 
 |                         '--java-opts', | 
 |                         '-J', | 
 |                         metavar='<JVM argument(s)>', | 
 |                         default=[], | 
 |                         action='append', | 
 |                         help='Additional options to pass to JVM invocation') | 
 |     parser.add_argument('--classfile', | 
 |                         help='Run with classfile output', | 
 |                         default=False, | 
 |                         action='store_true') | 
 |     parser.add_argument( | 
 |         '--debug-agent', | 
 |         help= | 
 |         'Enable Java debug agent and suspend compilation (default disabled)', | 
 |         default=False, | 
 |         action='store_true') | 
 |     parser.add_argument('--xmx', | 
 |                         help='Set JVM max heap size (-Xmx)', | 
 |                         default=None) | 
 |     parser.add_argument('--threads', | 
 |                         help='Set the number of threads to use', | 
 |                         default=None) | 
 |     parser.add_argument( | 
 |         '--min-api', | 
 |         help='Set min-api (default read from dump properties file)', | 
 |         default=None) | 
 |     parser.add_argument('--desugared-lib', | 
 |                         help='Set desugared-library (default set from dump)', | 
 |                         default=None) | 
 |     parser.add_argument( | 
 |         '--disable-desugared-lib', | 
 |         help='Disable desugared-libary if it will be set from dump', | 
 |         default=False, | 
 |         action='store_true') | 
 |     parser.add_argument('--loop', | 
 |                         help='Run the compilation in a loop', | 
 |                         default=False, | 
 |                         action='store_true') | 
 |     parser.add_argument('--enable-missing-library-api-modeling', | 
 |                         help='Run with api modeling', | 
 |                         default=False, | 
 |                         action='store_true') | 
 |     parser.add_argument('--android-platform-build', | 
 |                         help='Run as a platform build', | 
 |                         default=False, | 
 |                         action='store_true') | 
 |     parser.add_argument('--optimized-resource-shrinking', | 
 |                         help='Use optimized resource shrinking', | 
 |                         default=False, | 
 |                         action='store_true') | 
 |     parser.add_argument('--compilation-mode', | 
 |                         '--compilation_mode', | 
 |                         help='Run compilation in specified mode', | 
 |                         choices=['debug', 'release'], | 
 |                         default=None) | 
 |     parser.add_argument( | 
 |         '--ignore-features', | 
 |         help="Don't split into features when features are present." | 
 |         ' Instead include feature code in main app output.' | 
 |         ' This is always the case when compiler is d8.', | 
 |         default=False, | 
 |         action='store_true') | 
 |     parser.add_argument('--no-build', | 
 |                         help="Don't build when using --version main", | 
 |                         default=False, | 
 |                         action='store_true') | 
 |     parser.add_argument('--print-runtimeraw', | 
 |                         metavar='BENCHMARKNAME', | 
 |                         help='Print the line \'<BENCHMARKNAME>(RunTimeRaw):' + | 
 |                         ' <elapsed> ms\' at the end where <elapsed> is' + | 
 |                         ' the elapsed time in milliseconds.') | 
 |     return parser | 
 |  | 
 |  | 
 | def error(msg): | 
 |     print(msg) | 
 |     sys.exit(1) | 
 |  | 
 |  | 
 | class Dump(object): | 
 |  | 
 |     def __init__(self, directory): | 
 |         self.directory = directory | 
 |  | 
 |     def if_exists(self, name): | 
 |         f = os.path.join(self.directory, name) | 
 |         if os.path.exists(f): | 
 |             return f | 
 |         return None | 
 |  | 
 |     def program_jar(self): | 
 |         return self.if_exists('program.jar') | 
 |  | 
 |     def feature_jars(self): | 
 |         feature_jars = [] | 
 |         i = 1 | 
 |         while True: | 
 |             feature_jar = self.if_exists('feature-%s.jar' % i) | 
 |             feature_res = self.if_exists('feature-%s.ap_' % i) | 
 |             if feature_jar or feature_res: | 
 |                 # We can have either jar, res or both. | 
 |                 input_string = feature_jar | 
 |                 if feature_res: | 
 |                    input_string = '%s:%s' % ( | 
 |                        feature_jar if feature_jar else '', feature_res) | 
 |                 feature_jars.append(input_string) | 
 |                 i = i + 1 | 
 |             else: | 
 |                 return feature_jars | 
 |  | 
 |     def library_jar(self): | 
 |         return self.if_exists('library.jar') | 
 |  | 
 |     def classpath_jar(self): | 
 |         return self.if_exists('classpath.jar') | 
 |  | 
 |     def desugared_library_json(self): | 
 |         return self.if_exists('desugared-library.json') | 
 |  | 
 |     def proguard_input_map(self): | 
 |         if self.if_exists('proguard_input.config'): | 
 |             print("Unimplemented: proguard_input configuration.") | 
 |  | 
 |     def main_dex_list_resource(self): | 
 |         return self.if_exists('main-dex-list.txt') | 
 |  | 
 |     def main_dex_rules_resource(self): | 
 |         return self.if_exists('main-dex-rules.txt') | 
 |  | 
 |     def resource_ap_file(self): | 
 |         return self.if_exists('app-res.ap_') | 
 |  | 
 |     def art_profile_resources(self): | 
 |         art_profile_resources = [] | 
 |         while True: | 
 |             current_art_profile_index = len(art_profile_resources) + 1 | 
 |             art_profile_resource = self.if_exists('art-profile-%s.txt' % | 
 |                                                   current_art_profile_index) | 
 |             if art_profile_resource is None: | 
 |                 return art_profile_resources | 
 |             art_profile_resources.append(art_profile_resource) | 
 |  | 
 |     def startup_profile_resources(self): | 
 |         startup_profile_resources = [] | 
 |         while True: | 
 |             current_startup_profile_index = len(startup_profile_resources) + 1 | 
 |             startup_profile_resource = self.if_exists( | 
 |                 'startup-profile-%s.txt' % current_startup_profile_index) | 
 |             if startup_profile_resource is None: | 
 |                 return startup_profile_resources | 
 |             startup_profile_resources.append(startup_profile_resource) | 
 |  | 
 |     def build_properties_file(self): | 
 |         return self.if_exists('build.properties') | 
 |  | 
 |     def config_file(self): | 
 |         return self.if_exists('proguard.config') | 
 |  | 
 |     def r8_include_file(self): | 
 |         return self.if_exists('r8-include.txt') | 
 |  | 
 |     def r8_exclude_file(self): | 
 |         return self.if_exists('r8-exclude.txt') | 
 |  | 
 |     def version_file(self): | 
 |         return self.if_exists('r8-version') | 
 |  | 
 |     def version(self): | 
 |         f = self.version_file() | 
 |         if f: | 
 |             return open(f).read().split(' ')[0] | 
 |         return None | 
 |  | 
 |  | 
 | def read_dump_from_args(args, temp): | 
 |     if args.dump is None: | 
 |         error("A dump file or directory must be specified") | 
 |     return read_dump(args.dump, temp, args.override) | 
 |  | 
 |  | 
 | def read_dump(dump, temp, override=False): | 
 |     if os.path.isdir(dump): | 
 |         return Dump(dump) | 
 |     dump_file = zipfile.ZipFile(os.path.abspath(dump), 'r') | 
 |     r8_version_file = os.path.join(temp, 'r8-version') | 
 |  | 
 |     if override or not os.path.isfile(r8_version_file): | 
 |         dump_file.extractall(temp) | 
 |         if not os.path.isfile(r8_version_file): | 
 |             error( | 
 |                 "Did not extract into %s. Either the zip file is invalid or the " | 
 |                 "dump is missing files" % temp) | 
 |     return Dump(temp) | 
 |  | 
 |  | 
 | def determine_build_properties(args, dump): | 
 |     build_properties = {} | 
 |     build_properties_file = dump.build_properties_file() | 
 |     if build_properties_file: | 
 |         with open(build_properties_file) as f: | 
 |             build_properties_contents = f.readlines() | 
 |             for line in build_properties_contents: | 
 |                 stripped = line.strip() | 
 |                 if stripped: | 
 |                     pair = stripped.split('=') | 
 |                     build_properties[pair[0]] = pair[1] | 
 |         if 'mode' not in build_properties: | 
 |             build_properties['mode'] = 'release' | 
 |     return build_properties | 
 |  | 
 |  | 
 | def determine_version(args, dump): | 
 |     if args.version is None: | 
 |         return dump.version() | 
 |     return args.version | 
 |  | 
 |  | 
 | def determine_compiler(args, build_properties): | 
 |     compilers = ['d8', 'r8', 'r8full', 'l8', 'l8d8', 'tracereferences'] | 
 |     compiler = args.compiler | 
 |     if not compiler and 'tool' in build_properties: | 
 |         compiler = build_properties.get('tool').lower() | 
 |         if compiler == 'r8': | 
 |             if not 'force-proguard-compatibility' in build_properties: | 
 |                 error( | 
 |                     "Unable to determine R8 compiler variant from build.properties." | 
 |                     " No value for 'force-proguard-compatibility'.") | 
 |             if build_properties.get( | 
 |                     'force-proguard-compatibility').lower() == 'false': | 
 |                 compiler = 'r8full' | 
 |         elif compiler == 'r8partial': | 
 |             compiler = 'r8full' | 
 |         elif compiler == 'TraceReferences': | 
 |             compiler = build_properties.get('tool').lower() | 
 |     if compiler not in compilers: | 
 |         error("Unable to determine a compiler to use. Specified %s," | 
 |               " Valid options: %s" % (args.compiler, ', '.join(compilers))) | 
 |     return compiler | 
 |  | 
 |  | 
 | def determine_isolated_splits(build_properties, feature_jars): | 
 |     if feature_jars and 'isolated-splits' in build_properties: | 
 |         isolated_splits = build_properties.get('isolated-splits') | 
 |         assert isolated_splits == 'true' or isolated_splits == 'false' | 
 |         return isolated_splits == 'true' | 
 |     return None | 
 |  | 
 |  | 
 | def determine_trace_references_commands(build_properties, output): | 
 |     trace_ref_consumer = build_properties.get('trace_references_consumer') | 
 |     if trace_ref_consumer == 'com.android.tools.r8.tracereferences.TraceReferencesCheckConsumer': | 
 |         return ["--check"] | 
 |     else: | 
 |         assert trace_ref_consumer == 'com.android.tools.r8.tracereferences.TraceReferencesKeepRules' | 
 |         args = ['--allowobfuscation' | 
 |                ] if build_properties.get('minification') == 'true' else [] | 
 |         args.extend(['--keep-rules', '--output', output]) | 
 |         return args | 
 |  | 
 |  | 
 | def is_l8_compiler(compiler): | 
 |     return compiler.startswith('l8') | 
 |  | 
 |  | 
 | def is_r8_compiler(compiler): | 
 |     return compiler.startswith('r8') | 
 |  | 
 |  | 
 | def determine_config_files(args, dump, temp): | 
 |     if args.pg_conf: | 
 |         config_files = [] | 
 |         for config_file in args.pg_conf: | 
 |             dst = os.path.join(temp, 'proguard-%s.config' % len(config_files)) | 
 |             shutil.copyfile(config_file, dst) | 
 |             config_files.append(dst) | 
 |         return config_files | 
 |     dump_config_file = dump.config_file() | 
 |     if dump_config_file: | 
 |         return [dump_config_file] | 
 |     return [] | 
 |  | 
 |  | 
 | def determine_output(args, temp): | 
 |     if (args.output): | 
 |         return args.output | 
 |     return os.path.join(temp, 'out.jar') | 
 |  | 
 |  | 
 | def determine_min_api(args, build_properties): | 
 |     if args.min_api: | 
 |         return args.min_api | 
 |     if 'min-api' in build_properties: | 
 |         return build_properties.get('min-api') | 
 |     return None | 
 |  | 
 |  | 
 | def determine_residual_art_profile_output(art_profile, temp): | 
 |     return os.path.join(temp, os.path.basename(art_profile)[:-4] + ".out.txt") | 
 |  | 
 |  | 
 | def determine_desugared_lib_pg_conf_output(temp): | 
 |     return os.path.join(temp, 'desugared-library-keep-rules.config') | 
 |  | 
 | def output_name(input_name, suffix): | 
 |     return os.path.basename(input_name)[:-4] + ".out" + suffix | 
 |  | 
 |  | 
 | def determine_feature_output(feature_input, temp): | 
 |     output_exists = args.output and os.path.isdir(args.output) | 
 |     base_path = args.output if output_exists else temp | 
 |     if ":" in feature_input: | 
 |         split = feature_input.split(':') | 
 |         feature_jar = '' if len(split[0]) == 0 else os.path.join( | 
 |             base_path, output_name(split[0], '.jar')) | 
 |         feature_res = os.path.join(base_path, output_name(split[1], '.ap_')) | 
 |         return '%s:%s' % (feature_jar, feature_res) | 
 |     return os.path.join(base_path, output_name(feature_input, '.jar')) | 
 |  | 
 |  | 
 | def determine_program_jar(args, dump): | 
 |     if hasattr(args, 'program_jar') and args.program_jar: | 
 |         return args.program_jar | 
 |     return dump.program_jar() | 
 |  | 
 |  | 
 | def determine_class_file(args, build_properties): | 
 |     return args.classfile \ | 
 |         or build_properties.get('backend', 'dex').lower() == 'cf' | 
 |  | 
 |  | 
 | def determine_android_platform_build(args, build_properties): | 
 |     if args.android_platform_build: | 
 |         return True | 
 |     return build_properties.get('android-platform-build') == 'true' | 
 |  | 
 | def determine_optimized_resource_shrinking(args, build_properties): | 
 |     if args.optimized_resource_shrinking: | 
 |         return True | 
 |     return build_properties.get('optimized-resource-shrinking') == 'true' | 
 |  | 
 | def determine_enable_missing_library_api_modeling(args, build_properties): | 
 |     if args.enable_missing_library_api_modeling: | 
 |         return True | 
 |     return build_properties.get('enable-missing-library-api-modeling') == 'true' | 
 |  | 
 |  | 
 | def determine_compilation_mode(args, build_properties): | 
 |     if args.compilation_mode: | 
 |         return args.compilation_mode | 
 |     return build_properties.get('mode') | 
 |  | 
 |  | 
 | def determine_properties(build_properties): | 
 |     args = [] | 
 |     for key, value in build_properties.items(): | 
 |         # When writing dumps all system properties starting with com.android.tools.r8 | 
 |         # are written to the build.properties file in the format | 
 |         # system-property-com.android.tools.r8.XXX=<value> | 
 |         if key.startswith('system-property-'): | 
 |             name = key[len('system-property-'):] | 
 |             if name.endswith('dumpinputtofile') or name.endswith( | 
 |                     'dumpinputtodirectory'): | 
 |                 continue | 
 |             if len(value) == 0: | 
 |                 args.append('-D' + name) | 
 |             else: | 
 |                 args.append('-D' + name + '=' + value) | 
 |     return args | 
 |  | 
 |  | 
 | def download_distribution(version, args, temp): | 
 |     nolib = args.nolib | 
 |     if version == 'main': | 
 |         if not args.no_build: | 
 |             gradle.RunGradle( | 
 |                 [utils.GRADLE_TASK_R8] if nolib else [utils.GRADLE_TASK_R8LIB]) | 
 |         return utils.R8_JAR if nolib else utils.R8LIB_JAR | 
 |     if version == 'source': | 
 |         return '%s:%s' % (utils.BUILD_JAVA_MAIN_DIR, utils.ALL_DEPS_JAR) | 
 |     name = 'r8.jar' if nolib else 'r8lib.jar' | 
 |     source = archive.GetUploadDestination(version, name, is_hash(version)) | 
 |     dest = os.path.join(temp, 'r8.jar') | 
 |     utils.download_file_from_cloud_storage(source, dest) | 
 |     return dest | 
 |  | 
 |  | 
 | def clean_configs(files, args): | 
 |     for file in files: | 
 |         clean_config(file, args) | 
 |  | 
 |  | 
 | def clean_config(file, args): | 
 |     with open(file) as f: | 
 |         lines = f.readlines() | 
 |     minify = args.minify | 
 |     optimize = args.optimize | 
 |     shrink = args.shrink | 
 |     with open(file, 'w') as f: | 
 |         if minify == 'force-disable': | 
 |             print('Adding config line: -dontobfuscate') | 
 |             f.write('-dontobfuscate\n') | 
 |         if optimize == 'force-disable': | 
 |             print('Adding config line: -dontoptimize') | 
 |             f.write('-dontoptimize\n') | 
 |         if shrink == 'force-disable': | 
 |             print('Adding config line: -dontshrink') | 
 |             f.write('-dontshrink\n') | 
 |         for line in lines: | 
 |             if clean_config_line(line, minify, optimize, shrink): | 
 |                 print('Removing from config line: \n%s' % line) | 
 |             else: | 
 |                 f.write(line) | 
 |  | 
 |  | 
 | def clean_config_line(line, minify, optimize, shrink): | 
 |     if line.lstrip().startswith('#'): | 
 |         return False | 
 |     if ('-injars' in line or '-libraryjars' in line or '-print' in line or | 
 |             '-applymapping' in line or '-tracing' in line): | 
 |         return True | 
 |     if minify == 'force-enable' and '-dontobfuscate' in line: | 
 |         return True | 
 |     if optimize == 'force-enable' and '-dontoptimize' in line: | 
 |         return True | 
 |     if shrink == 'force-enable' and '-dontshrink' in line: | 
 |         return True | 
 |     return False | 
 |  | 
 |  | 
 | def compile_reflective_helper(temp, jdkhome): | 
 |     gradle.RunGradle([utils.GRADLE_TASK_MAIN_COMPILE]) | 
 |     base_path = os.path.join( | 
 |         utils.REPO_ROOT, | 
 |         'src/main/java/com/android/tools/r8/utils/compiledump') | 
 |  | 
 |     cmd = [ | 
 |         jdk.GetJavacExecutable(jdkhome), | 
 |         '-d', | 
 |         temp, | 
 |         '-cp', | 
 |         utils.BUILD_JAVA_MAIN_DIR, | 
 |     ] | 
 |     cmd.extend(os.path.join(base_path, f) for f in os.listdir(base_path)) | 
 |     utils.PrintCmd(cmd) | 
 |     subprocess.check_output(cmd) | 
 |  | 
 | def prepare_r8_wrapper(dist, temp, jdkhome): | 
 |     compile_reflective_helper(temp, jdkhome) | 
 |     compile_wrapper_with_javac( | 
 |         dist, temp, jdkhome, | 
 |         os.path.join( | 
 |             utils.REPO_ROOT, | 
 |             'src/main/java/com/android/tools/r8/utils/CompileDumpCompatR8.java') | 
 |     ) | 
 |  | 
 |  | 
 | def prepare_d8_wrapper(dist, temp, jdkhome): | 
 |     compile_reflective_helper(temp, jdkhome) | 
 |     compile_wrapper_with_javac( | 
 |         dist, temp, jdkhome, | 
 |         os.path.join( | 
 |             utils.REPO_ROOT, | 
 |             'src/main/java/com/android/tools/r8/utils/CompileDumpD8.java')) | 
 |  | 
 |  | 
 | def compile_wrapper_with_javac(dist, temp, jdkhome, path): | 
 |     base_path = os.path.join( | 
 |         utils.REPO_ROOT, | 
 |         'src/main/java/com/android/tools/r8/utils/CompileDumpBase.java') | 
 |     cmd = [ | 
 |         jdk.GetJavacExecutable(jdkhome), | 
 |         path, | 
 |         base_path, | 
 |         '-d', | 
 |         temp, | 
 |         '-cp', | 
 |         "%s:%s" % (dist, temp), | 
 |     ] | 
 |     utils.PrintCmd(cmd) | 
 |     subprocess.check_output(cmd) | 
 |  | 
 |  | 
 | def is_hash(version): | 
 |     return len(version) == 40 | 
 |  | 
 |  | 
 | def run1(out, args, otherargs, jdkhome=None, worker_id=None): | 
 |     jvmargs = [] | 
 |     compilerargs = [] | 
 |     for arg in otherargs: | 
 |         if arg.startswith('-D'): | 
 |             jvmargs.append(arg) | 
 |         else: | 
 |             compilerargs.append(arg) | 
 |     with utils.TempDir() as temp: | 
 |         if out: | 
 |             temp = out | 
 |             if not os.path.exists(temp): | 
 |                 os.makedirs(temp) | 
 |         dump = read_dump_from_args(args, temp) | 
 |         if not dump.program_jar(): | 
 |             error("Cannot compile dump with no program classes") | 
 |         if not dump.library_jar(): | 
 |             print("WARNING: Unexpected lack of library classes in dump") | 
 |         build_properties = determine_build_properties(args, dump) | 
 |         version = determine_version(args, dump) | 
 |         compiler = determine_compiler(args, build_properties) | 
 |         config_files = determine_config_files(args, dump, temp) | 
 |         out = determine_output(args, temp) | 
 |         min_api = determine_min_api(args, build_properties) | 
 |         classfile = determine_class_file(args, build_properties) | 
 |         android_platform_build = determine_android_platform_build( | 
 |             args, build_properties) | 
 |         optimized_resource_shrinking = determine_optimized_resource_shrinking( | 
 |             args, build_properties) | 
 |         enable_missing_library_api_modeling = determine_enable_missing_library_api_modeling( | 
 |             args, build_properties) | 
 |         mode = determine_compilation_mode(args, build_properties) | 
 |         jar = args.r8_jar if args.r8_jar else download_distribution( | 
 |             version, args, temp) | 
 |         if ':' not in jar and not os.path.exists(jar): | 
 |             error("Distribution does not exist: " + jar) | 
 |         cmd = [jdk.GetJavaExecutable(jdkhome)] | 
 |         cmd.extend(jvmargs) | 
 |         if args.debug_agent: | 
 |             if not args.nolib: | 
 |                 print( | 
 |                     "WARNING: Running debugging agent on r8lib is questionable..." | 
 |                 ) | 
 |             cmd.append( | 
 |                 '-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=*:5005' | 
 |             ) | 
 |         if args.xmx: | 
 |             cmd.append('-Xmx' + args.xmx) | 
 |         if not args.disable_assertions: | 
 |             cmd.append('-ea') | 
 |         if args.enable_test_assertions: | 
 |             cmd.append('-Dcom.android.tools.r8.enableTestAssertions=1') | 
 |         feature_jars = dump.feature_jars() | 
 |         if args.print_times: | 
 |             cmd.append('-Dcom.android.tools.r8.printtimes=1') | 
 |         if args.r8_flags: | 
 |             cmd.extend(args.r8_flags.split(' ')) | 
 |         if hasattr(args, 'properties'): | 
 |             cmd.extend(args.properties) | 
 |         cmd.extend(determine_properties(build_properties)) | 
 |         cmd.extend(args.java_opts) | 
 |         cmd.extend(['-cp', '%s:%s' % (temp, jar)]) | 
 |         if compiler == 'd8': | 
 |             prepare_d8_wrapper(jar, temp, jdkhome) | 
 |             cmd.append('com.android.tools.r8.utils.CompileDumpD8') | 
 |         if is_l8_compiler(compiler): | 
 |             cmd.append('com.android.tools.r8.L8') | 
 |         if compiler == 'tracereferences': | 
 |             cmd.append('com.android.tools.r8.tracereferences.TraceReferences') | 
 |             cmd.extend( | 
 |                 determine_trace_references_commands(build_properties, out)) | 
 |         if is_r8_compiler(compiler): | 
 |             prepare_r8_wrapper(jar, temp, jdkhome) | 
 |             cmd.append('com.android.tools.r8.utils.CompileDumpCompatR8') | 
 |             if compiler == 'r8': | 
 |                 cmd.append('--compat') | 
 |             elif compiler == 'r8full': | 
 |                 r8_partial_include_file = dump.r8_include_file() | 
 |                 if r8_partial_include_file: | 
 |                     cmd.append('--partial-include') | 
 |                     cmd.append(r8_partial_include_file) | 
 |                     r8_partial_exclude_file = dump.r8_exclude_file() | 
 |                     if r8_partial_exclude_file: | 
 |                         cmd.append('--partial-exclude') | 
 |                         cmd.append(r8_partial_exclude_file) | 
 |         if compiler != 'tracereferences': | 
 |             assert mode == 'debug' or mode == 'release' | 
 |             cmd.append('--' + mode) | 
 |         # For recompilation of dumps run_on_app_dumps pass in a program jar. | 
 |         program_jar = determine_program_jar(args, dump) | 
 |         if compiler != 'tracereferences': | 
 |             cmd.append(program_jar) | 
 |             cmd.extend(['--output', out]) | 
 |         else: | 
 |             cmd.extend(['--source', program_jar]) | 
 |         for feature_jar in feature_jars: | 
 |             if not args.ignore_features and compiler != 'd8': | 
 |                 cmd.extend([ | 
 |                     '--feature-jar', feature_jar, | 
 |                     determine_feature_output(feature_jar, temp) | 
 |                 ]) | 
 |             else: | 
 |                 cmd.append(feature_jar) | 
 |         if determine_isolated_splits(build_properties, feature_jars): | 
 |             cmd.append('--isolated-splits') | 
 |         if dump.library_jar(): | 
 |             cmd.extend(['--lib', dump.library_jar()]) | 
 |         if dump.resource_ap_file(): | 
 |             res_output = os.path.join(temp, 'app-res-out.ap_') | 
 |             cmd.extend(['--android-resources', dump.resource_ap_file(), | 
 |                         res_output]) | 
 |         if dump.classpath_jar() and not is_l8_compiler(compiler): | 
 |             cmd.extend([ | 
 |                 '--target' if compiler == 'tracereferences' else '--classpath', | 
 |                 dump.classpath_jar() | 
 |             ]) | 
 |         if dump.desugared_library_json() and not args.disable_desugared_lib: | 
 |             cmd.extend(['--desugared-lib', dump.desugared_library_json()]) | 
 |             if not is_l8_compiler(compiler): | 
 |                 cmd.extend([ | 
 |                     '--desugared-lib-pg-conf-output', | 
 |                     determine_desugared_lib_pg_conf_output(temp) | 
 |                 ]) | 
 |         if (is_r8_compiler(compiler) or compiler == 'l8') and config_files: | 
 |             if hasattr(args, | 
 |                        'config_files_consumer') and args.config_files_consumer: | 
 |                 args.config_files_consumer(config_files) | 
 |             else: | 
 |                 # If we get a dump from the wild we can't use -injars, -libraryjars or | 
 |                 # -print{mapping,usage} | 
 |                 clean_configs(config_files, args) | 
 |             for config_file in config_files: | 
 |                 cmd.extend(['--pg-conf', config_file]) | 
 |             cmd.extend(['--pg-map-output', '%s.map' % out]) | 
 |         if dump.main_dex_list_resource(): | 
 |             cmd.extend(['--main-dex-list', dump.main_dex_list_resource()]) | 
 |         if dump.main_dex_rules_resource(): | 
 |             cmd.extend(['--main-dex-rules', dump.main_dex_rules_resource()]) | 
 |         for art_profile_resource in dump.art_profile_resources(): | 
 |             residual_art_profile_output = \ | 
 |                 determine_residual_art_profile_output(art_profile_resource, temp) | 
 |             cmd.extend([ | 
 |                 '--art-profile', art_profile_resource, | 
 |                 residual_art_profile_output | 
 |             ]) | 
 |         for startup_profile_resource in dump.startup_profile_resources(): | 
 |             cmd.extend(['--startup-profile', startup_profile_resource]) | 
 |         if min_api: | 
 |             cmd.extend(['--min-api', min_api]) | 
 |         if classfile: | 
 |             cmd.extend(['--classfile']) | 
 |         if android_platform_build: | 
 |             cmd.extend(['--android-platform-build']) | 
 |         if optimized_resource_shrinking: | 
 |             cmd.extend(['--optimized-resource-shrinking']) | 
 |         if enable_missing_library_api_modeling: | 
 |             cmd.extend(['--enable-missing-library-api-modeling']) | 
 |         if args.threads: | 
 |             cmd.extend(['--threads', args.threads]) | 
 |         cmd.extend(compilerargs) | 
 |         utils.PrintCmd(cmd, worker_id=worker_id) | 
 |         try: | 
 |             start = time.time() | 
 |             output = subprocess.check_output(cmd, stderr=subprocess.STDOUT) | 
 |             end = time.time() | 
 |             print(output.decode('utf-8')) | 
 |             if args.print_runtimeraw: | 
 |                 benchmark_name = args.print_runtimeraw | 
 |                 duration = int((end - start) * 1000) | 
 |                 print('') | 
 |                 print('%s(RunTimeRaw): %s ms' % (benchmark_name, duration)) | 
 |             return 0 | 
 |         except subprocess.CalledProcessError as e: | 
 |             if args.nolib \ | 
 |                 or version == 'source' \ | 
 |                 or not try_retrace_output(e, version, temp): | 
 |                 print(e.output.decode('UTF-8')) | 
 |             return 1 | 
 |  | 
 |  | 
 | def try_retrace_output(e, version, temp): | 
 |     try: | 
 |         stacktrace = os.path.join(temp, 'stacktrace') | 
 |         open(stacktrace, 'w+').write(e.output.decode('UTF-8')) | 
 |         print("=" * 80) | 
 |         print(" RETRACED OUTPUT") | 
 |         print("=" * 80) | 
 |         retrace.run(get_map_file(version, temp), | 
 |                     stacktrace, | 
 |                     None, | 
 |                     no_r8lib=False) | 
 |         return True | 
 |     except Exception as e2: | 
 |         print("Failed to retrace for version: %s" % version) | 
 |         print(e2) | 
 |         return False | 
 |  | 
 |  | 
 | def get_map_file(version, temp): | 
 |     if version == 'main': | 
 |         return utils.R8LIB_MAP | 
 |     download_path = archive.GetUploadDestination(version, 'r8lib.jar.map', | 
 |                                                  is_hash(version)) | 
 |     if utils.file_exists_on_cloud_storage(download_path): | 
 |         map_path = os.path.join(temp, 'mapping.map') | 
 |         utils.download_file_from_cloud_storage(download_path, map_path) | 
 |         return map_path | 
 |     else: | 
 |         print('Could not find map file from argument: %s.' % version) | 
 |         return None | 
 |  | 
 |  | 
 | def summarize_dump_files(dumpfiles): | 
 |     if len(dumpfiles) == 0: | 
 |         error('Summary command expects a list of dumps to summarize') | 
 |     for f in dumpfiles: | 
 |         print(f + ':') | 
 |         try: | 
 |             with utils.TempDir() as temp: | 
 |                 dump = read_dump(f, temp) | 
 |                 summarize_dump(dump) | 
 |         except IOError as e: | 
 |             print("Error: " + str(e)) | 
 |         except zipfile.BadZipfile as e: | 
 |             print("Error: " + str(e)) | 
 |  | 
 |  | 
 | def summarize_dump(dump): | 
 |     version = dump.version() | 
 |     if not version: | 
 |         print('No dump version info') | 
 |         return | 
 |     print('version=' + version) | 
 |     props = dump.build_properties_file() | 
 |     if props: | 
 |         with open(props) as props_file: | 
 |             print(props_file.read()) | 
 |     if dump.library_jar(): | 
 |         print('library.jar present') | 
 |     if dump.classpath_jar(): | 
 |         print('classpath.jar present') | 
 |     prog = dump.program_jar() | 
 |     if prog: | 
 |         print('program.jar content:') | 
 |         summarize_jar(prog) | 
 |  | 
 |  | 
 | def summarize_jar(jar): | 
 |     with zipfile.ZipFile(jar) as zip: | 
 |         pkgs = {} | 
 |         for info in zip.infolist(): | 
 |             if info.filename.endswith('.class'): | 
 |                 pkg, clazz = os.path.split(info.filename) | 
 |                 count = pkgs.get(pkg, 0) | 
 |                 pkgs[pkg] = count + 1 | 
 |     sorted = list(pkgs.keys()) | 
 |     sorted.sort() | 
 |     for p in sorted: | 
 |         print('  ' + p + ': ' + str(pkgs[p])) | 
 |  | 
 |  | 
 | def run(args, otherargs): | 
 |     gradle.EnsureJdk() | 
 |     if args.summary: | 
 |         summarize_dump_files(otherargs) | 
 |     elif args.loop: | 
 |         count = 1 | 
 |         while True: | 
 |             print('Iteration {:03d}'.format(count)) | 
 |             out = args.temp | 
 |             if out: | 
 |                 out = os.path.join(out, '{:03d}'.format(count)) | 
 |             run1(out, args, otherargs) | 
 |             count += 1 | 
 |     else: | 
 |         run1(args.temp, args, otherargs) | 
 |  | 
 |  | 
 | if __name__ == '__main__': | 
 |     (args, otherargs) = make_parser().parse_known_args(sys.argv[1:]) | 
 |     sys.exit(run(args, otherargs)) |