aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/tools/android/java/com/google/devtools
diff options
context:
space:
mode:
authorGravatar Andrew Pellegrini <apell@google.com>2016-08-31 15:15:35 +0000
committerGravatar Klaus Aehlig <aehlig@google.com>2016-09-01 08:30:36 +0000
commit193e1d46d70a6d1044670996cc7372031194b74d (patch)
tree941a6c4c8495feacdd66a60d42c6c8efe32b42d0 /src/tools/android/java/com/google/devtools
parentd82f4a568df7bdc71e5eda53249b05046a4ac43a (diff)
Add parsing of Proguard mapping file for resource class fields. Fixes issue with obfuscated fields being stripped because they fail to match any known resource.
-- MOS_MIGRATED_REVID=131830443
Diffstat (limited to 'src/tools/android/java/com/google/devtools')
-rw-r--r--src/tools/android/java/com/google/devtools/build/android/ResourceShrinker.java70
1 files changed, 58 insertions, 12 deletions
diff --git a/src/tools/android/java/com/google/devtools/build/android/ResourceShrinker.java b/src/tools/android/java/com/google/devtools/build/android/ResourceShrinker.java
index 9d12f06dec..280c5e921f 100644
--- a/src/tools/android/java/com/google/devtools/build/android/ResourceShrinker.java
+++ b/src/tools/android/java/com/google/devtools/build/android/ResourceShrinker.java
@@ -55,6 +55,7 @@ import com.android.ide.common.xml.XmlPrettyPrinter;
import com.android.resources.FolderTypeRelationship;
import com.android.resources.ResourceFolderType;
import com.android.resources.ResourceType;
+import com.android.utils.Pair;
import com.android.utils.XmlUtils;
import org.objectweb.asm.ClassReader;
@@ -157,11 +158,12 @@ public class ResourceShrinker {
private Map<ResourceType, Map<String, Resource>> typeToName =
Maps.newEnumMap(ResourceType.class);
/**
- * Map from resource class owners (VM format class) to corresponding resource types. This will
- * typically be the fully qualified names of the R classes, as well as any renamed versions of
- * those discovered in the mapping.txt file from ProGuard
+ * Map from resource class owners (VM format class) to corresponding resource entries.
+ * This lets us map back from code references (obfuscated class and possibly obfuscated field
+ * reference) back to the corresponding resource type and name.
*/
- private Map<String, ResourceType> resourceClassOwners = Maps.newHashMapWithExpectedSize(20);
+ private final Map<String, Pair<ResourceType, Map<String, String>>> resourceObfuscation =
+ Maps.newHashMapWithExpectedSize(30);
public ResourceShrinker(
Set<String> resourcePackages,
@@ -680,9 +682,36 @@ public class ResourceShrinker {
}
final String arrowIndicator = " -> ";
final String resourceIndicator = ".R$";
+ Map<String, String> nameMap = null;
for (String line : Files.readLines(mapping.toFile(), UTF_8)) {
if (line.startsWith(" ") || line.startsWith("\t")) {
+ if (nameMap != null) {
+ // We're processing the members of a resource class: record names into the map
+ int n = line.length();
+ int i = 0;
+ for (; i < n; i++) {
+ if (!Character.isWhitespace(line.charAt(i))) {
+ break;
+ }
+ }
+ if (i < n && line.startsWith("int", i)) { // int or int[]
+ int start = line.indexOf(' ', i + 3) + 1;
+ int arrow = line.indexOf(arrowIndicator);
+ if (start > 0 && arrow != -1) {
+ int end = line.indexOf(' ', start + 1);
+ if (end != -1) {
+ String oldName = line.substring(start, end);
+ String newName = line.substring(arrow + arrowIndicator.length()).trim();
+ if (!newName.equals(oldName)) {
+ nameMap.put(newName, oldName);
+ }
+ }
+ }
+ }
+ }
continue;
+ } else {
+ nameMap = null;
}
int index = line.indexOf(resourceIndicator);
if (index == -1) {
@@ -703,7 +732,10 @@ public class ResourceShrinker {
}
String target = line.substring(arrow + arrowIndicator.length(), end).trim();
String ownerName = target.replace('.', '/');
- resourceClassOwners.put(ownerName, type);
+
+ nameMap = Maps.newHashMap();
+ Pair<ResourceType, Map<String, String>> pair = Pair.of(type, nameMap);
+ resourceObfuscation.put(ownerName, pair);
}
}
@@ -740,6 +772,22 @@ public class ResourceShrinker {
return null;
}
+ @VisibleForTesting
+ @Nullable
+ Resource getResourceFromCode(@NonNull String owner, @NonNull String name) {
+ Pair<ResourceType, Map<String, String>> pair = resourceObfuscation.get(owner);
+ if (pair != null) {
+ ResourceType type = pair.getFirst();
+ Map<String, String> nameMap = pair.getSecond();
+ String renamedField = nameMap.get(name);
+ if (renamedField != null) {
+ name = renamedField;
+ }
+ return getResource(type, name);
+ }
+ return null;
+ }
+
private void recordManifestUsages(Node node) {
short nodeType = node.getNodeType();
if (nodeType == Node.ELEMENT_NODE) {
@@ -945,7 +993,8 @@ public class ResourceShrinker {
String[] tokens = line.split(" ");
ResourceType type = ResourceType.getEnum(tokens[1]);
for (String resourcePackage : resourcePackages) {
- resourceClassOwners.put(resourcePackage.replace('.', '/') + "/R$" + type.getName(), type);
+ resourceObfuscation.put(resourcePackage.replace('.', '/') + "/R$" + type.getName(),
+ Pair.<ResourceType, Map<String, String>>of(type, Maps.<String, String>newHashMap()));
}
if (type == ResourceType.STYLEABLE) {
if (tokens[0].equals("int[]")) {
@@ -1113,12 +1162,9 @@ public class ResourceShrinker {
@Override
public void visitFieldInsn(int opcode, String owner, String name, String desc) {
if (opcode == Opcodes.GETSTATIC) {
- ResourceType type = resourceClassOwners.get(owner);
- if (type != null) {
- Resource resource = getResource(type, name);
- if (resource != null) {
- markReachable(resource);
- }
+ Resource resource = getResourceFromCode(owner, name);
+ if (resource != null) {
+ markReachable(resource);
}
}
}