|  | // Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file | 
|  | // for details. All rights reserved. Use of this source code is governed by a | 
|  | // BSD-style license that can be found in the LICENSE file. | 
|  | package com.android.tools.r8; | 
|  |  | 
|  | import static com.android.tools.r8.utils.InternalOptions.DETERMINISTIC_DEBUGGING; | 
|  |  | 
|  | import com.android.tools.r8.dex.Marker.Tool; | 
|  | import com.android.tools.r8.dump.DumpOptions; | 
|  | import com.android.tools.r8.errors.DexFileOverflowDiagnostic; | 
|  | import com.android.tools.r8.graph.DexItemFactory; | 
|  | import com.android.tools.r8.inspector.Inspector; | 
|  | import com.android.tools.r8.inspector.internal.InspectorImpl; | 
|  | import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibrarySpecification; | 
|  | import com.android.tools.r8.origin.Origin; | 
|  | import com.android.tools.r8.shaking.ProguardConfigurationParser; | 
|  | import com.android.tools.r8.shaking.ProguardConfigurationRule; | 
|  | import com.android.tools.r8.shaking.ProguardConfigurationSource; | 
|  | import com.android.tools.r8.shaking.ProguardConfigurationSourceFile; | 
|  | import com.android.tools.r8.shaking.ProguardConfigurationSourceStrings; | 
|  | import com.android.tools.r8.startup.StartupProfileProvider; | 
|  | import com.android.tools.r8.utils.AndroidApiLevel; | 
|  | import com.android.tools.r8.utils.AndroidApp; | 
|  | import com.android.tools.r8.utils.AssertionConfigurationWithDefault; | 
|  | import com.android.tools.r8.utils.DumpInputFlags; | 
|  | import com.android.tools.r8.utils.InternalGlobalSyntheticsProgramProvider; | 
|  | import com.android.tools.r8.utils.InternalOptions; | 
|  | import com.android.tools.r8.utils.InternalOptions.DesugarState; | 
|  | import com.android.tools.r8.utils.InternalOptions.HorizontalClassMergerOptions; | 
|  | import com.android.tools.r8.utils.InternalOptions.LineNumberOptimization; | 
|  | import com.android.tools.r8.utils.ProgramClassCollection; | 
|  | import com.android.tools.r8.utils.Reporter; | 
|  | import com.android.tools.r8.utils.StringDiagnostic; | 
|  | import com.android.tools.r8.utils.ThreadUtils; | 
|  | import com.google.common.collect.ImmutableList; | 
|  | import java.nio.file.Path; | 
|  | import java.nio.file.Paths; | 
|  | import java.util.ArrayList; | 
|  | import java.util.Arrays; | 
|  | import java.util.Collection; | 
|  | import java.util.List; | 
|  | import java.util.function.BiPredicate; | 
|  | import java.util.function.Consumer; | 
|  |  | 
|  | /** | 
|  | * Immutable command structure for an invocation of the {@link D8} compiler. | 
|  | * | 
|  | * <p>To build a D8 command use the {@link D8Command.Builder} class. For example: | 
|  | * | 
|  | * <pre> | 
|  | *   D8Command command = D8Command.builder() | 
|  | *     .addProgramFiles(path1, path2) | 
|  | *     .setMode(CompilationMode.RELEASE) | 
|  | *     .setOutput(Paths.get("output.zip", OutputMode.DexIndexed)) | 
|  | *     .build(); | 
|  | * </pre> | 
|  | */ | 
|  | @Keep | 
|  | public final class D8Command extends BaseCompilerCommand { | 
|  |  | 
|  | private static class DefaultD8DiagnosticsHandler implements DiagnosticsHandler { | 
|  |  | 
|  | @Override | 
|  | public void error(Diagnostic error) { | 
|  | if (error instanceof DexFileOverflowDiagnostic) { | 
|  | DexFileOverflowDiagnostic overflowDiagnostic = (DexFileOverflowDiagnostic) error; | 
|  | if (!overflowDiagnostic.hasMainDexSpecification()) { | 
|  | DiagnosticsHandler.super.error( | 
|  | new StringDiagnostic( | 
|  | overflowDiagnostic.getDiagnosticMessage() + ". Try supplying a main-dex list")); | 
|  | return; | 
|  | } | 
|  | } | 
|  | DiagnosticsHandler.super.error(error); | 
|  | } | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Builder for constructing a D8Command. | 
|  | * | 
|  | * <p>A builder is obtained by calling {@link D8Command#builder}. | 
|  | */ | 
|  | @Keep | 
|  | public static class Builder extends BaseCompilerCommand.Builder<D8Command, Builder> { | 
|  |  | 
|  | private boolean intermediate = false; | 
|  | private GlobalSyntheticsConsumer globalSyntheticsConsumer = null; | 
|  | private List<GlobalSyntheticsResourceProvider> globalSyntheticsResourceProviders = | 
|  | new ArrayList<>(); | 
|  | private DesugarGraphConsumer desugarGraphConsumer = null; | 
|  | private StringConsumer desugaredLibraryKeepRuleConsumer = null; | 
|  | private String synthesizedClassPrefix = ""; | 
|  | private boolean enableMainDexListCheck = true; | 
|  | private boolean minimalMainDex = false; | 
|  | private final List<ProguardConfigurationSource> mainDexRules = new ArrayList<>(); | 
|  | private boolean enableMissingLibraryApiModeling = false; | 
|  |  | 
|  | private Builder() { | 
|  | this(new DefaultD8DiagnosticsHandler()); | 
|  | } | 
|  |  | 
|  | private Builder(DiagnosticsHandler diagnosticsHandler) { | 
|  | super(diagnosticsHandler); | 
|  | } | 
|  |  | 
|  | private Builder(AndroidApp app) { | 
|  | super(app); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Add dex program-data. | 
|  | */ | 
|  | @Override | 
|  | public Builder addDexProgramData(byte[] data, Origin origin) { | 
|  | guard(() -> getAppBuilder().addDexProgramData(data, origin)); | 
|  | return self(); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Add classpath file resources. These have @Override to ensure binary compatibility. | 
|  | */ | 
|  | @Override | 
|  | public Builder addClasspathFiles(Path... files) { | 
|  | return super.addClasspathFiles(files); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Add classpath file resources. | 
|  | */ | 
|  | @Override | 
|  | public Builder addClasspathFiles(Collection<Path> files) { | 
|  | return super.addClasspathFiles(files); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Add classfile resources provider for class-path resources. | 
|  | */ | 
|  | @Override | 
|  | public Builder addClasspathResourceProvider(ClassFileResourceProvider provider) { | 
|  | return super.addClasspathResourceProvider(provider); | 
|  | } | 
|  |  | 
|  | /** Set input proguard map used for distribution of classes in multi-dex. */ | 
|  | public Builder setProguardInputMapFile(Path proguardInputMap) { | 
|  | getAppBuilder().setProguardMapInputData(proguardInputMap); | 
|  | return self(); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Set a consumer for receiving the proguard-map content. | 
|  | * | 
|  | * <p>Note that when a proguard-map consumer is specified for a release build, the compiler will | 
|  | * optimize the line-number information and obtaining a source-level stacktrace will require the | 
|  | * use of a retrace tool exactly as is needed for programs built by R8. | 
|  | * | 
|  | * <p>Note that any subsequent call to this method or {@link #setProguardMapOutputPath} will | 
|  | * override the previous setting. | 
|  | * | 
|  | * @param proguardMapConsumer Consumer to receive the content once produced. | 
|  | */ | 
|  | @Override | 
|  | public Builder setProguardMapConsumer(StringConsumer proguardMapConsumer) { | 
|  | return super.setProguardMapConsumer(proguardMapConsumer); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Set an output destination to which proguard-map content should be written. | 
|  | * | 
|  | * <p>Note that when a proguard-map output is specified for a release build, the compiler will | 
|  | * optimize the line-number information and obtaining a source-level stacktrace will require the | 
|  | * use of a retrace tool exactly as is needed for programs built by R8. | 
|  | * | 
|  | * <p>This is a short-hand for setting a {@link StringConsumer.FileConsumer} using {@link | 
|  | * #setProguardMapConsumer}. Note that any subsequent call to this method or {@link | 
|  | * #setProguardMapConsumer} will override the previous setting. | 
|  | * | 
|  | * @param proguardMapOutput File-system path to write output at. | 
|  | */ | 
|  | @Override | 
|  | public Builder setProguardMapOutputPath(Path proguardMapOutput) { | 
|  | return super.setProguardMapOutputPath(proguardMapOutput); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Indicate if compilation is to intermediate results, i.e., intended for later merging. | 
|  | * | 
|  | * <p>When compiling to intermediate mode, the compiler will avoid sharing of synthetic items, | 
|  | * and instead annotate them as synthetics for possible later merging. For global synthetics, | 
|  | * the compiler will emit these to a separate consumer (see {@code GlobalSyntheticsConsumer} | 
|  | * with the expectation that a later build step will consume them again as part of a | 
|  | * non-intermediate build (see {@code GlobalSyntheticsResourceProvider}. Synthetic items | 
|  | * typically come from the desugaring of various language features, such as lambdas and default | 
|  | * interface methods. Global synthetics are non-local in that many compilation units may | 
|  | * reference the same synthetic. For example, desugaring records requires a global tag to | 
|  | * distinguish the class of all records. | 
|  | * | 
|  | * <p>Intermediate mode is implied if compiling results to a "file-per-class-file". | 
|  | */ | 
|  | public Builder setIntermediate(boolean value) { | 
|  | this.intermediate = value; | 
|  | return self(); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Set a consumer for receiving the global synthetic content for the given compilation. | 
|  | * | 
|  | * <p>Note: this consumer is ignored if the compilation is not an "intermediate mode" | 
|  | * compilation. | 
|  | */ | 
|  | public Builder setGlobalSyntheticsConsumer(GlobalSyntheticsConsumer globalSyntheticsConsumer) { | 
|  | this.globalSyntheticsConsumer = globalSyntheticsConsumer; | 
|  | return self(); | 
|  | } | 
|  |  | 
|  | /** Add global synthetics resource providers. */ | 
|  | public Builder addGlobalSyntheticsResourceProviders( | 
|  | GlobalSyntheticsResourceProvider... providers) { | 
|  | return addGlobalSyntheticsResourceProviders(Arrays.asList(providers)); | 
|  | } | 
|  |  | 
|  | /** Add global synthetics resource providers. */ | 
|  | public Builder addGlobalSyntheticsResourceProviders( | 
|  | Collection<GlobalSyntheticsResourceProvider> providers) { | 
|  | providers.forEach(globalSyntheticsResourceProviders::add); | 
|  | return self(); | 
|  | } | 
|  |  | 
|  | /** Add global synthetics resource files. */ | 
|  | public Builder addGlobalSyntheticsFiles(Path... files) { | 
|  | return addGlobalSyntheticsFiles(Arrays.asList(files)); | 
|  | } | 
|  |  | 
|  | /** Add global synthetics resource files. */ | 
|  | public Builder addGlobalSyntheticsFiles(Collection<Path> files) { | 
|  | for (Path file : files) { | 
|  | addGlobalSyntheticsResourceProviders(new GlobalSyntheticsResourceFile(file)); | 
|  | } | 
|  | return self(); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Set a consumer for receiving the keep rules to use when compiling the desugared library for | 
|  | * the program being compiled in this compilation. | 
|  | * | 
|  | * @param keepRuleConsumer Consumer to receive the content once produced. | 
|  | */ | 
|  | public Builder setDesugaredLibraryKeepRuleConsumer(StringConsumer keepRuleConsumer) { | 
|  | this.desugaredLibraryKeepRuleConsumer = keepRuleConsumer; | 
|  | return self(); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Get the consumer that will receive dependency information for desugaring. | 
|  | */ | 
|  | public DesugarGraphConsumer getDesugarGraphConsumer() { | 
|  | return desugarGraphConsumer; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Set the consumer that will receive dependency information for desugaring. | 
|  | * | 
|  | * <p>Setting the consumer will clear any previously set consumer. | 
|  | */ | 
|  | public Builder setDesugarGraphConsumer(DesugarGraphConsumer desugarGraphConsumer) { | 
|  | this.desugarGraphConsumer = desugarGraphConsumer; | 
|  | return self(); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Add a collection of startup profile providers that should be used for distributing the | 
|  | * program classes in dex. | 
|  | * | 
|  | * <p>NOTE: Startup profiles are ignored when compiling to class files or the min-API level does | 
|  | * not support native multidex (API<=20). | 
|  | * | 
|  | * <p>NOTE: This API is experimental and may be subject to changes. | 
|  | */ | 
|  | @Override | 
|  | public Builder addStartupProfileProviders(StartupProfileProvider... startupProfileProviders) { | 
|  | return super.addStartupProfileProviders(startupProfileProviders); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Add a collection of startup profile providers that should be used for distributing the | 
|  | * program classes in dex. | 
|  | * | 
|  | * <p>NOTE: Startup profiles are ignored when compiling to class files or the min-API level does | 
|  | * not support native multidex (API<=20). | 
|  | * | 
|  | * <p>NOTE: This API is experimental and may be subject to changes. | 
|  | */ | 
|  | @Override | 
|  | public Builder addStartupProfileProviders( | 
|  | Collection<StartupProfileProvider> startupProfileProviders) { | 
|  | return super.addStartupProfileProviders(startupProfileProviders); | 
|  | } | 
|  |  | 
|  | @Override | 
|  | Builder self() { | 
|  | return this; | 
|  | } | 
|  |  | 
|  | @Override | 
|  | CompilationMode defaultCompilationMode() { | 
|  | return CompilationMode.DEBUG; | 
|  | } | 
|  |  | 
|  | Builder setSynthesizedClassesPrefix(String prefix) { | 
|  | synthesizedClassPrefix = prefix; | 
|  | return self(); | 
|  | } | 
|  |  | 
|  | @Deprecated | 
|  | // Internal helper for supporting bazel integration. | 
|  | Builder setEnableMainDexListCheck(boolean value) { | 
|  | enableMainDexListCheck = value; | 
|  | return self(); | 
|  | } | 
|  |  | 
|  | @Deprecated | 
|  | // Internal helper for supporting bazel integration. | 
|  | Builder setMinimalMainDex(boolean value) { | 
|  | minimalMainDex = value; | 
|  | return self(); | 
|  | } | 
|  |  | 
|  | /** Add proguard configuration files with rules for automatic main-dex-list calculation. */ | 
|  | public Builder addMainDexRulesFiles(Path... paths) { | 
|  | return addMainDexRulesFiles(Arrays.asList(paths)); | 
|  | } | 
|  |  | 
|  | /** Add proguard configuration files with rules for automatic main-dex-list calculation. */ | 
|  | public Builder addMainDexRulesFiles(Collection<Path> paths) { | 
|  | guard(() -> paths.forEach(p -> mainDexRules.add(new ProguardConfigurationSourceFile(p)))); | 
|  | return self(); | 
|  | } | 
|  |  | 
|  | /** Add proguard rules for automatic main-dex-list calculation. */ | 
|  | public Builder addMainDexRules(List<String> lines, Origin origin) { | 
|  | guard( | 
|  | () -> | 
|  | mainDexRules.add( | 
|  | new ProguardConfigurationSourceStrings(lines, Paths.get("."), origin))); | 
|  | return self(); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Enable experimental/pre-release support for modeling missing library APIs. | 
|  | * | 
|  | * <p>This allows enabling the feature while it is still default disabled by the compiler. Once | 
|  | * the feature is default enabled, calling this method will have no affect. | 
|  | */ | 
|  | @Deprecated | 
|  | public Builder setEnableExperimentalMissingLibraryApiModeling(boolean enable) { | 
|  | this.enableMissingLibraryApiModeling = enable; | 
|  | return self(); | 
|  | } | 
|  |  | 
|  | @Override | 
|  | void validate() { | 
|  | if (isPrintHelp()) { | 
|  | return; | 
|  | } | 
|  | Reporter reporter = getReporter(); | 
|  | if (getAppBuilder().hasMainDexList()) { | 
|  | if (intermediate) { | 
|  | reporter.error("Option --main-dex-list cannot be used with --intermediate"); | 
|  | } | 
|  | if (getProgramConsumer() instanceof DexFilePerClassFileConsumer) { | 
|  | reporter.error("Option --main-dex-list cannot be used with --file-per-class"); | 
|  | } | 
|  | } | 
|  | if (!mainDexRules.isEmpty()) { | 
|  | if (intermediate) { | 
|  | reporter.error("Option --main-dex-rules cannot be used with --intermediate"); | 
|  | } | 
|  | if (getProgramConsumer() instanceof DexFilePerClassFileConsumer) { | 
|  | reporter.error("Option --main-dex-rules cannot be used with --file-per-class"); | 
|  | } | 
|  | } | 
|  | if (getMainDexListConsumer() != null | 
|  | && mainDexRules.isEmpty() | 
|  | && !getAppBuilder().hasMainDexList()) { | 
|  | reporter.error( | 
|  | "Option --main-dex-list-output requires --main-dex-rules and/or --main-dex-list"); | 
|  | } | 
|  | if (getMinApiLevel() >= AndroidApiLevel.L.getLevel()) { | 
|  | if (getMainDexListConsumer() != null || getAppBuilder().hasMainDexList()) { | 
|  | reporter.error( | 
|  | "D8 does not support main-dex inputs and outputs when compiling to API level " | 
|  | + AndroidApiLevel.L.getLevel() | 
|  | + " and above"); | 
|  | } | 
|  | } | 
|  | if (hasDesugaredLibraryConfiguration() && getDisableDesugaring()) { | 
|  | reporter.error("Using desugared library configuration requires desugaring to be enabled"); | 
|  | } | 
|  | if (getProgramConsumer() instanceof ClassFileConsumer | 
|  | && getDisableDesugaring() | 
|  | && isMinApiLevelSet()) { | 
|  | reporter.error("Compiling to CF with --min-api and --no-desugaring is not supported"); | 
|  | } | 
|  | super.validate(); | 
|  | } | 
|  |  | 
|  | @Override | 
|  | D8Command makeCommand() { | 
|  | if (isPrintHelp() || isPrintVersion()) { | 
|  | return new D8Command(isPrintHelp(), isPrintVersion()); | 
|  | } | 
|  |  | 
|  | intermediate |= getProgramConsumer() instanceof DexFilePerClassFileConsumer; | 
|  |  | 
|  | DexItemFactory factory = new DexItemFactory(); | 
|  | DesugaredLibrarySpecification desugaredLibrarySpecification = | 
|  | getDesugaredLibraryConfiguration(factory, false); | 
|  |  | 
|  | ImmutableList<ProguardConfigurationRule> mainDexKeepRules = | 
|  | ProguardConfigurationParser.parse(mainDexRules, factory, getReporter()); | 
|  |  | 
|  | if (!globalSyntheticsResourceProviders.isEmpty()) { | 
|  | addProgramResourceProvider( | 
|  | new InternalGlobalSyntheticsProgramProvider(globalSyntheticsResourceProviders)); | 
|  | } | 
|  |  | 
|  | // If compiling to CF with --no-desugaring then the target API is B for consistency with R8. | 
|  | int minApiLevel = | 
|  | getProgramConsumer() instanceof ClassFileConsumer && getDisableDesugaring() | 
|  | ? AndroidApiLevel.B.getLevel() | 
|  | : getMinApiLevel(); | 
|  |  | 
|  | return new D8Command( | 
|  | getAppBuilder().build(), | 
|  | getMode(), | 
|  | getProgramConsumer(), | 
|  | getMainDexListConsumer(), | 
|  | minApiLevel, | 
|  | getReporter(), | 
|  | getDesugaringState(), | 
|  | intermediate, | 
|  | intermediate ? globalSyntheticsConsumer : null, | 
|  | isOptimizeMultidexForLinearAlloc(), | 
|  | getIncludeClassesChecksum(), | 
|  | getDexClassChecksumFilter(), | 
|  | getDesugarGraphConsumer(), | 
|  | desugaredLibraryKeepRuleConsumer, | 
|  | desugaredLibrarySpecification, | 
|  | getAssertionsConfiguration(), | 
|  | getOutputInspections(), | 
|  | synthesizedClassPrefix, | 
|  | enableMainDexListCheck, | 
|  | minimalMainDex, | 
|  | mainDexKeepRules, | 
|  | getThreadCount(), | 
|  | getDumpInputFlags(), | 
|  | getMapIdProvider(), | 
|  | proguardMapConsumer, | 
|  | enableMissingLibraryApiModeling, | 
|  | getAndroidPlatformBuild(), | 
|  | getStartupProfileProviders(), | 
|  | getClassConflictResolver(), | 
|  | factory); | 
|  | } | 
|  | } | 
|  |  | 
|  | private final boolean intermediate; | 
|  | private final GlobalSyntheticsConsumer globalSyntheticsConsumer; | 
|  | private final DesugarGraphConsumer desugarGraphConsumer; | 
|  | private final StringConsumer desugaredLibraryKeepRuleConsumer; | 
|  | private final DesugaredLibrarySpecification desugaredLibrarySpecification; | 
|  | private final String synthesizedClassPrefix; | 
|  | private final boolean enableMainDexListCheck; | 
|  | private final boolean minimalMainDex; | 
|  | private final ImmutableList<ProguardConfigurationRule> mainDexKeepRules; | 
|  | private final StringConsumer proguardMapConsumer; | 
|  | private final boolean enableMissingLibraryApiModeling; | 
|  | private final DexItemFactory factory; | 
|  |  | 
|  | public static Builder builder() { | 
|  | return new Builder(); | 
|  | } | 
|  |  | 
|  | public static Builder builder(DiagnosticsHandler diagnosticsHandler) { | 
|  | return new Builder(diagnosticsHandler); | 
|  | } | 
|  |  | 
|  | // Internal builder to start from an existing AndroidApp. | 
|  | static Builder builder(AndroidApp app) { | 
|  | return new Builder(app); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Parse the D8 command-line. | 
|  | * | 
|  | * <p>Parsing will set the supplied options or their default value if they have any. | 
|  | * | 
|  | * @param args Command-line arguments array. | 
|  | * @param origin Origin description of the command-line arguments. | 
|  | * @return D8 command builder with state set up according to parsed command line. | 
|  | */ | 
|  | public static Builder parse(String[] args, Origin origin) { | 
|  | return D8CommandParser.parse(args, origin); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Parse the D8 command-line. | 
|  | * | 
|  | * <p>Parsing will set the supplied options or their default value if they have any. | 
|  | * | 
|  | * @param args Command-line arguments array. | 
|  | * @param origin Origin description of the command-line arguments. | 
|  | * @param handler Custom defined diagnostics handler. | 
|  | * @return D8 command builder with state set up according to parsed command line. | 
|  | */ | 
|  | public static Builder parse(String[] args, Origin origin, DiagnosticsHandler handler) { | 
|  | return D8CommandParser.parse(args, origin, handler); | 
|  | } | 
|  |  | 
|  | /** Get the help description for the D8 supported flags. */ | 
|  | public static List<ParseFlagInfo> getParseFlagsInformation() { | 
|  | return D8CommandParser.getFlags(); | 
|  | } | 
|  |  | 
|  | private D8Command( | 
|  | AndroidApp inputApp, | 
|  | CompilationMode mode, | 
|  | ProgramConsumer programConsumer, | 
|  | StringConsumer mainDexListConsumer, | 
|  | int minApiLevel, | 
|  | Reporter diagnosticsHandler, | 
|  | DesugarState enableDesugaring, | 
|  | boolean intermediate, | 
|  | GlobalSyntheticsConsumer globalSyntheticsConsumer, | 
|  | boolean optimizeMultidexForLinearAlloc, | 
|  | boolean encodeChecksum, | 
|  | BiPredicate<String, Long> dexClassChecksumFilter, | 
|  | DesugarGraphConsumer desugarGraphConsumer, | 
|  | StringConsumer desugaredLibraryKeepRuleConsumer, | 
|  | DesugaredLibrarySpecification desugaredLibrarySpecification, | 
|  | List<AssertionsConfiguration> assertionsConfiguration, | 
|  | List<Consumer<Inspector>> outputInspections, | 
|  | String synthesizedClassPrefix, | 
|  | boolean enableMainDexListCheck, | 
|  | boolean minimalMainDex, | 
|  | ImmutableList<ProguardConfigurationRule> mainDexKeepRules, | 
|  | int threadCount, | 
|  | DumpInputFlags dumpInputFlags, | 
|  | MapIdProvider mapIdProvider, | 
|  | StringConsumer proguardMapConsumer, | 
|  | boolean enableMissingLibraryApiModeling, | 
|  | boolean isAndroidPlatformBuild, | 
|  | List<StartupProfileProvider> startupProfileProviders, | 
|  | ClassConflictResolver classConflictResolver, | 
|  | DexItemFactory factory) { | 
|  | super( | 
|  | inputApp, | 
|  | mode, | 
|  | programConsumer, | 
|  | mainDexListConsumer, | 
|  | minApiLevel, | 
|  | diagnosticsHandler, | 
|  | enableDesugaring, | 
|  | optimizeMultidexForLinearAlloc, | 
|  | encodeChecksum, | 
|  | dexClassChecksumFilter, | 
|  | assertionsConfiguration, | 
|  | outputInspections, | 
|  | threadCount, | 
|  | dumpInputFlags, | 
|  | mapIdProvider, | 
|  | null, | 
|  | isAndroidPlatformBuild, | 
|  | startupProfileProviders, | 
|  | classConflictResolver); | 
|  | this.intermediate = intermediate; | 
|  | this.globalSyntheticsConsumer = globalSyntheticsConsumer; | 
|  | this.desugarGraphConsumer = desugarGraphConsumer; | 
|  | this.desugaredLibraryKeepRuleConsumer = desugaredLibraryKeepRuleConsumer; | 
|  | this.desugaredLibrarySpecification = desugaredLibrarySpecification; | 
|  | this.synthesizedClassPrefix = synthesizedClassPrefix; | 
|  | this.enableMainDexListCheck = enableMainDexListCheck; | 
|  | this.minimalMainDex = minimalMainDex; | 
|  | this.mainDexKeepRules = mainDexKeepRules; | 
|  | this.proguardMapConsumer = proguardMapConsumer; | 
|  | this.enableMissingLibraryApiModeling = enableMissingLibraryApiModeling; | 
|  | this.factory = factory; | 
|  | } | 
|  |  | 
|  | private D8Command(boolean printHelp, boolean printVersion) { | 
|  | super(printHelp, printVersion); | 
|  | intermediate = false; | 
|  | globalSyntheticsConsumer = null; | 
|  | desugarGraphConsumer = null; | 
|  | desugaredLibraryKeepRuleConsumer = null; | 
|  | desugaredLibrarySpecification = null; | 
|  | synthesizedClassPrefix = null; | 
|  | enableMainDexListCheck = true; | 
|  | minimalMainDex = false; | 
|  | mainDexKeepRules = null; | 
|  | proguardMapConsumer = null; | 
|  | enableMissingLibraryApiModeling = false; | 
|  | factory = null; | 
|  | } | 
|  |  | 
|  | @Override | 
|  | InternalOptions getInternalOptions() { | 
|  | InternalOptions internal = new InternalOptions(factory, getReporter()); | 
|  | assert !internal.debug; | 
|  | internal.debug = getMode() == CompilationMode.DEBUG; | 
|  | internal.programConsumer = getProgramConsumer(); | 
|  | if (internal.isGeneratingClassFiles()) { | 
|  | // Turn off switch optimizations when generating class files. | 
|  | assert internal.enableSwitchRewriting; | 
|  | internal.enableSwitchRewriting = false; | 
|  | assert internal.enableStringSwitchConversion; | 
|  | internal.enableStringSwitchConversion = false; | 
|  | } else { | 
|  | assert !internal.desugarSpecificOptions().allowAllDesugaredInput | 
|  | || getDesugarState() == DesugarState.OFF; | 
|  | } | 
|  | internal.mainDexListConsumer = getMainDexListConsumer(); | 
|  | internal.minimalMainDex = internal.debug || minimalMainDex; | 
|  | internal.enableMainDexListCheck = enableMainDexListCheck; | 
|  | internal.setMinApiLevel(AndroidApiLevel.getAndroidApiLevel(getMinApiLevel())); | 
|  | internal.intermediate = intermediate; | 
|  | internal.retainCompileTimeAnnotations = intermediate; | 
|  | internal.setGlobalSyntheticsConsumer(globalSyntheticsConsumer); | 
|  | internal.desugarGraphConsumer = desugarGraphConsumer; | 
|  | internal.mainDexKeepRules = mainDexKeepRules; | 
|  | internal.proguardMapConsumer = proguardMapConsumer; | 
|  | internal.lineNumberOptimization = | 
|  | !internal.debug && proguardMapConsumer != null | 
|  | ? LineNumberOptimization.ON | 
|  | : LineNumberOptimization.OFF; | 
|  |  | 
|  | // Assert and fixup defaults. | 
|  | assert !internal.isShrinking(); | 
|  | assert !internal.isMinifying(); | 
|  | assert !internal.passthroughDexCode; | 
|  | internal.passthroughDexCode = true; | 
|  |  | 
|  | // Assert some of R8 optimizations are disabled. | 
|  | assert !internal.inlinerOptions().enableInlining; | 
|  | assert !internal.enableClassInlining; | 
|  | assert !internal.enableVerticalClassMerging; | 
|  | assert !internal.enableEnumValueOptimization; | 
|  | assert !internal.outline.enabled; | 
|  | assert !internal.enableTreeShakingOfLibraryMethodOverrides; | 
|  |  | 
|  | internal.desugarState = getDesugarState(); | 
|  | internal.encodeChecksums = getIncludeClassesChecksum(); | 
|  | internal.dexClassChecksumFilter = getDexClassChecksumFilter(); | 
|  | internal.enableInheritanceClassInDexDistributor = isOptimizeMultidexForLinearAlloc(); | 
|  | internal.setDesugaredLibrarySpecification(desugaredLibrarySpecification); | 
|  | internal.synthesizedClassPrefix = | 
|  | synthesizedClassPrefix.isEmpty() | 
|  | ? System.getProperty("com.android.tools.r8.synthesizedClassPrefix", "") | 
|  | : synthesizedClassPrefix; | 
|  | internal.desugaredLibraryKeepRuleConsumer = desugaredLibraryKeepRuleConsumer; | 
|  |  | 
|  | if (!enableMissingLibraryApiModeling) { | 
|  | internal.apiModelingOptions().disableApiCallerIdentification(); | 
|  | internal.apiModelingOptions().disableMissingApiModeling(); | 
|  | } | 
|  |  | 
|  | // Default is to remove all javac generated assertion code when generating dex. | 
|  | assert internal.assertionsConfiguration == null; | 
|  | internal.assertionsConfiguration = | 
|  | new AssertionConfigurationWithDefault( | 
|  | AssertionsConfiguration.builder(getReporter()) | 
|  | .setCompileTimeDisable() | 
|  | .setScopeAll() | 
|  | .build(), | 
|  | getAssertionsConfiguration()); | 
|  |  | 
|  | internal.outputInspections = InspectorImpl.wrapInspections(getOutputInspections()); | 
|  |  | 
|  | if (!DETERMINISTIC_DEBUGGING) { | 
|  | assert internal.threadCount == ThreadUtils.NOT_SPECIFIED; | 
|  | internal.threadCount = getThreadCount(); | 
|  | } | 
|  |  | 
|  | // Disable global optimizations. | 
|  | internal.disableGlobalOptimizations(); | 
|  |  | 
|  | HorizontalClassMergerOptions horizontalClassMergerOptions = | 
|  | internal.horizontalClassMergerOptions(); | 
|  | if (internal.isGeneratingDex()) { | 
|  | horizontalClassMergerOptions.setRestrictToSynthetics(); | 
|  | } else { | 
|  | assert internal.isGeneratingClassFiles(); | 
|  | horizontalClassMergerOptions.disable(); | 
|  | } | 
|  |  | 
|  | internal.configureAndroidPlatformBuild(getAndroidPlatformBuild()); | 
|  |  | 
|  | // TODO(b/238173796): Change StartupOptions to store a Collection<StartupProfileProvider>. | 
|  | if (getStartupProfileProviders().size() == 1) { | 
|  | internal.getStartupOptions().setStartupProfileProvider(getStartupProfileProviders().get(0)); | 
|  | } | 
|  |  | 
|  | internal.programClassConflictResolver = | 
|  | ProgramClassCollection.wrappedConflictResolver( | 
|  | getClassConflictResolver(), internal.reporter); | 
|  |  | 
|  | internal.setDumpInputFlags(getDumpInputFlags()); | 
|  | internal.dumpOptions = dumpOptions(); | 
|  |  | 
|  | return internal; | 
|  | } | 
|  |  | 
|  | private DumpOptions dumpOptions() { | 
|  | DumpOptions.Builder builder = DumpOptions.builder(Tool.D8).readCurrentSystemProperties(); | 
|  | dumpBaseCommandOptions(builder); | 
|  | return builder | 
|  | .setIntermediate(intermediate) | 
|  | .setDesugaredLibraryConfiguration(desugaredLibrarySpecification) | 
|  | .setMainDexKeepRules(mainDexKeepRules) | 
|  | .setEnableMissingLibraryApiModeling(enableMissingLibraryApiModeling) | 
|  | .build(); | 
|  | } | 
|  | } |