示例#1
0
def _SplitChildFeatures(options, feature_contexts, tmp_dir, mapping_path,
                        print_stdout):
    feature_map = {f.name: f for f in feature_contexts}
    parent_to_child = defaultdict(list)
    for child, parent in options.uses_split.items():
        parent_to_child[parent].append(child)
    for parent, children in parent_to_child.items():
        split_output = os.path.join(tmp_dir, 'split_%s' % parent)
        os.mkdir(split_output)
        # DexSplitter is not perfect and can cause issues related to inlining and
        # class merging (see crbug.com/1032609). If strange class loading errors
        # happen in DFMs specifying uses_split, this may be the cause.
        split_cmd = build_utils.JavaCmd(options.warnings_as_errors) + [
            '-cp',
            options.r8_path,
            'com.android.tools.r8.dexsplitter.DexSplitter',
            '--output',
            split_output,
            '--proguard-map',
            mapping_path,
        ]

        parent_jars = set(feature_map[parent].input_paths)
        for base_jar in sorted(parent_jars):
            split_cmd += ['--base-jar', base_jar]

        for child in children:
            for feature_jar in feature_map[child].input_paths:
                if feature_jar not in parent_jars:
                    split_cmd += [
                        '--feature-jar',
                        '%s:%s' % (feature_jar, child)
                    ]

        # The inputs are the outputs for the parent from the original R8 call.
        parent_dir = feature_map[parent].staging_dir
        for file_name in os.listdir(parent_dir):
            split_cmd += ['--input', os.path.join(parent_dir, file_name)]
        logging.debug('Running R8 DexSplitter')
        build_utils.CheckOutput(split_cmd,
                                print_stdout=print_stdout,
                                fail_on_output=options.warnings_as_errors)

        # Copy the parent dex back into the parent's staging dir.
        base_split_output = os.path.join(split_output, 'base')
        shutil.rmtree(parent_dir)
        os.mkdir(parent_dir)
        for dex_file in os.listdir(base_split_output):
            shutil.move(os.path.join(base_split_output, dex_file),
                        os.path.join(parent_dir, dex_file))

        # Copy each child dex back into the child's staging dir.
        for child in children:
            child_split_output = os.path.join(split_output, child)
            child_staging_dir = feature_map[child].staging_dir
            shutil.rmtree(child_staging_dir)
            os.mkdir(child_staging_dir)
            for dex_file in os.listdir(child_split_output):
                shutil.move(os.path.join(child_split_output, dex_file),
                            os.path.join(child_staging_dir, dex_file))
示例#2
0
def FinalizeApk(apksigner_path,
                zipalign_path,
                unsigned_apk_path,
                final_apk_path,
                key_path,
                key_passwd,
                key_name,
                min_sdk_version,
                warnings_as_errors=False):
    # Use a tempfile so that Ctrl-C does not leave the file with a fresh mtime
    # and a corrupted state.
    with tempfile.NamedTemporaryFile() as staging_file:
        if zipalign_path:
            # v2 signing requires that zipalign happen first.
            logging.debug('Running zipalign')
            zipalign_cmd = [
                zipalign_path, '-p', '-f', '4', unsigned_apk_path,
                staging_file.name
            ]
            build_utils.CheckOutput(zipalign_cmd,
                                    print_stdout=True,
                                    fail_on_output=warnings_as_errors)
            signer_input_path = staging_file.name
        else:
            signer_input_path = unsigned_apk_path

        sign_cmd = build_utils.JavaCmd(warnings_as_errors) + [
            '-jar',
            apksigner_path,
            'sign',
            '--in',
            signer_input_path,
            '--out',
            staging_file.name,
            '--ks',
            key_path,
            '--ks-key-alias',
            key_name,
            '--ks-pass',
            'pass:'******'--v3-signing-enabled', 'false']

        if min_sdk_version >= 24:
            # Disable v1 signatures when v2 signing can be used (it's much faster).
            # By default, both v1 and v2 signing happen.
            sign_cmd += ['--v1-signing-enabled', 'false']
        else:
            # Force SHA-1 (makes signing faster; insecure is fine for local builds).
            # Leave v2 signing enabled since it verifies faster on device when
            # supported.
            sign_cmd += ['--min-sdk-version', '1']

        logging.debug('Signing apk')
        build_utils.CheckOutput(sign_cmd,
                                print_stdout=True,
                                fail_on_output=warnings_as_errors)
        shutil.move(staging_file.name, final_apk_path)
        staging_file.delete = False
示例#3
0
def _OnStaleMd5(options, javac_cmd, javac_args, java_files):
    logging.info('Starting _OnStaleMd5')
    if options.enable_kythe_annotations:
        # Kythe requires those env variables to be set and compile_java.py does the
        # same
        if not os.environ.get('KYTHE_ROOT_DIRECTORY') or \
            not os.environ.get('KYTHE_OUTPUT_DIRECTORY'):
            raise Exception('--enable-kythe-annotations requires '
                            'KYTHE_ROOT_DIRECTORY and KYTHE_OUTPUT_DIRECTORY '
                            'environment variables to be set.')
        javac_extractor_cmd = build_utils.JavaCmd() + [
            '-jar',
            _JAVAC_EXTRACTOR,
        ]
        try:
            _RunCompiler(options,
                         javac_extractor_cmd + javac_args,
                         java_files,
                         options.classpath,
                         options.jar_path + '.javac_extractor',
                         save_outputs=False),
        except build_utils.CalledProcessError as e:
            # Having no index for particular target is better than failing entire
            # codesearch. Log and error and move on.
            logging.error('Could not generate kzip: %s', e)

    # Compiles with Error Prone take twice as long to run as pure javac. Thus GN
    # rules run both in parallel, with Error Prone only used for checks.
    _RunCompiler(options,
                 javac_cmd + javac_args,
                 java_files,
                 options.classpath,
                 options.jar_path,
                 save_outputs=not options.enable_errorprone)
    logging.info('Completed all steps in _OnStaleMd5')
示例#4
0
def _RunDexsplitter(options, output_dir):
    cmd = build_utils.JavaCmd() + [
        '-cp',
        options.r8_path,
        'com.android.tools.r8.dexsplitter.DexSplitter',
        '--output',
        output_dir,
        '--proguard-map',
        options.proguard_mapping_file,
    ]

    for base_jar in options.features['base']:
        cmd += ['--base-jar', base_jar]

    base_jars_lookup = set(options.features['base'])
    for feature in options.features:
        if feature == 'base':
            continue
        for feature_jar in options.features[feature]:
            if feature_jar not in base_jars_lookup:
                cmd += ['--feature-jar', feature_jar + ':' + feature]

    with build_utils.TempDir() as temp_dir:
        unzipped_files = build_utils.ExtractAll(options.input_dex_zip,
                                                temp_dir)
        for file_name in unzipped_files:
            cmd += ['--input', file_name]
        build_utils.CheckOutput(cmd)
示例#5
0
文件: dex.py 项目: zlederman/chromium
def MergeDexForIncrementalInstall(r8_jar_path, src_paths, dest_dex_jar):
    dex_cmd = build_utils.JavaCmd(verify=False) + [
        '-cp',
        r8_jar_path,
        'com.android.tools.r8.D8',
    ]
    with build_utils.TempDir() as tmp_dir:
        _CreateFinalDex(src_paths, dest_dex_jar, tmp_dir, dex_cmd)
示例#6
0
文件: desugar.py 项目: wzis/chromium
def main():
    args = build_utils.ExpandFileArgs(sys.argv[1:])
    parser = argparse.ArgumentParser()
    build_utils.AddDepfileOption(parser)
    parser.add_argument('--desugar-jar',
                        required=True,
                        help='Path to Desugar.jar.')
    parser.add_argument('--input-jar',
                        required=True,
                        help='Jar input path to include .class files from.')
    parser.add_argument('--output-jar', required=True, help='Jar output path.')
    parser.add_argument('--classpath',
                        action='append',
                        required=True,
                        help='Classpath.')
    parser.add_argument('--bootclasspath',
                        required=True,
                        help='Path to javac bootclasspath interface jar.')
    parser.add_argument('--warnings-as-errors',
                        action='store_true',
                        help='Treat all warnings as errors.')
    options = parser.parse_args(args)

    options.bootclasspath = build_utils.ParseGnList(options.bootclasspath)
    options.classpath = build_utils.ParseGnList(options.classpath)

    cmd = build_utils.JavaCmd(options.warnings_as_errors) + [
        '-jar',
        options.desugar_jar,
        '--input',
        options.input_jar,
        '--output',
        options.output_jar,
        '--generate_base_classes_for_default_methods',
        # Don't include try-with-resources files in every .jar. Instead, they
        # are included via //third_party/bazel/desugar:desugar_runtime_java.
        '--desugar_try_with_resources_omit_runtime_classes',
    ]
    for path in options.bootclasspath:
        cmd += ['--bootclasspath_entry', path]
    for path in options.classpath:
        cmd += ['--classpath_entry', path]
    build_utils.CheckOutput(
        cmd,
        print_stdout=False,
        stderr_filter=build_utils.FilterReflectiveAccessJavaWarnings,
        fail_on_output=options.warnings_as_errors)

    if options.depfile:
        build_utils.WriteDepfile(options.depfile,
                                 options.output_jar,
                                 inputs=options.bootclasspath +
                                 options.classpath)
