blob: b231f7cb5019862505e0aa5ed865aa7c4648d5c2 [file] [log] [blame]
/*
* 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.RuleKey;
import com.facebook.buck.rules.RuleKeyAppendable;
import com.facebook.buck.rules.SourcePath;
import com.facebook.buck.util.Optionals;
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import java.util.Collection;
import javax.annotation.concurrent.Immutable;
/**
* Bundles together some information about whether and how we should split up dex files.
*/
@Immutable
class DexSplitMode implements RuleKeyAppendable {
public static final DexSplitMode NO_SPLIT = new DexSplitMode(
/* shouldSplitDex */ false,
ZipSplitter.DexSplitStrategy.MAXIMIZE_PRIMARY_DEX_SIZE,
DexStore.JAR,
/* useLinearAllocSplitDex */ false,
/* linearAllocHardLimit */ 0,
/* primaryDexPatterns */ ImmutableSet.<String>of(),
/* primaryDexClassesFile */ Optional.<SourcePath>absent(),
/* primaryDexScenarioFile */ Optional.<SourcePath>absent(),
/* isPrimaryDexScenarioOverflowAllowed */ false,
/* secondaryDexHeadClassesFile */ Optional.<SourcePath>absent(),
/* secondaryDexTailClassesFile */ Optional.<SourcePath>absent());
private final boolean shouldSplitDex;
private final DexStore dexStore;
private final ZipSplitter.DexSplitStrategy dexSplitStrategy;
private final boolean useLinearAllocSplitDex;
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.
* @param useLinearAllocSplitDex If true, {@link com.facebook.buck.dalvik.DalvikAwareZipSplitter}
* will be used. Also, {@code linearAllocHardLimit} must have a positive value in this case.
*/
public DexSplitMode(
boolean shouldSplitDex,
ZipSplitter.DexSplitStrategy dexSplitStrategy,
DexStore dexStore,
boolean useLinearAllocSplitDex,
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.useLinearAllocSplitDex = useLinearAllocSplitDex;
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 boolean useLinearAllocSplitDex() {
return useLinearAllocSplitDex;
}
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;
}
/**
* @return All {@link SourcePath}s referenced by this object, for use in
* {@link com.facebook.buck.rules.AbstractBuildRule#getInputsToCompareToOutput()}.
*/
public Collection<SourcePath> getSourcePaths() {
ImmutableList.Builder<SourcePath> paths = ImmutableList.builder();
Optionals.addIfPresent(primaryDexClassesFile, paths);
Optionals.addIfPresent(primaryDexScenarioFile, paths);
Optionals.addIfPresent(secondaryDexHeadClassesFile, paths);
Optionals.addIfPresent(secondaryDexTailClassesFile, paths);
return paths.build();
}
@Override
public RuleKey.Builder appendToRuleKey(RuleKey.Builder builder, String key) {
builder.setReflectively(key + ".shouldSplitDex", shouldSplitDex);
builder.setReflectively(key + ".dexStore", dexStore.name());
builder.setReflectively(key + ".dexSplitStrategy", dexSplitStrategy.name());
builder.setReflectively(key + ".useLinearAllocSplitDex", useLinearAllocSplitDex);
builder.setReflectively(key + ".primaryDexPatterns", primaryDexPatterns);
builder.setReflectively(key + ".linearAllocHardLimit", linearAllocHardLimit);
builder.setReflectively(
key + ".isPrimaryDexScenarioOverflowAllowed",
isPrimaryDexScenarioOverflowAllowed);
return builder;
}
}