aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/tools/android/java/com/google/devtools/build/android/resources
diff options
context:
space:
mode:
authorGravatar corysmith <corysmith@google.com>2017-04-25 17:33:48 +0200
committerGravatar Vladimir Moskva <vladmos@google.com>2017-04-25 20:38:40 +0200
commit641318ac48dd4f110184c42b4b75485ee61416a8 (patch)
tree8eb64d4739516a2e115544a94551201bd29ba70a /src/tools/android/java/com/google/devtools/build/android/resources
parenta900f00e5f83d859bd404aa79bc9281b2886ae00 (diff)
Automated g4 rollback of commit 3c0bb56a74478cff675b636d5bf605a652451739.
*** Reason for rollback *** Rolling forward with a fix to avoid writing all resources to empty libraries. *** Original change description *** Automated g4 rollback of commit bdf0230534a59dab954ee76c5bf640394c88984e. *** 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: 154175593
Diffstat (limited to 'src/tools/android/java/com/google/devtools/build/android/resources')
-rw-r--r--src/tools/android/java/com/google/devtools/build/android/resources/FieldInitializer.java4
-rw-r--r--src/tools/android/java/com/google/devtools/build/android/resources/IntArrayFieldInitializer.java16
-rw-r--r--src/tools/android/java/com/google/devtools/build/android/resources/IntFieldInitializer.java15
-rw-r--r--src/tools/android/java/com/google/devtools/build/android/resources/RClassGenerator.java117
-rw-r--r--src/tools/android/java/com/google/devtools/build/android/resources/ResourceSymbols.java19
5 files changed, 114 insertions, 57 deletions
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 a1e322fef6..a0b4dd59bb 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,6 +15,7 @@ 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;
@@ -43,4 +44,7 @@ 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<String> 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 48e6496d89..be5fec2a46 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
@@ -13,12 +13,14 @@
// limitations under the License.
package com.google.devtools.build.android.resources;
+import com.google.common.base.MoreObjects;
import com.google.common.base.Preconditions;
import com.google.common.base.Splitter;
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;
@@ -92,7 +94,21 @@ 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<String> fieldNames) {
+ return fieldNames.contains(fieldName);
+ }
+
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(getClass())
+ .add("fieldName", fieldName)
+ .add("values", values)
+ .toString();
+ }
}
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 400c26789e..8442711b88 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
@@ -13,8 +13,10 @@
// limitations under the License.
package com.google.devtools.build.android.resources;
+import com.google.common.base.MoreObjects;
import java.io.IOException;
import java.io.Writer;
+import java.util.Set;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.commons.InstructionAdapter;
@@ -56,4 +58,17 @@ public final class IntFieldInitializer implements FieldInitializer {
writer.write(String.format(" public static int %s = 0x%x;\n",
fieldName, value));
}
+
+ @Override
+ public boolean nameIsIn(Set<String> fieldNames) {
+ return fieldNames.contains(fieldName);
+ }
+
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(getClass())
+ .add("fieldName", fieldName)
+ .add("value", value)
+ .toString();
+ }
}
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 2d92e783cc..5d414bf11f 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,19 +18,17 @@ 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.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;
@@ -44,112 +42,94 @@ 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<ResourceType, List<FieldInitializer>> initializers;
private final boolean finalFields;
private static final Splitter PACKAGE_SPLITTER = Splitter.on('.');
/**
- * Create an RClassGenerator given the final binary's symbol values, and a collection of symbols
- * for the given package.
+ * Create an RClassGenerator initialized with the ResourceSymbols values.
*
* @param outFolder base folder to place the output R class files.
- * @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 values the final symbol values
* @param finalFields true if the fields should be marked final
*/
public static RClassGenerator fromSymbols(
Path outFolder,
- String packageName,
ResourceSymbols values,
- Collection<ResourceSymbols> packageSymbols,
boolean finalFields)
throws IOException {
- Table<String, String, SymbolEntry> symbolsTable = getAllSymbols(packageSymbols);
Table<String, String, SymbolEntry> valuesTable = values.asTable();
Map<ResourceType, List<FieldInitializer>> initializers =
- getInitializers(symbolsTable, valuesTable);
- return new RClassGenerator(outFolder, packageName, initializers, finalFields);
+ getInitializers(valuesTable);
+ return new RClassGenerator(outFolder, 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<ResourceType, List<FieldInitializer>> initializers,
boolean finalFields) {
this.outFolder = outFolder;
- this.packageName = packageName;
this.finalFields = finalFields;
this.initializers = initializers;
}
-
- private static Table<String, String, SymbolEntry> getAllSymbols(
- Collection<ResourceSymbols> symbols) throws IOException {
- Table<String, String, SymbolEntry> mergedSymbols = HashBasedTable.create();
- for (ResourceSymbols tableProvider : symbols) {
- mergedSymbols.putAll(tableProvider.asTable());
- }
- return mergedSymbols;
- }
-
- /** Convert the {@link SymbolTableProvider} data, to a map of {@link FieldInitializer}. */
+ /** Convert the {@link ResourceSymbols} data, to a map of {@link FieldInitializer}. */
private static Map<ResourceType, List<FieldInitializer>> getInitializers(
- Table<String, String, SymbolEntry> symbols, Table<String, String, SymbolEntry> values) {
+ Table<String, String, SymbolEntry> values) {
Map<ResourceType, List<FieldInitializer>> initializers = new EnumMap<>(ResourceType.class);
- for (String typeName : symbols.rowKeySet()) {
+ for (String typeName : values.rowKeySet()) {
ResourceType resourceType = ResourceType.getEnum(typeName);
Preconditions.checkNotNull(resourceType);
- initializers.put(resourceType, getInitializers(typeName, symbols, values));
+ initializers.put(resourceType, getInitializers(typeName, values));
}
return initializers;
}
private static List<FieldInitializer> getInitializers(
String typeName,
- Table<String, String, SymbolEntry> symbols,
- Table<String, String, SymbolEntry> values) {
+ Table<String, String, SymbolEntry> symbols) {
Map<String, SymbolEntry> rowMap = symbols.row(typeName);
- Set<String> symbolSet = rowMap.keySet();
- List<String> symbolList = new ArrayList<>(symbolSet);
+ List<String> symbolList = new ArrayList<>(rowMap.keySet());
Collections.sort(symbolList);
List<FieldInitializer> initializers = new ArrayList<>();
for (String symbolName : symbolList) {
- // 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()));
- }
+ SymbolEntry value = symbols.get(typeName, symbolName);
+ if (value.getType().equals("int")) {
+ initializers.add(IntFieldInitializer.of(value.getName(), value.getValue()));
} else {
- // 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));
+ Preconditions.checkArgument(value.getType().equals("int[]"));
+ initializers.add(IntArrayFieldInitializer.of(value.getName(), value.getValue()));
}
}
return initializers;
}
- /** Builds the bytecode and writes out the R.class file, and R$inner.class files. */
- public void write() throws IOException {
+ /**
+ * Builds bytecode and writes out R.class file, and R$inner.class files for provided package and
+ * symbols.
+ */
+ public void write(String packageName, Map<ResourceType, Set<String>> symbolsToWrite)
+ throws IOException {
+ writeClasses(packageName, filterInitializers(symbolsToWrite));
+ }
+
+ /** Builds bytecode and writes out R.class file, and R$inner.class files for provided package. */
+ public void write(String packageName) throws IOException {
+ writeClasses(packageName, initializers);
+ }
+
+ private void writeClasses(String packageName,
+ Map<ResourceType, List<FieldInitializer>> initializersToWrite) throws IOException {
+
Iterable<String> folders = PACKAGE_SPLITTER.split(packageName);
Path packageDir = outFolder;
for (String folder : folders) {
@@ -158,9 +138,11 @@ 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);
- if (initializers.isEmpty()) {
+
+ if (initializersToWrite.isEmpty()) {
return;
}
+
Path rClassFile = packageDir.resolve(SdkConstants.FN_COMPILED_RESOURCE_CLASS);
String packageWithSlashes = packageName.replaceAll("\\.", "/");
@@ -175,9 +157,8 @@ public class RClassGenerator {
null /* interfaces */);
classWriter.visitSource(SdkConstants.FN_RESOURCE_CLASS, null);
writeConstructor(classWriter);
-
// Build the R.class w/ the inner classes, then later build the individual R$inner.class.
- for (ResourceType resourceType : initializers.keySet()) {
+ for (ResourceType resourceType : initializersToWrite.keySet()) {
String innerClassName = rClassName + "$" + resourceType;
classWriter.visitInnerClass(
innerClassName,
@@ -189,10 +170,32 @@ public class RClassGenerator {
Files.write(rClassFile, classWriter.toByteArray());
// Now generate the R$inner.class files.
- for (Map.Entry<ResourceType, List<FieldInitializer>> entry : initializers.entrySet()) {
+ for (Map.Entry<ResourceType, List<FieldInitializer>> entry : initializersToWrite.entrySet()) {
writeInnerClass(entry.getValue(), packageDir, rClassName, entry.getKey().toString());
}
}
+
+ private Map<ResourceType, List<FieldInitializer>> filterInitializers(
+ Map<ResourceType, Set<String>> symbolsToWrite) {
+ Map<ResourceType, List<FieldInitializer>> initializersToWrite =
+ new EnumMap<>(ResourceType.class);
+ for (Entry<ResourceType, Set<String>> entry : symbolsToWrite.entrySet()) {
+ List<FieldInitializer> 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<FieldInitializer> initializers,
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 1860e228a3..051bd58de3 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,6 +18,7 @@ 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;
@@ -31,10 +32,13 @@ 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;
@@ -185,4 +189,19 @@ public class ResourceSymbols {
}
writer.write();
}
+
+ public Map<ResourceType, Set<String>> asFilterMap() throws IOException {
+ Map<ResourceType, Set<String>> filter = new EnumMap<>(ResourceType.class);
+ Table<String, String, SymbolEntry> symbolTable = asTable();
+ for (String typeName : symbolTable.rowKeySet()) {
+ Set<String> 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;
+ }
}