示例#7
0
def _RunInstrumentCommand(parser):
    """Instruments class or Jar files using JaCoCo.

  Args:
    parser: ArgumentParser object.

  Returns:
    An exit code.
  """
    args = parser.parse_args()

    source_files = []
    if args.java_sources_file:
        source_files.extend(build_utils.ReadSourcesList(
            args.java_sources_file))

    with build_utils.TempDir() as temp_dir:
        instrument_cmd = build_utils.JavaCmd() + [
            '-jar', args.jacococli_jar, 'instrument'
        ]

        if not args.files_to_instrument:
            _InstrumentClassFiles(instrument_cmd, args.input_path,
                                  args.output_path, temp_dir)
        else:
            affected_files = build_utils.ReadSourcesList(
                args.files_to_instrument)
            source_set = set(source_files)
            affected_source_files = [
                f for f in affected_files if f in source_set
            ]

            # Copy input_path to output_path and return if no source file affected.
            if not affected_source_files:
                shutil.copyfile(args.input_path, args.output_path)
                # Create a dummy sources_json_file.
                _CreateSourcesJsonFile([], None, args.sources_json_file,
                                       build_utils.DIR_SOURCE_ROOT)
                return 0
            else:
                _InstrumentClassFiles(instrument_cmd, args.input_path,
                                      args.output_path, temp_dir,
                                      affected_source_files)

    source_dirs = _GetSourceDirsFromSourceFiles(source_files)
    # TODO(GYP): In GN, we are passed the list of sources, detecting source
    # directories, then walking them to re-establish the list of sources.
    # This can obviously be simplified!
    _CreateSourcesJsonFile(source_dirs, args.input_path,
                           args.sources_json_file, build_utils.DIR_SOURCE_ROOT)

    return 0
示例#8
0
def RunBundleTool(args, warnings_as_errors=()):
  # Use () instead of None because command-line flags are None by default.
  verify = warnings_as_errors == () or warnings_as_errors
  # ASAN builds failed with the default of 1GB (crbug.com/1120202).
  # Bug for bundletool: https://issuetracker.google.com/issues/165911616
  cmd = build_utils.JavaCmd(verify, xmx='4G')
  cmd += ['-jar', BUNDLETOOL_JAR_PATH]
  cmd += args
  logging.debug(' '.join(cmd))
  return build_utils.CheckOutput(
      cmd,
      print_stderr=True,
      fail_on_output=False,
      stderr_filter=build_utils.FilterReflectiveAccessJavaWarnings)
示例#9
0
def _OnStaleMd5(changes, options, javac_cmd, javac_args, java_files):
    logging.info('Starting _OnStaleMd5')
    if options.enable_kythe_annotations:
        # Kythe requires those env variables to be set and compile_java.py does the
        # same
        if not os.environ.get('KYTHE_ROOT_DIRECTORY') or \
            not os.environ.get('KYTHE_OUTPUT_DIRECTORY'):
            raise Exception('--enable-kythe-annotations requires '
                            'KYTHE_ROOT_DIRECTORY and KYTHE_OUTPUT_DIRECTORY '
                            'environment variables to be set.')
        javac_extractor_cmd = build_utils.JavaCmd() + [
            '-jar',
            _JAVAC_EXTRACTOR,
        ]
        try:
            # _RunCompiler()'s partial javac implementation does not support
            # generating outputs in $KYTHE_OUTPUT_DIRECTORY.
            _RunCompiler(changes,
                         options,
                         javac_extractor_cmd + javac_args,
                         java_files,
                         options.jar_path + '.javac_extractor',
                         enable_partial_javac=False)
        except build_utils.CalledProcessError as e:
            # Having no index for particular target is better than failing entire
            # codesearch. Log and error and move on.
            logging.error('Could not generate kzip: %s', e)

    intermediates_out_dir = None
    jar_info_path = None
    if not options.enable_errorprone:
        # Delete any stale files in the generated directory. The purpose of
        # options.generated_dir is for codesearch.
        shutil.rmtree(options.generated_dir, True)
        intermediates_out_dir = options.generated_dir

        jar_info_path = options.jar_path + '.info'

    # Compiles with Error Prone take twice as long to run as pure javac. Thus GN
    # rules run both in parallel, with Error Prone only used for checks.
    _RunCompiler(changes,
                 options,
                 javac_cmd + javac_args,
                 java_files,
                 options.jar_path,
                 jar_info_path=jar_info_path,
                 intermediates_out_dir=intermediates_out_dir,
                 enable_partial_javac=True)
    logging.info('Completed all steps in _OnStaleMd5')
示例#10
0
def _OutputKeepRules(r8_path, input_paths, classpath, targets_re_string,
                     keep_rules_output):
  cmd = build_utils.JavaCmd(False) + [
      '-cp', r8_path, 'com.android.tools.r8.tracereferences.TraceReferences',
      '--map-diagnostics:MissingDefinitionsDiagnostic', 'error', 'warning',
      '--keep-rules', '--output', keep_rules_output
  ]
  targets_re = re.compile(targets_re_string)
  for path in input_paths:
    if targets_re.search(path):
      cmd += ['--target', path]
    else:
      cmd += ['--source', path]
  for path in classpath:
    cmd += ['--lib', path]

  build_utils.CheckOutput(cmd, print_stderr=False, fail_on_output=False)
示例#11
0
def DexJdkLibJar(r8_path,
                 min_api,
                 desugar_jdk_libs_json,
                 desugar_jdk_libs_jar,
                 desugar_jdk_libs_configuration_jar,
                 output,
                 warnings_as_errors,
                 config_paths=None):
    # TODO(agrieve): Spews a lot of stderr about missing classes.
    with build_utils.TempDir() as tmp_dir:
        cmd = build_utils.JavaCmd(warnings_as_errors) + [
            '-cp',
            r8_path,
            'com.android.tools.r8.L8',
            '--min-api',
            min_api,
            '--lib',
            build_utils.JAVA_HOME,
            '--desugared-lib',
            desugar_jdk_libs_json,
        ]

        # If no desugaring is required, no keep rules are generated, and the keep
        # file will not be created.
        if config_paths is not None:
            for path in config_paths:
                cmd += ['--pg-conf', path]

        cmd += [
            '--output', tmp_dir, desugar_jdk_libs_jar,
            desugar_jdk_libs_configuration_jar
        ]

        build_utils.CheckOutput(cmd,
                                print_stdout=True,
                                fail_on_output=warnings_as_errors)
        if os.path.exists(os.path.join(tmp_dir, 'classes2.dex')):
            raise Exception(
                'Achievement unlocked: desugar_jdk_libs is multidex!')

        # classes.dex might not exists if the "desugar_jdk_libs_jar" is not used
        # at all.
        if os.path.exists(os.path.join(tmp_dir, 'classes.dex')):
            shutil.move(os.path.join(tmp_dir, 'classes.dex'), output)
            return True
        return False
