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