1*6777b538SAndroid Build Coastguard Worker#!/usr/bin/env python3 2*6777b538SAndroid Build Coastguard Worker# 3*6777b538SAndroid Build Coastguard Worker# Copyright 2013 The Chromium Authors 4*6777b538SAndroid Build Coastguard Worker# Use of this source code is governed by a BSD-style license that can be 5*6777b538SAndroid Build Coastguard Worker# found in the LICENSE file. 6*6777b538SAndroid Build Coastguard Worker 7*6777b538SAndroid Build Coastguard Workerimport argparse 8*6777b538SAndroid Build Coastguard Workerimport logging 9*6777b538SAndroid Build Coastguard Workerimport os 10*6777b538SAndroid Build Coastguard Workerimport pathlib 11*6777b538SAndroid Build Coastguard Workerimport re 12*6777b538SAndroid Build Coastguard Workerimport shutil 13*6777b538SAndroid Build Coastguard Workerimport sys 14*6777b538SAndroid Build Coastguard Workerimport zipfile 15*6777b538SAndroid Build Coastguard Worker 16*6777b538SAndroid Build Coastguard Workerimport dex 17*6777b538SAndroid Build Coastguard Workerfrom util import build_utils 18*6777b538SAndroid Build Coastguard Workerfrom util import diff_utils 19*6777b538SAndroid Build Coastguard Workerimport action_helpers # build_utils adds //build to sys.path. 20*6777b538SAndroid Build Coastguard Workerimport zip_helpers 21*6777b538SAndroid Build Coastguard Worker 22*6777b538SAndroid Build Coastguard Worker_IGNORE_WARNINGS = ( 23*6777b538SAndroid Build Coastguard Worker # E.g. Triggers for weblayer_instrumentation_test_apk since both it and its 24*6777b538SAndroid Build Coastguard Worker # apk_under_test have no shared_libraries. 25*6777b538SAndroid Build Coastguard Worker # https://crbug.com/1364192 << To fix this in a better way. 26*6777b538SAndroid Build Coastguard Worker r'Missing class org.chromium.build.NativeLibraries', 27*6777b538SAndroid Build Coastguard Worker # Caused by internal protobuf package: https://crbug.com/1183971 28*6777b538SAndroid Build Coastguard Worker r'referenced from: com\.google\.protobuf\.GeneratedMessageLite\$GeneratedExtension', # pylint: disable=line-too-long 29*6777b538SAndroid Build Coastguard Worker # Caused by protobuf runtime using -identifiernamestring in a way that 30*6777b538SAndroid Build Coastguard Worker # doesn't work with R8. Looks like: 31*6777b538SAndroid Build Coastguard Worker # Rule matches the static final field `...`, which may have been inlined... 32*6777b538SAndroid Build Coastguard Worker # com.google.protobuf.*GeneratedExtensionRegistryLite { 33*6777b538SAndroid Build Coastguard Worker # static java.lang.String CONTAINING_TYPE_*; 34*6777b538SAndroid Build Coastguard Worker # } 35*6777b538SAndroid Build Coastguard Worker r'GeneratedExtensionRegistryLite\.CONTAINING_TYPE_', 36*6777b538SAndroid Build Coastguard Worker # Relevant for R8 when optimizing an app that doesn't use protobuf. 37*6777b538SAndroid Build Coastguard Worker r'Ignoring -shrinkunusedprotofields since the protobuf-lite runtime is', 38*6777b538SAndroid Build Coastguard Worker # Ignore Unused Rule Warnings in third_party libraries. 39*6777b538SAndroid Build Coastguard Worker r'/third_party/.*Proguard configuration rule does not match anything', 40*6777b538SAndroid Build Coastguard Worker # Ignore cronet's test rules (low priority to fix). 41*6777b538SAndroid Build Coastguard Worker r'cronet/android/test/proguard.cfg.*Proguard configuration rule does not', 42*6777b538SAndroid Build Coastguard Worker r'Proguard configuration rule does not match anything:.*(?:' + '|'.join([ 43*6777b538SAndroid Build Coastguard Worker # aapt2 generates keeps for these. 44*6777b538SAndroid Build Coastguard Worker r'class android\.', 45*6777b538SAndroid Build Coastguard Worker # Used internally. 46*6777b538SAndroid Build Coastguard Worker r'com.no.real.class.needed.receiver', 47*6777b538SAndroid Build Coastguard Worker # Ignore Unused Rule Warnings for annotations. 48*6777b538SAndroid Build Coastguard Worker r'@', 49*6777b538SAndroid Build Coastguard Worker # Ignore Unused Rule Warnings for * implements Foo (androidx has these). 50*6777b538SAndroid Build Coastguard Worker r'class \*+ implements', 51*6777b538SAndroid Build Coastguard Worker # Ignore rules that opt out of this check. 52*6777b538SAndroid Build Coastguard Worker r'!cr_allowunused', 53*6777b538SAndroid Build Coastguard Worker # https://crbug.com/1441225 54*6777b538SAndroid Build Coastguard Worker r'EditorDialogToolbar', 55*6777b538SAndroid Build Coastguard Worker # https://crbug.com/1441226 56*6777b538SAndroid Build Coastguard Worker r'PaymentRequest[BH]', 57*6777b538SAndroid Build Coastguard Worker ]) + ')', 58*6777b538SAndroid Build Coastguard Worker # TODO(agrieve): Remove once we update to U SDK. 59*6777b538SAndroid Build Coastguard Worker r'OnBackAnimationCallback', 60*6777b538SAndroid Build Coastguard Worker # This class was added only in the U PrivacySandbox SDK: crbug.com/333713111 61*6777b538SAndroid Build Coastguard Worker r'Missing class android.adservices.common.AdServicesOutcomeReceiver', 62*6777b538SAndroid Build Coastguard Worker # We enforce that this class is removed via -checkdiscard. 63*6777b538SAndroid Build Coastguard Worker r'FastServiceLoader\.class:.*Could not inline ServiceLoader\.load', 64*6777b538SAndroid Build Coastguard Worker 65*6777b538SAndroid Build Coastguard Worker # Ignore MethodParameter attribute count isn't matching in espresso. 66*6777b538SAndroid Build Coastguard Worker # This is a banner warning and each individual file affected will have 67*6777b538SAndroid Build Coastguard Worker # its own warning. 68*6777b538SAndroid Build Coastguard Worker r'Warning: Invalid parameter counts in MethodParameter attributes', 69*6777b538SAndroid Build Coastguard Worker r'Warning in obj/third_party/androidx/androidx_test_espresso_espresso_core_java', # pylint: disable=line-too-long 70*6777b538SAndroid Build Coastguard Worker r'Warning in obj/third_party/androidx/androidx_test_espresso_espresso_web_java', # pylint: disable=line-too-long 71*6777b538SAndroid Build Coastguard Worker 72*6777b538SAndroid Build Coastguard Worker # We are following up in b/290389974 73*6777b538SAndroid Build Coastguard Worker r'AppSearchDocumentClassMap\.class:.*Could not inline ServiceLoader\.load', 74*6777b538SAndroid Build Coastguard Worker) 75*6777b538SAndroid Build Coastguard Worker 76*6777b538SAndroid Build Coastguard Worker_BLOCKLISTED_EXPECTATION_PATHS = [ 77*6777b538SAndroid Build Coastguard Worker # A separate expectation file is created for these files. 78*6777b538SAndroid Build Coastguard Worker 'clank/third_party/google3/pg_confs/', 79*6777b538SAndroid Build Coastguard Worker] 80*6777b538SAndroid Build Coastguard Worker 81*6777b538SAndroid Build Coastguard Worker_DUMP_DIR_NAME = 'r8inputs_dir' 82*6777b538SAndroid Build Coastguard Worker 83*6777b538SAndroid Build Coastguard Worker 84*6777b538SAndroid Build Coastguard Workerdef _ParseOptions(): 85*6777b538SAndroid Build Coastguard Worker args = build_utils.ExpandFileArgs(sys.argv[1:]) 86*6777b538SAndroid Build Coastguard Worker parser = argparse.ArgumentParser() 87*6777b538SAndroid Build Coastguard Worker action_helpers.add_depfile_arg(parser) 88*6777b538SAndroid Build Coastguard Worker parser.add_argument('--r8-path', 89*6777b538SAndroid Build Coastguard Worker required=True, 90*6777b538SAndroid Build Coastguard Worker help='Path to the R8.jar to use.') 91*6777b538SAndroid Build Coastguard Worker parser.add_argument('--custom-r8-path', 92*6777b538SAndroid Build Coastguard Worker required=True, 93*6777b538SAndroid Build Coastguard Worker help='Path to our custom R8 wrapepr to use.') 94*6777b538SAndroid Build Coastguard Worker parser.add_argument('--input-paths', 95*6777b538SAndroid Build Coastguard Worker action='append', 96*6777b538SAndroid Build Coastguard Worker required=True, 97*6777b538SAndroid Build Coastguard Worker help='GN-list of .jar files to optimize.') 98*6777b538SAndroid Build Coastguard Worker parser.add_argument('--output-path', help='Path to the generated .jar file.') 99*6777b538SAndroid Build Coastguard Worker parser.add_argument( 100*6777b538SAndroid Build Coastguard Worker '--proguard-configs', 101*6777b538SAndroid Build Coastguard Worker action='append', 102*6777b538SAndroid Build Coastguard Worker required=True, 103*6777b538SAndroid Build Coastguard Worker help='GN-list of configuration files.') 104*6777b538SAndroid Build Coastguard Worker parser.add_argument( 105*6777b538SAndroid Build Coastguard Worker '--apply-mapping', help='Path to ProGuard mapping to apply.') 106*6777b538SAndroid Build Coastguard Worker parser.add_argument( 107*6777b538SAndroid Build Coastguard Worker '--mapping-output', 108*6777b538SAndroid Build Coastguard Worker required=True, 109*6777b538SAndroid Build Coastguard Worker help='Path for ProGuard to output mapping file to.') 110*6777b538SAndroid Build Coastguard Worker parser.add_argument( 111*6777b538SAndroid Build Coastguard Worker '--extra-mapping-output-paths', 112*6777b538SAndroid Build Coastguard Worker help='GN-list of additional paths to copy output mapping file to.') 113*6777b538SAndroid Build Coastguard Worker parser.add_argument( 114*6777b538SAndroid Build Coastguard Worker '--classpath', 115*6777b538SAndroid Build Coastguard Worker action='append', 116*6777b538SAndroid Build Coastguard Worker help='GN-list of .jar files to include as libraries.') 117*6777b538SAndroid Build Coastguard Worker parser.add_argument('--main-dex-rules-path', 118*6777b538SAndroid Build Coastguard Worker action='append', 119*6777b538SAndroid Build Coastguard Worker help='Path to main dex rules for multidex.') 120*6777b538SAndroid Build Coastguard Worker parser.add_argument( 121*6777b538SAndroid Build Coastguard Worker '--min-api', help='Minimum Android API level compatibility.') 122*6777b538SAndroid Build Coastguard Worker parser.add_argument('--enable-obfuscation', 123*6777b538SAndroid Build Coastguard Worker action='store_true', 124*6777b538SAndroid Build Coastguard Worker help='Minify symbol names') 125*6777b538SAndroid Build Coastguard Worker parser.add_argument( 126*6777b538SAndroid Build Coastguard Worker '--verbose', '-v', action='store_true', help='Print all ProGuard output') 127*6777b538SAndroid Build Coastguard Worker parser.add_argument('--repackage-classes', 128*6777b538SAndroid Build Coastguard Worker default='', 129*6777b538SAndroid Build Coastguard Worker help='Value for -repackageclasses.') 130*6777b538SAndroid Build Coastguard Worker parser.add_argument( 131*6777b538SAndroid Build Coastguard Worker '--disable-checks', 132*6777b538SAndroid Build Coastguard Worker action='store_true', 133*6777b538SAndroid Build Coastguard Worker help='Disable -checkdiscard directives and missing symbols check') 134*6777b538SAndroid Build Coastguard Worker parser.add_argument('--source-file', help='Value for source file attribute.') 135*6777b538SAndroid Build Coastguard Worker parser.add_argument('--package-name', 136*6777b538SAndroid Build Coastguard Worker help='Goes into a comment in the mapping file.') 137*6777b538SAndroid Build Coastguard Worker parser.add_argument( 138*6777b538SAndroid Build Coastguard Worker '--force-enable-assertions', 139*6777b538SAndroid Build Coastguard Worker action='store_true', 140*6777b538SAndroid Build Coastguard Worker help='Forcefully enable javac generated assertion code.') 141*6777b538SAndroid Build Coastguard Worker parser.add_argument('--assertion-handler', 142*6777b538SAndroid Build Coastguard Worker help='The class name of the assertion handler class.') 143*6777b538SAndroid Build Coastguard Worker parser.add_argument( 144*6777b538SAndroid Build Coastguard Worker '--feature-jars', 145*6777b538SAndroid Build Coastguard Worker action='append', 146*6777b538SAndroid Build Coastguard Worker help='GN list of path to jars which comprise the corresponding feature.') 147*6777b538SAndroid Build Coastguard Worker parser.add_argument( 148*6777b538SAndroid Build Coastguard Worker '--dex-dest', 149*6777b538SAndroid Build Coastguard Worker action='append', 150*6777b538SAndroid Build Coastguard Worker dest='dex_dests', 151*6777b538SAndroid Build Coastguard Worker help='Destination for dex file of the corresponding feature.') 152*6777b538SAndroid Build Coastguard Worker parser.add_argument( 153*6777b538SAndroid Build Coastguard Worker '--feature-name', 154*6777b538SAndroid Build Coastguard Worker action='append', 155*6777b538SAndroid Build Coastguard Worker dest='feature_names', 156*6777b538SAndroid Build Coastguard Worker help='The name of the feature module.') 157*6777b538SAndroid Build Coastguard Worker parser.add_argument( 158*6777b538SAndroid Build Coastguard Worker '--uses-split', 159*6777b538SAndroid Build Coastguard Worker action='append', 160*6777b538SAndroid Build Coastguard Worker help='List of name pairs separated by : mapping a feature module to a ' 161*6777b538SAndroid Build Coastguard Worker 'dependent feature module.') 162*6777b538SAndroid Build Coastguard Worker parser.add_argument('--input-art-profile', 163*6777b538SAndroid Build Coastguard Worker help='Path to the input unobfuscated ART profile.') 164*6777b538SAndroid Build Coastguard Worker parser.add_argument('--output-art-profile', 165*6777b538SAndroid Build Coastguard Worker help='Path to the output obfuscated ART profile.') 166*6777b538SAndroid Build Coastguard Worker parser.add_argument( 167*6777b538SAndroid Build Coastguard Worker '--apply-startup-profile', 168*6777b538SAndroid Build Coastguard Worker action='store_true', 169*6777b538SAndroid Build Coastguard Worker help='Whether to pass --input-art-profile as a startup profile to R8.') 170*6777b538SAndroid Build Coastguard Worker parser.add_argument( 171*6777b538SAndroid Build Coastguard Worker '--keep-rules-targets-regex', 172*6777b538SAndroid Build Coastguard Worker metavar='KEEP_RULES_REGEX', 173*6777b538SAndroid Build Coastguard Worker help='If passed outputs keep rules for references from all other inputs ' 174*6777b538SAndroid Build Coastguard Worker 'to the subset of inputs that satisfy the KEEP_RULES_REGEX.') 175*6777b538SAndroid Build Coastguard Worker parser.add_argument( 176*6777b538SAndroid Build Coastguard Worker '--keep-rules-output-path', 177*6777b538SAndroid Build Coastguard Worker help='Output path to the keep rules for references to the ' 178*6777b538SAndroid Build Coastguard Worker '--keep-rules-targets-regex inputs from the rest of the inputs.') 179*6777b538SAndroid Build Coastguard Worker parser.add_argument('--warnings-as-errors', 180*6777b538SAndroid Build Coastguard Worker action='store_true', 181*6777b538SAndroid Build Coastguard Worker help='Treat all warnings as errors.') 182*6777b538SAndroid Build Coastguard Worker parser.add_argument('--show-desugar-default-interface-warnings', 183*6777b538SAndroid Build Coastguard Worker action='store_true', 184*6777b538SAndroid Build Coastguard Worker help='Enable desugaring warnings.') 185*6777b538SAndroid Build Coastguard Worker parser.add_argument('--dump-inputs', 186*6777b538SAndroid Build Coastguard Worker action='store_true', 187*6777b538SAndroid Build Coastguard Worker help='Use when filing R8 bugs to capture inputs.' 188*6777b538SAndroid Build Coastguard Worker ' Stores inputs to r8inputs.zip') 189*6777b538SAndroid Build Coastguard Worker parser.add_argument( 190*6777b538SAndroid Build Coastguard Worker '--dump-unknown-refs', 191*6777b538SAndroid Build Coastguard Worker action='store_true', 192*6777b538SAndroid Build Coastguard Worker help='Log all reasons why API modelling cannot determine API level') 193*6777b538SAndroid Build Coastguard Worker parser.add_argument( 194*6777b538SAndroid Build Coastguard Worker '--stamp', 195*6777b538SAndroid Build Coastguard Worker help='File to touch upon success. Mutually exclusive with --output-path') 196*6777b538SAndroid Build Coastguard Worker parser.add_argument('--desugared-library-keep-rule-output', 197*6777b538SAndroid Build Coastguard Worker help='Path to desugared library keep rule output file.') 198*6777b538SAndroid Build Coastguard Worker 199*6777b538SAndroid Build Coastguard Worker diff_utils.AddCommandLineFlags(parser) 200*6777b538SAndroid Build Coastguard Worker options = parser.parse_args(args) 201*6777b538SAndroid Build Coastguard Worker 202*6777b538SAndroid Build Coastguard Worker if options.feature_names: 203*6777b538SAndroid Build Coastguard Worker if options.output_path: 204*6777b538SAndroid Build Coastguard Worker parser.error('Feature splits cannot specify an output in GN.') 205*6777b538SAndroid Build Coastguard Worker if not options.actual_file and not options.stamp: 206*6777b538SAndroid Build Coastguard Worker parser.error('Feature splits require a stamp file as output.') 207*6777b538SAndroid Build Coastguard Worker elif not options.output_path: 208*6777b538SAndroid Build Coastguard Worker parser.error('Output path required when feature splits aren\'t used') 209*6777b538SAndroid Build Coastguard Worker 210*6777b538SAndroid Build Coastguard Worker if bool(options.keep_rules_targets_regex) != bool( 211*6777b538SAndroid Build Coastguard Worker options.keep_rules_output_path): 212*6777b538SAndroid Build Coastguard Worker parser.error('You must path both --keep-rules-targets-regex and ' 213*6777b538SAndroid Build Coastguard Worker '--keep-rules-output-path') 214*6777b538SAndroid Build Coastguard Worker 215*6777b538SAndroid Build Coastguard Worker if options.output_art_profile and not options.input_art_profile: 216*6777b538SAndroid Build Coastguard Worker parser.error('--output-art-profile requires --input-art-profile') 217*6777b538SAndroid Build Coastguard Worker if options.apply_startup_profile and not options.input_art_profile: 218*6777b538SAndroid Build Coastguard Worker parser.error('--apply-startup-profile requires --input-art-profile') 219*6777b538SAndroid Build Coastguard Worker 220*6777b538SAndroid Build Coastguard Worker if options.force_enable_assertions and options.assertion_handler: 221*6777b538SAndroid Build Coastguard Worker parser.error('Cannot use both --force-enable-assertions and ' 222*6777b538SAndroid Build Coastguard Worker '--assertion-handler') 223*6777b538SAndroid Build Coastguard Worker 224*6777b538SAndroid Build Coastguard Worker options.classpath = action_helpers.parse_gn_list(options.classpath) 225*6777b538SAndroid Build Coastguard Worker options.proguard_configs = action_helpers.parse_gn_list( 226*6777b538SAndroid Build Coastguard Worker options.proguard_configs) 227*6777b538SAndroid Build Coastguard Worker options.input_paths = action_helpers.parse_gn_list(options.input_paths) 228*6777b538SAndroid Build Coastguard Worker options.extra_mapping_output_paths = action_helpers.parse_gn_list( 229*6777b538SAndroid Build Coastguard Worker options.extra_mapping_output_paths) 230*6777b538SAndroid Build Coastguard Worker 231*6777b538SAndroid Build Coastguard Worker if options.feature_names: 232*6777b538SAndroid Build Coastguard Worker if 'base' not in options.feature_names: 233*6777b538SAndroid Build Coastguard Worker parser.error('"base" feature required when feature arguments are used.') 234*6777b538SAndroid Build Coastguard Worker if len(options.feature_names) != len(options.feature_jars) or len( 235*6777b538SAndroid Build Coastguard Worker options.feature_names) != len(options.dex_dests): 236*6777b538SAndroid Build Coastguard Worker parser.error('Invalid feature argument lengths.') 237*6777b538SAndroid Build Coastguard Worker 238*6777b538SAndroid Build Coastguard Worker options.feature_jars = [ 239*6777b538SAndroid Build Coastguard Worker action_helpers.parse_gn_list(x) for x in options.feature_jars 240*6777b538SAndroid Build Coastguard Worker ] 241*6777b538SAndroid Build Coastguard Worker 242*6777b538SAndroid Build Coastguard Worker split_map = {} 243*6777b538SAndroid Build Coastguard Worker if options.uses_split: 244*6777b538SAndroid Build Coastguard Worker for split_pair in options.uses_split: 245*6777b538SAndroid Build Coastguard Worker child, parent = split_pair.split(':') 246*6777b538SAndroid Build Coastguard Worker for name in (child, parent): 247*6777b538SAndroid Build Coastguard Worker if name not in options.feature_names: 248*6777b538SAndroid Build Coastguard Worker parser.error('"%s" referenced in --uses-split not present.' % name) 249*6777b538SAndroid Build Coastguard Worker split_map[child] = parent 250*6777b538SAndroid Build Coastguard Worker options.uses_split = split_map 251*6777b538SAndroid Build Coastguard Worker 252*6777b538SAndroid Build Coastguard Worker return options 253*6777b538SAndroid Build Coastguard Worker 254*6777b538SAndroid Build Coastguard Worker 255*6777b538SAndroid Build Coastguard Workerclass _SplitContext: 256*6777b538SAndroid Build Coastguard Worker def __init__(self, name, output_path, input_jars, work_dir, parent_name=None): 257*6777b538SAndroid Build Coastguard Worker self.name = name 258*6777b538SAndroid Build Coastguard Worker self.parent_name = parent_name 259*6777b538SAndroid Build Coastguard Worker self.input_jars = set(input_jars) 260*6777b538SAndroid Build Coastguard Worker self.final_output_path = output_path 261*6777b538SAndroid Build Coastguard Worker self.staging_dir = os.path.join(work_dir, name) 262*6777b538SAndroid Build Coastguard Worker os.mkdir(self.staging_dir) 263*6777b538SAndroid Build Coastguard Worker 264*6777b538SAndroid Build Coastguard Worker def CreateOutput(self): 265*6777b538SAndroid Build Coastguard Worker found_files = build_utils.FindInDirectory(self.staging_dir) 266*6777b538SAndroid Build Coastguard Worker if not found_files: 267*6777b538SAndroid Build Coastguard Worker raise Exception('Missing dex outputs in {}'.format(self.staging_dir)) 268*6777b538SAndroid Build Coastguard Worker 269*6777b538SAndroid Build Coastguard Worker if self.final_output_path.endswith('.dex'): 270*6777b538SAndroid Build Coastguard Worker if len(found_files) != 1: 271*6777b538SAndroid Build Coastguard Worker raise Exception('Expected exactly 1 dex file output, found: {}'.format( 272*6777b538SAndroid Build Coastguard Worker '\t'.join(found_files))) 273*6777b538SAndroid Build Coastguard Worker shutil.move(found_files[0], self.final_output_path) 274*6777b538SAndroid Build Coastguard Worker return 275*6777b538SAndroid Build Coastguard Worker 276*6777b538SAndroid Build Coastguard Worker # Add to .jar using Python rather than having R8 output to a .zip directly 277*6777b538SAndroid Build Coastguard Worker # in order to disable compression of the .jar, saving ~500ms. 278*6777b538SAndroid Build Coastguard Worker tmp_jar_output = self.staging_dir + '.jar' 279*6777b538SAndroid Build Coastguard Worker zip_helpers.add_files_to_zip(found_files, 280*6777b538SAndroid Build Coastguard Worker tmp_jar_output, 281*6777b538SAndroid Build Coastguard Worker base_dir=self.staging_dir) 282*6777b538SAndroid Build Coastguard Worker shutil.move(tmp_jar_output, self.final_output_path) 283*6777b538SAndroid Build Coastguard Worker 284*6777b538SAndroid Build Coastguard Worker 285*6777b538SAndroid Build Coastguard Workerdef _OptimizeWithR8(options, config_paths, libraries, dynamic_config_data): 286*6777b538SAndroid Build Coastguard Worker with build_utils.TempDir() as tmp_dir: 287*6777b538SAndroid Build Coastguard Worker if dynamic_config_data: 288*6777b538SAndroid Build Coastguard Worker dynamic_config_path = os.path.join(tmp_dir, 'dynamic_config.flags') 289*6777b538SAndroid Build Coastguard Worker with open(dynamic_config_path, 'w') as f: 290*6777b538SAndroid Build Coastguard Worker f.write(dynamic_config_data) 291*6777b538SAndroid Build Coastguard Worker config_paths = config_paths + [dynamic_config_path] 292*6777b538SAndroid Build Coastguard Worker 293*6777b538SAndroid Build Coastguard Worker tmp_mapping_path = os.path.join(tmp_dir, 'mapping.txt') 294*6777b538SAndroid Build Coastguard Worker # If there is no output (no classes are kept), this prevents this script 295*6777b538SAndroid Build Coastguard Worker # from failing. 296*6777b538SAndroid Build Coastguard Worker build_utils.Touch(tmp_mapping_path) 297*6777b538SAndroid Build Coastguard Worker 298*6777b538SAndroid Build Coastguard Worker tmp_output = os.path.join(tmp_dir, 'r8out') 299*6777b538SAndroid Build Coastguard Worker os.mkdir(tmp_output) 300*6777b538SAndroid Build Coastguard Worker 301*6777b538SAndroid Build Coastguard Worker split_contexts_by_name = {} 302*6777b538SAndroid Build Coastguard Worker if options.feature_names: 303*6777b538SAndroid Build Coastguard Worker for name, dest_dex, input_jars in zip(options.feature_names, 304*6777b538SAndroid Build Coastguard Worker options.dex_dests, 305*6777b538SAndroid Build Coastguard Worker options.feature_jars): 306*6777b538SAndroid Build Coastguard Worker parent_name = options.uses_split.get(name) 307*6777b538SAndroid Build Coastguard Worker if parent_name is None and name != 'base': 308*6777b538SAndroid Build Coastguard Worker parent_name = 'base' 309*6777b538SAndroid Build Coastguard Worker split_context = _SplitContext(name, 310*6777b538SAndroid Build Coastguard Worker dest_dex, 311*6777b538SAndroid Build Coastguard Worker input_jars, 312*6777b538SAndroid Build Coastguard Worker tmp_output, 313*6777b538SAndroid Build Coastguard Worker parent_name=parent_name) 314*6777b538SAndroid Build Coastguard Worker split_contexts_by_name[name] = split_context 315*6777b538SAndroid Build Coastguard Worker else: 316*6777b538SAndroid Build Coastguard Worker # Base context will get populated via "extra_jars" below. 317*6777b538SAndroid Build Coastguard Worker split_contexts_by_name['base'] = _SplitContext('base', 318*6777b538SAndroid Build Coastguard Worker options.output_path, [], 319*6777b538SAndroid Build Coastguard Worker tmp_output) 320*6777b538SAndroid Build Coastguard Worker base_context = split_contexts_by_name['base'] 321*6777b538SAndroid Build Coastguard Worker 322*6777b538SAndroid Build Coastguard Worker # R8 OOMs with the default xmx=1G. 323*6777b538SAndroid Build Coastguard Worker cmd = build_utils.JavaCmd(xmx='2G') + [ 324*6777b538SAndroid Build Coastguard Worker # Allows -whyareyounotinlining, which we don't have by default, but 325*6777b538SAndroid Build Coastguard Worker # which is useful for one-off queries. 326*6777b538SAndroid Build Coastguard Worker '-Dcom.android.tools.r8.experimental.enablewhyareyounotinlining=1', 327*6777b538SAndroid Build Coastguard Worker # Restricts horizontal class merging to apply only to classes that 328*6777b538SAndroid Build Coastguard Worker # share a .java file (nested classes). https://crbug.com/1363709 329*6777b538SAndroid Build Coastguard Worker '-Dcom.android.tools.r8.enableSameFilePolicy=1', 330*6777b538SAndroid Build Coastguard Worker ] 331*6777b538SAndroid Build Coastguard Worker if options.dump_inputs: 332*6777b538SAndroid Build Coastguard Worker cmd += [f'-Dcom.android.tools.r8.dumpinputtodirectory={_DUMP_DIR_NAME}'] 333*6777b538SAndroid Build Coastguard Worker if options.dump_unknown_refs: 334*6777b538SAndroid Build Coastguard Worker cmd += ['-Dcom.android.tools.r8.reportUnknownApiReferences=1'] 335*6777b538SAndroid Build Coastguard Worker cmd += [ 336*6777b538SAndroid Build Coastguard Worker '-cp', 337*6777b538SAndroid Build Coastguard Worker '{}:{}'.format(options.r8_path, options.custom_r8_path), 338*6777b538SAndroid Build Coastguard Worker 'org.chromium.build.CustomR8', 339*6777b538SAndroid Build Coastguard Worker '--no-data-resources', 340*6777b538SAndroid Build Coastguard Worker '--map-id-template', 341*6777b538SAndroid Build Coastguard Worker f'{options.source_file} ({options.package_name})', 342*6777b538SAndroid Build Coastguard Worker '--source-file-template', 343*6777b538SAndroid Build Coastguard Worker options.source_file, 344*6777b538SAndroid Build Coastguard Worker '--output', 345*6777b538SAndroid Build Coastguard Worker base_context.staging_dir, 346*6777b538SAndroid Build Coastguard Worker '--pg-map-output', 347*6777b538SAndroid Build Coastguard Worker tmp_mapping_path, 348*6777b538SAndroid Build Coastguard Worker ] 349*6777b538SAndroid Build Coastguard Worker 350*6777b538SAndroid Build Coastguard Worker if options.uses_split: 351*6777b538SAndroid Build Coastguard Worker cmd += ['--isolated-splits'] 352*6777b538SAndroid Build Coastguard Worker 353*6777b538SAndroid Build Coastguard Worker if options.disable_checks: 354*6777b538SAndroid Build Coastguard Worker cmd += ['--map-diagnostics:CheckDiscardDiagnostic', 'error', 'none'] 355*6777b538SAndroid Build Coastguard Worker cmd += ['--map-diagnostics', 'info', 'warning'] 356*6777b538SAndroid Build Coastguard Worker # An "error" level diagnostic causes r8 to return an error exit code. Doing 357*6777b538SAndroid Build Coastguard Worker # this allows our filter to decide what should/shouldn't break our build. 358*6777b538SAndroid Build Coastguard Worker cmd += ['--map-diagnostics', 'error', 'warning'] 359*6777b538SAndroid Build Coastguard Worker 360*6777b538SAndroid Build Coastguard Worker if options.min_api: 361*6777b538SAndroid Build Coastguard Worker cmd += ['--min-api', options.min_api] 362*6777b538SAndroid Build Coastguard Worker 363*6777b538SAndroid Build Coastguard Worker if options.assertion_handler: 364*6777b538SAndroid Build Coastguard Worker cmd += ['--force-assertions-handler:' + options.assertion_handler] 365*6777b538SAndroid Build Coastguard Worker elif options.force_enable_assertions: 366*6777b538SAndroid Build Coastguard Worker cmd += ['--force-enable-assertions'] 367*6777b538SAndroid Build Coastguard Worker 368*6777b538SAndroid Build Coastguard Worker for lib in libraries: 369*6777b538SAndroid Build Coastguard Worker cmd += ['--lib', lib] 370*6777b538SAndroid Build Coastguard Worker 371*6777b538SAndroid Build Coastguard Worker for config_file in config_paths: 372*6777b538SAndroid Build Coastguard Worker cmd += ['--pg-conf', config_file] 373*6777b538SAndroid Build Coastguard Worker 374*6777b538SAndroid Build Coastguard Worker if options.main_dex_rules_path: 375*6777b538SAndroid Build Coastguard Worker for main_dex_rule in options.main_dex_rules_path: 376*6777b538SAndroid Build Coastguard Worker cmd += ['--main-dex-rules', main_dex_rule] 377*6777b538SAndroid Build Coastguard Worker 378*6777b538SAndroid Build Coastguard Worker if options.output_art_profile: 379*6777b538SAndroid Build Coastguard Worker cmd += [ 380*6777b538SAndroid Build Coastguard Worker '--art-profile', 381*6777b538SAndroid Build Coastguard Worker options.input_art_profile, 382*6777b538SAndroid Build Coastguard Worker options.output_art_profile, 383*6777b538SAndroid Build Coastguard Worker ] 384*6777b538SAndroid Build Coastguard Worker if options.apply_startup_profile: 385*6777b538SAndroid Build Coastguard Worker cmd += [ 386*6777b538SAndroid Build Coastguard Worker '--startup-profile', 387*6777b538SAndroid Build Coastguard Worker options.input_art_profile, 388*6777b538SAndroid Build Coastguard Worker ] 389*6777b538SAndroid Build Coastguard Worker 390*6777b538SAndroid Build Coastguard Worker # Add any extra inputs to the base context (e.g. desugar runtime). 391*6777b538SAndroid Build Coastguard Worker extra_jars = set(options.input_paths) 392*6777b538SAndroid Build Coastguard Worker for split_context in split_contexts_by_name.values(): 393*6777b538SAndroid Build Coastguard Worker extra_jars -= split_context.input_jars 394*6777b538SAndroid Build Coastguard Worker base_context.input_jars.update(extra_jars) 395*6777b538SAndroid Build Coastguard Worker 396*6777b538SAndroid Build Coastguard Worker for split_context in split_contexts_by_name.values(): 397*6777b538SAndroid Build Coastguard Worker if split_context is base_context: 398*6777b538SAndroid Build Coastguard Worker continue 399*6777b538SAndroid Build Coastguard Worker for in_jar in sorted(split_context.input_jars): 400*6777b538SAndroid Build Coastguard Worker cmd += ['--feature', in_jar, split_context.staging_dir] 401*6777b538SAndroid Build Coastguard Worker 402*6777b538SAndroid Build Coastguard Worker cmd += sorted(base_context.input_jars) 403*6777b538SAndroid Build Coastguard Worker 404*6777b538SAndroid Build Coastguard Worker if options.verbose or os.environ.get('R8_VERBOSE') == '1': 405*6777b538SAndroid Build Coastguard Worker stderr_filter = None 406*6777b538SAndroid Build Coastguard Worker else: 407*6777b538SAndroid Build Coastguard Worker filters = list(dex.DEFAULT_IGNORE_WARNINGS) 408*6777b538SAndroid Build Coastguard Worker filters += _IGNORE_WARNINGS 409*6777b538SAndroid Build Coastguard Worker if options.show_desugar_default_interface_warnings: 410*6777b538SAndroid Build Coastguard Worker filters += dex.INTERFACE_DESUGARING_WARNINGS 411*6777b538SAndroid Build Coastguard Worker stderr_filter = dex.CreateStderrFilter(filters) 412*6777b538SAndroid Build Coastguard Worker 413*6777b538SAndroid Build Coastguard Worker try: 414*6777b538SAndroid Build Coastguard Worker logging.debug('Running R8') 415*6777b538SAndroid Build Coastguard Worker build_utils.CheckOutput(cmd, 416*6777b538SAndroid Build Coastguard Worker print_stdout=True, 417*6777b538SAndroid Build Coastguard Worker stderr_filter=stderr_filter, 418*6777b538SAndroid Build Coastguard Worker fail_on_output=options.warnings_as_errors) 419*6777b538SAndroid Build Coastguard Worker except build_utils.CalledProcessError as e: 420*6777b538SAndroid Build Coastguard Worker # Do not output command line because it is massive and makes the actual 421*6777b538SAndroid Build Coastguard Worker # error message hard to find. 422*6777b538SAndroid Build Coastguard Worker sys.stderr.write(e.output) 423*6777b538SAndroid Build Coastguard Worker sys.exit(1) 424*6777b538SAndroid Build Coastguard Worker 425*6777b538SAndroid Build Coastguard Worker logging.debug('Collecting ouputs') 426*6777b538SAndroid Build Coastguard Worker base_context.CreateOutput() 427*6777b538SAndroid Build Coastguard Worker for split_context in split_contexts_by_name.values(): 428*6777b538SAndroid Build Coastguard Worker if split_context is not base_context: 429*6777b538SAndroid Build Coastguard Worker split_context.CreateOutput() 430*6777b538SAndroid Build Coastguard Worker 431*6777b538SAndroid Build Coastguard Worker shutil.move(tmp_mapping_path, options.mapping_output) 432*6777b538SAndroid Build Coastguard Worker return split_contexts_by_name 433*6777b538SAndroid Build Coastguard Worker 434*6777b538SAndroid Build Coastguard Worker 435*6777b538SAndroid Build Coastguard Workerdef _OutputKeepRules(r8_path, input_paths, classpath, targets_re_string, 436*6777b538SAndroid Build Coastguard Worker keep_rules_output): 437*6777b538SAndroid Build Coastguard Worker 438*6777b538SAndroid Build Coastguard Worker cmd = build_utils.JavaCmd() + [ 439*6777b538SAndroid Build Coastguard Worker '-cp', r8_path, 'com.android.tools.r8.tracereferences.TraceReferences', 440*6777b538SAndroid Build Coastguard Worker '--map-diagnostics:MissingDefinitionsDiagnostic', 'error', 'warning', 441*6777b538SAndroid Build Coastguard Worker '--keep-rules', '--output', keep_rules_output 442*6777b538SAndroid Build Coastguard Worker ] 443*6777b538SAndroid Build Coastguard Worker targets_re = re.compile(targets_re_string) 444*6777b538SAndroid Build Coastguard Worker for path in input_paths: 445*6777b538SAndroid Build Coastguard Worker if targets_re.search(path): 446*6777b538SAndroid Build Coastguard Worker cmd += ['--target', path] 447*6777b538SAndroid Build Coastguard Worker else: 448*6777b538SAndroid Build Coastguard Worker cmd += ['--source', path] 449*6777b538SAndroid Build Coastguard Worker for path in classpath: 450*6777b538SAndroid Build Coastguard Worker cmd += ['--lib', path] 451*6777b538SAndroid Build Coastguard Worker 452*6777b538SAndroid Build Coastguard Worker build_utils.CheckOutput(cmd, print_stderr=False, fail_on_output=False) 453*6777b538SAndroid Build Coastguard Worker 454*6777b538SAndroid Build Coastguard Worker 455*6777b538SAndroid Build Coastguard Workerdef _CheckForMissingSymbols(r8_path, dex_files, classpath, warnings_as_errors, 456*6777b538SAndroid Build Coastguard Worker dump_inputs, error_title): 457*6777b538SAndroid Build Coastguard Worker cmd = build_utils.JavaCmd() 458*6777b538SAndroid Build Coastguard Worker 459*6777b538SAndroid Build Coastguard Worker if dump_inputs: 460*6777b538SAndroid Build Coastguard Worker cmd += [f'-Dcom.android.tools.r8.dumpinputtodirectory={_DUMP_DIR_NAME}'] 461*6777b538SAndroid Build Coastguard Worker 462*6777b538SAndroid Build Coastguard Worker cmd += [ 463*6777b538SAndroid Build Coastguard Worker '-cp', r8_path, 'com.android.tools.r8.tracereferences.TraceReferences', 464*6777b538SAndroid Build Coastguard Worker '--map-diagnostics:MissingDefinitionsDiagnostic', 'error', 'warning', 465*6777b538SAndroid Build Coastguard Worker '--check' 466*6777b538SAndroid Build Coastguard Worker ] 467*6777b538SAndroid Build Coastguard Worker 468*6777b538SAndroid Build Coastguard Worker for path in classpath: 469*6777b538SAndroid Build Coastguard Worker cmd += ['--lib', path] 470*6777b538SAndroid Build Coastguard Worker for path in dex_files: 471*6777b538SAndroid Build Coastguard Worker cmd += ['--source', path] 472*6777b538SAndroid Build Coastguard Worker 473*6777b538SAndroid Build Coastguard Worker failed_holder = [False] 474*6777b538SAndroid Build Coastguard Worker 475*6777b538SAndroid Build Coastguard Worker def stderr_filter(stderr): 476*6777b538SAndroid Build Coastguard Worker ignored_lines = [ 477*6777b538SAndroid Build Coastguard Worker # Summary contains warning count, which our filtering makes wrong. 478*6777b538SAndroid Build Coastguard Worker 'Warning: Tracereferences found', 479*6777b538SAndroid Build Coastguard Worker 480*6777b538SAndroid Build Coastguard Worker # TODO(agrieve): Create interface jars for these missing classes rather 481*6777b538SAndroid Build Coastguard Worker # than allowlisting here. 482*6777b538SAndroid Build Coastguard Worker 'dalvik.system', 483*6777b538SAndroid Build Coastguard Worker 'libcore.io', 484*6777b538SAndroid Build Coastguard Worker 'sun.misc.Unsafe', 485*6777b538SAndroid Build Coastguard Worker 486*6777b538SAndroid Build Coastguard Worker # Found in: com/facebook/fbui/textlayoutbuilder/StaticLayoutHelper 487*6777b538SAndroid Build Coastguard Worker 'android.text.StaticLayout.<init>', 488*6777b538SAndroid Build Coastguard Worker # TODO(crbug/1426964): Remove once chrome builds with Android U SDK. 489*6777b538SAndroid Build Coastguard Worker ' android.', 490*6777b538SAndroid Build Coastguard Worker 491*6777b538SAndroid Build Coastguard Worker # Explicictly guarded by try (NoClassDefFoundError) in Flogger's 492*6777b538SAndroid Build Coastguard Worker # PlatformProvider. 493*6777b538SAndroid Build Coastguard Worker 'com.google.common.flogger.backend.google.GooglePlatform', 494*6777b538SAndroid Build Coastguard Worker 'com.google.common.flogger.backend.system.DefaultPlatform', 495*6777b538SAndroid Build Coastguard Worker 496*6777b538SAndroid Build Coastguard Worker # TODO(agrieve): Exclude these only when use_jacoco_coverage=true. 497*6777b538SAndroid Build Coastguard Worker 'java.lang.instrument.ClassFileTransformer', 498*6777b538SAndroid Build Coastguard Worker 'java.lang.instrument.IllegalClassFormatException', 499*6777b538SAndroid Build Coastguard Worker 'java.lang.instrument.Instrumentation', 500*6777b538SAndroid Build Coastguard Worker 'java.lang.management.ManagementFactory', 501*6777b538SAndroid Build Coastguard Worker 'javax.management.MBeanServer', 502*6777b538SAndroid Build Coastguard Worker 'javax.management.ObjectInstance', 503*6777b538SAndroid Build Coastguard Worker 'javax.management.ObjectName', 504*6777b538SAndroid Build Coastguard Worker 'javax.management.StandardMBean', 505*6777b538SAndroid Build Coastguard Worker 506*6777b538SAndroid Build Coastguard Worker # Explicitly guarded by try (NoClassDefFoundError) in Firebase's 507*6777b538SAndroid Build Coastguard Worker # KotlinDetector: com.google.firebase.platforminfo.KotlinDetector. 508*6777b538SAndroid Build Coastguard Worker 'kotlin.KotlinVersion', 509*6777b538SAndroid Build Coastguard Worker ] 510*6777b538SAndroid Build Coastguard Worker 511*6777b538SAndroid Build Coastguard Worker had_unfiltered_items = ' ' in stderr 512*6777b538SAndroid Build Coastguard Worker stderr = build_utils.FilterLines( 513*6777b538SAndroid Build Coastguard Worker stderr, '|'.join(re.escape(x) for x in ignored_lines)) 514*6777b538SAndroid Build Coastguard Worker if stderr: 515*6777b538SAndroid Build Coastguard Worker if 'Missing' in stderr: 516*6777b538SAndroid Build Coastguard Worker failed_holder[0] = True 517*6777b538SAndroid Build Coastguard Worker stderr = 'TraceReferences failed: ' + error_title + """ 518*6777b538SAndroid Build Coastguard WorkerTip: Build with: 519*6777b538SAndroid Build Coastguard Worker is_java_debug=false 520*6777b538SAndroid Build Coastguard Worker treat_warnings_as_errors=false 521*6777b538SAndroid Build Coastguard Worker enable_proguard_obfuscation=false 522*6777b538SAndroid Build Coastguard Worker and then use dexdump to see which class(s) reference them. 523*6777b538SAndroid Build Coastguard Worker 524*6777b538SAndroid Build Coastguard Worker E.g.: 525*6777b538SAndroid Build Coastguard Worker third_party/android_sdk/public/build-tools/*/dexdump -d \ 526*6777b538SAndroid Build Coastguard Workerout/Release/apks/YourApk.apk > dex.txt 527*6777b538SAndroid Build Coastguard Worker""" + stderr 528*6777b538SAndroid Build Coastguard Worker elif had_unfiltered_items: 529*6777b538SAndroid Build Coastguard Worker # Left only with empty headings. All indented items filtered out. 530*6777b538SAndroid Build Coastguard Worker stderr = '' 531*6777b538SAndroid Build Coastguard Worker return stderr 532*6777b538SAndroid Build Coastguard Worker 533*6777b538SAndroid Build Coastguard Worker try: 534*6777b538SAndroid Build Coastguard Worker build_utils.CheckOutput(cmd, 535*6777b538SAndroid Build Coastguard Worker print_stdout=True, 536*6777b538SAndroid Build Coastguard Worker stderr_filter=stderr_filter, 537*6777b538SAndroid Build Coastguard Worker fail_on_output=warnings_as_errors) 538*6777b538SAndroid Build Coastguard Worker except build_utils.CalledProcessError as e: 539*6777b538SAndroid Build Coastguard Worker # Do not output command line because it is massive and makes the actual 540*6777b538SAndroid Build Coastguard Worker # error message hard to find. 541*6777b538SAndroid Build Coastguard Worker sys.stderr.write(e.output) 542*6777b538SAndroid Build Coastguard Worker sys.exit(1) 543*6777b538SAndroid Build Coastguard Worker return failed_holder[0] 544*6777b538SAndroid Build Coastguard Worker 545*6777b538SAndroid Build Coastguard Worker 546*6777b538SAndroid Build Coastguard Workerdef _CombineConfigs(configs, 547*6777b538SAndroid Build Coastguard Worker dynamic_config_data, 548*6777b538SAndroid Build Coastguard Worker embedded_configs, 549*6777b538SAndroid Build Coastguard Worker exclude_generated=False): 550*6777b538SAndroid Build Coastguard Worker # Sort in this way so //clank versions of the same libraries will sort 551*6777b538SAndroid Build Coastguard Worker # to the same spot in the file. 552*6777b538SAndroid Build Coastguard Worker def sort_key(path): 553*6777b538SAndroid Build Coastguard Worker return tuple(reversed(path.split(os.path.sep))) 554*6777b538SAndroid Build Coastguard Worker 555*6777b538SAndroid Build Coastguard Worker def format_config_contents(path, contents): 556*6777b538SAndroid Build Coastguard Worker formatted_contents = [] 557*6777b538SAndroid Build Coastguard Worker if not contents.strip(): 558*6777b538SAndroid Build Coastguard Worker return [] 559*6777b538SAndroid Build Coastguard Worker 560*6777b538SAndroid Build Coastguard Worker # Fix up line endings (third_party configs can have windows endings). 561*6777b538SAndroid Build Coastguard Worker contents = contents.replace('\r', '') 562*6777b538SAndroid Build Coastguard Worker # Remove numbers from generated rule comments to make file more 563*6777b538SAndroid Build Coastguard Worker # diff'able. 564*6777b538SAndroid Build Coastguard Worker contents = re.sub(r' #generated:\d+', '', contents) 565*6777b538SAndroid Build Coastguard Worker formatted_contents.append('# File: ' + path) 566*6777b538SAndroid Build Coastguard Worker formatted_contents.append(contents) 567*6777b538SAndroid Build Coastguard Worker formatted_contents.append('') 568*6777b538SAndroid Build Coastguard Worker return formatted_contents 569*6777b538SAndroid Build Coastguard Worker 570*6777b538SAndroid Build Coastguard Worker ret = [] 571*6777b538SAndroid Build Coastguard Worker for config in sorted(configs, key=sort_key): 572*6777b538SAndroid Build Coastguard Worker if exclude_generated and config.endswith('.resources.proguard.txt'): 573*6777b538SAndroid Build Coastguard Worker continue 574*6777b538SAndroid Build Coastguard Worker 575*6777b538SAndroid Build Coastguard Worker # Exclude some confs from expectations. 576*6777b538SAndroid Build Coastguard Worker if any(entry in config for entry in _BLOCKLISTED_EXPECTATION_PATHS): 577*6777b538SAndroid Build Coastguard Worker continue 578*6777b538SAndroid Build Coastguard Worker 579*6777b538SAndroid Build Coastguard Worker with open(config) as config_file: 580*6777b538SAndroid Build Coastguard Worker contents = config_file.read().rstrip() 581*6777b538SAndroid Build Coastguard Worker 582*6777b538SAndroid Build Coastguard Worker ret.extend(format_config_contents(config, contents)) 583*6777b538SAndroid Build Coastguard Worker 584*6777b538SAndroid Build Coastguard Worker for path, contents in sorted(embedded_configs.items()): 585*6777b538SAndroid Build Coastguard Worker ret.extend(format_config_contents(path, contents)) 586*6777b538SAndroid Build Coastguard Worker 587*6777b538SAndroid Build Coastguard Worker 588*6777b538SAndroid Build Coastguard Worker if dynamic_config_data: 589*6777b538SAndroid Build Coastguard Worker ret.append('# File: //build/android/gyp/proguard.py (generated rules)') 590*6777b538SAndroid Build Coastguard Worker ret.append(dynamic_config_data) 591*6777b538SAndroid Build Coastguard Worker ret.append('') 592*6777b538SAndroid Build Coastguard Worker return '\n'.join(ret) 593*6777b538SAndroid Build Coastguard Worker 594*6777b538SAndroid Build Coastguard Worker 595*6777b538SAndroid Build Coastguard Workerdef _CreateDynamicConfig(options): 596*6777b538SAndroid Build Coastguard Worker ret = [] 597*6777b538SAndroid Build Coastguard Worker if options.enable_obfuscation: 598*6777b538SAndroid Build Coastguard Worker ret.append(f"-repackageclasses '{options.repackage_classes}'") 599*6777b538SAndroid Build Coastguard Worker else: 600*6777b538SAndroid Build Coastguard Worker ret.append("-dontobfuscate") 601*6777b538SAndroid Build Coastguard Worker 602*6777b538SAndroid Build Coastguard Worker if options.apply_mapping: 603*6777b538SAndroid Build Coastguard Worker ret.append("-applymapping '%s'" % options.apply_mapping) 604*6777b538SAndroid Build Coastguard Worker 605*6777b538SAndroid Build Coastguard Worker return '\n'.join(ret) 606*6777b538SAndroid Build Coastguard Worker 607*6777b538SAndroid Build Coastguard Worker 608*6777b538SAndroid Build Coastguard Workerdef _ExtractEmbeddedConfigs(jar_path, embedded_configs): 609*6777b538SAndroid Build Coastguard Worker with zipfile.ZipFile(jar_path) as z: 610*6777b538SAndroid Build Coastguard Worker proguard_names = [] 611*6777b538SAndroid Build Coastguard Worker r8_names = [] 612*6777b538SAndroid Build Coastguard Worker for info in z.infolist(): 613*6777b538SAndroid Build Coastguard Worker if info.is_dir(): 614*6777b538SAndroid Build Coastguard Worker continue 615*6777b538SAndroid Build Coastguard Worker if info.filename.startswith('META-INF/proguard/'): 616*6777b538SAndroid Build Coastguard Worker proguard_names.append(info.filename) 617*6777b538SAndroid Build Coastguard Worker elif info.filename.startswith('META-INF/com.android.tools/r8/'): 618*6777b538SAndroid Build Coastguard Worker r8_names.append(info.filename) 619*6777b538SAndroid Build Coastguard Worker elif info.filename.startswith('META-INF/com.android.tools/r8-from'): 620*6777b538SAndroid Build Coastguard Worker # Assume our version of R8 is always latest. 621*6777b538SAndroid Build Coastguard Worker if '-upto-' not in info.filename: 622*6777b538SAndroid Build Coastguard Worker r8_names.append(info.filename) 623*6777b538SAndroid Build Coastguard Worker 624*6777b538SAndroid Build Coastguard Worker # Give preference to r8-from-*, then r8/, then proguard/. 625*6777b538SAndroid Build Coastguard Worker active = r8_names or proguard_names 626*6777b538SAndroid Build Coastguard Worker for filename in active: 627*6777b538SAndroid Build Coastguard Worker config_path = '{}:{}'.format(jar_path, filename) 628*6777b538SAndroid Build Coastguard Worker embedded_configs[config_path] = z.read(filename).decode('utf-8').rstrip() 629*6777b538SAndroid Build Coastguard Worker 630*6777b538SAndroid Build Coastguard Worker 631*6777b538SAndroid Build Coastguard Workerdef _MaybeWriteStampAndDepFile(options, inputs): 632*6777b538SAndroid Build Coastguard Worker output = options.output_path 633*6777b538SAndroid Build Coastguard Worker if options.stamp: 634*6777b538SAndroid Build Coastguard Worker build_utils.Touch(options.stamp) 635*6777b538SAndroid Build Coastguard Worker output = options.stamp 636*6777b538SAndroid Build Coastguard Worker if options.depfile: 637*6777b538SAndroid Build Coastguard Worker action_helpers.write_depfile(options.depfile, output, inputs=inputs) 638*6777b538SAndroid Build Coastguard Worker 639*6777b538SAndroid Build Coastguard Worker 640*6777b538SAndroid Build Coastguard Workerdef _IterParentContexts(context_name, split_contexts_by_name): 641*6777b538SAndroid Build Coastguard Worker while context_name: 642*6777b538SAndroid Build Coastguard Worker context = split_contexts_by_name[context_name] 643*6777b538SAndroid Build Coastguard Worker yield context 644*6777b538SAndroid Build Coastguard Worker context_name = context.parent_name 645*6777b538SAndroid Build Coastguard Worker 646*6777b538SAndroid Build Coastguard Worker 647*6777b538SAndroid Build Coastguard Workerdef _DoTraceReferencesChecks(options, split_contexts_by_name): 648*6777b538SAndroid Build Coastguard Worker # Set of all contexts that are a parent to another. 649*6777b538SAndroid Build Coastguard Worker parent_splits_context_names = { 650*6777b538SAndroid Build Coastguard Worker c.parent_name 651*6777b538SAndroid Build Coastguard Worker for c in split_contexts_by_name.values() if c.parent_name 652*6777b538SAndroid Build Coastguard Worker } 653*6777b538SAndroid Build Coastguard Worker context_sets = [ 654*6777b538SAndroid Build Coastguard Worker list(_IterParentContexts(n, split_contexts_by_name)) 655*6777b538SAndroid Build Coastguard Worker for n in parent_splits_context_names 656*6777b538SAndroid Build Coastguard Worker ] 657*6777b538SAndroid Build Coastguard Worker # Visit them in order of: base, base+chrome, base+chrome+thing. 658*6777b538SAndroid Build Coastguard Worker context_sets.sort(key=lambda x: (len(x), x[0].name)) 659*6777b538SAndroid Build Coastguard Worker 660*6777b538SAndroid Build Coastguard Worker # Ensure there are no missing references when considering all dex files. 661*6777b538SAndroid Build Coastguard Worker error_title = 'DEX contains references to non-existent symbols after R8.' 662*6777b538SAndroid Build Coastguard Worker dex_files = sorted(c.final_output_path 663*6777b538SAndroid Build Coastguard Worker for c in split_contexts_by_name.values()) 664*6777b538SAndroid Build Coastguard Worker if _CheckForMissingSymbols(options.r8_path, dex_files, options.classpath, 665*6777b538SAndroid Build Coastguard Worker options.warnings_as_errors, options.dump_inputs, 666*6777b538SAndroid Build Coastguard Worker error_title): 667*6777b538SAndroid Build Coastguard Worker # Failed but didn't raise due to warnings_as_errors=False 668*6777b538SAndroid Build Coastguard Worker return 669*6777b538SAndroid Build Coastguard Worker 670*6777b538SAndroid Build Coastguard Worker for context_set in context_sets: 671*6777b538SAndroid Build Coastguard Worker # Ensure there are no references from base -> chrome module, or from 672*6777b538SAndroid Build Coastguard Worker # chrome -> feature modules. 673*6777b538SAndroid Build Coastguard Worker error_title = (f'DEX within module "{context_set[0].name}" contains ' 674*6777b538SAndroid Build Coastguard Worker 'reference(s) to symbols within child splits') 675*6777b538SAndroid Build Coastguard Worker dex_files = [c.final_output_path for c in context_set] 676*6777b538SAndroid Build Coastguard Worker # Each check currently takes about 3 seconds on a fast dev machine, and we 677*6777b538SAndroid Build Coastguard Worker # run 3 of them (all, base, base+chrome). 678*6777b538SAndroid Build Coastguard Worker # We could run them concurrently, to shave off 5-6 seconds, but would need 679*6777b538SAndroid Build Coastguard Worker # to make sure that the order is maintained. 680*6777b538SAndroid Build Coastguard Worker if _CheckForMissingSymbols(options.r8_path, dex_files, options.classpath, 681*6777b538SAndroid Build Coastguard Worker options.warnings_as_errors, options.dump_inputs, 682*6777b538SAndroid Build Coastguard Worker error_title): 683*6777b538SAndroid Build Coastguard Worker # Failed but didn't raise due to warnings_as_errors=False 684*6777b538SAndroid Build Coastguard Worker return 685*6777b538SAndroid Build Coastguard Worker 686*6777b538SAndroid Build Coastguard Worker 687*6777b538SAndroid Build Coastguard Workerdef _Run(options): 688*6777b538SAndroid Build Coastguard Worker # ProGuard configs that are derived from flags. 689*6777b538SAndroid Build Coastguard Worker logging.debug('Preparing configs') 690*6777b538SAndroid Build Coastguard Worker dynamic_config_data = _CreateDynamicConfig(options) 691*6777b538SAndroid Build Coastguard Worker 692*6777b538SAndroid Build Coastguard Worker logging.debug('Looking for embedded configs') 693*6777b538SAndroid Build Coastguard Worker # If a jar is part of input no need to include it as library jar. 694*6777b538SAndroid Build Coastguard Worker libraries = [p for p in options.classpath if p not in options.input_paths] 695*6777b538SAndroid Build Coastguard Worker 696*6777b538SAndroid Build Coastguard Worker embedded_configs = {} 697*6777b538SAndroid Build Coastguard Worker for jar_path in options.input_paths + libraries: 698*6777b538SAndroid Build Coastguard Worker _ExtractEmbeddedConfigs(jar_path, embedded_configs) 699*6777b538SAndroid Build Coastguard Worker 700*6777b538SAndroid Build Coastguard Worker # ProGuard configs that are derived from flags. 701*6777b538SAndroid Build Coastguard Worker merged_configs = _CombineConfigs(options.proguard_configs, 702*6777b538SAndroid Build Coastguard Worker dynamic_config_data, 703*6777b538SAndroid Build Coastguard Worker embedded_configs, 704*6777b538SAndroid Build Coastguard Worker exclude_generated=True) 705*6777b538SAndroid Build Coastguard Worker 706*6777b538SAndroid Build Coastguard Worker depfile_inputs = options.proguard_configs + options.input_paths + libraries 707*6777b538SAndroid Build Coastguard Worker if options.expected_file: 708*6777b538SAndroid Build Coastguard Worker diff_utils.CheckExpectations(merged_configs, options) 709*6777b538SAndroid Build Coastguard Worker if options.only_verify_expectations: 710*6777b538SAndroid Build Coastguard Worker action_helpers.write_depfile(options.depfile, 711*6777b538SAndroid Build Coastguard Worker options.actual_file, 712*6777b538SAndroid Build Coastguard Worker inputs=depfile_inputs) 713*6777b538SAndroid Build Coastguard Worker return 714*6777b538SAndroid Build Coastguard Worker 715*6777b538SAndroid Build Coastguard Worker if options.keep_rules_output_path: 716*6777b538SAndroid Build Coastguard Worker _OutputKeepRules(options.r8_path, options.input_paths, options.classpath, 717*6777b538SAndroid Build Coastguard Worker options.keep_rules_targets_regex, 718*6777b538SAndroid Build Coastguard Worker options.keep_rules_output_path) 719*6777b538SAndroid Build Coastguard Worker return 720*6777b538SAndroid Build Coastguard Worker 721*6777b538SAndroid Build Coastguard Worker split_contexts_by_name = _OptimizeWithR8(options, options.proguard_configs, 722*6777b538SAndroid Build Coastguard Worker libraries, dynamic_config_data) 723*6777b538SAndroid Build Coastguard Worker 724*6777b538SAndroid Build Coastguard Worker if not options.disable_checks: 725*6777b538SAndroid Build Coastguard Worker logging.debug('Running tracereferences') 726*6777b538SAndroid Build Coastguard Worker _DoTraceReferencesChecks(options, split_contexts_by_name) 727*6777b538SAndroid Build Coastguard Worker 728*6777b538SAndroid Build Coastguard Worker for output in options.extra_mapping_output_paths: 729*6777b538SAndroid Build Coastguard Worker shutil.copy(options.mapping_output, output) 730*6777b538SAndroid Build Coastguard Worker 731*6777b538SAndroid Build Coastguard Worker if options.apply_mapping: 732*6777b538SAndroid Build Coastguard Worker depfile_inputs.append(options.apply_mapping) 733*6777b538SAndroid Build Coastguard Worker 734*6777b538SAndroid Build Coastguard Worker _MaybeWriteStampAndDepFile(options, depfile_inputs) 735*6777b538SAndroid Build Coastguard Worker 736*6777b538SAndroid Build Coastguard Worker 737*6777b538SAndroid Build Coastguard Workerdef main(): 738*6777b538SAndroid Build Coastguard Worker build_utils.InitLogging('PROGUARD_DEBUG') 739*6777b538SAndroid Build Coastguard Worker options = _ParseOptions() 740*6777b538SAndroid Build Coastguard Worker 741*6777b538SAndroid Build Coastguard Worker if options.dump_inputs: 742*6777b538SAndroid Build Coastguard Worker # Dumping inputs causes output to be emitted, avoid failing due to stdout. 743*6777b538SAndroid Build Coastguard Worker options.warnings_as_errors = False 744*6777b538SAndroid Build Coastguard Worker # Use dumpinputtodirectory instead of dumpinputtofile to avoid failing the 745*6777b538SAndroid Build Coastguard Worker # build and keep running tracereferences. 746*6777b538SAndroid Build Coastguard Worker dump_dir_name = _DUMP_DIR_NAME 747*6777b538SAndroid Build Coastguard Worker dump_dir_path = pathlib.Path(dump_dir_name) 748*6777b538SAndroid Build Coastguard Worker if dump_dir_path.exists(): 749*6777b538SAndroid Build Coastguard Worker shutil.rmtree(dump_dir_path) 750*6777b538SAndroid Build Coastguard Worker # The directory needs to exist before r8 adds the zip files in it. 751*6777b538SAndroid Build Coastguard Worker dump_dir_path.mkdir() 752*6777b538SAndroid Build Coastguard Worker 753*6777b538SAndroid Build Coastguard Worker # This ensure that the final outputs are zipped and easily uploaded to a bug. 754*6777b538SAndroid Build Coastguard Worker try: 755*6777b538SAndroid Build Coastguard Worker _Run(options) 756*6777b538SAndroid Build Coastguard Worker finally: 757*6777b538SAndroid Build Coastguard Worker if options.dump_inputs: 758*6777b538SAndroid Build Coastguard Worker zip_helpers.zip_directory('r8inputs.zip', _DUMP_DIR_NAME) 759*6777b538SAndroid Build Coastguard Worker 760*6777b538SAndroid Build Coastguard Worker 761*6777b538SAndroid Build Coastguard Workerif __name__ == '__main__': 762*6777b538SAndroid Build Coastguard Worker main() 763