示例#12
0
def main(argv):
    build_utils.InitLogging('TURBINE_DEBUG')
    argv = build_utils.ExpandFileArgs(argv[1:])
    parser = argparse.ArgumentParser()
    build_utils.AddDepfileOption(parser)
    parser.add_argument('--turbine-jar-path',
                        required=True,
                        help='Path to the turbine jar file.')
    parser.add_argument('--java-srcjars',
                        action='append',
                        default=[],
                        help='List of srcjars to include in compilation.')
    parser.add_argument(
        '--bootclasspath',
        action='append',
        default=[],
        help='Boot classpath for javac. If this is specified multiple times, '
        'they will all be appended to construct the classpath.')
    parser.add_argument(
        '--java-version',
        help=
        'Java language version to use in -source and -target args to javac.')
    parser.add_argument('--classpath',
                        action='append',
                        help='Classpath to use.')
    parser.add_argument('--processors',
                        action='append',
                        help='GN list of annotation processor main classes.')
    parser.add_argument(
        '--processorpath',
        action='append',
        help='GN list of jars that comprise the classpath used for Annotation '
        'Processors.')
    parser.add_argument(
        '--processor-args',
        action='append',
        help='key=value arguments for the annotation processors.')
    parser.add_argument('--jar-path', help='Jar output path.', required=True)
    parser.add_argument('--generated-jar-path',
                        required=True,
                        help='Output path for generated source files.')
    parser.add_argument('--warnings-as-errors',
                        action='store_true',
                        help='Treat all warnings as errors.')
    options, unknown_args = parser.parse_known_args(argv)

    options.bootclasspath = build_utils.ParseGnList(options.bootclasspath)
    options.classpath = build_utils.ParseGnList(options.classpath)
    options.processorpath = build_utils.ParseGnList(options.processorpath)
    options.processors = build_utils.ParseGnList(options.processors)
    options.java_srcjars = build_utils.ParseGnList(options.java_srcjars)

    files = []
    for arg in unknown_args:
        # Interpret a path prefixed with @ as a file containing a list of sources.
        if arg.startswith('@'):
            files.extend(build_utils.ReadSourcesList(arg[1:]))

    cmd = build_utils.JavaCmd(options.warnings_as_errors) + [
        '-classpath', options.turbine_jar_path, 'com.google.turbine.main.Main'
    ]
    javac_cmd = []

    # Turbine reads lists from command line args by consuming args until one
    # starts with double dash (--). Thus command line args should be grouped
    # together and passed in together.
    if options.processors:
        cmd += ['--processors']
        cmd += options.processors

    if options.java_version:
        javac_cmd.extend([
            '-source',
            options.java_version,
            '-target',
            options.java_version,
        ])
    if options.java_version == '1.8':
        # Android's boot jar doesn't contain all java 8 classes.
        options.bootclasspath.append(build_utils.RT_JAR_PATH)

    if options.bootclasspath:
        cmd += ['--bootclasspath']
        for bootclasspath in options.bootclasspath:
            cmd += bootclasspath.split(':')

    if options.processorpath:
        cmd += ['--processorpath']
        cmd += options.processorpath

    if options.processor_args:
        for arg in options.processor_args:
            javac_cmd.extend(['-A%s' % arg])

    if options.classpath:
        cmd += ['--classpath']
        cmd += options.classpath

    if options.java_srcjars:
        cmd += ['--source_jars']
        cmd += options.java_srcjars

    if files:
        # Use jar_path to ensure paths are relative (needed for goma).
        files_rsp_path = options.jar_path + '.files_list.txt'
        with open(files_rsp_path, 'w') as f:
            f.write(' '.join(files))
        # Pass source paths as response files to avoid extremely long command lines
        # that are tedius to debug.
        cmd += ['--sources']
        cmd += ['@' + files_rsp_path]

    if javac_cmd:
        cmd.append('--javacopts')
        cmd += javac_cmd
        cmd.append('--')  # Terminate javacopts

    # Use AtomicOutput so that output timestamps are not updated when outputs
    # are not changed.
    with build_utils.AtomicOutput(options.jar_path) as output_jar, \
        build_utils.AtomicOutput(options.generated_jar_path) as generated_jar:
        cmd += [
            '--output', output_jar.name, '--gensrc_output', generated_jar.name
        ]
        logging.debug('Command: %s', cmd)
        start = time.time()
        build_utils.CheckOutput(cmd,
                                print_stdout=True,
                                fail_on_output=options.warnings_as_errors)
        end = time.time() - start
        logging.info('Header compilation took %ss', end)

    if options.depfile:
        # GN already knows of the java files, so avoid listing individual java files
        # in the depfile.
        depfile_deps = (options.bootclasspath + options.classpath +
                        options.processorpath + options.java_srcjars)
        build_utils.WriteDepfile(options.depfile, options.jar_path,
                                 depfile_deps)
示例#13
0
def _OptimizeWithR8(options,
                    config_paths,
                    libraries,
                    dynamic_config_data,
                    print_stdout=False):
    with build_utils.TempDir() as tmp_dir:
        if dynamic_config_data:
            tmp_config_path = os.path.join(tmp_dir, 'proguard_config.txt')
            with open(tmp_config_path, 'w') as f:
                f.write(dynamic_config_data)
            config_paths = config_paths + [tmp_config_path]

        tmp_mapping_path = os.path.join(tmp_dir, 'mapping.txt')
        # If there is no output (no classes are kept), this prevents this script
        # from failing.
        build_utils.Touch(tmp_mapping_path)

        tmp_output = os.path.join(tmp_dir, 'r8out')
        os.mkdir(tmp_output)

        feature_contexts = []
        if options.feature_names:
            for name, dest_dex, input_paths in zip(options.feature_names,
                                                   options.dex_dests,
                                                   options.feature_jars):
                feature_context = _DexPathContext(name, dest_dex, input_paths,
                                                  tmp_output)
                if name == 'base':
                    base_dex_context = feature_context
                else:
                    feature_contexts.append(feature_context)
        else:
            base_dex_context = _DexPathContext('base', options.output_path,
                                               options.input_paths, tmp_output)

        cmd = build_utils.JavaCmd(options.warnings_as_errors) + [
            '-Dcom.android.tools.r8.allowTestProguardOptions=1',
            '-Dcom.android.tools.r8.verticalClassMerging=1',
        ]
        if options.disable_outlining:
            cmd += ['-Dcom.android.tools.r8.disableOutlining=1']
        cmd += [
            '-cp',
            options.r8_path,
            'com.android.tools.r8.R8',
            '--no-data-resources',
            '--output',
            base_dex_context.staging_dir,
            '--pg-map-output',
            tmp_mapping_path,
        ]

        if options.disable_checkdiscard:
            # Info level priority logs are not printed by default.
            cmd += [
                '--map-diagnostics:'
                'com.android.tools.r8.errors.CheckDiscardDiagnostic',
                'error',
                'info',
            ]

        if options.desugar_jdk_libs_json:
            cmd += [
                '--desugared-lib',
                options.desugar_jdk_libs_json,
                '--desugared-lib-pg-conf-output',
                options.desugared_library_keep_rule_output,
            ]

        if options.min_api:
            cmd += ['--min-api', options.min_api]

        if options.force_enable_assertions:
            cmd += ['--force-enable-assertions']

        for lib in libraries:
            cmd += ['--lib', lib]

        for config_file in config_paths:
            cmd += ['--pg-conf', config_file]

        if options.main_dex_rules_path:
            for main_dex_rule in options.main_dex_rules_path:
                cmd += ['--main-dex-rules', main_dex_rule]

        base_jars = set(base_dex_context.input_paths)
        # If a jar is present in multiple features, it should be moved to the base
        # module.
        all_feature_jars = set()
        for feature in feature_contexts:
            base_jars.update(all_feature_jars.intersection(
                feature.input_paths))
            all_feature_jars.update(feature.input_paths)

        module_input_jars = base_jars.copy()
        for feature in feature_contexts:
            feature_input_jars = [
                p for p in feature.input_paths if p not in module_input_jars
            ]
            module_input_jars.update(feature_input_jars)
            for in_jar in feature_input_jars:
                cmd += ['--feature', in_jar, feature.staging_dir]

        cmd += sorted(base_jars)
        # Add any extra input jars to the base module (e.g. desugar runtime).
        extra_jars = set(options.input_paths) - module_input_jars
        cmd += sorted(extra_jars)

        try:
            stderr_filter = dex.CreateStderrFilter(
                options.show_desugar_default_interface_warnings)
            logging.debug('Running R8')
            build_utils.CheckOutput(cmd,
                                    print_stdout=print_stdout,
                                    stderr_filter=stderr_filter,
                                    fail_on_output=options.warnings_as_errors)
        except build_utils.CalledProcessError as err:
            debugging_link = ('\n\nR8 failed. Please see {}.'.format(
                'https://chromium.googlesource.com/chromium/src/+/HEAD/build/'
                'android/docs/java_optimization.md#Debugging-common-failures\n'
            ))
            raise build_utils.CalledProcessError(err.cwd, err.args,
                                                 err.output + debugging_link)

        base_has_imported_lib = False
        if options.desugar_jdk_libs_json:
            logging.debug('Running L8')
            existing_files = build_utils.FindInDirectory(
                base_dex_context.staging_dir)
            jdk_dex_output = os.path.join(
                base_dex_context.staging_dir,
                'classes%d.dex' % (len(existing_files) + 1))
            base_has_imported_lib = dex_jdk_libs.DexJdkLibJar(
                options.r8_path, options.min_api,
                options.desugar_jdk_libs_json, options.desugar_jdk_libs_jar,
                options.desugar_jdk_libs_configuration_jar,
                options.desugared_library_keep_rule_output, jdk_dex_output,
                options.warnings_as_errors)

        logging.debug('Collecting ouputs')
        base_dex_context.CreateOutput(
            base_has_imported_lib, options.desugared_library_keep_rule_output)
        for feature in feature_contexts:
            feature.CreateOutput()

        with open(options.mapping_output, 'w') as out_file, \
            open(tmp_mapping_path) as in_file:
            # Mapping files generated by R8 include comments that may break
            # some of our tooling so remove those (specifically: apkanalyzer).
            out_file.writelines(l for l in in_file if not l.startswith('#'))
