aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/tools/android/java/com/google/devtools/build/android/aapt2/ResourceLinker.java
diff options
context:
space:
mode:
authorGravatar corysmith <corysmith@google.com>2018-07-31 10:39:15 -0700
committerGravatar Copybara-Service <copybara-piper@google.com>2018-07-31 10:41:13 -0700
commit3852edd46cb777191728c42e62873e39fd9fe4c4 (patch)
tree8acda6f07d4ff6d0e65337c0bbffd5040220fec0 /src/tools/android/java/com/google/devtools/build/android/aapt2/ResourceLinker.java
parentab8a844240cf6ccb4ee46e6bb8795fcc2b3fe6be (diff)
Automated rollback of commit 0a635c5236ce30ea84b765ce752267992733a649.
*** Reason for rollback *** Rolling forward with the correct attribute handling. *** Original change description *** Automated rollback of commit 8fe0f45852a620a078013310989396caed273342. *** Reason for rollback *** Breaks a couple of builds due to a bad merge. *** Original change description *** Add apk converted to proto and all attributes from CompiledResources to ResourcesZip. Add new proto format for tool attributes stored in the AndroidDataXml for storing them in the resources.zip. RELNOTES:None PiperOrigin-RevId: 206786645
Diffstat (limited to 'src/tools/android/java/com/google/devtools/build/android/aapt2/ResourceLinker.java')
-rw-r--r--src/tools/android/java/com/google/devtools/build/android/aapt2/ResourceLinker.java171
1 files changed, 162 insertions, 9 deletions
diff --git a/src/tools/android/java/com/google/devtools/build/android/aapt2/ResourceLinker.java b/src/tools/android/java/com/google/devtools/build/android/aapt2/ResourceLinker.java
index 3839a5d94b..9ea3703d42 100644
--- a/src/tools/android/java/com/google/devtools/build/android/aapt2/ResourceLinker.java
+++ b/src/tools/android/java/com/google/devtools/build/android/aapt2/ResourceLinker.java
@@ -21,26 +21,39 @@ import com.google.common.base.Joiner;
import com.google.common.base.MoreObjects;
import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
+import com.google.common.collect.HashMultimap;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Multimap;
import com.google.common.collect.Streams;
import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.devtools.build.android.AaptCommandBuilder;
+import com.google.devtools.build.android.AndroidCompiledDataDeserializer;
+import com.google.devtools.build.android.AndroidDataWritingVisitor;
+import com.google.devtools.build.android.AndroidResourceMerger.MergingException;
import com.google.devtools.build.android.AndroidResourceOutputs;
+import com.google.devtools.build.android.FullyQualifiedName;
import com.google.devtools.build.android.Profiler;
import com.google.devtools.build.android.aapt2.ResourceCompiler.CompiledType;
+import com.google.devtools.build.android.proto.SerializeFormat.ToolAttributes;
+import com.google.devtools.build.android.xml.Namespaces;
import com.google.devtools.build.android.ziputils.DirectoryEntry;
import com.google.devtools.build.android.ziputils.ZipIn;
import com.google.devtools.build.android.ziputils.ZipOut;
+import java.io.BufferedOutputStream;
import java.io.IOException;
+import java.io.OutputStream;
import java.nio.channels.FileChannel;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.util.Collection;
import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
import java.util.Objects;
import java.util.Optional;
+import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.function.Function;
@@ -263,7 +276,7 @@ public class ResourceLinker {
}
private List<String> compiledResourcesToPaths(
- CompiledResources compiled, Predicate<DirectoryEntry> shouldKeep) throws IOException {
+ CompiledResources compiled, Predicate<DirectoryEntry> shouldKeep) {
// Using sequential streams to maintain the overlay order for aapt2.
return Stream.concat(include.stream(), Stream.of(compiled))
.sequential()
@@ -323,9 +336,61 @@ public class ResourceLinker {
R apply(T arg) throws Throwable;
}
+ private String replaceExtension(String fileName, String newExtension) {
+ int lastIndex = fileName.lastIndexOf('.');
+ if (lastIndex == -1) {
+ return fileName.concat(".").concat(newExtension);
+ }
+ return fileName.substring(0, lastIndex).concat(".").concat(newExtension);
+ }
+
+ public Path convertToBinary(Path protoApk) {
+ try {
+ profiler.startTask("convertToBinary");
+ final Path outPath =
+ workingDirectory.resolveSibling(
+ replaceExtension(protoApk.getFileName().toString(), "apk"));
+ logger.fine(
+ new AaptCommandBuilder(aapt2)
+ .add("convert")
+ .add("-o", outPath)
+ .add("--output-format", "binary")
+ .add(protoApk.toString())
+ .execute("Converting " + protoApk));
+ profiler.recordEndOf("convertToBinary");
+ return outPath;
+ } catch (IOException e) {
+ throw new LinkError(e);
+ }
+ }
+
+ public Path optimizeApk(Path apk) {
+ try {
+ profiler.startTask("optimizeApk");
+ final Path outPath =
+ workingDirectory.resolveSibling(
+ replaceExtension(apk.getFileName().toString(), ".optimized.apk"));
+ logger.fine(
+ new AaptCommandBuilder(aapt2)
+ .forBuildToolsVersion(buildToolsVersion)
+ .forVariantType(VariantType.DEFAULT)
+ .add("optimize")
+ .when(Objects.equals(logger.getLevel(), Level.FINE))
+ .thenAdd("-v")
+ .add("-o", outPath)
+ .add(apk.toString())
+ .execute(String.format("Optimizing %s", apk)));
+ return outPath;
+ } catch (IOException e) {
+ throw new LinkError(e);
+ } finally {
+ profiler.recordEndOf("optimizeApk");
+ }
+ }
+
public PackagedResources link(CompiledResources compiled) {
try {
- final Path outPath = workingDirectory.resolve("bin.apk");
+ final Path outPath = workingDirectory.resolve("bin.pb");
Path rTxt = workingDirectory.resolve("R.txt");
Path proguardConfig = workingDirectory.resolve("proguard.cfg");
Path mainDexProguard = workingDirectory.resolve("proguard.maindex.cfg");
@@ -342,8 +407,7 @@ public class ResourceLinker {
.thenAdd("--no-version-vectors")
// Turn off namespaced resources
.add("--no-static-lib-packages")
- .when(outputAsProto)
- .thenAdd("--proto-format")
+ .add("--proto-format")
.when(Objects.equals(logger.getLevel(), Level.FINE))
.thenAdd("-v")
.add("--manifest", compiled.getManifest())
@@ -387,13 +451,35 @@ public class ResourceLinker {
.thenAdd("--proguard-conditional-keep-rules")
.add("-o", outPath)
.execute(String.format("Linking %s", compiled.getManifest())));
- profiler.recordEndOf("fulllink");
- profiler.startTask("optimize");
+ profiler.recordEndOf("fulllink").startTask("attributes");
+
+ final Path attributes = workingDirectory.resolve("tool.attributes");
+ // extract tool annotations from the compile resources.
+ final ToolProtoWriter writer = new ToolProtoWriter(attributes);
+ Stream.concat(include.stream(), Stream.of(compiled))
+ .parallel()
+ .map(AndroidCompiledDataDeserializer.create()::readAttributes)
+ .map(Map::entrySet)
+ .flatMap(Set::stream)
+ .distinct()
+ .forEach(e -> e.getValue().writeResource((FullyQualifiedName) e.getKey(), writer));
+ writer.flush();
+
+ profiler.recordEndOf("attributes");
if (densities.size() < 2) {
return PackagedResources.of(
- outPath, rTxt, proguardConfig, mainDexProguard, javaSourceDirectory, resourceIds);
+ outputAsProto ? outPath : convertToBinary(outPath), // convert proto to apk
+ outPath,
+ rTxt,
+ proguardConfig,
+ mainDexProguard,
+ javaSourceDirectory,
+ resourceIds,
+ attributes);
}
- final Path optimized = workingDirectory.resolve("optimized.apk");
+
+ profiler.startTask("optimize");
+ final Path optimized = workingDirectory.resolve("optimized.pb");
logger.fine(
new AaptCommandBuilder(aapt2)
.forBuildToolsVersion(buildToolsVersion)
@@ -406,8 +492,16 @@ public class ResourceLinker {
.add(outPath.toString())
.execute(String.format("Optimizing %s", compiled.getManifest())));
profiler.recordEndOf("optimize");
+
return PackagedResources.of(
- optimized, rTxt, proguardConfig, mainDexProguard, javaSourceDirectory, resourceIds);
+ outputAsProto ? optimized : convertToBinary(optimized),
+ optimized,
+ rTxt,
+ proguardConfig,
+ mainDexProguard,
+ javaSourceDirectory,
+ resourceIds,
+ attributes);
} catch (IOException e) {
throw new LinkError(e);
}
@@ -442,4 +536,63 @@ public class ResourceLinker {
.add("baseApk", baseApk)
.toString();
}
+
+ private static class ToolProtoWriter implements AndroidDataWritingVisitor {
+
+ final Multimap<String, String> attributes = HashMultimap.create();
+ private final Path out;
+
+ ToolProtoWriter(Path out) {
+ this.out = out;
+ }
+
+ @Override
+ public void flush() throws IOException {
+ ToolAttributes.Builder builder = ToolAttributes.newBuilder();
+ for (Entry<String, Collection<String>> entry : attributes.asMap().entrySet()) {
+ builder.putAttributes(
+ entry.getKey(),
+ ToolAttributes.ToolAttributeValues.newBuilder().addAllValues(entry.getValue()).build());
+ }
+ try (OutputStream stream = new BufferedOutputStream(Files.newOutputStream(out))) {
+ builder.build().writeTo(stream);
+ }
+ }
+
+ @Override
+ public Path copyManifest(Path sourceManifest) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void copyAsset(Path source, String relativeDestinationPath) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void copyResource(Path source, String relativeDestinationPath) throws MergingException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void defineAttribute(FullyQualifiedName fqn, String name, String value) {
+ attributes.put(removeNamespace(name), value);
+ }
+
+ private String removeNamespace(String qualifiedName) {
+ int indexColon = qualifiedName.indexOf(':');
+ if (indexColon == -1) {
+ return qualifiedName;
+ }
+ return qualifiedName.substring(indexColon);
+ }
+
+ @Override
+ public void defineNamespacesFor(FullyQualifiedName fqn, Namespaces namespaces) {}
+
+ @Override
+ public ValueResourceDefinitionMetadata define(FullyQualifiedName fqn) {
+ throw new UnsupportedOperationException();
+ }
+ }
}