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