示例#14
0
def main(args):
    build_utils.InitLogging('DEX_DEBUG')
    options = _ParseArgs(args)

    options.class_inputs += options.class_inputs_filearg
    options.dex_inputs += options.dex_inputs_filearg

    input_paths = options.class_inputs + options.dex_inputs
    if options.multi_dex and options.main_dex_list_path:
        input_paths.append(options.main_dex_list_path)
    input_paths.append(options.r8_jar_path)
    input_paths.append(options.custom_d8_jar_path)

    depfile_deps = options.class_inputs_filearg + options.dex_inputs_filearg

    output_paths = [options.output]

    if options.incremental_dir:
        final_dex_inputs = _IntermediateDexFilePathsFromInputJars(
            options.class_inputs, options.incremental_dir)
        output_paths += final_dex_inputs
        track_subpaths_allowlist = options.class_inputs
    else:
        final_dex_inputs = list(options.class_inputs)
        track_subpaths_allowlist = None
    final_dex_inputs += options.dex_inputs

    dex_cmd = build_utils.JavaCmd(options.warnings_as_errors) + [
        '-cp',
        '{}:{}'.format(options.r8_jar_path, options.custom_d8_jar_path),
        'org.chromium.build.CustomD8',
    ]
    if options.release:
        dex_cmd += ['--release']
    if options.min_api:
        dex_cmd += ['--min-api', options.min_api]

    if not options.desugar:
        dex_cmd += ['--no-desugaring']
    elif options.classpath:
        # The classpath is used by D8 to for interface desugaring.
        classpath_paths = options.classpath
        if options.desugar_dependencies:
            dex_cmd += ['--desugar-dependencies', options.desugar_dependencies]
            if os.path.exists(options.desugar_dependencies):
                with open(options.desugar_dependencies, 'r') as f:
                    lines = [line.strip() for line in f.readlines()]
                    # Use a set to deduplicate entries.
                    desugar_dependencies = set(dep for dep in lines if dep)
                # Desugar dependencies are a subset of classpath.
                classpath_paths = list(desugar_dependencies)
        depfile_deps += classpath_paths
        input_paths += classpath_paths
        dex_cmd += ['--lib', build_utils.JAVA_HOME]
        for path in options.bootclasspath:
            dex_cmd += ['--lib', path]
        # Still pass the entire classpath in case a new dependency is needed by
        # desugar, so that desugar_dependencies will be updated for the next build.
        for path in options.classpath:
            dex_cmd += ['--classpath', path]
        depfile_deps += options.bootclasspath
        input_paths += options.bootclasspath

    if options.desugar_jdk_libs_json:
        dex_cmd += ['--desugared-lib', options.desugar_jdk_libs_json]
    if options.force_enable_assertions:
        dex_cmd += ['--force-enable-assertions']

    md5_check.CallAndWriteDepfileIfStale(
        lambda changes: _OnStaleMd5(changes, options, final_dex_inputs, dex_cmd
                                    ),
        options,
        input_paths=input_paths,
        input_strings=dex_cmd + [bool(options.incremental_dir)],
        output_paths=output_paths,
        pass_changes=True,
        track_subpaths_allowlist=track_subpaths_allowlist,
        depfile_deps=depfile_deps)
示例#15
0
def _CheckForMissingSymbols(r8_path, dex_files, classpath, warnings_as_errors,
                            error_title):
  cmd = build_utils.JavaCmd(warnings_as_errors) + [
      '-cp', r8_path, 'com.android.tools.r8.tracereferences.TraceReferences',
      '--map-diagnostics:MissingDefinitionsDiagnostic', 'error', 'warning',
      '--check'
  ]

  for path in classpath:
    cmd += ['--lib', path]
  for path in dex_files:
    cmd += ['--source', path]

  def stderr_filter(stderr):
    ignored_lines = [
        # Summary contains warning count, which our filtering makes wrong.
        'Warning: Tracereferences found',

        # TODO(agrieve): Create interface jars for these missing classes rather
        #     than allowlisting here.
        'dalvik.system',
        'libcore.io',
        'sun.misc.Unsafe',

        # Found in: com/facebook/fbui/textlayoutbuilder/StaticLayoutHelper
        'android.text.StaticLayout.<init>',

        # Explicictly guarded by try (NoClassDefFoundError) in Flogger's
        # PlatformProvider.
        'com.google.common.flogger.backend.google.GooglePlatform',
        'com.google.common.flogger.backend.system.DefaultPlatform',

        # trichrome_webview_google_bundle contains this missing reference.
        # TODO(crbug.com/1142530): Fix this missing reference properly.
        'org.chromium.build.NativeLibraries',

        # TODO(agrieve): Exclude these only when use_jacoco_coverage=true.
        'java.lang.instrument.ClassFileTransformer',
        'java.lang.instrument.IllegalClassFormatException',
        'java.lang.instrument.Instrumentation',
        'java.lang.management.ManagementFactory',
        'javax.management.MBeanServer',
        'javax.management.ObjectInstance',
        'javax.management.ObjectName',
        'javax.management.StandardMBean',

        # Explicitly guarded by try (NoClassDefFoundError) in Firebase's
        # KotlinDetector: com.google.firebase.platforminfo.KotlinDetector.
        'kotlin.KotlinVersion',
    ]

    had_unfiltered_items = '  ' in stderr
    stderr = build_utils.FilterLines(
        stderr, '|'.join(re.escape(x) for x in ignored_lines))
    if stderr:
      if '  ' in stderr:
        stderr = error_title + """
Tip: Build with:
        is_java_debug=false
        treat_warnings_as_errors=false
        enable_proguard_obfuscation=false
     and then use dexdump to see which class(s) reference them.

     E.g.:
       third_party/android_sdk/public/build-tools/*/dexdump -d \
out/Release/apks/YourApk.apk > dex.txt
""" + stderr

        if 'FragmentActivity' in stderr:
          stderr += """
You may need to update build configs to run FragmentActivityReplacer for
additional targets. See
https://chromium.googlesource.com/chromium/src.git/+/master/docs/ui/android/bytecode_rewriting.md.
"""
      elif had_unfiltered_items:
        # Left only with empty headings. All indented items filtered out.
        stderr = ''
    return stderr

  logging.debug('cmd: %s', ' '.join(cmd))
  build_utils.CheckOutput(cmd,
                          print_stdout=True,
                          stderr_filter=stderr_filter,
                          fail_on_output=warnings_as_errors)
