aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/java/com/google/devtools/build/lib/rules
diff options
context:
space:
mode:
authorGravatar Alex Humesky <ahumesky@google.com>2016-03-01 00:37:06 +0000
committerGravatar Kristina Chodorow <kchodorow@google.com>2016-03-01 19:13:23 +0000
commit9ca85b10e3e19ed50e326319d5137ecd597e074f (patch)
treeeed406f4071894b960e8d57a9445f5034d3bab99 /src/main/java/com/google/devtools/build/lib/rules
parentb622595680769bb1f4378abe77d98a0069fe8fa0 (diff)
Adds a manifest for detailing the inputs to an android apk.
-- MOS_MIGRATED_REVID=115920640
Diffstat (limited to 'src/main/java/com/google/devtools/build/lib/rules')
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/android/AndroidBinary.java53
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/android/AndroidRuleClasses.java4
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/android/ApkManifestAction.java202
3 files changed, 258 insertions, 1 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 7181a1a4d8..7fa4575bc9 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
@@ -343,6 +343,7 @@ public abstract class AndroidBinary implements RuleConfiguredTargetFactory {
JavaTargetAttributes resourceClasses,
ImmutableList<Artifact> apksUnderTest,
Artifact proguardMapping) throws InterruptedException {
+
ImmutableList<Artifact> proguardSpecs = ProguardHelper.collectTransitiveProguardSpecs(
ruleContext, ImmutableList.of(resourceApk.getResourceProguardConfig()));
@@ -555,6 +556,28 @@ public abstract class AndroidBinary implements RuleConfiguredTargetFactory {
.add(splitDeployMarker)
.build();
+ Artifact apkManifest =
+ ruleContext.getImplicitOutputArtifact(AndroidRuleClasses.APK_MANIFEST);
+ createApkManifestAction(
+ ruleContext,
+ apkManifest,
+ false, // text proto
+ androidCommon,
+ resourceClasses,
+ resourceApk,
+ nativeLibs);
+
+ Artifact apkManifestText =
+ ruleContext.getImplicitOutputArtifact(AndroidRuleClasses.APK_MANIFEST_TEXT);
+ createApkManifestAction(
+ ruleContext,
+ apkManifestText,
+ true, // text proto
+ androidCommon,
+ resourceClasses,
+ resourceApk,
+ nativeLibs);
+
androidCommon.addTransitiveInfoProviders(
builder, androidSemantics, resourceApk, zipAlignedApk, apksUnderTest);
androidSemantics.addTransitiveInfoProviders(
@@ -584,7 +607,9 @@ public abstract class AndroidBinary implements RuleConfiguredTargetFactory {
.add(AndroidPreDexJarProvider.class, new AndroidPreDexJarProvider(jarToDex))
.addOutputGroup("mobile_install_full", fullDeployMarker)
.addOutputGroup("mobile_install_incremental", incrementalDeployMarker)
- .addOutputGroup("mobile_install_split", splitOutputGroup);
+ .addOutputGroup("mobile_install_split", splitOutputGroup)
+ .addOutputGroup("apk_manifest", apkManifest)
+ .addOutputGroup("apk_manifest_text", apkManifestText);
}
private static void createSplitInstallAction(RuleContext ruleContext,
@@ -708,6 +733,32 @@ public abstract class AndroidBinary implements RuleConfiguredTargetFactory {
return stubDex;
}
+ private static void createApkManifestAction(
+ RuleContext ruleContext,
+ Artifact apkManfiest,
+ boolean textProto,
+ AndroidCommon androidCommon,
+ JavaTargetAttributes resourceClasses,
+ ResourceApk resourceApk,
+ NativeLibs nativeLibs) {
+
+ Iterable<Artifact> jars = Iterables.concat(
+ resourceClasses.getArchiveInputs(true), androidCommon.getRuntimeJars());
+
+ AndroidSdkProvider sdk = AndroidSdkProvider.fromRuleContext(ruleContext);
+
+ ApkManifestAction manifestAction = new ApkManifestAction(
+ ruleContext.getActionOwner(),
+ apkManfiest,
+ textProto,
+ sdk,
+ jars,
+ resourceApk.getArtifact(),
+ nativeLibs);
+
+ ruleContext.registerAction(manifestAction);
+ }
+
/** Generates an uncompressed _deploy.jar of all the runtime jars. */
public static Artifact createDeployJar(
RuleContext ruleContext, JavaSemantics javaSemantics, AndroidCommon common,
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidRuleClasses.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidRuleClasses.java
index 49ed57ad30..8a7cc46643 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidRuleClasses.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidRuleClasses.java
@@ -114,6 +114,10 @@ public final class AndroidRuleClasses {
fromTemplates("%{name}_files/split_deploy_marker");
public static final SafeImplicitOutputsFunction MOBILE_INSTALL_ARGS =
fromTemplates("%{name}_files/mobile_install_args");
+ public static final SafeImplicitOutputsFunction APK_MANIFEST =
+ fromTemplates("%{name}_files/apk_manifest");
+ public static final SafeImplicitOutputsFunction APK_MANIFEST_TEXT =
+ fromTemplates("%{name}_files/apk_manifest_text");
// This needs to be in its own directory because ApkBuilder only has a function (-rf) for source
// folders but not source files, and it's easiest to guarantee that nothing gets put beside this
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/ApkManifestAction.java b/src/main/java/com/google/devtools/build/lib/rules/android/ApkManifestAction.java
new file mode 100644
index 0000000000..2494f07a2e
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/ApkManifestAction.java
@@ -0,0 +1,202 @@
+// 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 com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
+import com.google.devtools.build.lib.actions.ActionExecutionContext;
+import com.google.devtools.build.lib.actions.ActionOwner;
+import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.actions.cache.MetadataHandler;
+import com.google.devtools.build.lib.analysis.FilesToRunProvider;
+import com.google.devtools.build.lib.analysis.actions.AbstractFileWriteAction;
+import com.google.devtools.build.lib.rules.android.apkmanifest.ApkManifestOuterClass;
+import com.google.devtools.build.lib.rules.android.apkmanifest.ApkManifestOuterClass.ApkManifest;
+import com.google.devtools.build.lib.util.Fingerprint;
+import com.google.protobuf.ByteString;
+import com.google.protobuf.TextFormat;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.util.Map;
+
+public class ApkManifestAction extends AbstractFileWriteAction {
+
+ private static Iterable<Artifact> makeInputs(
+ AndroidSdkProvider sdk,
+ Iterable<Artifact> jars,
+ Artifact resourceApk,
+ NativeLibs nativeLibs) {
+
+ return ImmutableList.<Artifact>builder()
+ .add(sdk.getAapt().getExecutable())
+ .add(sdk.getAdb().getExecutable())
+ .add(sdk.getAidl().getExecutable())
+ .add(sdk.getAndroidJar())
+ .add(sdk.getAnnotationsJar())
+ .add(sdk.getApkBuilder().getExecutable())
+ .add(sdk.getDx().getExecutable())
+ .add(sdk.getFrameworkAidl())
+ .add(sdk.getJack().getExecutable())
+ .add(sdk.getJill().getExecutable())
+ .add(sdk.getMainDexClasses())
+ .add(sdk.getMainDexListCreator().getExecutable())
+ .add(sdk.getProguard().getExecutable())
+ .add(sdk.getResourceExtractor().getExecutable())
+ .add(sdk.getShrinkedAndroidJar())
+ .add(sdk.getZipalign().getExecutable())
+
+ .addAll(jars)
+ .add(resourceApk)
+ .addAll(nativeLibs.getAllNativeLibs())
+ .build();
+ }
+
+ private static final String GUID = "7b6f4858-d1f2-11e5-83b0-cf6ddc5a32d9";
+
+ private final boolean textOutput;
+ private final AndroidSdkProvider sdk;
+ private final Iterable<Artifact> jars;
+ private final Artifact resourceApk;
+ private final NativeLibs nativeLibs;
+
+ public ApkManifestAction(
+ ActionOwner owner,
+ Artifact outputFile,
+ boolean textOutput,
+ AndroidSdkProvider sdk,
+ Iterable<Artifact> jars,
+ Artifact resourceApk,
+ NativeLibs nativeLibs) {
+
+ super(owner, makeInputs(sdk, jars, resourceApk, nativeLibs), outputFile, false);
+ this.textOutput = textOutput;
+ this.sdk = sdk;
+ this.jars = jars;
+ this.resourceApk = resourceApk;
+ this.nativeLibs = nativeLibs;
+ }
+
+ @Override
+ public DeterministicWriter newDeterministicWriter(ActionExecutionContext ctx) throws IOException {
+
+ ApkManifestCreator manifestCreator = new ApkManifestCreator(
+ ctx.getMetadataHandler());
+
+ final ApkManifest manifest = manifestCreator.createManifest();
+
+ return new DeterministicWriter() {
+ @Override
+ public void writeOutputFile(OutputStream out) throws IOException {
+ if (textOutput) {
+ TextFormat.print(manifest, new PrintStream(out));
+ } else {
+ manifest.writeTo(out);
+ }
+ }
+ };
+ }
+
+ @Override
+ protected String computeKey() {
+ return new Fingerprint()
+ .addString(GUID)
+ .hexDigestAndReset();
+ }
+
+ private class ApkManifestCreator {
+
+ private final MetadataHandler metadataHandler;
+
+ private ApkManifestCreator(MetadataHandler metadataHandler) {
+ this.metadataHandler = metadataHandler;
+ }
+
+ private ApkManifest createManifest() throws IOException {
+ ApkManifest.Builder manifestBuilder = ApkManifest.newBuilder();
+
+ for (Artifact jar : jars) {
+ manifestBuilder.addJars(makeArtifactProto(jar));
+ }
+
+ manifestBuilder.setResourceApk(makeArtifactProto(resourceApk));
+
+ for (Map.Entry<String, Iterable<Artifact>> nativeLib : nativeLibs.getMap().entrySet()) {
+ if (!Iterables.isEmpty(nativeLib.getValue())) {
+ manifestBuilder.addNativeLibBuilder()
+ .setArch(nativeLib.getKey())
+ .addAllNativeLibs(makeArtifactProtos(nativeLib.getValue()));
+ }
+ }
+
+ manifestBuilder.setAndroidSdk(createAndroidSdk(sdk));
+ return manifestBuilder.build();
+ }
+
+ private Iterable<ApkManifestOuterClass.Artifact> makeArtifactProtos(
+ Iterable<Artifact> artifacts) throws IOException {
+
+ ImmutableList.Builder<ApkManifestOuterClass.Artifact> protoArtifacts =
+ ImmutableList.builder();
+ for (Artifact artifact : artifacts) {
+ protoArtifacts.add(makeArtifactProto(artifact));
+ }
+ return protoArtifacts.build();
+ }
+
+ private ApkManifestOuterClass.Artifact makeArtifactProto(Artifact artifact) throws IOException {
+ byte[] digest = metadataHandler.getMetadata(artifact).digest;
+ return ApkManifestOuterClass.Artifact.newBuilder()
+ .setExecRootPath(artifact.getExecPathString())
+ .setHash(ByteString.copyFrom(digest))
+ .build();
+ }
+
+ private String getArtifactPath(Artifact artifact) {
+ return artifact.getExecPathString();
+ }
+
+ private String getArtifactPath(FilesToRunProvider filesToRunProvider) {
+ return filesToRunProvider.getExecutable().getExecPathString();
+ }
+
+ private ApkManifestOuterClass.AndroidSdk createAndroidSdk(AndroidSdkProvider sdk) {
+
+ ApkManifestOuterClass.AndroidSdk.Builder sdkProto =
+ ApkManifestOuterClass.AndroidSdk.newBuilder();
+
+ sdkProto.setAapt(getArtifactPath(sdk.getAapt()));
+ sdkProto.setAdb(getArtifactPath(sdk.getAdb()));
+ sdkProto.setAidl(getArtifactPath(sdk.getAidl()));
+ sdkProto.setAndroidJar(getArtifactPath(sdk.getAndroidJar()));
+ sdkProto.setAnnotationsJar(getArtifactPath(sdk.getAnnotationsJar()));
+ sdkProto.setApkbuilder(getArtifactPath(sdk.getApkBuilder()));
+ sdkProto.setDx(getArtifactPath(sdk.getDx()));
+ sdkProto.setFrameworkAidl(getArtifactPath(sdk.getFrameworkAidl()));
+ sdkProto.setJack(getArtifactPath(sdk.getJack()));
+ sdkProto.setJill(getArtifactPath(sdk.getJill()));
+ sdkProto.setMainDexClasses(getArtifactPath(sdk.getMainDexClasses()));
+ sdkProto.setMainDexListCreator(getArtifactPath(sdk.getMainDexListCreator()));
+ sdkProto.setProguard(getArtifactPath(sdk.getProguard()));
+ sdkProto.setResourceExtractor(getArtifactPath(sdk.getResourceExtractor()));
+ sdkProto.setShrinkedAndroidJar(getArtifactPath(sdk.getShrinkedAndroidJar()));
+ sdkProto.setZipalign(getArtifactPath(sdk.getZipalign()));
+ sdkProto.setBuildToolsVersion(sdk.getBuildToolsVersion());
+
+ return sdkProto.build();
+ }
+ }
+}