Private resources are now package-private in R classes. Private resources thus have their visibility checked by the build system: * unknown commit - private resources in deps omitted in R.* * unknown commit - private resources in deps inaccessible from XML * this CL - private resources in R.* inaccessible from other packages PiperOrigin-RevId: 291051825
diff --git a/src/tools/android/java/com/google/devtools/build/android/PlaceholderIdFieldInitializerBuilder.java b/src/tools/android/java/com/google/devtools/build/android/PlaceholderIdFieldInitializerBuilder.java index c4b60e9..36d3af2 100644 --- a/src/tools/android/java/com/google/devtools/build/android/PlaceholderIdFieldInitializerBuilder.java +++ b/src/tools/android/java/com/google/devtools/build/android/PlaceholderIdFieldInitializerBuilder.java
@@ -14,6 +14,7 @@ package com.google.devtools.build.android; import com.android.resources.ResourceType; +import com.google.auto.value.AutoValue; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; @@ -139,7 +140,7 @@ private final AndroidFrameworkAttrIdProvider androidIdProvider; - private final Map<ResourceType, SortedMap<String, DependencyInfo>> innerClasses = + private final Map<ResourceType, SortedMap<String, ResourceLinkageInfo>> innerClasses = new EnumMap<>(ResourceType.class); private final Map<String, Map<String, /*inlineable=*/ Boolean>> styleableAttrs = @@ -151,10 +152,9 @@ public void addSimpleResource( DependencyInfo dependencyInfo, Visibility visibility, ResourceType type, String name) { - Object unused = visibility; // TODO(b/26297204): use 'visibility' innerClasses .computeIfAbsent(type, t -> new TreeMap<>()) - .put(normalizeName(name), dependencyInfo); + .put(normalizeName(name), ResourceLinkageInfo.create(dependencyInfo, visibility)); } public void addStyleableResource( @@ -162,7 +162,6 @@ Visibility visibility, FullyQualifiedName key, Map<FullyQualifiedName, Boolean> attrs) { - Object unused = visibility; // TODO(b/26297204): use 'visibility' ResourceType type = ResourceType.STYLEABLE; // The configuration can play a role in sorting, but that isn't modeled yet. String normalizedStyleableName = normalizeName(key.name()); @@ -230,10 +229,10 @@ new EnumMap<>(ResourceType.class); Map<ResourceType, Integer> typeIdMap = chooseTypeIds(); Map<String, Integer> attrAssignments = assignAttrIds(typeIdMap.get(ResourceType.ATTR)); - for (Map.Entry<ResourceType, SortedMap<String, DependencyInfo>> fieldEntries : + for (Map.Entry<ResourceType, SortedMap<String, ResourceLinkageInfo>> fieldEntries : innerClasses.entrySet()) { ResourceType type = fieldEntries.getKey(); - SortedMap<String, DependencyInfo> sortedFields = fieldEntries.getValue(); + SortedMap<String, ResourceLinkageInfo> sortedFields = fieldEntries.getValue(); ImmutableList<FieldInitializer> fields; if (type == ResourceType.STYLEABLE) { fields = getStyleableInitializers(attrAssignments, sortedFields); @@ -277,43 +276,48 @@ } private static ImmutableList<FieldInitializer> getAttrInitializers( - Map<String, Integer> attrAssignments, SortedMap<String, DependencyInfo> sortedFields) { + Map<String, Integer> attrAssignments, SortedMap<String, ResourceLinkageInfo> sortedFields) { ImmutableList.Builder<FieldInitializer> initList = ImmutableList.builder(); - for (Map.Entry<String, DependencyInfo> entry : sortedFields.entrySet()) { + for (Map.Entry<String, ResourceLinkageInfo> entry : sortedFields.entrySet()) { String field = entry.getKey(); - DependencyInfo dependencyInfo = entry.getValue(); + ResourceLinkageInfo linkageInfo = entry.getValue(); int attrId = attrAssignments.get(field); - initList.add(IntFieldInitializer.of(dependencyInfo, field, attrId)); + initList.add( + IntFieldInitializer.of( + linkageInfo.dependencyInfo(), linkageInfo.visibility(), field, attrId)); } return initList.build(); } private ImmutableList<FieldInitializer> getResourceInitializers( - int typeId, SortedMap<String, DependencyInfo> sortedFields) { + int typeId, SortedMap<String, ResourceLinkageInfo> sortedFields) { ImmutableList.Builder<FieldInitializer> initList = ImmutableList.builder(); Map<String, Integer> publicNameToId = new LinkedHashMap<>(); Set<Integer> assignedIds = ImmutableSet.of(); int resourceIds = nextFreeId(getInitialIdForTypeId(typeId), assignedIds); - for (Map.Entry<String, DependencyInfo> entry : sortedFields.entrySet()) { + for (Map.Entry<String, ResourceLinkageInfo> entry : sortedFields.entrySet()) { String field = entry.getKey(); - DependencyInfo dependencyInfo = entry.getValue(); + ResourceLinkageInfo linkageInfo = entry.getValue(); Integer fieldValue = publicNameToId.get(field); if (fieldValue == null) { fieldValue = resourceIds; resourceIds = nextFreeId(resourceIds + 1, assignedIds); } - initList.add(IntFieldInitializer.of(dependencyInfo, field, fieldValue)); + initList.add( + IntFieldInitializer.of( + linkageInfo.dependencyInfo(), linkageInfo.visibility(), field, fieldValue)); } return initList.build(); } private ImmutableList<FieldInitializer> getStyleableInitializers( - Map<String, Integer> attrAssignments, SortedMap<String, DependencyInfo> sortedFields) + Map<String, Integer> attrAssignments, SortedMap<String, ResourceLinkageInfo> sortedFields) throws AttrLookupException { ImmutableList.Builder<FieldInitializer> initList = ImmutableList.builder(); - for (Map.Entry<String, DependencyInfo> entry : sortedFields.entrySet()) { + for (Map.Entry<String, ResourceLinkageInfo> entry : sortedFields.entrySet()) { String field = entry.getKey(); - DependencyInfo dependencyInfo = entry.getValue(); + ResourceLinkageInfo linkageInfo = entry.getValue(); + DependencyInfo dependencyInfo = linkageInfo.dependencyInfo(); Set<String> attrs = styleableAttrs.get(field).keySet(); ImmutableMap.Builder<String, Integer> arrayInitValues = ImmutableMap.builder(); for (String attr : attrs) { @@ -345,10 +349,15 @@ arrayInitValues.orderEntriesByValue(Ordering.<Integer>natural()).build(); initList.add( IntArrayFieldInitializer.of( - dependencyInfo, field, ImmutableList.copyOf(arrayInitMap.values()))); + dependencyInfo, + linkageInfo.visibility(), + field, + ImmutableList.copyOf(arrayInitMap.values()))); int index = 0; for (String attr : arrayInitMap.keySet()) { - initList.add(IntFieldInitializer.of(dependencyInfo, field + "_" + attr, index)); + initList.add( + IntFieldInitializer.of( + dependencyInfo, linkageInfo.visibility(), field + "_" + attr, index)); ++index; } } @@ -365,4 +374,16 @@ static String normalizeName(String resourceName) { return resourceName.replace('.', '_'); } + + @AutoValue + abstract static class ResourceLinkageInfo { + abstract DependencyInfo dependencyInfo(); + + abstract Visibility visibility(); + + static ResourceLinkageInfo create(DependencyInfo dependencyInfo, Visibility visibility) { + return new AutoValue_PlaceholderIdFieldInitializerBuilder_ResourceLinkageInfo( + dependencyInfo, visibility); + } + } }
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 077223d..5dc0d86 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
@@ -28,8 +28,7 @@ * * @return true if the initializer is deferred to clinit code. */ - boolean writeFieldDefinition( - ClassWriter cw, int accessLevel, boolean isFinal, boolean annotateTransitiveFields); + boolean writeFieldDefinition(ClassWriter cw, boolean isFinal, boolean annotateTransitiveFields); /** * Write the bytecode for the clinit portion of initializer.
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 e198bce..5ef5506 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
@@ -24,6 +24,7 @@ import org.objectweb.asm.AnnotationVisitor; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.FieldVisitor; +import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import org.objectweb.asm.commons.InstructionAdapter; @@ -33,22 +34,28 @@ private static final String DESC = "[I"; private final DependencyInfo dependencyInfo; + private final Visibility visibility; private final String fieldName; private final ImmutableList<Integer> values; private IntArrayFieldInitializer( - DependencyInfo dependencyInfo, String fieldName, ImmutableList<Integer> values) { + DependencyInfo dependencyInfo, + Visibility visibility, + String fieldName, + ImmutableList<Integer> values) { this.dependencyInfo = dependencyInfo; + this.visibility = visibility; this.fieldName = fieldName; this.values = values; } - public static FieldInitializer of(DependencyInfo dependencyInfo, String fieldName, String value) { + public static FieldInitializer of( + DependencyInfo dependencyInfo, Visibility visibility, String fieldName, String value) { Preconditions.checkArgument(value.startsWith("{ "), "Expected list starting with { "); Preconditions.checkArgument(value.endsWith(" }"), "Expected list ending with } "); // Check for an empty list, which is "{ }". if (value.length() < 4) { - return of(dependencyInfo, fieldName, ImmutableList.of()); + return of(dependencyInfo, visibility, fieldName, ImmutableList.of()); } ImmutableList.Builder<Integer> intValues = ImmutableList.builder(); String trimmedValue = value.substring(2, value.length() - 2); @@ -56,17 +63,27 @@ for (String valueString : valueStrings) { intValues.add(Integer.decode(valueString)); } - return of(dependencyInfo, fieldName, intValues.build()); + return of(dependencyInfo, visibility, fieldName, intValues.build()); } public static IntArrayFieldInitializer of( - DependencyInfo dependencyInfo, String fieldName, ImmutableList<Integer> values) { - return new IntArrayFieldInitializer(dependencyInfo, fieldName, values); + DependencyInfo dependencyInfo, + Visibility visibility, + String fieldName, + ImmutableList<Integer> values) { + return new IntArrayFieldInitializer(dependencyInfo, visibility, fieldName, values); } @Override public boolean writeFieldDefinition( - ClassWriter cw, int accessLevel, boolean isFinal, boolean annotateTransitiveFields) { + ClassWriter cw, boolean isFinal, boolean annotateTransitiveFields) { + int accessLevel = Opcodes.ACC_STATIC; + if (visibility != Visibility.PRIVATE) { + accessLevel |= Opcodes.ACC_PUBLIC; + } + if (isFinal) { + accessLevel |= Opcodes.ACC_FINAL; + } FieldVisitor fv = cw.visitField(accessLevel, fieldName, DESC, null, null); if (annotateTransitiveFields && dependencyInfo.dependencyType() == DependencyInfo.DependencyType.TRANSITIVE) { @@ -113,8 +130,11 @@ writer.write( String.format( - " public static %sint[] %s = { %s };\n", - finalFields ? "final " : "", fieldName, builder.toString())); + " %s static %sint[] %s = { %s };\n", + visibility != Visibility.PRIVATE ? "public" : "", + finalFields ? "final " : "", + fieldName, + builder)); } @Override
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 8948951..b651ca9 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
@@ -17,9 +17,11 @@ import com.google.devtools.build.android.DependencyInfo; import java.io.IOException; import java.io.Writer; +import java.util.Objects; import org.objectweb.asm.AnnotationVisitor; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.FieldVisitor; +import org.objectweb.asm.Opcodes; import org.objectweb.asm.commons.InstructionAdapter; /** Models an int field initializer. */ @@ -28,26 +30,39 @@ private static final String DESC = "I"; private final DependencyInfo dependencyInfo; + private final Visibility visibility; private final String fieldName; private final int value; - private IntFieldInitializer(DependencyInfo dependencyInfo, String fieldName, int value) { + private IntFieldInitializer( + DependencyInfo dependencyInfo, Visibility visibility, String fieldName, int value) { this.dependencyInfo = dependencyInfo; + this.visibility = visibility; this.fieldName = fieldName; this.value = value; } - public static FieldInitializer of(DependencyInfo dependencyInfo, String fieldName, String value) { - return of(dependencyInfo, fieldName, Integer.decode(value)); + public static FieldInitializer of( + DependencyInfo dependencyInfo, Visibility visibility, String fieldName, String value) { + return of(dependencyInfo, visibility, fieldName, Integer.decode(value)); } - public static IntFieldInitializer of(DependencyInfo dependencyInfo, String fieldName, int value) { - return new IntFieldInitializer(dependencyInfo, fieldName, value); + public static IntFieldInitializer of( + DependencyInfo dependencyInfo, Visibility visibility, String fieldName, int value) { + return new IntFieldInitializer(dependencyInfo, visibility, fieldName, value); } @Override public boolean writeFieldDefinition( - ClassWriter cw, int accessLevel, boolean isFinal, boolean annotateTransitiveFields) { + ClassWriter cw, boolean isFinal, boolean annotateTransitiveFields) { + int accessLevel = Opcodes.ACC_STATIC; + if (visibility != Visibility.PRIVATE) { + accessLevel |= Opcodes.ACC_PUBLIC; + } + if (isFinal) { + accessLevel |= Opcodes.ACC_FINAL; + } + FieldVisitor fv = cw.visitField(accessLevel, fieldName, DESC, null, isFinal ? value : null); if (annotateTransitiveFields && dependencyInfo.dependencyType() == DependencyInfo.DependencyType.TRANSITIVE) { @@ -73,8 +88,11 @@ public void writeInitSource(Writer writer, boolean finalFields) throws IOException { writer.write( String.format( - " public static %sint %s = 0x%x;\n", - finalFields ? "final " : "", fieldName, value)); + " %s static %sint %s = 0x%x;\n", + visibility != Visibility.PRIVATE ? "public" : "", + finalFields ? "final " : "", + fieldName, + value)); } @Override @@ -96,7 +114,10 @@ public boolean equals(Object obj) { if (obj instanceof IntFieldInitializer) { IntFieldInitializer other = (IntFieldInitializer) obj; - return value == other.value; + return Objects.equals(dependencyInfo, other.dependencyInfo) + && Objects.equals(visibility, other.visibility) + && Objects.equals(fieldName, other.fieldName) + && value == other.value; } return false; }
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 f1b6a4f..0ed89cd 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
@@ -177,15 +177,10 @@ writeInnerClassHeader(fullyQualifiedOuterClass, innerClass, innerClassWriter); List<FieldInitializer> deferredInitializers = new ArrayList<>(); - int fieldAccessLevel = Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC; - if (finalFields) { - fieldAccessLevel |= Opcodes.ACC_FINAL; - } for (FieldInitializer init : initializers) { JavaIdentifierValidator.validate( init.getFieldName(), "in class:", fullyQualifiedInnerClass, "and package:", packageDir); - if (init.writeFieldDefinition( - innerClassWriter, fieldAccessLevel, finalFields, annotateTransitiveFields)) { + if (init.writeFieldDefinition(innerClassWriter, finalFields, annotateTransitiveFields)) { deferredInitializers.add(init); } }
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 d655df1..095a9e6 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
@@ -77,9 +77,12 @@ FieldInitializer initializer; if ("int".equals(type)) { - initializer = IntFieldInitializer.of(DependencyInfo.UNKNOWN, name, value); + initializer = + IntFieldInitializer.of(DependencyInfo.UNKNOWN, Visibility.UNKNOWN, name, value); } else { - initializer = IntArrayFieldInitializer.of(DependencyInfo.UNKNOWN, name, value); + initializer = + IntArrayFieldInitializer.of( + DependencyInfo.UNKNOWN, Visibility.UNKNOWN, name, value); } initializers