示例#16
0
def _OptimizeWithR8(options,
                    config_paths,
                    libraries,
                    dynamic_config_data,
                    print_stdout=False):
  with build_utils.TempDir() as tmp_dir:
    if dynamic_config_data:
      dynamic_config_path = os.path.join(tmp_dir, 'dynamic_config.flags')
      with open(dynamic_config_path, 'w') as f:
        f.write(dynamic_config_data)
      config_paths = config_paths + [dynamic_config_path]

    tmp_mapping_path = os.path.join(tmp_dir, 'mapping.txt')
    # If there is no output (no classes are kept), this prevents this script
    # from failing.
    build_utils.Touch(tmp_mapping_path)

    tmp_output = os.path.join(tmp_dir, 'r8out')
    os.mkdir(tmp_output)

    split_contexts_by_name = {}
    if options.feature_names:
      for name, dest_dex, input_jars in zip(options.feature_names,
                                            options.dex_dests,
                                            options.feature_jars):
        parent_name = options.uses_split.get(name)
        if parent_name is None and name != 'base':
          parent_name = 'base'
        split_context = _SplitContext(name,
                                      dest_dex,
                                      input_jars,
                                      tmp_output,
                                      parent_name=parent_name)
        split_contexts_by_name[name] = split_context
    else:
      # Base context will get populated via "extra_jars" below.
      split_contexts_by_name['base'] = _SplitContext('base',
                                                     options.output_path, [],
                                                     tmp_output)
    base_context = split_contexts_by_name['base']

    # R8 OOMs with the default xmx=1G.
    cmd = build_utils.JavaCmd(options.warnings_as_errors, xmx='2G') + [
        '-Dcom.android.tools.r8.allowTestProguardOptions=1',
        '-Dcom.android.tools.r8.disableHorizontalClassMerging=1',
    ]
    if options.disable_outlining:
      cmd += ['-Dcom.android.tools.r8.disableOutlining=1']
    if options.dump_inputs:
      cmd += ['-Dcom.android.tools.r8.dumpinputtofile=r8inputs.zip']
    cmd += [
        '-cp',
        options.r8_path,
        'com.android.tools.r8.R8',
        '--no-data-resources',
        '--output',
        base_context.staging_dir,
        '--pg-map-output',
        tmp_mapping_path,
    ]

    if options.disable_checks:
      # Info level priority logs are not printed by default.
      cmd += ['--map-diagnostics:CheckDiscardDiagnostic', 'error', 'info']

    if options.desugar_jdk_libs_json:
      cmd += [
          '--desugared-lib',
          options.desugar_jdk_libs_json,
          '--desugared-lib-pg-conf-output',
          options.desugared_library_keep_rule_output,
      ]

    if options.min_api:
      cmd += ['--min-api', options.min_api]

    if options.force_enable_assertions:
      cmd += ['--force-enable-assertions']

    for lib in libraries:
      cmd += ['--lib', lib]

    for config_file in config_paths:
      cmd += ['--pg-conf', config_file]

    if options.main_dex_rules_path:
      for main_dex_rule in options.main_dex_rules_path:
        cmd += ['--main-dex-rules', main_dex_rule]

    _DeDupeInputJars(split_contexts_by_name)

    # Add any extra inputs to the base context (e.g. desugar runtime).
    extra_jars = set(options.input_paths)
    for split_context in split_contexts_by_name.values():
      extra_jars -= split_context.input_jars
    base_context.input_jars.update(extra_jars)

    for split_context in split_contexts_by_name.values():
      if split_context is base_context:
        continue
      for in_jar in sorted(split_context.input_jars):
        cmd += ['--feature', in_jar, split_context.staging_dir]

    cmd += sorted(base_context.input_jars)

    try:
      stderr_filter = dex.CreateStderrFilter(
          options.show_desugar_default_interface_warnings)
      logging.debug('Running R8')
      build_utils.CheckOutput(cmd,
                              print_stdout=print_stdout,
                              stderr_filter=stderr_filter,
                              fail_on_output=options.warnings_as_errors)
    except build_utils.CalledProcessError as err:
      debugging_link = ('\n\nR8 failed. Please see {}.'.format(
          'https://chromium.googlesource.com/chromium/src/+/HEAD/build/'
          'android/docs/java_optimization.md#Debugging-common-failures\n'))
      raise build_utils.CalledProcessError(err.cwd, err.args,
                                           err.output + debugging_link)

    base_has_imported_lib = False
    if options.desugar_jdk_libs_json:
      logging.debug('Running L8')
      existing_files = build_utils.FindInDirectory(base_context.staging_dir)
      jdk_dex_output = os.path.join(base_context.staging_dir,
                                    'classes%d.dex' % (len(existing_files) + 1))
      # Use -applymapping to avoid name collisions.
      l8_dynamic_config_path = os.path.join(tmp_dir, 'l8_dynamic_config.flags')
      with open(l8_dynamic_config_path, 'w') as f:
        f.write("-applymapping '{}'\n".format(tmp_mapping_path))
      # Pass the dynamic config so that obfuscation options are picked up.
      l8_config_paths = [dynamic_config_path, l8_dynamic_config_path]
      if os.path.exists(options.desugared_library_keep_rule_output):
        l8_config_paths.append(options.desugared_library_keep_rule_output)

      base_has_imported_lib = dex_jdk_libs.DexJdkLibJar(
          options.r8_path, options.min_api, options.desugar_jdk_libs_json,
          options.desugar_jdk_libs_jar,
          options.desugar_jdk_libs_configuration_jar, jdk_dex_output,
          options.warnings_as_errors, l8_config_paths)
      if int(options.min_api) >= 24 and base_has_imported_lib:
        with open(jdk_dex_output, 'rb') as f:
          dexfile = dex_parser.DexFile(bytearray(f.read()))
          for m in dexfile.IterMethodSignatureParts():
            print('{}#{}'.format(m[0], m[2]))
        assert False, (
            'Desugared JDK libs are disabled on Monochrome and newer - see '
            'crbug.com/1159984 for details, and see above list for desugared '
            'classes and methods.')

    logging.debug('Collecting ouputs')
    base_context.CreateOutput(base_has_imported_lib,
                              options.desugared_library_keep_rule_output)
    for split_context in split_contexts_by_name.values():
      if split_context is not base_context:
        split_context.CreateOutput()

    with open(options.mapping_output, 'w') as out_file, \
        open(tmp_mapping_path) as in_file:
      # Mapping files generated by R8 include comments that may break
      # some of our tooling so remove those (specifically: apkanalyzer).
      out_file.writelines(l for l in in_file if not l.startswith('#'))
  return base_context
示例#17
0
def _CheckForMissingSymbols(r8_path, dex_files, classpath, warnings_as_errors):
    cmd = build_utils.JavaCmd(warnings_as_errors) + [
        '-cp', r8_path, 'com.android.tools.r8.tracereferences.TraceReferences',
        '--map-diagnostics:MissingDefinitionsDiagnostic', 'error', 'warning',
        '--check'
    ]

    for path in classpath:
        cmd += ['--lib', path]
    for path in dex_files:
        cmd += ['--source', path]

    def stderr_filter(stderr):
        ignored_lines = [
            # Summary contains warning count, which our filtering makes wrong.
            'Warning: Tracereferences found',

            # TODO(agrieve): Create interface jars for these missing classes rather
            #     than allowlisting here.
            'dalvik/system',
            'libcore/io',
            'sun/misc/Unsafe',

            # Found in: com/facebook/fbui/textlayoutbuilder/StaticLayoutHelper
            ('android/text/StaticLayout;<init>(Ljava/lang/CharSequence;IILandroid'
             '/text/TextPaint;ILandroid/text/Layout$Alignment;Landroid/text/'
             'TextDirectionHeuristic;FFZLandroid/text/TextUtils$TruncateAt;II)V'
             ),

            # Found in
            # com/google/android/gms/cast/framework/media/internal/ResourceProvider
            # Missing due to setting "strip_resources = true".
            'com/google/android/gms/cast/framework/R',

            # Found in com/google/android/gms/common/GoogleApiAvailability
            # Missing due to setting "strip_drawables = true".
            'com/google/android/gms/base/R$drawable',

            # Explicictly guarded by try (NoClassDefFoundError) in Flogger's
            # PlatformProvider.
            'com/google/common/flogger/backend/google/GooglePlatform',
            'com/google/common/flogger/backend/system/DefaultPlatform',

            # trichrome_webview_google_bundle contains this missing reference.
            # TODO(crbug.com/1142530): Fix this missing reference properly.
            'org/chromium/base/library_loader/NativeLibraries',

            # TODO(agrieve): Exclude these only when use_jacoco_coverage=true.
            'Ljava/lang/instrument/ClassFileTransformer',
            'Ljava/lang/instrument/IllegalClassFormatException',
            'Ljava/lang/instrument/Instrumentation',
            'Ljava/lang/management/ManagementFactory',
            'Ljavax/management/MBeanServer',
            'Ljavax/management/ObjectInstance',
            'Ljavax/management/ObjectName',
            'Ljavax/management/StandardMBean',

            # Explicitly guarded by try (NoClassDefFoundError) in Firebase's
            # KotlinDetector: com.google.firebase.platforminfo.KotlinDetector.
            'Lkotlin/KotlinVersion',
        ]

        had_unfiltered_items = '  ' in stderr
        stderr = build_utils.FilterLines(
            stderr, '|'.join(re.escape(x) for x in ignored_lines))
        if stderr:
            if '  ' in stderr:
                stderr = """
DEX contains references to non-existent symbols after R8 optimization.
Tip: Build with:
        is_java_debug=false
        treat_warnings_as_errors=false
        enable_proguard_obfuscation=false
     and then use dexdump to see which class(s) reference them.

     E.g.:
       third_party/android_sdk/public/build-tools/*/dexdump -d \
out/Release/apks/YourApk.apk > dex.txt
""" + stderr

                if 'FragmentActivity' in stderr:
                    stderr += """
You may need to update build configs to run FragmentActivityReplacer for
additional targets. See
https://chromium.googlesource.com/chromium/src.git/+/master/docs/ui/android/bytecode_rewriting.md.
"""
            elif had_unfiltered_items:
                # Left only with empty headings. All indented items filtered out.
                stderr = ''
        return stderr

    logging.debug('cmd: %s', ' '.join(cmd))
    build_utils.CheckOutput(cmd,
                            print_stdout=True,
                            stderr_filter=stderr_filter,
                            fail_on_output=warnings_as_errors)
