/* * Copyright 2012-present Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package com.facebook.buck.android; import com.facebook.buck.dalvik.ZipSplitter; import com.facebook.buck.rules.RuleKeyAppendable; import com.facebook.buck.rules.RuleKeyObjectSink; import com.facebook.buck.rules.SourcePath; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableSet; import java.util.Collection; import java.util.Optional; /** Bundles together some information about whether and how we should split up dex files. */ class DexSplitMode implements RuleKeyAppendable { public static final DexSplitMode NO_SPLIT = new DexSplitMode( /* shouldSplitDex */ false, ZipSplitter.DexSplitStrategy.MAXIMIZE_PRIMARY_DEX_SIZE, DexStore.JAR, /* linearAllocHardLimit */ 0, /* primaryDexPatterns */ ImmutableSet.of(), /* primaryDexClassesFile */ Optional.empty(), /* primaryDexScenarioFile */ Optional.empty(), /* isPrimaryDexScenarioOverflowAllowed */ false, /* secondaryDexHeadClassesFile */ Optional.empty(), /* secondaryDexTailClassesFile */ Optional.empty()); private final boolean shouldSplitDex; private final DexStore dexStore; private final ZipSplitter.DexSplitStrategy dexSplitStrategy; private final long linearAllocHardLimit; private final ImmutableSet<String> primaryDexPatterns; /** * File that whitelists the class files that should be in the primary dex. * * <p>Values in this file must match JAR entries (without the .class suffix), so they should * contain path separators. For example: * * <pre> * java/util/Map$Entry * </pre> */ private final Optional<SourcePath> primaryDexClassesFile; /** * File identifying the class files used in scenarios we want to fit in the primary dex. We will * add these classes and their dependencies, as well as base classes/interfaces thereof to the * primary dex. * * <p>Values in this file must match JAR entries (without the .class suffix), so they should * contain path separators. For example: * * <pre> * java/util/Map$Entry * </pre> */ private final Optional<SourcePath> primaryDexScenarioFile; /** * Boolean identifying whether we should allow the build to succeed if all the classes identified * by primaryDexScenarioFile + dependencies do not fit in the primary dex. The default is false, * which causes the build to fail in this case. */ private final boolean isPrimaryDexScenarioOverflowAllowed; /** * File that whitelists the class files that should be in the first secondary dexes. * * <p>Values in this file must match JAR entries (without the .class suffix), so they should * contain path separators. For example: * * <pre> * java/util/Map$Entry * </pre> */ private final Optional<SourcePath> secondaryDexHeadClassesFile; /** * File that whitelists the class files that should be in the last secondary dexes. * * <p>Values in this file must match JAR entries (without the .class suffix), so they should * contain path separators. For example: * * <pre> * java/util/Map$Entry * </pre> */ private final Optional<SourcePath> secondaryDexTailClassesFile; /** * @param primaryDexPatterns Set of substrings that, when matched, will cause individual input * class or resource files to be placed into the primary jar (and thus the primary dex * output). These classes are required for correctness. * @param primaryDexClassesFile Path to a file containing a list of classes that must be included * in the primary dex. These classes are required for correctness. * @param primaryDexScenarioFile Path to a file containing a list of classes used in a scenario * that should be included in the primary dex along with all dependency classes required for * preverification. These dependencies will be calculated by buck. This list is used for * performance, not correctness. * @param isPrimaryDexScenarioOverflowAllowed A boolean indicating whether to fail the build if * any classes required by primaryDexScenarioFile cannot fit (false) or to allow the build to * to proceed on a best-effort basis (true). * @param secondaryDexHeadClassesFile Path to a file containing a list of classes that are put in * the first secondary dexes. * @param secondaryDexTailClassesFile Path to a file containing a list of classes that are put in * the last secondary dexes. */ public DexSplitMode( boolean shouldSplitDex, ZipSplitter.DexSplitStrategy dexSplitStrategy, DexStore dexStore, long linearAllocHardLimit, Collection<String> primaryDexPatterns, Optional<SourcePath> primaryDexClassesFile, Optional<SourcePath> primaryDexScenarioFile, boolean isPrimaryDexScenarioOverflowAllowed, Optional<SourcePath> secondaryDexHeadClassesFile, Optional<SourcePath> secondaryDexTailClassesFile) { this.shouldSplitDex = shouldSplitDex; this.dexSplitStrategy = dexSplitStrategy; this.dexStore = dexStore; this.linearAllocHardLimit = linearAllocHardLimit; this.primaryDexPatterns = ImmutableSet.copyOf(primaryDexPatterns); this.primaryDexClassesFile = primaryDexClassesFile; this.primaryDexScenarioFile = primaryDexScenarioFile; this.isPrimaryDexScenarioOverflowAllowed = isPrimaryDexScenarioOverflowAllowed; this.secondaryDexHeadClassesFile = secondaryDexHeadClassesFile; this.secondaryDexTailClassesFile = secondaryDexTailClassesFile; } public DexStore getDexStore() { return dexStore; } public boolean isShouldSplitDex() { return shouldSplitDex; } ZipSplitter.DexSplitStrategy getDexSplitStrategy() { Preconditions.checkState(isShouldSplitDex()); return dexSplitStrategy; } public long getLinearAllocHardLimit() { return linearAllocHardLimit; } public ImmutableSet<String> getPrimaryDexPatterns() { return primaryDexPatterns; } public Optional<SourcePath> getPrimaryDexClassesFile() { return primaryDexClassesFile; } public Optional<SourcePath> getPrimaryDexScenarioFile() { return primaryDexScenarioFile; } public boolean isPrimaryDexScenarioOverflowAllowed() { return isPrimaryDexScenarioOverflowAllowed; } public Optional<SourcePath> getSecondaryDexHeadClassesFile() { return secondaryDexHeadClassesFile; } public Optional<SourcePath> getSecondaryDexTailClassesFile() { return secondaryDexTailClassesFile; } @Override public void appendToRuleKey(RuleKeyObjectSink sink) { sink.setReflectively("dexStore", dexStore); sink.setReflectively("dexSplitStrategy", dexSplitStrategy); sink.setReflectively( "isPrimaryDexScenarioOverflowAllowed", isPrimaryDexScenarioOverflowAllowed); sink.setReflectively("linearAllocHardLimit", linearAllocHardLimit); sink.setReflectively("primaryDexPatterns", primaryDexPatterns); sink.setReflectively("primaryDexClassesFile", primaryDexClassesFile); sink.setReflectively("primaryDexScenarioFile", primaryDexScenarioFile); sink.setReflectively("secondaryDexHeadClassesFile", secondaryDexHeadClassesFile); sink.setReflectively("secondaryDexTailClassesFile", secondaryDexTailClassesFile); sink.setReflectively("shouldSplitDex", shouldSplitDex); } }