xref: /aosp_15_r20/external/cronet/build/android/gyp/dex.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 collections
9*6777b538SAndroid Build Coastguard Workerimport logging
10*6777b538SAndroid Build Coastguard Workerimport os
11*6777b538SAndroid Build Coastguard Workerimport re
12*6777b538SAndroid Build Coastguard Workerimport shutil
13*6777b538SAndroid Build Coastguard Workerimport shlex
14*6777b538SAndroid Build Coastguard Workerimport sys
15*6777b538SAndroid Build Coastguard Workerimport tempfile
16*6777b538SAndroid Build Coastguard Workerimport zipfile
17*6777b538SAndroid Build Coastguard Worker
18*6777b538SAndroid Build Coastguard Workerfrom util import build_utils
19*6777b538SAndroid Build Coastguard Workerfrom util import md5_check
20*6777b538SAndroid Build Coastguard Workerimport action_helpers  # build_utils adds //build to sys.path.
21*6777b538SAndroid Build Coastguard Workerimport zip_helpers
22*6777b538SAndroid Build Coastguard Worker
23*6777b538SAndroid Build Coastguard Worker
24*6777b538SAndroid Build Coastguard Worker_DEX_XMX = '2G'  # Increase this when __final_dex OOMs.
25*6777b538SAndroid Build Coastguard Worker
26*6777b538SAndroid Build Coastguard WorkerDEFAULT_IGNORE_WARNINGS = (
27*6777b538SAndroid Build Coastguard Worker    # Warning: Running R8 version main (build engineering), which cannot be
28*6777b538SAndroid Build Coastguard Worker    # represented as a semantic version. Using an artificial version newer than
29*6777b538SAndroid Build Coastguard Worker    # any known version for selecting Proguard configurations embedded under
30*6777b538SAndroid Build Coastguard Worker    # META-INF/. This means that all rules with a '-upto-' qualifier will be
31*6777b538SAndroid Build Coastguard Worker    # excluded and all rules with a -from- qualifier will be included.
32*6777b538SAndroid Build Coastguard Worker    r'Running R8 version main', )
33*6777b538SAndroid Build Coastguard Worker
34*6777b538SAndroid Build Coastguard WorkerINTERFACE_DESUGARING_WARNINGS = (r'default or static interface methods', )
35*6777b538SAndroid Build Coastguard Worker
36*6777b538SAndroid Build Coastguard Worker_SKIPPED_CLASS_FILE_NAMES = (
37*6777b538SAndroid Build Coastguard Worker    'module-info.class',  # Explicitly skipped by r8/utils/FileUtils#isClassFile
38*6777b538SAndroid Build Coastguard Worker)
39*6777b538SAndroid Build Coastguard Worker
40*6777b538SAndroid Build Coastguard Worker
41*6777b538SAndroid Build Coastguard Workerdef _ParseArgs(args):
42*6777b538SAndroid Build Coastguard Worker  args = build_utils.ExpandFileArgs(args)
43*6777b538SAndroid Build Coastguard Worker  parser = argparse.ArgumentParser()
44*6777b538SAndroid Build Coastguard Worker
45*6777b538SAndroid Build Coastguard Worker  action_helpers.add_depfile_arg(parser)
46*6777b538SAndroid Build Coastguard Worker  parser.add_argument('--output', required=True, help='Dex output path.')
47*6777b538SAndroid Build Coastguard Worker  parser.add_argument(
48*6777b538SAndroid Build Coastguard Worker      '--class-inputs',
49*6777b538SAndroid Build Coastguard Worker      action='append',
50*6777b538SAndroid Build Coastguard Worker      help='GN-list of .jars with .class files.')
51*6777b538SAndroid Build Coastguard Worker  parser.add_argument(
52*6777b538SAndroid Build Coastguard Worker      '--class-inputs-filearg',
53*6777b538SAndroid Build Coastguard Worker      action='append',
54*6777b538SAndroid Build Coastguard Worker      help='GN-list of .jars with .class files (added to depfile).')
55*6777b538SAndroid Build Coastguard Worker  parser.add_argument(
56*6777b538SAndroid Build Coastguard Worker      '--dex-inputs', action='append', help='GN-list of .jars with .dex files.')
57*6777b538SAndroid Build Coastguard Worker  parser.add_argument(
58*6777b538SAndroid Build Coastguard Worker      '--dex-inputs-filearg',
59*6777b538SAndroid Build Coastguard Worker      action='append',
60*6777b538SAndroid Build Coastguard Worker      help='GN-list of .jars with .dex files (added to depfile).')
61*6777b538SAndroid Build Coastguard Worker  parser.add_argument(
62*6777b538SAndroid Build Coastguard Worker      '--incremental-dir',
63*6777b538SAndroid Build Coastguard Worker      help='Path of directory to put intermediate dex files.')
64*6777b538SAndroid Build Coastguard Worker  parser.add_argument('--library',
65*6777b538SAndroid Build Coastguard Worker                      action='store_true',
66*6777b538SAndroid Build Coastguard Worker                      help='Allow numerous dex files within output.')
67*6777b538SAndroid Build Coastguard Worker  parser.add_argument('--r8-jar-path', required=True, help='Path to R8 jar.')
68*6777b538SAndroid Build Coastguard Worker  parser.add_argument('--skip-custom-d8',
69*6777b538SAndroid Build Coastguard Worker                      action='store_true',
70*6777b538SAndroid Build Coastguard Worker                      help='When rebuilding the CustomD8 jar, this may be '
71*6777b538SAndroid Build Coastguard Worker                      'necessary to avoid incompatibility with the new r8 '
72*6777b538SAndroid Build Coastguard Worker                      'jar.')
73*6777b538SAndroid Build Coastguard Worker  parser.add_argument('--custom-d8-jar-path',
74*6777b538SAndroid Build Coastguard Worker                      required=True,
75*6777b538SAndroid Build Coastguard Worker                      help='Path to our customized d8 jar.')
76*6777b538SAndroid Build Coastguard Worker  parser.add_argument('--desugar-dependencies',
77*6777b538SAndroid Build Coastguard Worker                      help='Path to store desugar dependencies.')
78*6777b538SAndroid Build Coastguard Worker  parser.add_argument('--desugar', action='store_true')
79*6777b538SAndroid Build Coastguard Worker  parser.add_argument(
80*6777b538SAndroid Build Coastguard Worker      '--bootclasspath',
81*6777b538SAndroid Build Coastguard Worker      action='append',
82*6777b538SAndroid Build Coastguard Worker      help='GN-list of bootclasspath. Needed for --desugar')
83*6777b538SAndroid Build Coastguard Worker  parser.add_argument('--show-desugar-default-interface-warnings',
84*6777b538SAndroid Build Coastguard Worker                      action='store_true',
85*6777b538SAndroid Build Coastguard Worker                      help='Enable desugaring warnings.')
86*6777b538SAndroid Build Coastguard Worker  parser.add_argument(
87*6777b538SAndroid Build Coastguard Worker      '--classpath',
88*6777b538SAndroid Build Coastguard Worker      action='append',
89*6777b538SAndroid Build Coastguard Worker      help='GN-list of full classpath. Needed for --desugar')
90*6777b538SAndroid Build Coastguard Worker  parser.add_argument('--release',
91*6777b538SAndroid Build Coastguard Worker                      action='store_true',
92*6777b538SAndroid Build Coastguard Worker                      help='Run D8 in release mode.')
93*6777b538SAndroid Build Coastguard Worker  parser.add_argument(
94*6777b538SAndroid Build Coastguard Worker      '--min-api', help='Minimum Android API level compatibility.')
95*6777b538SAndroid Build Coastguard Worker  parser.add_argument('--force-enable-assertions',
96*6777b538SAndroid Build Coastguard Worker                      action='store_true',
97*6777b538SAndroid Build Coastguard Worker                      help='Forcefully enable javac generated assertion code.')
98*6777b538SAndroid Build Coastguard Worker  parser.add_argument('--assertion-handler',
99*6777b538SAndroid Build Coastguard Worker                      help='The class name of the assertion handler class.')
100*6777b538SAndroid Build Coastguard Worker  parser.add_argument('--warnings-as-errors',
101*6777b538SAndroid Build Coastguard Worker                      action='store_true',
102*6777b538SAndroid Build Coastguard Worker                      help='Treat all warnings as errors.')
103*6777b538SAndroid Build Coastguard Worker  parser.add_argument('--dump-inputs',
104*6777b538SAndroid Build Coastguard Worker                      action='store_true',
105*6777b538SAndroid Build Coastguard Worker                      help='Use when filing D8 bugs to capture inputs.'
106*6777b538SAndroid Build Coastguard Worker                      ' Stores inputs to d8inputs.zip')
107*6777b538SAndroid Build Coastguard Worker  options = parser.parse_args(args)
108*6777b538SAndroid Build Coastguard Worker
109*6777b538SAndroid Build Coastguard Worker  if options.force_enable_assertions and options.assertion_handler:
110*6777b538SAndroid Build Coastguard Worker    parser.error('Cannot use both --force-enable-assertions and '
111*6777b538SAndroid Build Coastguard Worker                 '--assertion-handler')
112*6777b538SAndroid Build Coastguard Worker
113*6777b538SAndroid Build Coastguard Worker  options.class_inputs = action_helpers.parse_gn_list(options.class_inputs)
114*6777b538SAndroid Build Coastguard Worker  options.class_inputs_filearg = action_helpers.parse_gn_list(
115*6777b538SAndroid Build Coastguard Worker      options.class_inputs_filearg)
116*6777b538SAndroid Build Coastguard Worker  options.bootclasspath = action_helpers.parse_gn_list(options.bootclasspath)
117*6777b538SAndroid Build Coastguard Worker  options.classpath = action_helpers.parse_gn_list(options.classpath)
118*6777b538SAndroid Build Coastguard Worker  options.dex_inputs = action_helpers.parse_gn_list(options.dex_inputs)
119*6777b538SAndroid Build Coastguard Worker  options.dex_inputs_filearg = action_helpers.parse_gn_list(
120*6777b538SAndroid Build Coastguard Worker      options.dex_inputs_filearg)
121*6777b538SAndroid Build Coastguard Worker
122*6777b538SAndroid Build Coastguard Worker  return options
123*6777b538SAndroid Build Coastguard Worker
124*6777b538SAndroid Build Coastguard Worker
125*6777b538SAndroid Build Coastguard Workerdef CreateStderrFilter(filters):
126*6777b538SAndroid Build Coastguard Worker  def filter_stderr(output):
127*6777b538SAndroid Build Coastguard Worker    # Set this when debugging R8 output.
128*6777b538SAndroid Build Coastguard Worker    if os.environ.get('R8_SHOW_ALL_OUTPUT', '0') != '0':
129*6777b538SAndroid Build Coastguard Worker      return output
130*6777b538SAndroid Build Coastguard Worker
131*6777b538SAndroid Build Coastguard Worker    # All missing definitions are logged as a single warning, but start on a
132*6777b538SAndroid Build Coastguard Worker    # new line like "Missing class ...".
133*6777b538SAndroid Build Coastguard Worker    warnings = re.split(r'^(?=Warning|Error|Missing (?:class|field|method))',
134*6777b538SAndroid Build Coastguard Worker                        output,
135*6777b538SAndroid Build Coastguard Worker                        flags=re.MULTILINE)
136*6777b538SAndroid Build Coastguard Worker    preamble, *warnings = warnings
137*6777b538SAndroid Build Coastguard Worker
138*6777b538SAndroid Build Coastguard Worker    combined_pattern = '|'.join(filters)
139*6777b538SAndroid Build Coastguard Worker    preamble = build_utils.FilterLines(preamble, combined_pattern)
140*6777b538SAndroid Build Coastguard Worker
141*6777b538SAndroid Build Coastguard Worker    compiled_re = re.compile(combined_pattern, re.DOTALL)
142*6777b538SAndroid Build Coastguard Worker    warnings = [w for w in warnings if not compiled_re.search(w)]
143*6777b538SAndroid Build Coastguard Worker
144*6777b538SAndroid Build Coastguard Worker    return preamble + ''.join(warnings)
145*6777b538SAndroid Build Coastguard Worker
146*6777b538SAndroid Build Coastguard Worker  return filter_stderr
147*6777b538SAndroid Build Coastguard Worker
148*6777b538SAndroid Build Coastguard Worker
149*6777b538SAndroid Build Coastguard Workerdef _RunD8(dex_cmd, input_paths, output_path, warnings_as_errors,
150*6777b538SAndroid Build Coastguard Worker           show_desugar_default_interface_warnings):
151*6777b538SAndroid Build Coastguard Worker  dex_cmd = dex_cmd + ['--output', output_path] + input_paths
152*6777b538SAndroid Build Coastguard Worker
153*6777b538SAndroid Build Coastguard Worker  # Missing deps can happen for prebuilts that are missing transitive deps
154*6777b538SAndroid Build Coastguard Worker  # and have set enable_bytecode_checks=false.
155*6777b538SAndroid Build Coastguard Worker  filters = list(DEFAULT_IGNORE_WARNINGS)
156*6777b538SAndroid Build Coastguard Worker  if not show_desugar_default_interface_warnings:
157*6777b538SAndroid Build Coastguard Worker    filters += INTERFACE_DESUGARING_WARNINGS
158*6777b538SAndroid Build Coastguard Worker
159*6777b538SAndroid Build Coastguard Worker  stderr_filter = CreateStderrFilter(filters)
160*6777b538SAndroid Build Coastguard Worker
161*6777b538SAndroid Build Coastguard Worker  is_debug = logging.getLogger().isEnabledFor(logging.DEBUG)
162*6777b538SAndroid Build Coastguard Worker
163*6777b538SAndroid Build Coastguard Worker  # Avoid deleting the flag file when DEX_DEBUG is set in case the flag file
164*6777b538SAndroid Build Coastguard Worker  # needs to be examined after the build.
165*6777b538SAndroid Build Coastguard Worker  with tempfile.NamedTemporaryFile(mode='w', delete=not is_debug) as flag_file:
166*6777b538SAndroid Build Coastguard Worker    # Chosen arbitrarily. Needed to avoid command-line length limits.
167*6777b538SAndroid Build Coastguard Worker    MAX_ARGS = 50
168*6777b538SAndroid Build Coastguard Worker    orig_dex_cmd = dex_cmd
169*6777b538SAndroid Build Coastguard Worker    if len(dex_cmd) > MAX_ARGS:
170*6777b538SAndroid Build Coastguard Worker      # Add all flags to D8 (anything after the first --) as well as all
171*6777b538SAndroid Build Coastguard Worker      # positional args at the end to the flag file.
172*6777b538SAndroid Build Coastguard Worker      for idx, cmd in enumerate(dex_cmd):
173*6777b538SAndroid Build Coastguard Worker        if cmd.startswith('--'):
174*6777b538SAndroid Build Coastguard Worker          flag_file.write('\n'.join(dex_cmd[idx:]))
175*6777b538SAndroid Build Coastguard Worker          flag_file.flush()
176*6777b538SAndroid Build Coastguard Worker          dex_cmd = dex_cmd[:idx]
177*6777b538SAndroid Build Coastguard Worker          dex_cmd.append('@' + flag_file.name)
178*6777b538SAndroid Build Coastguard Worker          break
179*6777b538SAndroid Build Coastguard Worker
180*6777b538SAndroid Build Coastguard Worker    # stdout sometimes spams with things like:
181*6777b538SAndroid Build Coastguard Worker    # Stripped invalid locals information from 1 method.
182*6777b538SAndroid Build Coastguard Worker    try:
183*6777b538SAndroid Build Coastguard Worker      build_utils.CheckOutput(dex_cmd,
184*6777b538SAndroid Build Coastguard Worker                              stderr_filter=stderr_filter,
185*6777b538SAndroid Build Coastguard Worker                              fail_on_output=warnings_as_errors)
186*6777b538SAndroid Build Coastguard Worker    except Exception as e:
187*6777b538SAndroid Build Coastguard Worker      if isinstance(e, build_utils.CalledProcessError):
188*6777b538SAndroid Build Coastguard Worker        output = e.output  # pylint: disable=no-member
189*6777b538SAndroid Build Coastguard Worker        if "global synthetic for 'Record desugaring'" in output:
190*6777b538SAndroid Build Coastguard Worker          sys.stderr.write('Java records are not supported.\n')
191*6777b538SAndroid Build Coastguard Worker          sys.stderr.write(
192*6777b538SAndroid Build Coastguard Worker              'See https://chromium.googlesource.com/chromium/src/+/' +
193*6777b538SAndroid Build Coastguard Worker              'main/styleguide/java/java.md#Records\n')
194*6777b538SAndroid Build Coastguard Worker          sys.exit(1)
195*6777b538SAndroid Build Coastguard Worker      if orig_dex_cmd is not dex_cmd:
196*6777b538SAndroid Build Coastguard Worker        sys.stderr.write('Full command: ' + shlex.join(orig_dex_cmd) + '\n')
197*6777b538SAndroid Build Coastguard Worker      raise
198*6777b538SAndroid Build Coastguard Worker
199*6777b538SAndroid Build Coastguard Worker
200*6777b538SAndroid Build Coastguard Workerdef _ZipAligned(dex_files, output_path):
201*6777b538SAndroid Build Coastguard Worker  """Creates a .dex.jar with 4-byte aligned files.
202*6777b538SAndroid Build Coastguard Worker
203*6777b538SAndroid Build Coastguard Worker  Args:
204*6777b538SAndroid Build Coastguard Worker    dex_files: List of dex files.
205*6777b538SAndroid Build Coastguard Worker    output_path: The output file in which to write the zip.
206*6777b538SAndroid Build Coastguard Worker  """
207*6777b538SAndroid Build Coastguard Worker  with zipfile.ZipFile(output_path, 'w') as z:
208*6777b538SAndroid Build Coastguard Worker    for i, dex_file in enumerate(dex_files):
209*6777b538SAndroid Build Coastguard Worker      name = 'classes{}.dex'.format(i + 1 if i > 0 else '')
210*6777b538SAndroid Build Coastguard Worker      zip_helpers.add_to_zip_hermetic(z, name, src_path=dex_file, alignment=4)
211*6777b538SAndroid Build Coastguard Worker
212*6777b538SAndroid Build Coastguard Worker
213*6777b538SAndroid Build Coastguard Workerdef _CreateFinalDex(d8_inputs, output, tmp_dir, dex_cmd, options=None):
214*6777b538SAndroid Build Coastguard Worker  tmp_dex_output = os.path.join(tmp_dir, 'tmp_dex_output.zip')
215*6777b538SAndroid Build Coastguard Worker  needs_dexing = not all(f.endswith('.dex') for f in d8_inputs)
216*6777b538SAndroid Build Coastguard Worker  needs_dexmerge = output.endswith('.dex') or not (options and options.library)
217*6777b538SAndroid Build Coastguard Worker  if needs_dexing or needs_dexmerge:
218*6777b538SAndroid Build Coastguard Worker    tmp_dex_dir = os.path.join(tmp_dir, 'tmp_dex_dir')
219*6777b538SAndroid Build Coastguard Worker    os.mkdir(tmp_dex_dir)
220*6777b538SAndroid Build Coastguard Worker
221*6777b538SAndroid Build Coastguard Worker    _RunD8(dex_cmd, d8_inputs, tmp_dex_dir,
222*6777b538SAndroid Build Coastguard Worker           (not options or options.warnings_as_errors),
223*6777b538SAndroid Build Coastguard Worker           (options and options.show_desugar_default_interface_warnings))
224*6777b538SAndroid Build Coastguard Worker    logging.debug('Performed dex merging')
225*6777b538SAndroid Build Coastguard Worker
226*6777b538SAndroid Build Coastguard Worker    dex_files = [os.path.join(tmp_dex_dir, f) for f in os.listdir(tmp_dex_dir)]
227*6777b538SAndroid Build Coastguard Worker
228*6777b538SAndroid Build Coastguard Worker    if output.endswith('.dex'):
229*6777b538SAndroid Build Coastguard Worker      if len(dex_files) > 1:
230*6777b538SAndroid Build Coastguard Worker        raise Exception('%d files created, expected 1' % len(dex_files))
231*6777b538SAndroid Build Coastguard Worker      tmp_dex_output = dex_files[0]
232*6777b538SAndroid Build Coastguard Worker    else:
233*6777b538SAndroid Build Coastguard Worker      _ZipAligned(sorted(dex_files), tmp_dex_output)
234*6777b538SAndroid Build Coastguard Worker  else:
235*6777b538SAndroid Build Coastguard Worker    # Skip dexmerger. Just put all incrementals into the .jar individually.
236*6777b538SAndroid Build Coastguard Worker    _ZipAligned(sorted(d8_inputs), tmp_dex_output)
237*6777b538SAndroid Build Coastguard Worker    logging.debug('Quick-zipped %d files', len(d8_inputs))
238*6777b538SAndroid Build Coastguard Worker
239*6777b538SAndroid Build Coastguard Worker  # The dex file is complete and can be moved out of tmp_dir.
240*6777b538SAndroid Build Coastguard Worker  shutil.move(tmp_dex_output, output)
241*6777b538SAndroid Build Coastguard Worker
242*6777b538SAndroid Build Coastguard Worker
243*6777b538SAndroid Build Coastguard Workerdef _IntermediateDexFilePathsFromInputJars(class_inputs, incremental_dir):
244*6777b538SAndroid Build Coastguard Worker  """Returns a list of all intermediate dex file paths."""
245*6777b538SAndroid Build Coastguard Worker  dex_files = []
246*6777b538SAndroid Build Coastguard Worker  for jar in class_inputs:
247*6777b538SAndroid Build Coastguard Worker    with zipfile.ZipFile(jar, 'r') as z:
248*6777b538SAndroid Build Coastguard Worker      for subpath in z.namelist():
249*6777b538SAndroid Build Coastguard Worker        if _IsClassFile(subpath):
250*6777b538SAndroid Build Coastguard Worker          subpath = subpath[:-5] + 'dex'
251*6777b538SAndroid Build Coastguard Worker          dex_files.append(os.path.join(incremental_dir, subpath))
252*6777b538SAndroid Build Coastguard Worker  return dex_files
253*6777b538SAndroid Build Coastguard Worker
254*6777b538SAndroid Build Coastguard Worker
255*6777b538SAndroid Build Coastguard Workerdef _DeleteStaleIncrementalDexFiles(dex_dir, dex_files):
256*6777b538SAndroid Build Coastguard Worker  """Deletes intermediate .dex files that are no longer needed."""
257*6777b538SAndroid Build Coastguard Worker  all_files = build_utils.FindInDirectory(dex_dir)
258*6777b538SAndroid Build Coastguard Worker  desired_files = set(dex_files)
259*6777b538SAndroid Build Coastguard Worker  for path in all_files:
260*6777b538SAndroid Build Coastguard Worker    if path not in desired_files:
261*6777b538SAndroid Build Coastguard Worker      os.unlink(path)
262*6777b538SAndroid Build Coastguard Worker
263*6777b538SAndroid Build Coastguard Worker
264*6777b538SAndroid Build Coastguard Workerdef _ParseDesugarDeps(desugar_dependencies_file):
265*6777b538SAndroid Build Coastguard Worker  # pylint: disable=line-too-long
266*6777b538SAndroid Build Coastguard Worker  """Returns a dict of dependent/dependency mapping parsed from the file.
267*6777b538SAndroid Build Coastguard Worker
268*6777b538SAndroid Build Coastguard Worker  Example file format:
269*6777b538SAndroid Build Coastguard Worker  $ tail out/Debug/gen/base/base_java__dex.desugardeps
270*6777b538SAndroid Build Coastguard Worker  org/chromium/base/task/SingleThreadTaskRunnerImpl.class
271*6777b538SAndroid Build Coastguard Worker    <-  org/chromium/base/task/SingleThreadTaskRunner.class
272*6777b538SAndroid Build Coastguard Worker    <-  org/chromium/base/task/TaskRunnerImpl.class
273*6777b538SAndroid Build Coastguard Worker  org/chromium/base/task/TaskRunnerImpl.class
274*6777b538SAndroid Build Coastguard Worker    <-  org/chromium/base/task/TaskRunner.class
275*6777b538SAndroid Build Coastguard Worker  org/chromium/base/task/TaskRunnerImplJni$1.class
276*6777b538SAndroid Build Coastguard Worker    <-  obj/base/jni_java.turbine.jar:org/jni_zero/JniStaticTestMocker.class
277*6777b538SAndroid Build Coastguard Worker  org/chromium/base/task/TaskRunnerImplJni.class
278*6777b538SAndroid Build Coastguard Worker    <-  org/chromium/base/task/TaskRunnerImpl$Natives.class
279*6777b538SAndroid Build Coastguard Worker  """
280*6777b538SAndroid Build Coastguard Worker  # pylint: enable=line-too-long
281*6777b538SAndroid Build Coastguard Worker  dependents_from_dependency = collections.defaultdict(set)
282*6777b538SAndroid Build Coastguard Worker  if desugar_dependencies_file and os.path.exists(desugar_dependencies_file):
283*6777b538SAndroid Build Coastguard Worker    with open(desugar_dependencies_file, 'r') as f:
284*6777b538SAndroid Build Coastguard Worker      dependent = None
285*6777b538SAndroid Build Coastguard Worker      for line in f:
286*6777b538SAndroid Build Coastguard Worker        line = line.rstrip()
287*6777b538SAndroid Build Coastguard Worker        if line.startswith('  <-  '):
288*6777b538SAndroid Build Coastguard Worker          dependency = line[len('  <-  '):]
289*6777b538SAndroid Build Coastguard Worker          # Note that this is a reversed mapping from the one in CustomD8.java.
290*6777b538SAndroid Build Coastguard Worker          dependents_from_dependency[dependency].add(dependent)
291*6777b538SAndroid Build Coastguard Worker        else:
292*6777b538SAndroid Build Coastguard Worker          dependent = line
293*6777b538SAndroid Build Coastguard Worker  return dependents_from_dependency
294*6777b538SAndroid Build Coastguard Worker
295*6777b538SAndroid Build Coastguard Worker
296*6777b538SAndroid Build Coastguard Workerdef _ComputeRequiredDesugarClasses(changes, desugar_dependencies_file,
297*6777b538SAndroid Build Coastguard Worker                                   class_inputs, classpath):
298*6777b538SAndroid Build Coastguard Worker  dependents_from_dependency = _ParseDesugarDeps(desugar_dependencies_file)
299*6777b538SAndroid Build Coastguard Worker  required_classes = set()
300*6777b538SAndroid Build Coastguard Worker  # Gather classes that need to be re-desugared from changes in the classpath.
301*6777b538SAndroid Build Coastguard Worker  for jar in classpath:
302*6777b538SAndroid Build Coastguard Worker    for subpath in changes.IterChangedSubpaths(jar):
303*6777b538SAndroid Build Coastguard Worker      dependency = '{}:{}'.format(jar, subpath)
304*6777b538SAndroid Build Coastguard Worker      required_classes.update(dependents_from_dependency[dependency])
305*6777b538SAndroid Build Coastguard Worker
306*6777b538SAndroid Build Coastguard Worker  for jar in class_inputs:
307*6777b538SAndroid Build Coastguard Worker    for subpath in changes.IterChangedSubpaths(jar):
308*6777b538SAndroid Build Coastguard Worker      required_classes.update(dependents_from_dependency[subpath])
309*6777b538SAndroid Build Coastguard Worker
310*6777b538SAndroid Build Coastguard Worker  return required_classes
311*6777b538SAndroid Build Coastguard Worker
312*6777b538SAndroid Build Coastguard Worker
313*6777b538SAndroid Build Coastguard Workerdef _IsClassFile(path):
314*6777b538SAndroid Build Coastguard Worker  if os.path.basename(path) in _SKIPPED_CLASS_FILE_NAMES:
315*6777b538SAndroid Build Coastguard Worker    return False
316*6777b538SAndroid Build Coastguard Worker  return path.endswith('.class')
317*6777b538SAndroid Build Coastguard Worker
318*6777b538SAndroid Build Coastguard Worker
319*6777b538SAndroid Build Coastguard Workerdef _ExtractClassFiles(changes, tmp_dir, class_inputs, required_classes_set):
320*6777b538SAndroid Build Coastguard Worker  classes_list = []
321*6777b538SAndroid Build Coastguard Worker  for jar in class_inputs:
322*6777b538SAndroid Build Coastguard Worker    if changes:
323*6777b538SAndroid Build Coastguard Worker      changed_class_list = (set(changes.IterChangedSubpaths(jar))
324*6777b538SAndroid Build Coastguard Worker                            | required_classes_set)
325*6777b538SAndroid Build Coastguard Worker      predicate = lambda x: x in changed_class_list and _IsClassFile(x)
326*6777b538SAndroid Build Coastguard Worker    else:
327*6777b538SAndroid Build Coastguard Worker      predicate = _IsClassFile
328*6777b538SAndroid Build Coastguard Worker
329*6777b538SAndroid Build Coastguard Worker    classes_list.extend(
330*6777b538SAndroid Build Coastguard Worker        build_utils.ExtractAll(jar, path=tmp_dir, predicate=predicate))
331*6777b538SAndroid Build Coastguard Worker  return classes_list
332*6777b538SAndroid Build Coastguard Worker
333*6777b538SAndroid Build Coastguard Worker
334*6777b538SAndroid Build Coastguard Workerdef _CreateIntermediateDexFiles(changes, options, tmp_dir, dex_cmd):
335*6777b538SAndroid Build Coastguard Worker  # Create temporary directory for classes to be extracted to.
336*6777b538SAndroid Build Coastguard Worker  tmp_extract_dir = os.path.join(tmp_dir, 'tmp_extract_dir')
337*6777b538SAndroid Build Coastguard Worker  os.mkdir(tmp_extract_dir)
338*6777b538SAndroid Build Coastguard Worker
339*6777b538SAndroid Build Coastguard Worker  # Do a full rebuild when changes occur in non-input files.
340*6777b538SAndroid Build Coastguard Worker  allowed_changed = set(options.class_inputs)
341*6777b538SAndroid Build Coastguard Worker  allowed_changed.update(options.dex_inputs)
342*6777b538SAndroid Build Coastguard Worker  allowed_changed.update(options.classpath)
343*6777b538SAndroid Build Coastguard Worker  strings_changed = changes.HasStringChanges()
344*6777b538SAndroid Build Coastguard Worker  non_direct_input_changed = next(
345*6777b538SAndroid Build Coastguard Worker      (p for p in changes.IterChangedPaths() if p not in allowed_changed), None)
346*6777b538SAndroid Build Coastguard Worker
347*6777b538SAndroid Build Coastguard Worker  if strings_changed or non_direct_input_changed:
348*6777b538SAndroid Build Coastguard Worker    logging.debug('Full dex required: strings_changed=%s path_changed=%s',
349*6777b538SAndroid Build Coastguard Worker                  strings_changed, non_direct_input_changed)
350*6777b538SAndroid Build Coastguard Worker    changes = None
351*6777b538SAndroid Build Coastguard Worker
352*6777b538SAndroid Build Coastguard Worker  if changes is None:
353*6777b538SAndroid Build Coastguard Worker    required_desugar_classes_set = set()
354*6777b538SAndroid Build Coastguard Worker  else:
355*6777b538SAndroid Build Coastguard Worker    required_desugar_classes_set = _ComputeRequiredDesugarClasses(
356*6777b538SAndroid Build Coastguard Worker        changes, options.desugar_dependencies, options.class_inputs,
357*6777b538SAndroid Build Coastguard Worker        options.classpath)
358*6777b538SAndroid Build Coastguard Worker    logging.debug('Class files needing re-desugar: %d',
359*6777b538SAndroid Build Coastguard Worker                  len(required_desugar_classes_set))
360*6777b538SAndroid Build Coastguard Worker  class_files = _ExtractClassFiles(changes, tmp_extract_dir,
361*6777b538SAndroid Build Coastguard Worker                                   options.class_inputs,
362*6777b538SAndroid Build Coastguard Worker                                   required_desugar_classes_set)
363*6777b538SAndroid Build Coastguard Worker  logging.debug('Extracted class files: %d', len(class_files))
364*6777b538SAndroid Build Coastguard Worker
365*6777b538SAndroid Build Coastguard Worker  # If the only change is deleting a file, class_files will be empty.
366*6777b538SAndroid Build Coastguard Worker  if class_files:
367*6777b538SAndroid Build Coastguard Worker    # Dex necessary classes into intermediate dex files.
368*6777b538SAndroid Build Coastguard Worker    dex_cmd = dex_cmd + ['--intermediate', '--file-per-class-file']
369*6777b538SAndroid Build Coastguard Worker    if options.desugar_dependencies and not options.skip_custom_d8:
370*6777b538SAndroid Build Coastguard Worker      # Adding os.sep to remove the entire prefix.
371*6777b538SAndroid Build Coastguard Worker      dex_cmd += ['--file-tmp-prefix', tmp_extract_dir + os.sep]
372*6777b538SAndroid Build Coastguard Worker      if changes is None and os.path.exists(options.desugar_dependencies):
373*6777b538SAndroid Build Coastguard Worker        # Since incremental dexing only ever adds to the desugar_dependencies
374*6777b538SAndroid Build Coastguard Worker        # file, whenever full dexes are required the .desugardeps files need to
375*6777b538SAndroid Build Coastguard Worker        # be manually removed.
376*6777b538SAndroid Build Coastguard Worker        os.unlink(options.desugar_dependencies)
377*6777b538SAndroid Build Coastguard Worker    _RunD8(dex_cmd, class_files, options.incremental_dir,
378*6777b538SAndroid Build Coastguard Worker           options.warnings_as_errors,
379*6777b538SAndroid Build Coastguard Worker           options.show_desugar_default_interface_warnings)
380*6777b538SAndroid Build Coastguard Worker    logging.debug('Dexed class files.')
381*6777b538SAndroid Build Coastguard Worker
382*6777b538SAndroid Build Coastguard Worker
383*6777b538SAndroid Build Coastguard Workerdef _OnStaleMd5(changes, options, final_dex_inputs, dex_cmd):
384*6777b538SAndroid Build Coastguard Worker  logging.debug('_OnStaleMd5')
385*6777b538SAndroid Build Coastguard Worker  with build_utils.TempDir() as tmp_dir:
386*6777b538SAndroid Build Coastguard Worker    if options.incremental_dir:
387*6777b538SAndroid Build Coastguard Worker      # Create directory for all intermediate dex files.
388*6777b538SAndroid Build Coastguard Worker      if not os.path.exists(options.incremental_dir):
389*6777b538SAndroid Build Coastguard Worker        os.makedirs(options.incremental_dir)
390*6777b538SAndroid Build Coastguard Worker
391*6777b538SAndroid Build Coastguard Worker      _DeleteStaleIncrementalDexFiles(options.incremental_dir, final_dex_inputs)
392*6777b538SAndroid Build Coastguard Worker      logging.debug('Stale files deleted')
393*6777b538SAndroid Build Coastguard Worker      _CreateIntermediateDexFiles(changes, options, tmp_dir, dex_cmd)
394*6777b538SAndroid Build Coastguard Worker
395*6777b538SAndroid Build Coastguard Worker    _CreateFinalDex(
396*6777b538SAndroid Build Coastguard Worker        final_dex_inputs, options.output, tmp_dir, dex_cmd, options=options)
397*6777b538SAndroid Build Coastguard Worker
398*6777b538SAndroid Build Coastguard Worker
399*6777b538SAndroid Build Coastguard Workerdef MergeDexForIncrementalInstall(r8_jar_path, src_paths, dest_dex_jar,
400*6777b538SAndroid Build Coastguard Worker                                  min_api):
401*6777b538SAndroid Build Coastguard Worker  dex_cmd = build_utils.JavaCmd(xmx=_DEX_XMX) + [
402*6777b538SAndroid Build Coastguard Worker      '-cp',
403*6777b538SAndroid Build Coastguard Worker      r8_jar_path,
404*6777b538SAndroid Build Coastguard Worker      'com.android.tools.r8.D8',
405*6777b538SAndroid Build Coastguard Worker      '--min-api',
406*6777b538SAndroid Build Coastguard Worker      min_api,
407*6777b538SAndroid Build Coastguard Worker  ]
408*6777b538SAndroid Build Coastguard Worker  with build_utils.TempDir() as tmp_dir:
409*6777b538SAndroid Build Coastguard Worker    _CreateFinalDex(src_paths, dest_dex_jar, tmp_dir, dex_cmd)
410*6777b538SAndroid Build Coastguard Worker
411*6777b538SAndroid Build Coastguard Worker
412*6777b538SAndroid Build Coastguard Workerdef main(args):
413*6777b538SAndroid Build Coastguard Worker  build_utils.InitLogging('DEX_DEBUG')
414*6777b538SAndroid Build Coastguard Worker  options = _ParseArgs(args)
415*6777b538SAndroid Build Coastguard Worker
416*6777b538SAndroid Build Coastguard Worker  options.class_inputs += options.class_inputs_filearg
417*6777b538SAndroid Build Coastguard Worker  options.dex_inputs += options.dex_inputs_filearg
418*6777b538SAndroid Build Coastguard Worker
419*6777b538SAndroid Build Coastguard Worker  input_paths = ([
420*6777b538SAndroid Build Coastguard Worker      build_utils.JAVA_PATH_FOR_INPUTS, options.r8_jar_path,
421*6777b538SAndroid Build Coastguard Worker      options.custom_d8_jar_path
422*6777b538SAndroid Build Coastguard Worker  ] + options.class_inputs + options.dex_inputs)
423*6777b538SAndroid Build Coastguard Worker
424*6777b538SAndroid Build Coastguard Worker  depfile_deps = options.class_inputs_filearg + options.dex_inputs_filearg
425*6777b538SAndroid Build Coastguard Worker
426*6777b538SAndroid Build Coastguard Worker  output_paths = [options.output]
427*6777b538SAndroid Build Coastguard Worker
428*6777b538SAndroid Build Coastguard Worker  track_subpaths_allowlist = []
429*6777b538SAndroid Build Coastguard Worker  if options.incremental_dir:
430*6777b538SAndroid Build Coastguard Worker    final_dex_inputs = _IntermediateDexFilePathsFromInputJars(
431*6777b538SAndroid Build Coastguard Worker        options.class_inputs, options.incremental_dir)
432*6777b538SAndroid Build Coastguard Worker    output_paths += final_dex_inputs
433*6777b538SAndroid Build Coastguard Worker    track_subpaths_allowlist += options.class_inputs
434*6777b538SAndroid Build Coastguard Worker  else:
435*6777b538SAndroid Build Coastguard Worker    final_dex_inputs = list(options.class_inputs)
436*6777b538SAndroid Build Coastguard Worker  final_dex_inputs += options.dex_inputs
437*6777b538SAndroid Build Coastguard Worker
438*6777b538SAndroid Build Coastguard Worker  dex_cmd = build_utils.JavaCmd(xmx=_DEX_XMX)
439*6777b538SAndroid Build Coastguard Worker
440*6777b538SAndroid Build Coastguard Worker  if options.dump_inputs:
441*6777b538SAndroid Build Coastguard Worker    dex_cmd += ['-Dcom.android.tools.r8.dumpinputtofile=d8inputs.zip']
442*6777b538SAndroid Build Coastguard Worker
443*6777b538SAndroid Build Coastguard Worker  if not options.skip_custom_d8:
444*6777b538SAndroid Build Coastguard Worker    dex_cmd += [
445*6777b538SAndroid Build Coastguard Worker        '-cp',
446*6777b538SAndroid Build Coastguard Worker        '{}:{}'.format(options.r8_jar_path, options.custom_d8_jar_path),
447*6777b538SAndroid Build Coastguard Worker        'org.chromium.build.CustomD8',
448*6777b538SAndroid Build Coastguard Worker    ]
449*6777b538SAndroid Build Coastguard Worker  else:
450*6777b538SAndroid Build Coastguard Worker    dex_cmd += [
451*6777b538SAndroid Build Coastguard Worker        '-cp',
452*6777b538SAndroid Build Coastguard Worker        options.r8_jar_path,
453*6777b538SAndroid Build Coastguard Worker        'com.android.tools.r8.D8',
454*6777b538SAndroid Build Coastguard Worker    ]
455*6777b538SAndroid Build Coastguard Worker
456*6777b538SAndroid Build Coastguard Worker  if options.release:
457*6777b538SAndroid Build Coastguard Worker    dex_cmd += ['--release']
458*6777b538SAndroid Build Coastguard Worker  if options.min_api:
459*6777b538SAndroid Build Coastguard Worker    dex_cmd += ['--min-api', options.min_api]
460*6777b538SAndroid Build Coastguard Worker
461*6777b538SAndroid Build Coastguard Worker  if not options.desugar:
462*6777b538SAndroid Build Coastguard Worker    dex_cmd += ['--no-desugaring']
463*6777b538SAndroid Build Coastguard Worker  elif options.classpath:
464*6777b538SAndroid Build Coastguard Worker    # The classpath is used by D8 to for interface desugaring.
465*6777b538SAndroid Build Coastguard Worker    if options.desugar_dependencies and not options.skip_custom_d8:
466*6777b538SAndroid Build Coastguard Worker      dex_cmd += ['--desugar-dependencies', options.desugar_dependencies]
467*6777b538SAndroid Build Coastguard Worker      if track_subpaths_allowlist:
468*6777b538SAndroid Build Coastguard Worker        track_subpaths_allowlist += options.classpath
469*6777b538SAndroid Build Coastguard Worker    depfile_deps += options.classpath
470*6777b538SAndroid Build Coastguard Worker    input_paths += options.classpath
471*6777b538SAndroid Build Coastguard Worker    # Still pass the entire classpath in case a new dependency is needed by
472*6777b538SAndroid Build Coastguard Worker    # desugar, so that desugar_dependencies will be updated for the next build.
473*6777b538SAndroid Build Coastguard Worker    for path in options.classpath:
474*6777b538SAndroid Build Coastguard Worker      dex_cmd += ['--classpath', path]
475*6777b538SAndroid Build Coastguard Worker
476*6777b538SAndroid Build Coastguard Worker  if options.classpath:
477*6777b538SAndroid Build Coastguard Worker    dex_cmd += ['--lib', build_utils.JAVA_HOME]
478*6777b538SAndroid Build Coastguard Worker    for path in options.bootclasspath:
479*6777b538SAndroid Build Coastguard Worker      dex_cmd += ['--lib', path]
480*6777b538SAndroid Build Coastguard Worker    depfile_deps += options.bootclasspath
481*6777b538SAndroid Build Coastguard Worker    input_paths += options.bootclasspath
482*6777b538SAndroid Build Coastguard Worker
483*6777b538SAndroid Build Coastguard Worker
484*6777b538SAndroid Build Coastguard Worker  if options.assertion_handler:
485*6777b538SAndroid Build Coastguard Worker    dex_cmd += ['--force-assertions-handler:' + options.assertion_handler]
486*6777b538SAndroid Build Coastguard Worker  if options.force_enable_assertions:
487*6777b538SAndroid Build Coastguard Worker    dex_cmd += ['--force-enable-assertions']
488*6777b538SAndroid Build Coastguard Worker
489*6777b538SAndroid Build Coastguard Worker  # The changes feature from md5_check allows us to only re-dex the class files
490*6777b538SAndroid Build Coastguard Worker  # that have changed and the class files that need to be re-desugared by D8.
491*6777b538SAndroid Build Coastguard Worker  md5_check.CallAndWriteDepfileIfStale(
492*6777b538SAndroid Build Coastguard Worker      lambda changes: _OnStaleMd5(changes, options, final_dex_inputs, dex_cmd),
493*6777b538SAndroid Build Coastguard Worker      options,
494*6777b538SAndroid Build Coastguard Worker      input_paths=input_paths,
495*6777b538SAndroid Build Coastguard Worker      input_strings=dex_cmd + [str(bool(options.incremental_dir))],
496*6777b538SAndroid Build Coastguard Worker      output_paths=output_paths,
497*6777b538SAndroid Build Coastguard Worker      pass_changes=True,
498*6777b538SAndroid Build Coastguard Worker      track_subpaths_allowlist=track_subpaths_allowlist,
499*6777b538SAndroid Build Coastguard Worker      depfile_deps=depfile_deps)
500*6777b538SAndroid Build Coastguard Worker
501*6777b538SAndroid Build Coastguard Worker
502*6777b538SAndroid Build Coastguard Workerif __name__ == '__main__':
503*6777b538SAndroid Build Coastguard Worker  sys.exit(main(sys.argv[1:]))
504