示例#18
0
def main(argv):
    argv = build_utils.ExpandFileArgs(argv)
    parser = argparse.ArgumentParser(description=__doc__)
    build_utils.AddDepfileOption(parser)
    parser.add_argument('--android-sdk-cmdline-tools',
                        help='Path to SDK\'s cmdline-tools folder.',
                        required=True)
    parser.add_argument('--root-manifest',
                        help='Root manifest which to merge into',
                        required=True)
    parser.add_argument('--output', help='Output manifest path', required=True)
    parser.add_argument('--extras',
                        help='GN list of additional manifest to merge')
    parser.add_argument('--min-sdk-version',
                        required=True,
                        help='android:minSdkVersion for merging.')
    parser.add_argument('--target-sdk-version',
                        required=True,
                        help='android:targetSdkVersion for merging.')
    parser.add_argument('--max-sdk-version',
                        help='android:maxSdkVersion for merging.')
    parser.add_argument('--manifest-package',
                        help='Package name of the merged AndroidManifest.xml.')
    parser.add_argument('--warnings-as-errors',
                        action='store_true',
                        help='Treat all warnings as errors.')
    args = parser.parse_args(argv)

    classpath = _BuildManifestMergerClasspath(args.android_sdk_cmdline_tools)

    with build_utils.AtomicOutput(args.output) as output:
        cmd = build_utils.JavaCmd(args.warnings_as_errors) + [
            '-cp',
            classpath,
            _MANIFEST_MERGER_MAIN_CLASS,
            '--out',
            output.name,
            '--property',
            'MIN_SDK_VERSION=' + args.min_sdk_version,
            '--property',
            'TARGET_SDK_VERSION=' + args.target_sdk_version,
        ]

        if args.max_sdk_version:
            cmd += [
                '--property',
                'MAX_SDK_VERSION=' + args.max_sdk_version,
            ]

        extras = build_utils.ParseGnList(args.extras)
        if extras:
            cmd += ['--libs', ':'.join(extras)]

        with _ProcessManifest(args.root_manifest, args.min_sdk_version,
                              args.target_sdk_version, args.max_sdk_version,
                              args.manifest_package) as tup:
            root_manifest, package = tup
            cmd += [
                '--main',
                root_manifest,
                '--property',
                'PACKAGE=' + package,
                '--remove-tools-declarations',
            ]
            build_utils.CheckOutput(
                cmd,
                # https://issuetracker.google.com/issues/63514300:
                # The merger doesn't set a nonzero exit code for failures.
                fail_func=lambda returncode, stderr: returncode != 0 or
                build_utils.IsTimeStale(output.name, [root_manifest] + extras),
                fail_on_output=args.warnings_as_errors)

        # Check for correct output.
        _, manifest, _ = manifest_utils.ParseManifest(output.name)
        manifest_utils.AssertUsesSdk(manifest, args.min_sdk_version,
                                     args.target_sdk_version)
        manifest_utils.AssertPackage(manifest, package)

    if args.depfile:
        inputs = extras + classpath.split(':')
        build_utils.WriteDepfile(args.depfile, args.output, inputs=inputs)
示例#19
0
def main(argv):
    build_utils.InitLogging('TURBINE_DEBUG')
    argv = build_utils.ExpandFileArgs(argv[1:])
    parser = argparse.ArgumentParser()
    build_utils.AddDepfileOption(parser)
    parser.add_argument('--turbine-jar-path',
                        required=True,
                        help='Path to the turbine jar file.')
    parser.add_argument('--java-srcjars',
                        action='append',
                        default=[],
                        help='List of srcjars to include in compilation.')
    parser.add_argument(
        '--bootclasspath',
        action='append',
        default=[],
        help='Boot classpath for javac. If this is specified multiple times, '
        'they will all be appended to construct the classpath.')
    parser.add_argument(
        '--java-version',
        help=
        'Java language version to use in -source and -target args to javac.')
    parser.add_argument('--classpath',
                        action='append',
                        help='Classpath to use.')
    parser.add_argument('--processors',
                        action='append',
                        help='GN list of annotation processor main classes.')
    parser.add_argument(
        '--processorpath',
        action='append',
        help='GN list of jars that comprise the classpath used for Annotation '
        'Processors.')
    parser.add_argument(
        '--processor-args',
        action='append',
        help='key=value arguments for the annotation processors.')
    parser.add_argument('--jar-path', help='Jar output path.', required=True)
    parser.add_argument('--generated-jar-path',
                        required=True,
                        help='Output path for generated source files.')
    parser.add_argument('--warnings-as-errors',
                        action='store_true',
                        help='Treat all warnings as errors.')
    options, unknown_args = parser.parse_known_args(argv)

    options.bootclasspath = build_utils.ParseGnList(options.bootclasspath)
    options.classpath = build_utils.ParseGnList(options.classpath)
    options.processorpath = build_utils.ParseGnList(options.processorpath)
    options.processors = build_utils.ParseGnList(options.processors)
    options.java_srcjars = build_utils.ParseGnList(options.java_srcjars)

    files = []
    for arg in unknown_args:
        # Interpret a path prefixed with @ as a file containing a list of sources.
        if arg.startswith('@'):
            files.extend(build_utils.ReadSourcesList(arg[1:]))

    cmd = build_utils.JavaCmd(options.warnings_as_errors) + [
        '-classpath', options.turbine_jar_path, 'com.google.turbine.main.Main'
    ]
    javac_cmd = []

    # Turbine reads lists from command line args by consuming args until one
    # starts with double dash (--). Thus command line args should be grouped
    # together and passed in together.
    if options.processors:
        cmd += ['--processors']
        cmd += options.processors

    if options.java_version:
        javac_cmd.extend([
            '-source',
            options.java_version,
            '-target',
            options.java_version,
        ])
    if options.java_version == '1.8':
        # Android's boot jar doesn't contain all java 8 classes.
        options.bootclasspath.append(build_utils.RT_JAR_PATH)

    if options.bootclasspath:
        cmd += ['--bootclasspath']
        for bootclasspath in options.bootclasspath:
            cmd += bootclasspath.split(':')

    if options.processorpath:
        cmd += ['--processorpath']
        cmd += options.processorpath

    if options.processor_args:
        for arg in options.processor_args:
            javac_cmd.extend(['-A%s' % arg])

    classpath_inputs = (options.bootclasspath + options.classpath +
                        options.processorpath)

    # GN already knows of the java files, so avoid listing individual java files
    # in the depfile.
    depfile_deps = classpath_inputs + options.java_srcjars
    input_paths = depfile_deps + files

    output_paths = [
        options.jar_path,
        options.generated_jar_path,
    ]

    input_strings = cmd + options.classpath + files

    md5_check.CallAndWriteDepfileIfStale(
        lambda: _OnStaleMd5(options, cmd, javac_cmd, files, options.classpath),
        options,
        depfile_deps=depfile_deps,
        input_paths=input_paths,
        input_strings=input_strings,
        output_paths=output_paths)
示例#20
0
def main(args):
    build_utils.InitLogging('DEX_DEBUG')
    options = _ParseArgs(args)

    options.class_inputs += options.class_inputs_filearg
    options.dex_inputs += options.dex_inputs_filearg

    input_paths = options.class_inputs + options.dex_inputs
    if options.multi_dex and options.main_dex_list_path:
        input_paths.append(options.main_dex_list_path)
    input_paths.append(options.r8_jar_path)

    depfile_deps = options.class_inputs_filearg + options.dex_inputs_filearg

    output_paths = [options.output]

    if options.incremental_dir:
        final_dex_inputs = _IntermediateDexFilePathsFromInputJars(
            options.class_inputs, options.incremental_dir)
        output_paths += final_dex_inputs
        track_subpaths_allowlist = options.class_inputs
    else:
        final_dex_inputs = list(options.class_inputs)
        track_subpaths_allowlist = None
    final_dex_inputs += options.dex_inputs

    dex_cmd = build_utils.JavaCmd(options.warnings_as_errors) + [
        '-cp',
        options.r8_jar_path,
        'com.android.tools.r8.D8',
    ]
    if options.release:
        dex_cmd += ['--release']
    if options.min_api:
        dex_cmd += ['--min-api', options.min_api]

    if not options.desugar:
        dex_cmd += ['--no-desugaring']
    elif options.classpath:
        # Don't pass classpath when Desugar.jar is doing interface desugaring.
        dex_cmd += ['--lib', build_utils.JAVA_HOME]
        for path in options.bootclasspath:
            dex_cmd += ['--lib', path]
        for path in options.classpath:
            dex_cmd += ['--classpath', path]
        depfile_deps += options.classpath
        depfile_deps += options.bootclasspath
        input_paths += options.classpath
        input_paths += options.bootclasspath

    if options.desugar_jdk_libs_json:
        dex_cmd += ['--desugared-lib', options.desugar_jdk_libs_json]
    if options.force_enable_assertions:
        dex_cmd += ['--force-enable-assertions']

    md5_check.CallAndWriteDepfileIfStale(
        lambda changes: _OnStaleMd5(changes, options, final_dex_inputs, dex_cmd
                                    ),
        options,
        input_paths=input_paths,
        input_strings=dex_cmd + [bool(options.incremental_dir)],
        output_paths=output_paths,
        pass_changes=True,
        track_subpaths_allowlist=track_subpaths_allowlist,
        depfile_deps=depfile_deps)
