diff options
author | Googler <noreply@google.com> | 2016-04-21 22:52:35 +0000 |
---|---|---|
committer | Damien Martin-Guillerez <dmarting@google.com> | 2016-04-22 11:50:20 +0000 |
commit | e345ba54feda0c630679d18e3d039fd1ee8843bd (patch) | |
tree | 4df0272a0694df00be0670840bd7d34aae75b123 /src/main/java/com/google/devtools/build/lib/rules/android | |
parent | c761661bfcc84eb2bdd229e10ecee338a53d3b41 (diff) |
Add android deploy info.
Each android binary build operation will output a deploy info
proto providing information about how to deploy and launch the
APK. The information will vary between build mode (normal,
mobile-install, split-apk) and is configuration-dependent.
NO_SQ: Presubmit broken
--
MOS_MIGRATED_REVID=120494036
Diffstat (limited to 'src/main/java/com/google/devtools/build/lib/rules/android')
4 files changed, 195 insertions, 4 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 e534f372a8..9e8117ad2a 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 @@ -365,6 +365,7 @@ public abstract class AndroidBinary implements RuleConfiguredTargetFactory { splitResourceApk, resourceClasses, ImmutableList.<Artifact>of(), + ImmutableList.<Artifact>of(), proguardMapping); } @@ -385,6 +386,7 @@ public abstract class AndroidBinary implements RuleConfiguredTargetFactory { ResourceApk splitResourceApk, JavaTargetAttributes resourceClasses, ImmutableList<Artifact> apksUnderTest, + ImmutableList<Artifact> additionalMergedManifests, Artifact proguardMapping) throws InterruptedException { ImmutableList<Artifact> proguardSpecs = ProguardHelper.collectTransitiveProguardSpecs( @@ -449,6 +451,14 @@ public abstract class AndroidBinary implements RuleConfiguredTargetFactory { filesBuilder.add(unsignedApk); filesBuilder.add(zipAlignedApk); + Artifact deployInfo = ruleContext.getImplicitOutputArtifact(AndroidRuleClasses.DEPLOY_INFO); + AndroidDeployInfoAction.createDeployInfoAction(ruleContext, + deployInfo, + applicationManifest.getManifest(), + additionalMergedManifests, + Iterables.concat(ImmutableList.of(zipAlignedApk), apksUnderTest)); + filesBuilder.add(deployInfo); + NestedSet<Artifact> filesToBuild = filesBuilder.build(); NestedSet<Artifact> coverageMetadata = (androidCommon.getInstrumentedJar() != null) @@ -518,6 +528,25 @@ public abstract class AndroidBinary implements RuleConfiguredTargetFactory { nativeLibs, stubData); + Artifact incrementalDeployInfo = ruleContext.getImplicitOutputArtifact( + AndroidRuleClasses.DEPLOY_INFO_INCREMENTAL); + + AndroidDeployInfoAction.createDeployInfoAction(ruleContext, + incrementalDeployInfo, + applicationManifest.getManifest(), + additionalMergedManifests, + ImmutableList.<Artifact>of()); + + NestedSet<Artifact> fullOutputGroup = NestedSetBuilder.<Artifact>stableOrder() + .add(fullDeployMarker) + .add(incrementalDeployInfo) + .build(); + + NestedSet<Artifact> incrementalOutputGroup = NestedSetBuilder.<Artifact>stableOrder() + .add(incrementalDeployMarker) + .add(incrementalDeployInfo) + .build(); + NestedSetBuilder<Artifact> splitApkSetBuilder = NestedSetBuilder.compileOrder(); // Put the Android resource APK first so that this split gets installed first. @@ -599,9 +628,19 @@ public abstract class AndroidBinary implements RuleConfiguredTargetFactory { createSplitInstallAction(ruleContext, splitDeployMarker, argsArtifact, splitMainApk, splitApks, stubData); + Artifact splitDeployInfo = ruleContext.getImplicitOutputArtifact( + AndroidRuleClasses.DEPLOY_INFO_SPLIT); + AndroidDeployInfoAction.createDeployInfoAction( + ruleContext, + splitDeployInfo, + applicationManifest.getManifest(), + additionalMergedManifests, + ImmutableList.<Artifact>of()); + NestedSet<Artifact> splitOutputGroup = NestedSetBuilder.<Artifact>stableOrder() .addTransitive(allSplitApks) .add(splitDeployMarker) + .add(splitDeployInfo) .build(); Artifact apkManifest = @@ -653,10 +692,13 @@ public abstract class AndroidBinary implements RuleConfiguredTargetFactory { .add( ApkProvider.class, new ApkProvider( - NestedSetBuilder.create(Order.STABLE_ORDER, zipAlignedApk), coverageMetadata)) + NestedSetBuilder.create(Order.STABLE_ORDER, zipAlignedApk), + coverageMetadata, + NestedSetBuilder.create(Order.STABLE_ORDER, applicationManifest.getManifest()) + )) .add(AndroidPreDexJarProvider.class, new AndroidPreDexJarProvider(jarToDex)) - .addOutputGroup("mobile_install_full", fullDeployMarker) - .addOutputGroup("mobile_install_incremental", incrementalDeployMarker) + .addOutputGroup("mobile_install_full", fullOutputGroup) + .addOutputGroup("mobile_install_incremental", incrementalOutputGroup) .addOutputGroup("mobile_install_split", splitOutputGroup) .addOutputGroup("apk_manifest", apkManifest) .addOutputGroup("apk_manifest_text", apkManifestText); diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidDeployInfoAction.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidDeployInfoAction.java new file mode 100644 index 0000000000..cae2cece29 --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidDeployInfoAction.java @@ -0,0 +1,132 @@ +// 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.annotations.VisibleForTesting; +import com.google.common.collect.ImmutableList; +import com.google.common.io.ByteStreams; +import com.google.devtools.build.lib.actions.Action; +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.analysis.RuleContext; +import com.google.devtools.build.lib.analysis.actions.AbstractFileWriteAction; +import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable; +import com.google.devtools.build.lib.rules.android.deployinfo.AndroidDeployInfoOuterClass; +import com.google.devtools.build.lib.rules.android.deployinfo.AndroidDeployInfoOuterClass.AndroidDeployInfo; +import com.google.devtools.build.lib.util.Fingerprint; +import com.google.protobuf.ByteString; +import com.google.protobuf.InvalidProtocolBufferException; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +/** + * Writes AndroidDeployInfo proto message. This proto describes how + * to deploy and launch an android_binary/android_test. + */ +@Immutable +public final class AndroidDeployInfoAction extends AbstractFileWriteAction { + + private static Iterable<Artifact> makeInputs( + Artifact mergedManifest, + Iterable<Artifact> additionalMergedManifests, + Iterable<Artifact> apksToDeploy) { + + return ImmutableList.<Artifact>builder() + .add(mergedManifest) + .addAll(additionalMergedManifests) + .addAll(apksToDeploy) + .build(); + } + + private static final String GUID = "eda283ba-9000-4b80-8dc4-7939101c44ba"; + private final ByteString byteString; + + AndroidDeployInfoAction( + ActionOwner owner, + Artifact outputFile, + Artifact mergedManifest, + Iterable<Artifact> additionalMergedManifests, + Iterable<Artifact> apksToDeploy) { + super(owner, makeInputs(mergedManifest, additionalMergedManifests, apksToDeploy), + outputFile, false); + AndroidDeployInfoOuterClass.AndroidDeployInfo.Builder builder = + AndroidDeployInfoOuterClass.AndroidDeployInfo.newBuilder(); + builder.setMergedManifest(makeArtifactProto(mergedManifest)); + for (Artifact additionMergedManifest : additionalMergedManifests) { + builder.addAdditionalMergedManifests(makeArtifactProto(additionMergedManifest)); + } + for (Artifact apk : apksToDeploy) { + builder.addApksToDeploy(makeArtifactProto(apk)); + } + this.byteString = builder.build().toByteString(); + } + + static void createDeployInfoAction( + RuleContext ruleContext, + Artifact deployInfo, + Artifact mergedManifest, + Iterable<Artifact> additionalMergedManifests, + Iterable<Artifact> apksToDeploy) { + Action action = new AndroidDeployInfoAction(ruleContext.getActionOwner(), + deployInfo, mergedManifest, additionalMergedManifests, apksToDeploy); + ruleContext.registerAction(action); + } + + @Override + public DeterministicWriter newDeterministicWriter(ActionExecutionContext ctx) throws IOException { + + return new DeterministicWriter() { + @Override + public void writeOutputFile(OutputStream out) throws IOException { + try (InputStream in = byteString.newInput()) { + ByteStreams.copy(in, out); + } + out.flush(); + } + }; + } + + @VisibleForTesting + public AndroidDeployInfo getDeployInfo() throws InvalidProtocolBufferException { + return AndroidDeployInfo.parseFrom(byteString); + } + + @Override + protected String computeKey() { + Fingerprint f = new Fingerprint() + .addString(GUID); + + try (InputStream in = byteString.newInput()) { + byte[] buffer = new byte[512]; + int amountRead; + while ((amountRead = in.read(buffer)) != -1) { + f.addBytes(buffer, 0, amountRead); + } + } catch (IOException e) { + throw new RuntimeException(e); + } + + return f.hexDigestAndReset(); + } + + private static AndroidDeployInfoOuterClass.Artifact makeArtifactProto(Artifact artifact) { + return AndroidDeployInfoOuterClass.Artifact.newBuilder() + .setExecRootPath(artifact.getExecPathString()) + .build(); + } +} 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 56db345650..7cd976d654 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 @@ -137,6 +137,12 @@ public final class AndroidRuleClasses { fromTemplates("%{name}_files/apk_manifest"); public static final SafeImplicitOutputsFunction APK_MANIFEST_TEXT = fromTemplates("%{name}_files/apk_manifest_text"); + public static final SafeImplicitOutputsFunction DEPLOY_INFO = + fromTemplates("%{name}_files/deploy_info.deployinfo.pb"); + public static final SafeImplicitOutputsFunction DEPLOY_INFO_INCREMENTAL = + fromTemplates("%{name}_files/deploy_info_incremental.deployinfo.pb"); + public static final SafeImplicitOutputsFunction DEPLOY_INFO_SPLIT = + fromTemplates("%{name}_files/deploy_info_split.deployinfo.pb"); // 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/ApkProvider.java b/src/main/java/com/google/devtools/build/lib/rules/android/ApkProvider.java index 0f943dcfa2..2ac6c0d69b 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/android/ApkProvider.java +++ b/src/main/java/com/google/devtools/build/lib/rules/android/ApkProvider.java @@ -28,9 +28,13 @@ public final class ApkProvider implements TransitiveInfoProvider { private final NestedSet<Artifact> coverageMetadata; - public ApkProvider(NestedSet<Artifact> transitiveApks, NestedSet<Artifact> coverageMetdata) { + private final NestedSet<Artifact> mergedManifests; + + public ApkProvider(NestedSet<Artifact> transitiveApks, NestedSet<Artifact> coverageMetdata, + NestedSet<Artifact> mergedManifests) { this.transitiveApks = transitiveApks; this.coverageMetadata = coverageMetdata; + this.mergedManifests = mergedManifests; } /** @@ -46,4 +50,11 @@ public final class ApkProvider implements TransitiveInfoProvider { public NestedSet<Artifact> getCoverageMetadata() { return coverageMetadata; } + + /** + * Returns the merged manifests + */ + public NestedSet<Artifact> getMergedManifests() { + return mergedManifests; + } } |