aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar Tobias Werth <twerth@google.com>2017-03-20 09:00:09 +0000
committerGravatar Yue Gan <yueg@google.com>2017-03-20 11:45:40 +0000
commitbd40871283a54268945dcb0c47c0326645ffda18 (patch)
tree7e9a88258f3f3936e47dd230769300e793eedf74
parentc6a6a7791b1464bea79bf9af01f00360b0147450 (diff)
*** Reason for rollback *** broke over 100k targets, in the depot, see [] *** Original change description *** Move library R generation to a separate action, ensuring the merging happens off the java critical path. -- PiperOrigin-RevId: 150602545 MOS_MIGRATED_REVID=150602545
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/android/AarImport.java23
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/android/AndroidLibrary.java37
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/android/AndroidResourceMergingActionBuilder.java14
-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/ApplicationManifest.java65
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/android/LibraryRGeneratorActionBuilder.java117
-rw-r--r--src/tools/android/java/com/google/devtools/build/android/AndroidDataDeserializer.java70
-rw-r--r--src/tools/android/java/com/google/devtools/build/android/AndroidResourceMerger.java34
-rw-r--r--src/tools/android/java/com/google/devtools/build/android/AndroidResourceProcessor.java53
-rw-r--r--src/tools/android/java/com/google/devtools/build/android/LibraryRClassGeneratorAction.java3
10 files changed, 125 insertions, 295 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AarImport.java b/src/main/java/com/google/devtools/build/lib/rules/android/AarImport.java
index 516db565c0..7c340694cb 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/AarImport.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/AarImport.java
@@ -99,18 +99,17 @@ public class AarImport implements RuleConfiguredTargetFactory {
Artifact resourcesZip =
ruleContext.getImplicitOutputArtifact(AndroidRuleClasses.ANDROID_RESOURCES_ZIP);
- ResourceApk resourceApk =
- androidManifest.packWithDataAndResources(
- ruleContext,
- new LocalResourceContainer.Builder(ruleContext)
- .withResources(ImmutableList.of(resourcesProvider))
- .build(),
- ResourceDependencies.fromRuleDeps(ruleContext, JavaCommon.isNeverLink(ruleContext)),
- ruleContext.getImplicitOutputArtifact(AndroidRuleClasses.ANDROID_R_TXT),
- ruleContext.getImplicitOutputArtifact(AndroidRuleClasses.ANDROID_LOCAL_SYMBOLS),
- ruleContext.getImplicitOutputArtifact(AndroidRuleClasses.ANDROID_PROCESSED_MANIFEST),
- resourcesZip,
- /* alwaysExportManifest = */ true);
+ ResourceApk resourceApk = androidManifest.packWithDataAndResources(
+ ruleContext,
+ new LocalResourceContainer.Builder(ruleContext)
+ .withResources(ImmutableList.of(resourcesProvider))
+ .build(),
+ ResourceDependencies.fromRuleDeps(ruleContext, JavaCommon.isNeverLink(ruleContext)),
+ ruleContext.getImplicitOutputArtifact(AndroidRuleClasses.ANDROID_R_TXT),
+ ruleContext.getImplicitOutputArtifact(AndroidRuleClasses.ANDROID_SYMBOLS),
+ ruleContext.getImplicitOutputArtifact(AndroidRuleClasses.ANDROID_PROCESSED_MANIFEST),
+ resourcesZip,
+ /* alwaysExportManifest = */ true);
// There isn't really any use case for building an aar_import target on its own, so the files to
// build could be empty. The resources zip and merged jars are added here as a sanity check for
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidLibrary.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidLibrary.java
index c70b10780a..f194aa559c 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidLibrary.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidLibrary.java
@@ -90,26 +90,23 @@ public abstract class AndroidLibrary implements RuleConfiguredTargetFactory {
if (definesLocalResources) {
ApplicationManifest applicationManifest = androidSemantics.getManifestForRule(ruleContext)
.renamePackage(ruleContext, AndroidCommon.getJavaPackage(ruleContext));
- resourceApk =
- applicationManifest.packWithDataAndResources(
- null, /* resourceApk -- not needed for library */
- ruleContext,
- true, /* isLibrary */
- ResourceDependencies.fromRuleDeps(ruleContext, JavaCommon.isNeverLink(ruleContext)),
- ruleContext.getImplicitOutputArtifact(AndroidRuleClasses.ANDROID_R_TXT),
- ruleContext.getImplicitOutputArtifact(AndroidRuleClasses.ANDROID_LOCAL_SYMBOLS),
- ResourceConfigurationFilter.empty(ruleContext),
- ImmutableList.<String>of(), /* uncompressedExtensions */
- false, /* crunchPng */
- ImmutableList.<String>of(), /* densities */
- false, /* incremental */
- null, /* proguardCfgOut */
- null, /* mainDexProguardCfg */
- ruleContext.getImplicitOutputArtifact(AndroidRuleClasses.ANDROID_PROCESSED_MANIFEST),
- ruleContext.getImplicitOutputArtifact(AndroidRuleClasses.ANDROID_RESOURCES_ZIP),
- DataBinding.isEnabled(ruleContext)
- ? DataBinding.getLayoutInfoFile(ruleContext)
- : null);
+ resourceApk = applicationManifest.packWithDataAndResources(
+ null, /* resourceApk -- not needed for library */
+ ruleContext,
+ true, /* isLibrary */
+ ResourceDependencies.fromRuleDeps(ruleContext, JavaCommon.isNeverLink(ruleContext)),
+ ruleContext.getImplicitOutputArtifact(AndroidRuleClasses.ANDROID_R_TXT),
+ ruleContext.getImplicitOutputArtifact(AndroidRuleClasses.ANDROID_SYMBOLS),
+ ResourceConfigurationFilter.empty(ruleContext),
+ ImmutableList.<String>of(), /* uncompressedExtensions */
+ false, /* crunchPng */
+ ImmutableList.<String>of(), /* densities */
+ false, /* incremental */
+ null, /* proguardCfgOut */
+ null, /* mainDexProguardCfg */
+ ruleContext.getImplicitOutputArtifact(AndroidRuleClasses.ANDROID_PROCESSED_MANIFEST),
+ ruleContext.getImplicitOutputArtifact(AndroidRuleClasses.ANDROID_RESOURCES_ZIP),
+ DataBinding.isEnabled(ruleContext) ? DataBinding.getLayoutInfoFile(ruleContext) : null);
if (ruleContext.hasErrors()) {
return null;
}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidResourceMergingActionBuilder.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidResourceMergingActionBuilder.java
index dc84ee5dc5..3d7886d368 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidResourceMergingActionBuilder.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidResourceMergingActionBuilder.java
@@ -144,11 +144,10 @@ public class AndroidResourceMergingActionBuilder {
ResourceContainerConverter.convertDependencies(
dependencies, builder, inputs, RESOURCE_CONTAINER_TO_ARG, RESOURCE_CONTAINER_TO_ARTIFACTS);
+ Preconditions.checkNotNull(classJarOut);
List<Artifact> outs = new ArrayList<>();
- if (classJarOut != null) {
- builder.addExecPath("--classJarOutput", classJarOut);
- outs.add(classJarOut);
- }
+ builder.addExecPath("--classJarOutput", classJarOut);
+ outs.add(classJarOut);
if (mergedResourcesOut != null) {
builder.addExecPath("--resourcesOutput", mergedResourcesOut);
@@ -188,11 +187,8 @@ public class AndroidResourceMergingActionBuilder {
.build(context));
// Return the full set of processed transitive dependencies.
- ResourceContainer.Builder result = primary.toBuilder();
- if (classJarOut != null) {
- // ensure the classJar is propgated if it exists. Otherwise, AndroidCommon tries to make it.
- result.setJavaClassJar(classJarOut);
- }
+ ResourceContainer.Builder result = primary.toBuilder()
+ .setJavaClassJar(classJarOut);
if (manifestOut != null) {
result.setManifest(manifestOut);
}
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 8ab8794eb9..36eb19c3aa 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
@@ -116,8 +116,8 @@ public final class AndroidRuleClasses {
fromTemplates("%{name}_symbols/R.txt");
public static final SafeImplicitOutputsFunction ANDROID_LOCAL_SYMBOLS =
fromTemplates("%{name}_symbols/local.bin");
- public static final SafeImplicitOutputsFunction ANDROID_MERGED_SYMBOLS =
- fromTemplates("%{name}_symbols/merged.bin");
+ public static final SafeImplicitOutputsFunction ANDROID_SYMBOLS =
+ fromTemplates("%{name}_symbols/symbols.bin");
public static final ImplicitOutputsFunction ANDROID_PROCESSED_MANIFEST =
fromTemplates("%{name}_processed_manifest/AndroidManifest.xml");
public static final SafeImplicitOutputsFunction MOBILE_INSTALL_STUB_APPLICATION_MANIFEST =
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
index 5f08ee6c88..4467c823c7 100644
--- 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
@@ -453,43 +453,38 @@ public final class ApplicationManifest {
if (isLibrary && AndroidCommon.getAndroidConfig(ruleContext).useParallelResourceProcessing()) {
// android_library should only build the APK one way (!incremental).
Preconditions.checkArgument(!incremental);
- Artifact rJavaClassJar =
- ruleContext.getImplicitOutputArtifact(AndroidRuleClasses.ANDROID_RESOURCES_CLASS_JAR);
-
- ResourceContainer parsed =
- new AndroidResourceParsingActionBuilder(ruleContext)
- .setParse(data)
- .withPrimary(resourceContainer)
- .setOutput(resourceContainer.getSymbols())
- .build(ruleContext);
-
- ResourceContainer generated =
- new LibraryRGeneratorActionBuilder()
- .setJavaPackage(resourceContainer.getJavaPackage())
- .withPrimary(parsed)
- .withDependencies(resourceDeps)
- .setClassJarOut(rJavaClassJar)
- .build(ruleContext);
+ Artifact rJavaClassJar = ruleContext.getImplicitOutputArtifact(
+ AndroidRuleClasses.ANDROID_RESOURCES_CLASS_JAR);
+
+ if (resourceContainer.getSymbols() != null) {
+ new AndroidResourceParsingActionBuilder(ruleContext)
+ .withPrimary(resourceContainer)
+ .setParse(data)
+ .setOutput(resourceContainer.getSymbols())
+ .build(ruleContext);
+ }
- ResourceContainer merged =
+ AndroidResourceMergingActionBuilder resourcesMergerBuilder =
new AndroidResourceMergingActionBuilder(ruleContext)
- .setJavaPackage(generated.getJavaPackage())
- .withPrimary(generated)
+ .setJavaPackage(resourceContainer.getJavaPackage())
+ .withPrimary(resourceContainer)
.withDependencies(resourceDeps)
.setMergedResourcesOut(mergedResources)
.setManifestOut(manifestOut)
- .setDataBindingInfoZip(dataBindingInfoZip)
- .build(ruleContext);
+ .setClassJarOut(rJavaClassJar)
+ .setDataBindingInfoZip(dataBindingInfoZip);
+ ResourceContainer merged = resourcesMergerBuilder.build(ruleContext);
- processed =
+ AndroidResourceValidatorActionBuilder validatorBuilder =
new AndroidResourceValidatorActionBuilder(ruleContext)
.setJavaPackage(merged.getJavaPackage())
- .setDebug(ruleContext.getConfiguration().getCompilationMode() != CompilationMode.OPT)
+ .setDebug(
+ ruleContext.getConfiguration().getCompilationMode() != CompilationMode.OPT)
.setMergedResources(mergedResources)
.withPrimary(merged)
.setSourceJarOut(merged.getJavaSourceJar())
- .setRTxtOut(merged.getRTxt())
- .build(ruleContext);
+ .setRTxtOut(merged.getRTxt());
+ processed = validatorBuilder.build(ruleContext);
} else {
AndroidResourcesProcessorBuilder builder =
new AndroidResourcesProcessorBuilder(ruleContext)
@@ -635,16 +630,14 @@ public final class ApplicationManifest {
aaptActionHelper.createGenerateApkAction(resourceApk,
resourceContainer.getRenameManifestPackage(), additionalAaptOpts.build(), densities);
- ResourceContainer updatedResources =
- resourceContainer
- .toBuilder()
- .setLabel(ruleContext.getLabel())
- .setApk(resourceApk)
- .setManifest(getManifest())
- .setJavaSourceJar(javaSourcesJar)
- .setJavaClassJar(null)
- .setSymbols(null)
- .build();
+ ResourceContainer updatedResources = resourceContainer.toBuilder()
+ .setLabel(ruleContext.getLabel())
+ .setApk(resourceApk)
+ .setManifest(getManifest())
+ .setJavaSourceJar(javaSourcesJar)
+ .setJavaClassJar(null)
+ .setSymbols(null)
+ .build();
aaptActionHelper.createGenerateProguardAction(proguardCfg, mainDexProguardCfg);
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/LibraryRGeneratorActionBuilder.java b/src/main/java/com/google/devtools/build/lib/rules/android/LibraryRGeneratorActionBuilder.java
deleted file mode 100644
index 361a70a803..0000000000
--- a/src/main/java/com/google/devtools/build/lib/rules/android/LibraryRGeneratorActionBuilder.java
+++ /dev/null
@@ -1,117 +0,0 @@
-// Copyright 2017 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.base.Function;
-import com.google.common.base.Strings;
-import com.google.common.collect.FluentIterable;
-import com.google.common.collect.ImmutableList;
-import com.google.devtools.build.lib.actions.Artifact;
-import com.google.devtools.build.lib.actions.ParameterFile.ParameterFileType;
-import com.google.devtools.build.lib.analysis.FilesToRunProvider;
-import com.google.devtools.build.lib.analysis.RuleConfiguredTarget.Mode;
-import com.google.devtools.build.lib.analysis.RuleContext;
-import com.google.devtools.build.lib.analysis.actions.CustomCommandLine;
-import com.google.devtools.build.lib.analysis.actions.SpawnAction;
-import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
-import com.google.devtools.build.lib.collect.nestedset.Order;
-
-/** Builder for the action that generates the R class for libraries. */
-public class LibraryRGeneratorActionBuilder {
- static final Function<ResourceContainer, Artifact> TO_SYMBOL_ARTIFACT =
- new Function<ResourceContainer, Artifact>() {
- @Override
- public Artifact apply(ResourceContainer input) {
- return input.getSymbols();
- }
- };
- static final Function<ResourceContainer, String> TO_SYMBOL_PATH =
- new Function<ResourceContainer, String>() {
- @Override
- public String apply(ResourceContainer container) {
- return container.getSymbols().getExecPathString();
- }
- };
-
- private String javaPackage;
- private Iterable<ResourceContainer> deps = ImmutableList.<ResourceContainer>of();
- private ResourceContainer resourceContainer;
- private Artifact rJavaClassJar;
-
- public LibraryRGeneratorActionBuilder setJavaPackage(String javaPackage) {
- this.javaPackage = javaPackage;
- return this;
- }
-
- public LibraryRGeneratorActionBuilder withPrimary(ResourceContainer resourceContainer) {
- this.resourceContainer = resourceContainer;
- return this;
- }
-
- public LibraryRGeneratorActionBuilder withDependencies(ResourceDependencies resourceDeps) {
- this.deps = resourceDeps.getResources();
- return this;
- }
-
- public LibraryRGeneratorActionBuilder setClassJarOut(Artifact rJavaClassJar) {
- this.rJavaClassJar = rJavaClassJar;
- return this;
- }
-
- public ResourceContainer build(RuleContext ruleContext) {
- AndroidSdkProvider sdk = AndroidSdkProvider.fromRuleContext(ruleContext);
-
- CustomCommandLine.Builder builder = new CustomCommandLine.Builder();
- NestedSetBuilder<Artifact> inputs = NestedSetBuilder.naiveLinkOrder();
- FilesToRunProvider executable =
- ruleContext.getExecutablePrerequisite("$android_resources_busybox", Mode.HOST);
- inputs.addAll(executable.getRunfilesSupport().getRunfilesArtifactsWithoutMiddlemen());
-
- builder.add("--tool").add("GENERATE_LIBRARY_R").add("--");
-
- if (!Strings.isNullOrEmpty(javaPackage)) {
- builder.add("--packageForR").add(javaPackage);
- }
-
- FluentIterable<ResourceContainer> symbolProviders =
- FluentIterable.from(deps).append(resourceContainer);
-
- builder.addJoinStrings(
- "--symbols",
- ruleContext.getConfiguration().getHostPathSeparator(),
- symbolProviders.transform(TO_SYMBOL_PATH));
- inputs.addTransitive(
- NestedSetBuilder.wrap(
- Order.NAIVE_LINK_ORDER, symbolProviders.transform(TO_SYMBOL_ARTIFACT)));
-
- builder.addExecPath("--classJarOutput", rJavaClassJar);
-
- builder.addExecPath("--androidJar", sdk.getAndroidJar());
- inputs.add(sdk.getAndroidJar());
-
- // Create the spawn action.
- SpawnAction.Builder spawnActionBuilder = new SpawnAction.Builder();
- ruleContext.registerAction(
- spawnActionBuilder
- .addTransitiveInputs(inputs.build())
- .addOutputs(ImmutableList.<Artifact>of(rJavaClassJar))
- .useParameterFile(ParameterFileType.UNQUOTED)
- .setCommandLine(builder.build())
- .setExecutable(executable)
- .setProgressMessage("Generating Library R Classes: " + ruleContext.getLabel())
- .setMnemonic("LibraryRClassGenerator")
- .build(ruleContext));
- return resourceContainer.toBuilder().setJavaClassJar(rJavaClassJar).build();
- }
-}
diff --git a/src/tools/android/java/com/google/devtools/build/android/AndroidDataDeserializer.java b/src/tools/android/java/com/google/devtools/build/android/AndroidDataDeserializer.java
index e9e1f3e22c..c42e870bbd 100644
--- a/src/tools/android/java/com/google/devtools/build/android/AndroidDataDeserializer.java
+++ b/src/tools/android/java/com/google/devtools/build/android/AndroidDataDeserializer.java
@@ -13,63 +13,24 @@
// limitations under the License.
package com.google.devtools.build.android;
-import com.android.ide.common.res2.MergingException;
import com.google.common.base.Stopwatch;
import com.google.common.collect.Maps;
-import com.google.common.util.concurrent.ListenableFuture;
-import com.google.common.util.concurrent.ListeningExecutorService;
-import com.google.common.util.concurrent.MoreExecutors;
-import com.google.devtools.build.android.ParsedAndroidData.Builder;
import com.google.devtools.build.android.ParsedAndroidData.KeyValueConsumer;
import com.google.devtools.build.android.proto.SerializeFormat;
import com.google.devtools.build.android.proto.SerializeFormat.Header;
-import java.io.Closeable;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.FileSystem;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
-import java.util.ArrayList;
-import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
-import java.util.concurrent.Callable;
-import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;
/** Deserializes {@link DataKey}, {@link DataValue} entries from a binary file. */
public class AndroidDataDeserializer {
- /** Task to deserialize resources from a path. */
- static final class Deserialize implements Callable<Boolean> {
-
- private final Path symbolPath;
-
- private final Builder finalDataBuilder;
- private final AndroidDataDeserializer deserializer;
-
- private Deserialize(
- AndroidDataDeserializer deserializer, Path symbolPath, Builder finalDataBuilder) {
- this.deserializer = deserializer;
- this.symbolPath = symbolPath;
- this.finalDataBuilder = finalDataBuilder;
- }
-
- @Override
- public Boolean call() throws Exception {
- final Builder parsedDataBuilder = ParsedAndroidData.Builder.newBuilder();
- deserializer.read(symbolPath, parsedDataBuilder.consumers());
- // The builder isn't threadsafe, so synchronize the copyTo call.
- synchronized (finalDataBuilder) {
- // All the resources are sorted before writing, so they can be aggregated in
- // whatever order here.
- parsedDataBuilder.copyTo(finalDataBuilder);
- }
- return Boolean.TRUE;
- }
- }
-
private static final Logger logger = Logger.getLogger(AndroidDataDeserializer.class.getName());
public static AndroidDataDeserializer create() {
@@ -153,35 +114,4 @@ public class AndroidDataDeserializer {
}
}
}
-
- /** Deserializes a list of serialized resource paths to a {@link ParsedAndroidData}. */
- public static ParsedAndroidData deserializeSymbolsToData(List<Path> symbolPaths)
- throws IOException, MergingException {
- AndroidDataDeserializer deserializer = create();
- final ListeningExecutorService executorService =
- MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(15));
- final Builder deserializedDataBuilder = ParsedAndroidData.Builder.newBuilder();
- try (Closeable closeable = ExecutorServiceCloser.createWith(executorService)) {
- List<ListenableFuture<Boolean>> deserializing = new ArrayList<>();
- for (final Path symbolPath : symbolPaths) {
- deserializing.add(
- executorService.submit(
- new AndroidDataDeserializer.Deserialize(
- deserializer, symbolPath, deserializedDataBuilder)));
- }
- FailedFutureAggregator<MergingException> aggregator =
- FailedFutureAggregator.createForMergingExceptionWithMessage(
- "Failure(s) during dependency parsing");
- aggregator.aggregateAndMaybeThrow(deserializing);
- }
- return deserializedDataBuilder.build();
- }
-
- public static ParsedAndroidData deserializeSingleAndroidData(SerializedAndroidData data)
- throws MergingException {
- final ParsedAndroidData.Builder builder = ParsedAndroidData.Builder.newBuilder();
- final AndroidDataDeserializer deserializer = create();
- data.deserialize(deserializer, builder.consumers());
- return builder.build();
- }
}
diff --git a/src/tools/android/java/com/google/devtools/build/android/AndroidResourceMerger.java b/src/tools/android/java/com/google/devtools/build/android/AndroidResourceMerger.java
index e0a40362f7..0ab4c32275 100644
--- a/src/tools/android/java/com/google/devtools/build/android/AndroidResourceMerger.java
+++ b/src/tools/android/java/com/google/devtools/build/android/AndroidResourceMerger.java
@@ -28,13 +28,12 @@ import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;
-/** Collects all the functionality for an action to merge resources. */
-// TODO(bazel-team): Turn into an instance object, in order to use an external ExecutorService.
+/** Collects all the functionationality for an action to merge resources. */
public class AndroidResourceMerger {
static final Logger logger = Logger.getLogger(AndroidResourceProcessor.class.getName());
/** Merges all secondary resources with the primary resources. */
- public static MergedAndroidData mergeData(
+ static MergedAndroidData mergeData(
final ParsedAndroidData primary,
final Path primaryManifest,
final List<? extends SerializedAndroidData> direct,
@@ -50,14 +49,11 @@ public class AndroidResourceMerger {
final ListeningExecutorService executorService =
MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(15));
try (Closeable closeable = ExecutorServiceCloser.createWith(executorService)) {
+ AndroidDataMerger merger = AndroidDataMerger.createWithPathDeduplictor(executorService);
UnwrittenMergedAndroidData merged =
- mergeData(
- executorService,
- transitive,
- direct,
- primary,
- primaryManifest,
- type != VariantType.LIBRARY);
+ merger.loadAndMerge(
+ transitive, direct, primary, primaryManifest, type != VariantType.LIBRARY);
+ logger.fine(String.format("merge finished in %sms", timer.elapsed(TimeUnit.MILLISECONDS)));
timer.reset().start();
if (symbolsOut != null) {
AndroidDataSerializer serializer = AndroidDataSerializer.create();
@@ -86,24 +82,6 @@ public class AndroidResourceMerger {
}
}
- public static UnwrittenMergedAndroidData mergeData(
- ListeningExecutorService executorService,
- List<? extends SerializedAndroidData> transitive,
- List<? extends SerializedAndroidData> direct,
- ParsedAndroidData primary,
- Path primaryManifest,
- boolean allowPrimaryOverrideAll)
- throws MergingException {
- Stopwatch timer = Stopwatch.createStarted();
- try {
- AndroidDataMerger merger = AndroidDataMerger.createWithPathDeduplictor(executorService);
- return merger.loadAndMerge(
- transitive, direct, primary, primaryManifest, allowPrimaryOverrideAll);
- } finally {
- logger.fine(String.format("merge finished in %sms", timer.elapsed(TimeUnit.MILLISECONDS)));
- }
- }
-
/**
* Merges all secondary resources with the primary resources, given that the primary resources
* have not yet been parsed and serialized.
diff --git a/src/tools/android/java/com/google/devtools/build/android/AndroidResourceProcessor.java b/src/tools/android/java/com/google/devtools/build/android/AndroidResourceProcessor.java
index 4da08f1ee3..e33928d19c 100644
--- a/src/tools/android/java/com/google/devtools/build/android/AndroidResourceProcessor.java
+++ b/src/tools/android/java/com/google/devtools/build/android/AndroidResourceProcessor.java
@@ -28,6 +28,7 @@ import com.android.builder.model.AaptOptions;
import com.android.ide.common.internal.CommandLineRunner;
import com.android.ide.common.internal.ExecutorSingleton;
import com.android.ide.common.internal.LoggedErrorException;
+import com.android.ide.common.res2.MergingException;
import com.android.io.FileWrapper;
import com.android.io.StreamException;
import com.android.repository.Revision;
@@ -45,6 +46,7 @@ import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.common.util.concurrent.MoreExecutors;
import com.google.devtools.build.android.Converters.ExistingPathConverter;
import com.google.devtools.build.android.Converters.RevisionConverter;
+import com.google.devtools.build.android.ParsedAndroidData.Builder;
import com.google.devtools.build.android.SplitConfigurationFilter.UnrecognizedSplitsException;
import com.google.devtools.build.android.resources.RClassGenerator;
import com.google.devtools.common.options.Converters.CommaSeparatedOptionListConverter;
@@ -705,4 +707,55 @@ public class AndroidResourceProcessor {
}
return Files.createDirectories(out);
}
+
+ /** Deserializes a list of serialized resource paths to a {@link ParsedAndroidData}. */
+ public ParsedAndroidData deserializeSymbolsToData(List<Path> symbolPaths)
+ throws IOException, MergingException {
+ AndroidDataDeserializer deserializer = AndroidDataDeserializer.create();
+ final ListeningExecutorService executorService =
+ MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(15));
+ final Builder deserializedDataBuilder = ParsedAndroidData.Builder.newBuilder();
+ try (Closeable closeable = ExecutorServiceCloser.createWith(executorService)) {
+ List<ListenableFuture<Boolean>> deserializing = new ArrayList<>();
+ for (final Path symbolPath : symbolPaths) {
+ deserializing.add(
+ executorService.submit(
+ new Deserialize(deserializer, symbolPath, deserializedDataBuilder)));
+ }
+ FailedFutureAggregator<MergingException> aggregator =
+ FailedFutureAggregator.createForMergingExceptionWithMessage(
+ "Failure(s) during dependency parsing");
+ aggregator.aggregateAndMaybeThrow(deserializing);
+ }
+ return deserializedDataBuilder.build();
+ }
+
+ /** Task to deserialize resources from a path. */
+ private static final class Deserialize implements Callable<Boolean> {
+
+ private final Path symbolPath;
+
+ private final Builder finalDataBuilder;
+ private final AndroidDataDeserializer deserializer;
+
+ private Deserialize(
+ AndroidDataDeserializer deserializer, Path symbolPath, Builder finalDataBuilder) {
+ this.deserializer = deserializer;
+ this.symbolPath = symbolPath;
+ this.finalDataBuilder = finalDataBuilder;
+ }
+
+ @Override
+ public Boolean call() throws Exception {
+ final Builder parsedDataBuilder = ParsedAndroidData.Builder.newBuilder();
+ deserializer.read(symbolPath, parsedDataBuilder.consumers());
+ // The builder isn't threadsafe, so synchronize the copyTo call.
+ synchronized (finalDataBuilder) {
+ // All the resources are sorted before writing, so they can be aggregated in
+ // whatever order here.
+ parsedDataBuilder.copyTo(finalDataBuilder);
+ }
+ return Boolean.TRUE;
+ }
+ }
}
diff --git a/src/tools/android/java/com/google/devtools/build/android/LibraryRClassGeneratorAction.java b/src/tools/android/java/com/google/devtools/build/android/LibraryRClassGeneratorAction.java
index 1cb816c01e..51c771946b 100644
--- a/src/tools/android/java/com/google/devtools/build/android/LibraryRClassGeneratorAction.java
+++ b/src/tools/android/java/com/google/devtools/build/android/LibraryRClassGeneratorAction.java
@@ -93,10 +93,11 @@ public class LibraryRClassGeneratorAction {
Strings.nullToEmpty(options.packageForR));
resourceClassWriter.setIncludeClassFile(true);
resourceClassWriter.setIncludeJavaFile(false);
+ final AndroidResourceProcessor resourceProcessor = new AndroidResourceProcessor(stdLogger);
logger.fine(String.format("Setup finished at %sms", timer.elapsed(TimeUnit.MILLISECONDS)));
final ParsedAndroidData data =
- AndroidDataDeserializer.deserializeSymbolsToData(options.symbols);
+ resourceProcessor.deserializeSymbolsToData(options.symbols);
logger.fine(
String.format("Deserialization finished at %sms", timer.elapsed(TimeUnit.MILLISECONDS)));