示例#21
0
def main(args):
    args = build_utils.ExpandFileArgs(args)
    options = _ParseArgs(args)

    split_dimensions = []
    if options.split_dimensions:
        split_dimensions = [x.upper() for x in options.split_dimensions]

    with build_utils.TempDir() as tmp_dir:
        module_zips = [
            _SplitModuleForAssetTargeting(module, tmp_dir, split_dimensions) \
            for module in options.module_zips]

        base_master_resource_ids = None
        if options.base_module_rtxt_path:
            base_master_resource_ids = _GenerateBaseResourcesAllowList(
                options.base_module_rtxt_path,
                options.base_allowlist_rtxt_path)

        bundle_config = _GenerateBundleConfigJson(
            options.uncompressed_assets, options.compress_shared_libraries,
            split_dimensions, base_master_resource_ids)

        tmp_bundle = os.path.join(tmp_dir, 'tmp_bundle')

        tmp_unsigned_bundle = tmp_bundle
        if options.keystore_path:
            tmp_unsigned_bundle = tmp_bundle + '.unsigned'

        # Important: bundletool requires that the bundle config file is
        # named with a .pb.json extension.
        tmp_bundle_config = tmp_bundle + '.BundleConfig.pb.json'

        with open(tmp_bundle_config, 'w') as f:
            f.write(bundle_config)

        cmd_args = build_utils.JavaCmd(options.warnings_as_errors) + [
            '-jar',
            bundletool.BUNDLETOOL_JAR_PATH,
            'build-bundle',
            '--modules=' + ','.join(module_zips),
            '--output=' + tmp_unsigned_bundle,
            '--config=' + tmp_bundle_config,
        ]

        build_utils.CheckOutput(
            cmd_args,
            print_stdout=True,
            print_stderr=True,
            stderr_filter=build_utils.FilterReflectiveAccessJavaWarnings,
            fail_on_output=options.warnings_as_errors)

        if options.validate_services:
            # TODO(crbug.com/1126301): This step takes 0.4s locally for bundles with
            # isolated splits disabled and 2s for bundles with isolated splits
            # enabled.  Consider making this run in parallel or move into a separate
            # step before enabling isolated splits by default.
            _MaybeCheckServicesPresentInBase(tmp_unsigned_bundle, module_zips)

        if options.keystore_path:
            # NOTE: As stated by the public documentation, apksigner cannot be used
            # to sign the bundle (because it rejects anything that isn't an APK).
            # The signature and digest algorithm selection come from the internal
            # App Bundle documentation. There is no corresponding public doc :-(
            signing_cmd_args = [
                'jarsigner',
                '-sigalg',
                'SHA256withRSA',
                '-digestalg',
                'SHA-256',
                '-keystore',
                'file:' + options.keystore_path,
                '-storepass',
                options.keystore_password,
                '-signedjar',
                tmp_bundle,
                tmp_unsigned_bundle,
                options.key_name,
            ]
            build_utils.CheckOutput(signing_cmd_args,
                                    print_stderr=True,
                                    fail_on_output=options.warnings_as_errors)

        shutil.move(tmp_bundle, options.out_bundle)

    if options.rtxt_out_path:
        _ConcatTextFiles(options.rtxt_in_paths, options.rtxt_out_path)

    if options.pathmap_out_path:
        _WriteBundlePathmap(options.pathmap_in_paths, options.module_names,
                            options.pathmap_out_path)
示例#22
0
def main():
    args = _ParseArgs()
    proguard_cmd = build_utils.JavaCmd(args.warnings_as_errors) + [
        '-cp',
        args.r8_path,
        'com.android.tools.r8.R8',
        '--classfile',
        '--no-desugaring',
        '--lib',
        args.shrinked_android_path,
    ]

    for m in args.main_dex_rules_paths:
        proguard_cmd.extend(['--pg-conf', m])

    proguard_flags = [
        '-forceprocessing',
        '-dontwarn',
        '-dontoptimize',
        '-dontobfuscate',
        '-dontpreverify',
    ]

    if args.negative_main_dex_globs:
        for glob in args.negative_main_dex_globs:
            # Globs come with 1 asterix, but we want 2 to match subpackages.
            proguard_flags.append('-checkdiscard class ' +
                                  glob.replace('*', '**').replace('/', '.'))

    main_dex_list = ''
    try:
        with tempfile.NamedTemporaryFile(suffix='.jar') as temp_jar:
            # Step 1: Use R8 to find all @MainDex code, and all code reachable
            # from @MainDex code (recursive).
            proguard_cmd += ['--output', temp_jar.name]
            with tempfile.NamedTemporaryFile() as proguard_flags_file:
                for flag in proguard_flags:
                    proguard_flags_file.write(flag + '\n')
                proguard_flags_file.flush()
                proguard_cmd += ['--pg-conf', proguard_flags_file.name]
                for injar in args.class_inputs:
                    proguard_cmd.append(injar)
                build_utils.CheckOutput(proguard_cmd,
                                        print_stderr=False,
                                        fail_on_output=args.warnings_as_errors)

            # Record the classes kept by ProGuard. Not used by the build, but useful
            # for debugging what classes are kept by ProGuard vs. MainDexListBuilder.
            with zipfile.ZipFile(temp_jar.name) as z:
                kept_classes = [
                    p for p in z.namelist() if p.endswith('.class')
                ]
            with open(args.main_dex_list_path + '.partial', 'w') as f:
                f.write('\n'.join(kept_classes) + '\n')

            # Step 2: Expand inclusion list to all classes referenced by the .class
            # files of kept classes (non-recursive).
            main_dex_list_cmd = build_utils.JavaCmd() + [
                '-cp',
                args.dx_path,
                'com.android.multidex.MainDexListBuilder',
                # This workaround increases main dex size and does not seem to
                # be needed by Chrome. See comment in the source:
                # https://android.googlesource.com/platform/dalvik/+/master/dx/src/com/android/multidex/MainDexListBuilder.java
                '--disable-annotation-resolution-workaround',
                temp_jar.name,
                ':'.join(args.class_inputs)
            ]
            main_dex_list = build_utils.CheckOutput(
                main_dex_list_cmd, fail_on_output=args.warnings_as_errors)

    except build_utils.CalledProcessError as e:
        if 'output jar is empty' in e.output:
            pass
        elif "input doesn't contain any classes" in e.output:
            pass
        else:
            raise

    with build_utils.AtomicOutput(args.main_dex_list_path) as f:
        f.write(main_dex_list)

    if args.depfile:
        build_utils.WriteDepfile(args.depfile,
                                 args.main_dex_list_path,
                                 inputs=args.class_inputs_filearg)
