aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/java/com/google/devtools/build/lib
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/com/google/devtools/build/lib')
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/android/AndroidBinary.java11
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/android/AndroidBinaryMobileInstall.java2
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/android/AndroidConfiguration.java2
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/android/AndroidLocalTestBase.java8
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/android/AndroidManifest.java159
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/android/AndroidSemantics.java6
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/android/AndroidSkylarkData.java28
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/android/ApplicationManifest.java272
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/android/StampedAndroidManifest.java119
9 files changed, 257 insertions, 350 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidBinary.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidBinary.java
index 3c723466f0..5d95ce9a50 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidBinary.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidBinary.java
@@ -17,6 +17,7 @@ package com.google.devtools.build.lib.rules.android;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.collect.ImmutableList.toImmutableList;
+import static com.google.devtools.build.lib.syntax.Type.STRING;
import static java.nio.charset.StandardCharsets.ISO_8859_1;
import com.google.auto.value.AutoValue;
@@ -183,15 +184,19 @@ public abstract class AndroidBinary implements RuleConfiguredTargetFactory {
AndroidResources.validateRuleContext(ruleContext);
final AndroidDataContext dataContext = androidSemantics.makeContextForNative(ruleContext);
+ Map<String, String> manifestValues = StampedAndroidManifest.getManifestValues(ruleContext);
StampedAndroidManifest manifest =
AndroidManifest.fromAttributes(ruleContext, dataContext, androidSemantics)
.mergeWithDeps(
dataContext,
androidSemantics,
+ ruleContext,
resourceDeps,
- ApplicationManifest.getManifestValues(ruleContext),
- ApplicationManifest.useLegacyMerging(ruleContext));
+ manifestValues,
+ ruleContext.getRule().isAttrDefined("manifest_merger", STRING)
+ ? ruleContext.attributes().get("manifest_merger", STRING)
+ : null);
AndroidAaptVersion aaptVersion = AndroidAaptVersion.chooseTargetAaptVersion(ruleContext);
final ResourceApk resourceApk =
@@ -201,7 +206,7 @@ public abstract class AndroidBinary implements RuleConfiguredTargetFactory {
manifest,
/* conditionalKeepRules = */ shouldShrinkResourceCycles(
dataContext.getAndroidConfig(), ruleContext, shrinkResources),
- ApplicationManifest.getManifestValues(ruleContext),
+ manifestValues,
aaptVersion,
AndroidResources.from(ruleContext, "resource_files"),
AndroidAssets.from(ruleContext),
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidBinaryMobileInstall.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidBinaryMobileInstall.java
index 29529bbfc0..0669f0bad3 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidBinaryMobileInstall.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidBinaryMobileInstall.java
@@ -62,7 +62,7 @@ public final class AndroidBinaryMobileInstall {
final ResourceApk incrementalResourceApk;
final ResourceApk splitResourceApk;
- Map<String, String> manifestValues = ApplicationManifest.getManifestValues(ruleContext);
+ Map<String, String> manifestValues = StampedAndroidManifest.getManifestValues(ruleContext);
incrementalResourceApk =
ProcessedAndroidData.processIncrementalBinaryDataFrom(
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidConfiguration.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidConfiguration.java
index 98ec4dafde..f7657ed8b2 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidConfiguration.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidConfiguration.java
@@ -221,7 +221,7 @@ public class AndroidConfiguration extends BuildConfiguration.Fragment
}
}
- // TODO(corysmith): Move to ApplicationManifest when no longer needed as a public function.
+ // TODO(corysmith): Move to an appropriate place when no longer needed as a public function.
@Nullable
public static AndroidAaptVersion chooseTargetAaptVersion(RuleContext ruleContext)
throws RuleErrorException {
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidLocalTestBase.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidLocalTestBase.java
index b484479169..8ee5a16afc 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidLocalTestBase.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidLocalTestBase.java
@@ -36,6 +36,7 @@ import com.google.devtools.build.lib.collect.nestedset.NestedSet;
import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
import com.google.devtools.build.lib.collect.nestedset.Order;
import com.google.devtools.build.lib.packages.BuildType;
+import com.google.devtools.build.lib.packages.RuleErrorConsumer;
import com.google.devtools.build.lib.rules.android.AndroidConfiguration.AndroidAaptVersion;
import com.google.devtools.build.lib.rules.android.DataBinding.DataBindingContext;
import com.google.devtools.build.lib.rules.java.ClasspathConfiguredFragment;
@@ -97,13 +98,14 @@ public abstract class AndroidLocalTestBase implements RuleConfiguredTargetFactor
buildResourceApk(
dataContext,
androidSemantics,
+ ruleContext,
DataBinding.contextFrom(ruleContext, dataContext.getAndroidConfig()),
AndroidManifest.fromAttributes(ruleContext, dataContext),
AndroidResources.from(ruleContext, "resource_files"),
AndroidAssets.from(ruleContext),
ResourceDependencies.fromRuleDeps(ruleContext, /* neverlink = */ false),
AssetDependencies.fromRuleDeps(ruleContext, /* neverlink = */ false),
- ApplicationManifest.getManifestValues(ruleContext),
+ StampedAndroidManifest.getManifestValues(ruleContext),
AndroidAaptVersion.chooseTargetAaptVersion(ruleContext));
attributesBuilder.addRuntimeClassPathEntry(resourceApk.getResourceJavaClassJar());
@@ -492,6 +494,7 @@ public abstract class AndroidLocalTestBase implements RuleConfiguredTargetFactor
static ResourceApk buildResourceApk(
AndroidDataContext dataContext,
AndroidSemantics androidSemantics,
+ RuleErrorConsumer errorConsumer,
DataBindingContext dataBindingContext,
AndroidManifest manifest,
AndroidResources resources,
@@ -506,9 +509,10 @@ public abstract class AndroidLocalTestBase implements RuleConfiguredTargetFactor
manifest.mergeWithDeps(
dataContext,
androidSemantics,
+ errorConsumer,
resourceDeps,
manifestValues,
- /* useLegacyMerger = */ false);
+ /* manifestMerger = */ null);
return ProcessedAndroidData.processLocalTestDataFrom(
dataContext,
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidManifest.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidManifest.java
index 160ccb3980..6a552b8c7b 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidManifest.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidManifest.java
@@ -13,13 +13,19 @@
// limitations under the License.
package com.google.devtools.build.lib.rules.android;
+import static com.google.common.base.Strings.isNullOrEmpty;
+
+import com.google.common.collect.ImmutableSortedMap;
import com.google.devtools.build.lib.actions.Artifact;
import com.google.devtools.build.lib.analysis.RuleContext;
import com.google.devtools.build.lib.analysis.actions.ActionConstructionContext;
+import com.google.devtools.build.lib.analysis.actions.SymlinkAction;
+import com.google.devtools.build.lib.analysis.configuredtargets.RuleConfiguredTarget.Mode;
import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
import com.google.devtools.build.lib.packages.RuleClass.ConfiguredTargetFactory.RuleErrorException;
import com.google.devtools.build.lib.packages.RuleErrorConsumer;
+import com.google.devtools.build.lib.rules.android.AndroidConfiguration.AndroidManifestMerger;
import com.google.devtools.build.lib.rules.java.JavaUtil;
import com.google.devtools.build.lib.syntax.Type;
import com.google.devtools.build.lib.vfs.PathFragment;
@@ -74,7 +80,7 @@ public class AndroidManifest {
Artifact rawManifest = null;
if (AndroidResources.definesAndroidResources(ruleContext.attributes())) {
AndroidResources.validateRuleContext(ruleContext);
- rawManifest = ApplicationManifest.getManifestFromAttributes(ruleContext);
+ rawManifest = ruleContext.getPrerequisiteArtifact("manifest", Mode.TARGET);
}
return from(
@@ -110,9 +116,16 @@ public class AndroidManifest {
/**
* Inner method to create an AndroidManifest.
*
- * <p>AndroidSemantics-specific processing will be used if a non-null AndroidSemantics is passed.
+ * @param rawManifest If non-null, the returned object will wrap this manifest. Otherwise, the
+ * returned object will wrap a generated dummy manifest.
+ * @param androidSemantics If non-null, will invoke
+ * AndroidSemantics#renameManifest(AndroidDataContext, AndroidManifest)} to do
+ * platform-specific processing on the manifest.
+ * @param pkg If non-null, this Android package will be used for the manifest, and the manifest
+ * will be stamped with it when the {@link #stamp(AndroidDataContext)} method is called.
+ * Otherwise, the default package, based on the current target's Bazel package, will be used.
*/
- static AndroidManifest from(
+ public static AndroidManifest from(
AndroidDataContext dataContext,
RuleErrorConsumer errorConsumer,
@Nullable Artifact rawManifest,
@@ -129,21 +142,40 @@ public class AndroidManifest {
if (rawManifest == null) {
// Generate a dummy manifest
return StampedAndroidManifest.createEmpty(
- dataContext.getActionConstructionContext(), pkg, /* exported = */ false);
+ dataContext.getActionConstructionContext(), pkg, exportsManifest);
}
- Artifact renamedManifest;
+ AndroidManifest raw = new AndroidManifest(rawManifest, pkg, exportsManifest);
+
if (androidSemantics != null) {
- renamedManifest = androidSemantics.renameManifest(dataContext, rawManifest);
- } else {
- renamedManifest = ApplicationManifest.renameManifestIfNeeded(dataContext, rawManifest);
+ return androidSemantics.renameManifest(dataContext, raw);
}
+ return raw.renameManifestIfNeeded(dataContext);
+ }
- return new AndroidManifest(renamedManifest, pkg, exportsManifest);
+ AndroidManifest renameManifestIfNeeded(AndroidDataContext dataContext)
+ throws InterruptedException {
+ if (manifest.getFilename().equals("AndroidManifest.xml")) {
+ return this;
+ } else {
+ /*
+ * If the manifest file is not named AndroidManifest.xml, we create a symlink named
+ * AndroidManifest.xml to it. aapt requires the manifest to be named as such.
+ */
+ Artifact manifestSymlink =
+ dataContext.createOutputArtifact(AndroidRuleClasses.ANDROID_SYMLINKED_MANIFEST);
+ dataContext.registerAction(
+ new SymlinkAction(
+ dataContext.getActionConstructionContext().getActionOwner(),
+ manifest,
+ manifestSymlink,
+ "Renaming Android manifest for " + dataContext.getLabel()));
+ return updateManifest(manifestSymlink);
+ }
}
- AndroidManifest(AndroidManifest other, Artifact manifest) {
- this(manifest, other.pkg, other.exported);
+ public AndroidManifest updateManifest(Artifact manifest) {
+ return new AndroidManifest(manifest, pkg, exported);
}
/**
@@ -158,25 +190,18 @@ public class AndroidManifest {
/** If needed, stamps the manifest with the correct Java package */
public StampedAndroidManifest stamp(AndroidDataContext dataContext) {
- return new StampedAndroidManifest(
- ApplicationManifest.maybeSetManifestPackage(dataContext, manifest, pkg).orElse(manifest),
- pkg,
- exported);
- }
+ Artifact outputManifest = getManifest();
+ if (!isNullOrEmpty(pkg)) {
+ outputManifest = dataContext.getUniqueDirectoryArtifact("_renamed", "AndroidManifest.xml");
+ new ManifestMergerActionBuilder()
+ .setManifest(manifest)
+ .setLibrary(true)
+ .setCustomPackage(pkg)
+ .setManifestOutput(outputManifest)
+ .build(dataContext);
+ }
- /**
- * Stamps the manifest with values from the "manifest_values" attributes.
- *
- * <p>If no manifest values are specified, the manifest will remain unstamped.
- */
- public StampedAndroidManifest stampWithManifestValues(
- RuleContext ruleContext, AndroidDataContext dataContext, AndroidSemantics androidSemantics) {
- return mergeWithDeps(
- dataContext,
- androidSemantics,
- ResourceDependencies.empty(),
- ApplicationManifest.getManifestValues(ruleContext),
- ApplicationManifest.useLegacyMerging(ruleContext));
+ return new StampedAndroidManifest(outputManifest, pkg, exported);
}
/**
@@ -186,27 +211,79 @@ public class AndroidManifest {
*
* <p>If there is no merging to be done and no manifest values are specified, the manifest will
* remain unstamped.
+ *
+ * @param manifestMerger if not null, a string dictating which manifest merger to use
*/
public StampedAndroidManifest mergeWithDeps(
AndroidDataContext dataContext,
AndroidSemantics androidSemantics,
+ RuleErrorConsumer errorConsumer,
ResourceDependencies resourceDeps,
Map<String, String> manifestValues,
- boolean useLegacyMerger) {
- Artifact newManifest =
- ApplicationManifest.maybeMergeWith(
- dataContext,
- androidSemantics,
- manifest,
- resourceDeps,
- manifestValues,
- useLegacyMerger,
- pkg)
- .orElse(manifest);
+ @Nullable String manifestMerger) {
+ Map<Artifact, Label> mergeeManifests = getMergeeManifests(resourceDeps.getResourceContainers());
+
+ Artifact newManifest;
+ if (useLegacyMerging(errorConsumer, dataContext.getAndroidConfig(), manifestMerger)) {
+ newManifest =
+ androidSemantics
+ .maybeDoLegacyManifestMerging(mergeeManifests, dataContext, manifest)
+ .orElse(manifest);
+
+ } else if (!mergeeManifests.isEmpty() || !manifestValues.isEmpty()) {
+ newManifest = dataContext.getUniqueDirectoryArtifact("_merged", "AndroidManifest.xml");
+
+ new ManifestMergerActionBuilder()
+ .setManifest(manifest)
+ .setMergeeManifests(mergeeManifests)
+ .setLibrary(false)
+ .setManifestValues(manifestValues)
+ .setCustomPackage(pkg)
+ .setManifestOutput(newManifest)
+ .setLogOut(dataContext.getUniqueDirectoryArtifact("_merged", "manifest_merger_log.txt"))
+ .build(dataContext);
+
+ } else {
+ newManifest = manifest;
+ }
return new StampedAndroidManifest(newManifest, pkg, exported);
}
+ /**
+ * Checks if the legacy manifest merger should be used, based on an optional string specifying the
+ * merger to use.
+ */
+ private static boolean useLegacyMerging(
+ RuleErrorConsumer errorConsumer,
+ AndroidConfiguration androidConfig,
+ @Nullable String mergerString) {
+ AndroidManifestMerger merger = AndroidManifestMerger.fromString(mergerString);
+ if (merger == null) {
+ merger = androidConfig.getManifestMerger();
+ }
+ if (merger == AndroidManifestMerger.LEGACY) {
+ errorConsumer.ruleWarning(
+ "manifest_merger 'legacy' is deprecated. Please update to 'android'.\n"
+ + "See https://developer.android.com/studio/build/manifest-merge.html for more "
+ + "information about the manifest merger.");
+ }
+
+ return merger == AndroidManifestMerger.LEGACY;
+ }
+
+ private static Map<Artifact, Label> getMergeeManifests(
+ Iterable<ValidatedAndroidResources> transitiveData) {
+ ImmutableSortedMap.Builder<Artifact, Label> builder =
+ ImmutableSortedMap.orderedBy(Artifact.EXEC_PATH_COMPARATOR);
+ for (ValidatedAndroidResources d : transitiveData) {
+ if (d.isManifestExported()) {
+ builder.put(d.getManifest(), d.getLabel());
+ }
+ }
+ return builder.build();
+ }
+
public Artifact getManifest() {
return manifest;
}
@@ -283,7 +360,7 @@ public class AndroidManifest {
@Override
public boolean equals(Object object) {
- if (object == null || getClass() != object.getClass()) {
+ if (!(object instanceof AndroidManifest)) {
return false;
}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidSemantics.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidSemantics.java
index 9e06e3750f..b7d2b7d4fb 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidSemantics.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidSemantics.java
@@ -36,9 +36,9 @@ import java.util.Optional;
*/
public interface AndroidSemantics {
- default Artifact renameManifest(AndroidDataContext dataContext, Artifact rawManifest)
- throws InterruptedException {
- return ApplicationManifest.renameManifestIfNeeded(dataContext, rawManifest);
+ default AndroidManifest renameManifest(
+ AndroidDataContext dataContext, AndroidManifest rawManifest) throws InterruptedException {
+ return rawManifest.renameManifestIfNeeded(dataContext);
}
default Optional<Artifact> maybeDoLegacyManifestMerging(
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidSkylarkData.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidSkylarkData.java
index e23d77156e..023b95b89c 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidSkylarkData.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidSkylarkData.java
@@ -109,23 +109,16 @@ public abstract class AndroidSkylarkData
String pkg = fromNoneable(customPackage, String.class);
try (SkylarkErrorReporter errorReporter =
SkylarkErrorReporter.from(ctx.getActionConstructionContext(), location, env)) {
- if (pkg == null) {
- pkg =
- AndroidManifest.getDefaultPackage(
- env.getCallerLabel(), ctx.getActionConstructionContext(), errorReporter);
- }
- }
-
- Artifact primaryManifest = fromNoneable(manifest, Artifact.class);
- if (primaryManifest == null) {
- return StampedAndroidManifest.createEmpty(ctx.getActionConstructionContext(), pkg, exported)
+ return AndroidManifest.from(
+ ctx,
+ errorReporter,
+ fromNoneable(manifest, Artifact.class),
+ getAndroidSemantics(),
+ pkg,
+ exported)
+ .stamp(ctx)
.toProvider();
}
-
- // If needed, rename the manifest to "AndroidManifest.xml", which aapt expects.
- Artifact renamedManifest = getAndroidSemantics().renameManifest(ctx, primaryManifest);
-
- return new AndroidManifest(renamedManifest, pkg, exported).stamp(ctx).toProvider();
}
@Override
@@ -419,6 +412,7 @@ public abstract class AndroidSkylarkData
AndroidLocalTestBase.buildResourceApk(
ctx,
getAndroidSemantics(),
+ errorReporter,
DataBinding.asDisabledDataBindingContext(),
rawManifest,
AndroidResources.from(errorReporter, getFileProviders(resources), "resource_files"),
@@ -548,10 +542,10 @@ public abstract class AndroidSkylarkData
rawManifest.mergeWithDeps(
ctx,
getAndroidSemantics(),
+ errorReporter,
resourceDeps,
manifestValues,
- ApplicationManifest.useLegacyMerging(
- errorReporter, ctx.getAndroidConfig(), manifestMerger));
+ manifestMerger);
ResourceApk resourceApk =
ProcessedAndroidData.processBinaryDataFrom(
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/ApplicationManifest.java b/src/main/java/com/google/devtools/build/lib/rules/android/ApplicationManifest.java
deleted file mode 100644
index 3b4f239a1a..0000000000
--- a/src/main/java/com/google/devtools/build/lib/rules/android/ApplicationManifest.java
+++ /dev/null
@@ -1,272 +0,0 @@
-// Copyright 2015 The Bazel Authors. All rights reserved.
-//
-// 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.google.devtools.build.lib.rules.android;
-
-import static com.google.common.base.Strings.isNullOrEmpty;
-import static com.google.devtools.build.lib.syntax.Type.STRING;
-
-import com.google.common.base.Joiner;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSortedMap;
-import com.google.devtools.build.lib.actions.Artifact;
-import com.google.devtools.build.lib.analysis.RuleContext;
-import com.google.devtools.build.lib.analysis.actions.ActionConstructionContext;
-import com.google.devtools.build.lib.analysis.actions.CustomCommandLine;
-import com.google.devtools.build.lib.analysis.actions.FileWriteAction;
-import com.google.devtools.build.lib.analysis.actions.SpawnAction;
-import com.google.devtools.build.lib.analysis.actions.SymlinkAction;
-import com.google.devtools.build.lib.analysis.configuredtargets.RuleConfiguredTarget.Mode;
-import com.google.devtools.build.lib.cmdline.Label;
-import com.google.devtools.build.lib.packages.RuleErrorConsumer;
-import com.google.devtools.build.lib.rules.android.AndroidConfiguration.AndroidManifestMerger;
-import com.google.devtools.build.lib.syntax.Type;
-import java.util.Map;
-import java.util.Optional;
-import java.util.TreeMap;
-import javax.annotation.Nullable;
-
-/** Represents a AndroidManifest, that may have been merged from dependencies. */
-public final class ApplicationManifest {
-
- static Artifact createSplitManifest(
- RuleContext ruleContext, Artifact manifest, String splitName, boolean hasCode) {
- // aapt insists that manifests be called AndroidManifest.xml, even though they have to be
- // explicitly designated as manifests on the command line
- Artifact result =
- AndroidBinary.getDxArtifact(ruleContext, "split_" + splitName + "/AndroidManifest.xml");
- SpawnAction.Builder builder =
- new SpawnAction.Builder()
- .setExecutable(
- ruleContext.getExecutablePrerequisite("$build_split_manifest", Mode.HOST))
- .setProgressMessage("Creating manifest for split %s", splitName)
- .setMnemonic("AndroidBuildSplitManifest")
- .addInput(manifest)
- .addOutput(result);
- CustomCommandLine.Builder commandLine =
- CustomCommandLine.builder()
- .addExecPath("--main_manifest", manifest)
- .addExecPath("--split_manifest", result)
- .add("--split", splitName);
- if (hasCode) {
- commandLine.add("--hascode");
- } else {
- commandLine.add("--nohascode");
- }
-
- String overridePackage = getManifestValues(ruleContext).get("applicationId");
- if (overridePackage != null) {
- commandLine.add("--override_package", overridePackage);
- }
-
- builder.addCommandLine(commandLine.build());
- ruleContext.registerAction(builder.build(ruleContext));
- return result;
- }
-
- static Artifact addMobileInstallStubApplication(RuleContext ruleContext, Artifact manifest)
- throws InterruptedException {
-
- Artifact stubManifest =
- ruleContext.getImplicitOutputArtifact(
- AndroidRuleClasses.MOBILE_INSTALL_STUB_APPLICATION_MANIFEST);
- Artifact stubData =
- ruleContext.getImplicitOutputArtifact(
- AndroidRuleClasses.MOBILE_INSTALL_STUB_APPLICATION_DATA);
-
- SpawnAction.Builder builder =
- new SpawnAction.Builder()
- .setExecutable(ruleContext.getExecutablePrerequisite("$stubify_manifest", Mode.HOST))
- .setProgressMessage("Injecting mobile install stub application")
- .setMnemonic("InjectMobileInstallStubApplication")
- .addInput(manifest)
- .addOutput(stubManifest)
- .addOutput(stubData);
- CustomCommandLine.Builder commandLine =
- CustomCommandLine.builder()
- .add("--mode=mobile_install")
- .addExecPath("--input_manifest", manifest)
- .addExecPath("--output_manifest", stubManifest)
- .addExecPath("--output_datafile", stubData);
-
- String overridePackage = getManifestValues(ruleContext).get("applicationId");
- if (overridePackage != null) {
- commandLine.add("--override_package", overridePackage);
- }
-
- builder.addCommandLine(commandLine.build());
- ruleContext.registerAction(builder.build(ruleContext));
-
- return stubManifest;
- }
-
- public static Artifact getManifestFromAttributes(RuleContext ruleContext) {
- return ruleContext.getPrerequisiteArtifact("manifest", Mode.TARGET);
- }
-
- static Artifact renameManifestIfNeeded(AndroidDataContext dataContext, Artifact manifest)
- throws InterruptedException {
- if (manifest.getFilename().equals("AndroidManifest.xml")) {
- return manifest;
- } else {
- /*
- * If the manifest file is not named AndroidManifest.xml, we create a symlink named
- * AndroidManifest.xml to it. aapt requires the manifest to be named as such.
- */
- Artifact manifestSymlink =
- dataContext.createOutputArtifact(AndroidRuleClasses.ANDROID_SYMLINKED_MANIFEST);
- dataContext.registerAction(
- new SymlinkAction(
- dataContext.getActionConstructionContext().getActionOwner(),
- manifest,
- manifestSymlink,
- "Renaming Android manifest for " + dataContext.getLabel()));
- return manifestSymlink;
- }
- }
-
- /**
- * Creates an action to generate an empty manifest file with a specific package name.
- *
- * @return an artifact for the generated manifest
- */
- public static Artifact generateManifest(
- ActionConstructionContext context, String manifestPackage) {
- Artifact generatedManifest =
- context.getUniqueDirectoryArtifact("_generated", "AndroidManifest.xml");
-
- String contents =
- Joiner.on("\n")
- .join(
- "<?xml version=\"1.0\" encoding=\"utf-8\"?>",
- "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"",
- " package=\"" + manifestPackage + "\">",
- " <application>",
- " </application>",
- "</manifest>");
- context.registerAction(
- FileWriteAction.create(context, generatedManifest, contents, /*makeExecutable=*/ false));
- return generatedManifest;
- }
-
- /** Gets a map of manifest values from this rule's 'manifest_values' attribute */
- public static ImmutableMap<String, String> getManifestValues(RuleContext context) {
- Map<String, String> manifestValues = new TreeMap<>();
- if (context.attributes().isAttributeValueExplicitlySpecified("manifest_values")) {
- manifestValues.putAll(context.attributes().get("manifest_values", Type.STRING_DICT));
- }
-
- for (String variable : manifestValues.keySet()) {
- manifestValues.put(
- variable, context.getExpander().expand("manifest_values", manifestValues.get(variable)));
- }
- return ImmutableMap.copyOf(manifestValues);
- }
-
- private ApplicationManifest() {}
-
- static Optional<Artifact> maybeMergeWith(
- AndroidDataContext dataContext,
- AndroidSemantics androidSemantics,
- Artifact primaryManifest,
- ResourceDependencies resourceDeps,
- Map<String, String> manifestValues,
- boolean useLegacyMerging,
- String customPackage) {
- Map<Artifact, Label> mergeeManifests = getMergeeManifests(resourceDeps.getResourceContainers());
-
- if (useLegacyMerging) {
- return androidSemantics.maybeDoLegacyManifestMerging(
- mergeeManifests, dataContext, primaryManifest);
- } else {
- if (!mergeeManifests.isEmpty() || !manifestValues.isEmpty()) {
- Artifact outputManifest =
- dataContext.getUniqueDirectoryArtifact("_merged", "AndroidManifest.xml");
- Artifact mergeLog =
- dataContext.getUniqueDirectoryArtifact("_merged", "manifest_merger_log.txt");
- new ManifestMergerActionBuilder()
- .setManifest(primaryManifest)
- .setMergeeManifests(mergeeManifests)
- .setLibrary(false)
- .setManifestValues(manifestValues)
- .setCustomPackage(customPackage)
- .setManifestOutput(outputManifest)
- .setLogOut(mergeLog)
- .build(dataContext);
- return Optional.of(outputManifest);
- }
- }
- return Optional.empty();
- }
-
- /** Checks if the legacy manifest merger should be used, based on a rule attribute */
- public static boolean useLegacyMerging(RuleContext ruleContext) {
- return ruleContext.isLegalFragment(AndroidConfiguration.class)
- && ruleContext.getRule().isAttrDefined("manifest_merger", STRING)
- && useLegacyMerging(
- ruleContext,
- AndroidCommon.getAndroidConfig(ruleContext),
- ruleContext.attributes().get("manifest_merger", STRING));
- }
-
- /**
- * Checks if the legacy manifest merger should be used, based on an optional string specifying the
- * merger to use.
- */
- public static boolean useLegacyMerging(
- RuleErrorConsumer errorConsumer,
- AndroidConfiguration androidConfig,
- @Nullable String mergerString) {
- AndroidManifestMerger merger = AndroidManifestMerger.fromString(mergerString);
- if (merger == null) {
- merger = androidConfig.getManifestMerger();
- }
- if (merger == AndroidManifestMerger.LEGACY) {
- errorConsumer.ruleWarning(
- "manifest_merger 'legacy' is deprecated. Please update to 'android'.\n"
- + "See https://developer.android.com/studio/build/manifest-merge.html for more "
- + "information about the manifest merger.");
- }
-
- return merger == AndroidManifestMerger.LEGACY;
- }
-
- private static Map<Artifact, Label> getMergeeManifests(
- Iterable<ValidatedAndroidResources> transitiveData) {
- ImmutableSortedMap.Builder<Artifact, Label> builder =
- ImmutableSortedMap.orderedBy(Artifact.EXEC_PATH_COMPARATOR);
- for (ValidatedAndroidResources d : transitiveData) {
- if (d.isManifestExported()) {
- builder.put(d.getManifest(), d.getLabel());
- }
- }
- return builder.build();
- }
-
- static Optional<Artifact> maybeSetManifestPackage(
- AndroidDataContext dataContext, Artifact manifest, String customPackage) {
- if (isNullOrEmpty(customPackage)) {
- return Optional.empty();
- }
- Artifact outputManifest =
- dataContext.getUniqueDirectoryArtifact("_renamed", "AndroidManifest.xml");
- new ManifestMergerActionBuilder()
- .setManifest(manifest)
- .setLibrary(true)
- .setCustomPackage(customPackage)
- .setManifestOutput(outputManifest)
- .build(dataContext);
-
- return Optional.of(outputManifest);
- }
-}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/StampedAndroidManifest.java b/src/main/java/com/google/devtools/build/lib/rules/android/StampedAndroidManifest.java
index a0ef0dd9d7..5cb4dd1df0 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/StampedAndroidManifest.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/StampedAndroidManifest.java
@@ -13,10 +13,19 @@
// limitations under the License.
package com.google.devtools.build.lib.rules.android;
+import com.google.common.base.Joiner;
+import com.google.common.collect.ImmutableMap;
import com.google.devtools.build.lib.actions.Artifact;
import com.google.devtools.build.lib.analysis.RuleContext;
import com.google.devtools.build.lib.analysis.actions.ActionConstructionContext;
+import com.google.devtools.build.lib.analysis.actions.CustomCommandLine;
+import com.google.devtools.build.lib.analysis.actions.FileWriteAction;
+import com.google.devtools.build.lib.analysis.actions.SpawnAction;
+import com.google.devtools.build.lib.analysis.configuredtargets.RuleConfiguredTarget.Mode;
import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
+import com.google.devtools.build.lib.syntax.Type;
+import java.util.Map;
+import java.util.TreeMap;
import javax.annotation.Nullable;
/** An {@link AndroidManifest} stamped with the correct package. */
@@ -55,27 +64,117 @@ public class StampedAndroidManifest extends AndroidManifest {
/** Creates an empty manifest stamped with a specified package. */
public static StampedAndroidManifest createEmpty(
ActionConstructionContext context, String pkg, boolean exported) {
- return new StampedAndroidManifest(
- ApplicationManifest.generateManifest(context, pkg), pkg, exported);
+ Artifact generatedManifest =
+ context.getUniqueDirectoryArtifact("_generated", "AndroidManifest.xml");
+
+ String contents =
+ Joiner.on("\n")
+ .join(
+ "<?xml version=\"1.0\" encoding=\"utf-8\"?>",
+ "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"",
+ " package=\"" + pkg + "\">",
+ " <application>",
+ " </application>",
+ "</manifest>");
+ context.registerAction(
+ FileWriteAction.create(context, generatedManifest, contents, /*makeExecutable=*/ false));
+ return new StampedAndroidManifest(generatedManifest, pkg, exported);
}
public StampedAndroidManifest addMobileInstallStubApplication(RuleContext ruleContext)
throws InterruptedException {
- return new StampedAndroidManifest(
- ApplicationManifest.addMobileInstallStubApplication(ruleContext, getManifest()),
- getPackage(),
- isExported());
+
+ Artifact stubManifest =
+ ruleContext.getImplicitOutputArtifact(
+ AndroidRuleClasses.MOBILE_INSTALL_STUB_APPLICATION_MANIFEST);
+ Artifact stubData =
+ ruleContext.getImplicitOutputArtifact(
+ AndroidRuleClasses.MOBILE_INSTALL_STUB_APPLICATION_DATA);
+
+ SpawnAction.Builder builder =
+ new SpawnAction.Builder()
+ .setExecutable(ruleContext.getExecutablePrerequisite("$stubify_manifest", Mode.HOST))
+ .setProgressMessage("Injecting mobile install stub application")
+ .setMnemonic("InjectMobileInstallStubApplication")
+ .addInput(getManifest())
+ .addOutput(stubManifest)
+ .addOutput(stubData);
+ CustomCommandLine.Builder commandLine =
+ CustomCommandLine.builder()
+ .add("--mode=mobile_install")
+ .addExecPath("--input_manifest", getManifest())
+ .addExecPath("--output_manifest", stubManifest)
+ .addExecPath("--output_datafile", stubData);
+
+ String overridePackage = getManifestValues(ruleContext).get("applicationId");
+ if (overridePackage != null) {
+ commandLine.add("--override_package", overridePackage);
+ }
+
+ builder.addCommandLine(commandLine.build());
+ ruleContext.registerAction(builder.build(ruleContext));
+
+ return new StampedAndroidManifest(stubManifest, getPackage(), isExported());
+ }
+
+ public static Map<String, String> getManifestValues(RuleContext context) {
+ if (!context.attributes().isAttributeValueExplicitlySpecified("manifest_values")) {
+ return ImmutableMap.of();
+ }
+
+ Map<String, String> manifestValues =
+ new TreeMap<>(context.attributes().get("manifest_values", Type.STRING_DICT));
+
+ for (String variable : manifestValues.keySet()) {
+ manifestValues.put(
+ variable, context.getExpander().expand("manifest_values", manifestValues.get(variable)));
+ }
+ return ImmutableMap.copyOf(manifestValues);
}
public StampedAndroidManifest createSplitManifest(
RuleContext ruleContext, String splitName, boolean hasCode) {
- return new StampedAndroidManifest(
- ApplicationManifest.createSplitManifest(ruleContext, getManifest(), splitName, hasCode),
- getPackage(),
- isExported());
+ // aapt insists that manifests be called AndroidManifest.xml, even though they have to be
+ // explicitly designated as manifests on the command line
+ Artifact splitManifest =
+ AndroidBinary.getDxArtifact(ruleContext, "split_" + splitName + "/AndroidManifest.xml");
+ SpawnAction.Builder builder =
+ new SpawnAction.Builder()
+ .setExecutable(
+ ruleContext.getExecutablePrerequisite("$build_split_manifest", Mode.HOST))
+ .setProgressMessage("Creating manifest for split %s", splitName)
+ .setMnemonic("AndroidBuildSplitManifest")
+ .addInput(getManifest())
+ .addOutput(splitManifest);
+ CustomCommandLine.Builder commandLine =
+ CustomCommandLine.builder()
+ .addExecPath("--main_manifest", getManifest())
+ .addExecPath("--split_manifest", splitManifest)
+ .add("--split", splitName);
+ if (hasCode) {
+ commandLine.add("--hascode");
+ } else {
+ commandLine.add("--nohascode");
+ }
+
+ String overridePackage = getManifestValues(ruleContext).get("applicationId");
+
+ if (overridePackage != null) {
+ commandLine.add("--override_package", overridePackage);
+ }
+
+ builder.addCommandLine(commandLine.build());
+ ruleContext.registerAction(builder.build(ruleContext));
+
+ return new StampedAndroidManifest(splitManifest, getPackage(), isExported());
}
public AndroidManifestInfo toProvider() {
return AndroidManifestInfo.of(getManifest(), getPackage(), isExported());
}
+
+ @Override
+ public boolean equals(Object object) {
+ return (object instanceof StampedAndroidManifest && super.equals(object));
+ }
}