From 3c0bb56a74478cff675b636d5bf605a652451739 Mon Sep 17 00:00:00 2001 From: corysmith Date: Thu, 20 Apr 2017 00:19:47 +0200 Subject: Automated g4 rollback of commit 3217832d638f9a8fdf22e88e32d75bda32ff7235. *** Reason for rollback *** Causes issues with library R generation. *** Original change description *** Refactor the RClassGenerator to be reusable for different packages. RELNOTES: None PiperOrigin-RevId: 153641485 --- .../build/android/AndroidResourceClassWriter.java | 4 +- .../build/android/AndroidResourceProcessor.java | 16 ++- .../build/android/resources/FieldInitializer.java | 4 - .../resources/IntArrayFieldInitializer.java | 7 -- .../android/resources/IntFieldInitializer.java | 6 -- .../build/android/resources/RClassGenerator.java | 114 ++++++++++----------- .../build/android/resources/ResourceSymbols.java | 19 ---- 7 files changed, 70 insertions(+), 100 deletions(-) (limited to 'src/tools/android/java') diff --git a/src/tools/android/java/com/google/devtools/build/android/AndroidResourceClassWriter.java b/src/tools/android/java/com/google/devtools/build/android/AndroidResourceClassWriter.java index 1f0360c85b..37fb7a81a2 100644 --- a/src/tools/android/java/com/google/devtools/build/android/AndroidResourceClassWriter.java +++ b/src/tools/android/java/com/google/devtools/build/android/AndroidResourceClassWriter.java @@ -474,8 +474,8 @@ public class AndroidResourceClassWriter implements Flushable { private void writeAsClass(Map> initializers) throws IOException { RClassGenerator rClassGenerator = - new RClassGenerator(outputBasePath, initializers, false /* finalFields */); - rClassGenerator.write(packageName); + new RClassGenerator(outputBasePath, packageName, initializers, false /* finalFields */); + rClassGenerator.write(); } private static String normalizeName(String resourceName) { 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 45187f2d14..a9243d2584 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 @@ -544,15 +544,23 @@ public class AndroidResourceProcessor { Path classesOut, boolean finalFields) throws IOException { - RClassGenerator classWriter = - RClassGenerator.fromSymbols(classesOut, fullSymbolValues, finalFields); for (String packageName : libMap.keySet()) { - classWriter.write(packageName, ResourceSymbols.merge(libMap.get(packageName)).asFilterMap()); + Collection symbols = libMap.get(packageName); + RClassGenerator classWriter = RClassGenerator.fromSymbols( + classesOut, packageName, fullSymbolValues, symbols, finalFields); + classWriter.write(); } if (appPackageName != null) { // Unlike the R.java generation, we also write the app's R.class file so that the class // jar file can be complete (aapt doesn't generate it for us). - classWriter.write(appPackageName); + RClassGenerator classWriter = + RClassGenerator.fromSymbols( + classesOut, + appPackageName, + fullSymbolValues, + ImmutableList.of(fullSymbolValues), + finalFields); + classWriter.write(); } } diff --git a/src/tools/android/java/com/google/devtools/build/android/resources/FieldInitializer.java b/src/tools/android/java/com/google/devtools/build/android/resources/FieldInitializer.java index a0b4dd59bb..a1e322fef6 100644 --- a/src/tools/android/java/com/google/devtools/build/android/resources/FieldInitializer.java +++ b/src/tools/android/java/com/google/devtools/build/android/resources/FieldInitializer.java @@ -15,7 +15,6 @@ package com.google.devtools.build.android.resources; import java.io.IOException; import java.io.Writer; -import java.util.Set; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.commons.InstructionAdapter; @@ -44,7 +43,4 @@ public interface FieldInitializer { * for final fields yet. */ void writeInitSource(Writer writer) throws IOException; - - /** Tests if the field's name is in the provided set. */ - boolean nameIsIn(Set fieldNames); } diff --git a/src/tools/android/java/com/google/devtools/build/android/resources/IntArrayFieldInitializer.java b/src/tools/android/java/com/google/devtools/build/android/resources/IntArrayFieldInitializer.java index eb78d53ade..48e6496d89 100644 --- a/src/tools/android/java/com/google/devtools/build/android/resources/IntArrayFieldInitializer.java +++ b/src/tools/android/java/com/google/devtools/build/android/resources/IntArrayFieldInitializer.java @@ -19,7 +19,6 @@ import com.google.common.collect.ImmutableCollection; import com.google.common.collect.ImmutableList; import java.io.IOException; import java.io.Writer; -import java.util.Set; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.Type; import org.objectweb.asm.commons.InstructionAdapter; @@ -93,13 +92,7 @@ public final class IntArrayFieldInitializer implements FieldInitializer { builder.append(String.format(", 0x%x", attrId)); } } - writer.write(String.format(" public static int[] %s = { %s };\n", fieldName, builder.toString())); } - - @Override - public boolean nameIsIn(Set fieldNames) { - return fieldNames.contains(fieldName); - } } diff --git a/src/tools/android/java/com/google/devtools/build/android/resources/IntFieldInitializer.java b/src/tools/android/java/com/google/devtools/build/android/resources/IntFieldInitializer.java index 2223a1a05f..400c26789e 100644 --- a/src/tools/android/java/com/google/devtools/build/android/resources/IntFieldInitializer.java +++ b/src/tools/android/java/com/google/devtools/build/android/resources/IntFieldInitializer.java @@ -15,7 +15,6 @@ package com.google.devtools.build.android.resources; import java.io.IOException; import java.io.Writer; -import java.util.Set; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.commons.InstructionAdapter; @@ -57,9 +56,4 @@ public final class IntFieldInitializer implements FieldInitializer { writer.write(String.format(" public static int %s = 0x%x;\n", fieldName, value)); } - - @Override - public boolean nameIsIn(Set fieldNames) { - return fieldNames.contains(fieldName); - } } diff --git a/src/tools/android/java/com/google/devtools/build/android/resources/RClassGenerator.java b/src/tools/android/java/com/google/devtools/build/android/resources/RClassGenerator.java index e1149281ee..2d92e783cc 100644 --- a/src/tools/android/java/com/google/devtools/build/android/resources/RClassGenerator.java +++ b/src/tools/android/java/com/google/devtools/build/android/resources/RClassGenerator.java @@ -18,18 +18,19 @@ import com.android.builder.internal.SymbolLoader.SymbolEntry; import com.android.resources.ResourceType; import com.google.common.base.Preconditions; import com.google.common.base.Splitter; -import com.google.common.collect.ImmutableMap; +import com.google.common.collect.HashBasedTable; import com.google.common.collect.Table; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.EnumMap; import java.util.List; import java.util.Map; -import java.util.Map.Entry; import java.util.Set; +import java.util.logging.Logger; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; @@ -43,83 +44,112 @@ import org.objectweb.asm.commons.InstructionAdapter; * information. Also, the order of the constant pool tends to be different. */ public class RClassGenerator { + + private static final Logger logger = Logger.getLogger(RClassGenerator.class.getName()); private static final int JAVA_VERSION = Opcodes.V1_7; private static final String SUPER_CLASS = "java/lang/Object"; private final Path outFolder; + private final String packageName; private final Map> initializers; private final boolean finalFields; private static final Splitter PACKAGE_SPLITTER = Splitter.on('.'); /** - * Create an RClassGenerator initialized with the ResourceSymbols values. + * Create an RClassGenerator given the final binary's symbol values, and a collection of symbols + * for the given package. * * @param outFolder base folder to place the output R class files. - * @param values the final symbol values + * @param packageName the java package to use for the R class + * @param values the final symbol values (may include more symbols than needed for this package) + * @param packageSymbols the symbols in this package * @param finalFields true if the fields should be marked final */ public static RClassGenerator fromSymbols( Path outFolder, + String packageName, ResourceSymbols values, + Collection packageSymbols, boolean finalFields) throws IOException { + Table symbolsTable = getAllSymbols(packageSymbols); Table valuesTable = values.asTable(); Map> initializers = - getInitializers(valuesTable); - return new RClassGenerator(outFolder, initializers, finalFields); + getInitializers(symbolsTable, valuesTable); + return new RClassGenerator(outFolder, packageName, initializers, finalFields); } /** * Create an RClassGenerator given a collection of initializers. * * @param outFolder base folder to place the output R class files. + * @param packageName the java package to use for the R class * @param initializers the list of initializers to use for each inner class * @param finalFields true if the fields should be marked final */ public RClassGenerator( Path outFolder, + String packageName, Map> initializers, boolean finalFields) { this.outFolder = outFolder; + this.packageName = packageName; this.finalFields = finalFields; this.initializers = initializers; } - /** Convert the {@link ResourceSymbols} data, to a map of {@link FieldInitializer}. */ + + private static Table getAllSymbols( + Collection symbols) throws IOException { + Table mergedSymbols = HashBasedTable.create(); + for (ResourceSymbols tableProvider : symbols) { + mergedSymbols.putAll(tableProvider.asTable()); + } + return mergedSymbols; + } + + /** Convert the {@link SymbolTableProvider} data, to a map of {@link FieldInitializer}. */ private static Map> getInitializers( - Table values) { + Table symbols, Table values) { Map> initializers = new EnumMap<>(ResourceType.class); - for (String typeName : values.rowKeySet()) { + for (String typeName : symbols.rowKeySet()) { ResourceType resourceType = ResourceType.getEnum(typeName); Preconditions.checkNotNull(resourceType); - initializers.put(resourceType, getInitializers(typeName, values)); + initializers.put(resourceType, getInitializers(typeName, symbols, values)); } return initializers; } private static List getInitializers( String typeName, - Table symbols) { + Table symbols, + Table values) { Map rowMap = symbols.row(typeName); - List symbolList = new ArrayList<>(rowMap.keySet()); + Set symbolSet = rowMap.keySet(); + List symbolList = new ArrayList<>(symbolSet); Collections.sort(symbolList); List initializers = new ArrayList<>(); for (String symbolName : symbolList) { - SymbolEntry value = symbols.get(typeName, symbolName); - if (value.getType().equals("int")) { - initializers.add(IntFieldInitializer.of(value.getName(), value.getValue())); + // get the matching SymbolEntry from the values Table. + SymbolEntry value = values.get(typeName, symbolName); + if (value != null) { + if (value.getType().equals("int")) { + initializers.add(IntFieldInitializer.of(value.getName(), value.getValue())); + } else { + Preconditions.checkArgument(value.getType().equals("int[]")); + initializers.add(IntArrayFieldInitializer.of(value.getName(), value.getValue())); + } } else { - Preconditions.checkArgument(value.getType().equals("int[]")); - initializers.add(IntArrayFieldInitializer.of(value.getName(), value.getValue())); + // Value may be missing if resource overriding eliminates resources at the binary + // level, which were originally present at the library level. + logger.fine( + String.format( + "Skipping R.%s.%s -- value not known in binary's R.txt", typeName, symbolName)); } } return initializers; } - /** - * Builds bytecode and writes out R.class file, and R$inner.class files for provided package and - * symbols - */ - public void write(String packageName, Map> symbolsToWrite) - throws IOException { + /** Builds the bytecode and writes out the R.class file, and R$inner.class files. */ + public void write() throws IOException { Iterable folders = PACKAGE_SPLITTER.split(packageName); Path packageDir = outFolder; for (String folder : folders) { @@ -128,9 +158,7 @@ public class RClassGenerator { // At least create the outFolder that was requested. However, if there are no symbols, don't // create the R.class and inner class files (no need to have an empty class). Files.createDirectories(packageDir); - Map> initializersToWrite = - filterInitializers(symbolsToWrite); - if (initializersToWrite.isEmpty()) { + if (initializers.isEmpty()) { return; } Path rClassFile = packageDir.resolve(SdkConstants.FN_COMPILED_RESOURCE_CLASS); @@ -149,7 +177,7 @@ public class RClassGenerator { writeConstructor(classWriter); // Build the R.class w/ the inner classes, then later build the individual R$inner.class. - for (ResourceType resourceType : initializersToWrite.keySet()) { + for (ResourceType resourceType : initializers.keySet()) { String innerClassName = rClassName + "$" + resourceType; classWriter.visitInnerClass( innerClassName, @@ -161,41 +189,11 @@ public class RClassGenerator { Files.write(rClassFile, classWriter.toByteArray()); // Now generate the R$inner.class files. - for (Map.Entry> entry : initializersToWrite.entrySet()) { + for (Map.Entry> entry : initializers.entrySet()) { writeInnerClass(entry.getValue(), packageDir, rClassName, entry.getKey().toString()); } } - /** Builds bytecode and writes out R.class file, and R$inner.class files for provided package. */ - public void write(String packageName) throws IOException { - write(packageName, ImmutableMap.>of()); - } - - private Map> filterInitializers( - Map> symbolsToWrite) { - Map> initializersToWrite = - new EnumMap<>(ResourceType.class); - if (symbolsToWrite.isEmpty()) { - return initializers; - } - for (Entry> entry : symbolsToWrite.entrySet()) { - List fieldsToWrite = new ArrayList<>(); - // Resource type may be missing if resource overriding eliminates resources at the binary - // level, which were originally present at the library level. - if (initializers.containsKey(entry.getKey())) { - for (FieldInitializer field : initializers.get(entry.getKey())) { - if (field.nameIsIn(entry.getValue())) { - fieldsToWrite.add(field); - } - } - } - if (!fieldsToWrite.isEmpty()) { - initializersToWrite.put(entry.getKey(), fieldsToWrite); - } - } - return initializersToWrite; - } - private void writeInnerClass( List initializers, Path packageDir, diff --git a/src/tools/android/java/com/google/devtools/build/android/resources/ResourceSymbols.java b/src/tools/android/java/com/google/devtools/build/android/resources/ResourceSymbols.java index 051bd58de3..1860e228a3 100644 --- a/src/tools/android/java/com/google/devtools/build/android/resources/ResourceSymbols.java +++ b/src/tools/android/java/com/google/devtools/build/android/resources/ResourceSymbols.java @@ -18,7 +18,6 @@ import com.android.builder.dependency.SymbolFileProvider; import com.android.builder.internal.SymbolLoader; import com.android.builder.internal.SymbolLoader.SymbolEntry; import com.android.builder.internal.SymbolWriter; -import com.android.resources.ResourceType; import com.android.utils.ILogger; import com.google.common.collect.HashBasedTable; import com.google.common.collect.HashMultimap; @@ -32,13 +31,10 @@ import java.lang.reflect.Field; import java.lang.reflect.Method; import java.nio.file.Path; import java.util.Collection; -import java.util.EnumMap; import java.util.HashMap; -import java.util.HashSet; import java.util.Map; import java.util.Map.Entry; import java.util.Objects; -import java.util.Set; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import javax.annotation.Nullable; @@ -189,19 +185,4 @@ public class ResourceSymbols { } writer.write(); } - - public Map> asFilterMap() throws IOException { - Map> filter = new EnumMap<>(ResourceType.class); - Table symbolTable = asTable(); - for (String typeName : symbolTable.rowKeySet()) { - Set fields = new HashSet<>(); - for (SymbolEntry symbolEntry : symbolTable.row(typeName).values()) { - fields.add(symbolEntry.getName()); - } - if (!fields.isEmpty()) { - filter.put(ResourceType.getEnum(typeName), fields); - } - } - return filter; - } } -- cgit v1.2.3