xref: /aosp_15_r20/external/angle/build/android/gyp/proguard.py (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
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