示例#23
0
def _CheckForMissingSymbols(r8_path, dex_files, classpath, warnings_as_errors):
  cmd = build_utils.JavaCmd(warnings_as_errors) + [
      '-cp', r8_path, 'com.android.tools.r8.tracereferences.TraceReferences',
      '--map-diagnostics:MissingDefinitionsDiagnostic', 'error', 'warning'
  ]

  for path in classpath:
    cmd += ['--lib', path]
  for path in dex_files:
    cmd += ['--source', path]

  def stderr_filter(stderr):
    ignored_lines = [
        # Summary contains warning count, which our filtering makes wrong.
        'Warning: Tracereferences found',

        # TODO(agrieve): Create interface jars for these missing classes rather
        #     than allowlisting here.
        'dalvik/system',
        'libcore/io',
        'sun/misc/Unsafe',

        # Found in: com/facebook/fbui/textlayoutbuilder/StaticLayoutHelper
        ('android/text/StaticLayout;<init>(Ljava/lang/CharSequence;IILandroid'
         '/text/TextPaint;ILandroid/text/Layout$Alignment;Landroid/text/'
         'TextDirectionHeuristic;FFZLandroid/text/TextUtils$TruncateAt;II)V'),

        # Found in
        # com/google/android/gms/cast/framework/media/internal/ResourceProvider
        # Missing due to setting "strip_resources = true".
        'com/google/android/gms/cast/framework/R',

        # Found in com/google/android/gms/common/GoogleApiAvailability
        # Missing due to setting "strip_drawables = true".
        'com/google/android/gms/base/R$drawable',

        # Explicictly guarded by try (NoClassDefFoundError) in Flogger's
        # PlatformProvider.
        'com/google/common/flogger/backend/google/GooglePlatform',
        'com/google/common/flogger/backend/system/DefaultPlatform',

        # trichrome_webview_google_bundle contains this missing reference.
        # TODO(crbug.com/1142530): Fix this missing reference properly.
        'org/chromium/base/library_loader/NativeLibraries',

        # Currently required when enable_chrome_android_internal=true.
        'com/google/protos/research/ink/InkEventProto',
        'ink_sdk/com/google/protobuf/Internal$EnumVerifier',
        'ink_sdk/com/google/protobuf/MessageLite',
        'com/google/protobuf/GeneratedMessageLite$GeneratedExtension',

        # Referenced from GeneratedExtensionRegistryLite.
        # Exists only for Chrome Modern (not Monochrome nor Trichrome).
        # TODO(agrieve): Figure out why. Perhaps related to Feed V2.
        ('com/google/wireless/android/play/playlog/proto/ClientAnalytics$'
         'ClientInfo'),

        # TODO(agrieve): Exclude these only when use_jacoco_coverage=true.
        'Ljava/lang/instrument/ClassFileTransformer',
        'Ljava/lang/instrument/IllegalClassFormatException',
        'Ljava/lang/instrument/Instrumentation',
        'Ljava/lang/management/ManagementFactory',
        'Ljavax/management/MBeanServer',
        'Ljavax/management/ObjectInstance',
        'Ljavax/management/ObjectName',
        'Ljavax/management/StandardMBean',
    ]

    had_unfiltered_items = '  ' in stderr
    stderr = build_utils.FilterLines(
        stderr, '|'.join(re.escape(x) for x in ignored_lines))
    if stderr:
      if '  ' in stderr:
        stderr = """
DEX contains references to non-existent symbols after R8 optimization.
Tip: Build with:
        is_java_debug=false
        treat_warnings_as_errors=false
        enable_proguard_obfuscation=false
     and then use dexdump to see which class(s) reference them.

     E.g.:
       third_party/android_sdk/public/build-tools/*/dexdump -d \
out/Release/apks/YourApk.apk > dex.txt
""" + stderr
      elif had_unfiltered_items:
        # Left only with empty headings. All indented items filtered out.
        stderr = ''
    return stderr

  logging.debug('cmd: %s', ' '.join(cmd))
  build_utils.CheckOutput(cmd,
                          print_stdout=True,
                          stderr_filter=stderr_filter,
                          fail_on_output=warnings_as_errors)
示例#24
0
文件: dex.py 项目: zlederman/chromium
def main(args):
    build_utils.InitLogging('DEX_DEBUG')
    options = _ParseArgs(args)

    options.class_inputs += options.class_inputs_filearg
    options.dex_inputs += options.dex_inputs_filearg

    input_paths = options.class_inputs + options.dex_inputs
    if options.multi_dex and options.main_dex_list_path:
        input_paths.append(options.main_dex_list_path)
    input_paths.append(options.r8_jar_path)
    input_paths.append(options.custom_d8_jar_path)

    depfile_deps = options.class_inputs_filearg + options.dex_inputs_filearg

    output_paths = [options.output]

    track_subpaths_allowlist = []
    if options.incremental_dir:
        final_dex_inputs = _IntermediateDexFilePathsFromInputJars(
            options.class_inputs, options.incremental_dir)
        output_paths += final_dex_inputs
        track_subpaths_allowlist += options.class_inputs
    else:
        final_dex_inputs = list(options.class_inputs)
    final_dex_inputs += options.dex_inputs

    dex_cmd = build_utils.JavaCmd(options.warnings_as_errors) + [
        '-cp',
        '{}:{}'.format(options.r8_jar_path, options.custom_d8_jar_path),
        'org.chromium.build.CustomD8',
    ]
    if options.release:
        dex_cmd += ['--release']
    if options.min_api:
        dex_cmd += ['--min-api', options.min_api]

    if not options.desugar:
        dex_cmd += ['--no-desugaring']
    elif options.classpath:
        # The classpath is used by D8 to for interface desugaring.
        if options.desugar_dependencies:
            dex_cmd += ['--desugar-dependencies', options.desugar_dependencies]
            if track_subpaths_allowlist:
                track_subpaths_allowlist += options.classpath
        depfile_deps += options.classpath
        input_paths += options.classpath
        dex_cmd += ['--lib', build_utils.JAVA_HOME]
        for path in options.bootclasspath:
            dex_cmd += ['--lib', path]
        # Still pass the entire classpath in case a new dependency is needed by
        # desugar, so that desugar_dependencies will be updated for the next build.
        for path in options.classpath:
            dex_cmd += ['--classpath', path]
        depfile_deps += options.bootclasspath
        input_paths += options.bootclasspath

    if options.desugar_jdk_libs_json:
        dex_cmd += ['--desugared-lib', options.desugar_jdk_libs_json]
    if options.force_enable_assertions:
        dex_cmd += ['--force-enable-assertions']

    # The changes feature from md5_check allows us to only re-dex the class files
    # that have changed and the class files that need to be re-desugared by D8.
    md5_check.CallAndWriteDepfileIfStale(
        lambda changes: _OnStaleMd5(changes, options, final_dex_inputs, dex_cmd
                                    ),
        options,
        input_paths=input_paths,
        input_strings=dex_cmd + [bool(options.incremental_dir)],
        output_paths=output_paths,
        pass_changes=True,
        track_subpaths_allowlist=track_subpaths_allowlist,
        depfile_deps=depfile_deps)
示例#25
0
def main(args):
    args = build_utils.ExpandFileArgs(args)
    options = _ParseArgs(args)

    split_dimensions = []
    if options.split_dimensions:
        split_dimensions = [x.upper() for x in options.split_dimensions]

    with build_utils.TempDir() as tmp_dir:
        module_zips = [
            _SplitModuleForAssetTargeting(module, tmp_dir, split_dimensions) \
            for module in options.module_zips]

        base_master_resource_ids = None
        if options.base_module_rtxt_path:
            base_master_resource_ids = _GenerateBaseResourcesAllowList(
                options.base_module_rtxt_path,
                options.base_allowlist_rtxt_path)

        bundle_config = _GenerateBundleConfigJson(
            options.uncompressed_assets, options.compress_shared_libraries,
            split_dimensions, base_master_resource_ids)

        tmp_bundle = os.path.join(tmp_dir, 'tmp_bundle')

        # Important: bundletool requires that the bundle config file is
        # named with a .pb.json extension.
        tmp_bundle_config = tmp_bundle + '.BundleConfig.pb.json'

        with open(tmp_bundle_config, 'w') as f:
            f.write(bundle_config)

        cmd_args = build_utils.JavaCmd(options.warnings_as_errors) + [
            '-jar',
            bundletool.BUNDLETOOL_JAR_PATH,
            'build-bundle',
            '--modules=' + ','.join(module_zips),
            '--output=' + tmp_bundle,
            '--config=' + tmp_bundle_config,
        ]

        build_utils.CheckOutput(
            cmd_args,
            print_stdout=True,
            print_stderr=True,
            stderr_filter=build_utils.FilterReflectiveAccessJavaWarnings,
            fail_on_output=options.warnings_as_errors)

        if options.validate_services:
            # TODO(crbug.com/1126301): This step takes 0.4s locally for bundles with
            # isolated splits disabled and 2s for bundles with isolated splits
            # enabled.  Consider making this run in parallel or move into a separate
            # step before enabling isolated splits by default.
            _MaybeCheckServicesAndProvidersPresentInBase(
                tmp_bundle, module_zips)

        shutil.move(tmp_bundle, options.out_bundle)

    if options.rtxt_out_path:
        _ConcatTextFiles(options.rtxt_in_paths, options.rtxt_out_path)

    if options.pathmap_out_path:
        _WriteBundlePathmap(options.pathmap_in_paths, options.module_names,
                            options.pathmap_out_path)