aboutsummaryrefslogtreecommitdiff
path: root/dexlib2/src
diff options
context:
space:
mode:
authorBen Gruver <bgruv@google.com>2016-02-20 11:56:22 -0800
committerBen Gruver <bgruv@google.com>2016-02-26 21:13:29 -0800
commit6417e812e167c87c53655a6c27af35aea34faca5 (patch)
treebc77f7b0c86158409d871b350b9602a66868f502 /dexlib2/src
parentaebb205aebd103044de0b62fb9e971631f396057 (diff)
downloadsmali-6417e812e167c87c53655a6c27af35aea34faca5.tar.gz
Refactor ClassPath to take ClassProviders
This allows for a more general mechanism for providing defined classes
Diffstat (limited to 'dexlib2/src')
-rw-r--r--dexlib2/src/main/java/org/jf/dexlib2/analysis/ClassPath.java107
-rw-r--r--dexlib2/src/main/java/org/jf/dexlib2/analysis/ClassProvider.java40
-rw-r--r--dexlib2/src/main/java/org/jf/dexlib2/analysis/DexClassProvider.java56
-rw-r--r--dexlib2/src/test/java/org/jf/dexlib2/analysis/CommonSuperclassTest.java4
-rw-r--r--dexlib2/src/test/java/org/jf/dexlib2/analysis/util/SuperclassChainTest.java6
5 files changed, 145 insertions, 68 deletions
diff --git a/dexlib2/src/main/java/org/jf/dexlib2/analysis/ClassPath.java b/dexlib2/src/main/java/org/jf/dexlib2/analysis/ClassPath.java
index cf75dffe..9f9e396b 100644
--- a/dexlib2/src/main/java/org/jf/dexlib2/analysis/ClassPath.java
+++ b/dexlib2/src/main/java/org/jf/dexlib2/analysis/ClassPath.java
@@ -36,7 +36,9 @@ import com.google.common.base.Suppliers;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
-import com.google.common.collect.*;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Lists;
import org.jf.dexlib2.DexFileFactory;
import org.jf.dexlib2.DexFileFactory.DexFileNotFound;
import org.jf.dexlib2.DexFileFactory.MultipleDexFilesException;
@@ -52,63 +54,41 @@ import javax.annotation.Nonnull;
import java.io.File;
import java.io.IOException;
import java.io.Serializable;
-import java.util.ArrayList;
-import java.util.HashMap;
+import java.util.Arrays;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class ClassPath {
@Nonnull private final TypeProto unknownClass;
- @Nonnull private HashMap<String, ClassDef> availableClasses = Maps.newHashMap();
+ @Nonnull private List<ClassProvider> classProviders;
private final boolean checkPackagePrivateAccess;
public final int oatVersion;
public static final int NOT_ART = -1;
/**
- * Creates a new ClassPath instance that can load classes from the given dex files
+ * Creates a new ClassPath instance that can load classes from the given providers
*
- * @param classPath An array of DexFile objects. When loading a class, these dex files will be searched in order
+ * @param classProviders An iterable of ClassProviders. When loading a class, these providers will be searched in
+ * order
*/
- public ClassPath(DexFile... classPath) throws IOException {
- this(Lists.newArrayList(classPath), 15);
+ public ClassPath(ClassProvider... classProviders) throws IOException {
+ this(Arrays.asList(classProviders), false, NOT_ART);
}
/**
- * Creates a new ClassPath instance that can load classes from the given dex files
+ * Creates a new ClassPath instance that can load classes from the given providers
*
- * @param classPath An iterable of DexFile objects. When loading a class, these dex files will be searched in order
- * @param api API level
- */
- public ClassPath(@Nonnull Iterable<? extends DexFile> classPath, int api) {
- this(Lists.newArrayList(classPath), api == 17);
- }
-
- /**
- * Creates a new ClassPath instance that can load classes from the given dex files
- *
- * @param classPath An iterable of DexFile objects. When loading a class, these dex files will be searched in order
- * @param checkPackagePrivateAccess Whether checkPackagePrivateAccess is needed, enabled for ONLY early API 17 by
- * default
- */
- public ClassPath(@Nonnull Iterable<? extends DexFile> classPath, boolean checkPackagePrivateAccess) {
- this(classPath, checkPackagePrivateAccess, NOT_ART);
- }
-
- /**
- * Creates a new ClassPath instance that can load classes from the given dex files
- *
- * @param classPath An iterable of DexFile objects. When loading a class, these dex files will be searched in order
+ * @param classProviders An iterable of ClassProviders. When loading a class, these providers will be searched in
+ * order
* @param checkPackagePrivateAccess Whether checkPackagePrivateAccess is needed, enabled for ONLY early API 17 by
* default
* @param oatVersion The applicable oat version, or NOT_ART
*/
- public ClassPath(@Nonnull Iterable<? extends DexFile> classPath, boolean checkPackagePrivateAccess,
+ public ClassPath(@Nonnull Iterable<? extends ClassProvider> classProviders, boolean checkPackagePrivateAccess,
int oatVersion) {
// add fallbacks for certain special classes that must be present
- Iterable<DexFile> dexFiles = Iterables.concat(classPath, Lists.newArrayList(getBasicClasses()));
-
unknownClass = new UnknownClassProto(this);
loadedClasses.put(unknownClass.getType(), unknownClass);
this.checkPackagePrivateAccess = checkPackagePrivateAccess;
@@ -124,30 +104,23 @@ public class ClassPath {
loadPrimitiveType("D");
loadPrimitiveType("L");
- for (DexFile dexFile: dexFiles) {
- for (ClassDef classDef: dexFile.getClasses()) {
- ClassDef prev = availableClasses.get(classDef.getType());
- if (prev == null) {
- availableClasses.put(classDef.getType(), classDef);
- }
- }
- }
+ this.classProviders = Lists.newArrayList(classProviders);
+ this.classProviders.add(getBasicClasses());
}
private void loadPrimitiveType(String type) {
loadedClasses.put(type, new PrimitiveProto(this, type));
}
- private static DexFile getBasicClasses() {
+ private static ClassProvider getBasicClasses() {
// fallbacks for some special classes that we assume are present
- return new ImmutableDexFile(Opcodes.forApi(19),
- ImmutableSet.of(
- new ReflectionClassDef(Class.class),
- new ReflectionClassDef(Cloneable.class),
- new ReflectionClassDef(Object.class),
- new ReflectionClassDef(Serializable.class),
- new ReflectionClassDef(String.class),
- new ReflectionClassDef(Throwable.class)));
+ return new DexClassProvider(new ImmutableDexFile(Opcodes.forApi(19), ImmutableSet.of(
+ new ReflectionClassDef(Class.class),
+ new ReflectionClassDef(Cloneable.class),
+ new ReflectionClassDef(Object.class),
+ new ReflectionClassDef(Serializable.class),
+ new ReflectionClassDef(String.class),
+ new ReflectionClassDef(Throwable.class))));
}
public boolean isArt() {
@@ -173,11 +146,13 @@ public class ClassPath {
@Nonnull
public ClassDef getClassDef(String type) {
- ClassDef ret = availableClasses.get(type);
- if (ret == null) {
- throw new UnresolvedClassException("Could not resolve class %s", type);
+ for (ClassProvider provider: classProviders) {
+ ClassDef classDef = provider.getClassDef(type);
+ if (classDef != null) {
+ return classDef;
+ }
}
- return ret;
+ throw new UnresolvedClassException("Could not resolve class %s", type);
}
@Nonnull
@@ -198,7 +173,7 @@ public class ClassPath {
@Nonnull
public static ClassPath fromClassPath(Iterable<String> classPathDirs, Iterable<String> classPath, DexFile dexFile,
int api, boolean checkPackagePrivateAccess, boolean experimental) {
- ArrayList<DexFile> dexFiles = Lists.newArrayList();
+ List<ClassProvider> providers = Lists.newArrayList();
int oatVersion = NOT_ART;
@@ -213,23 +188,29 @@ public class ClassPath {
}
}
}
- dexFiles.addAll(classPathDexFiles);
+ for (DexFile classPathDexFile: classPathDexFiles) {
+ providers.add(new DexClassProvider(classPathDexFile));
+ }
}
- dexFiles.add(dexFile);
- return new ClassPath(dexFiles, checkPackagePrivateAccess, oatVersion);
+ providers.add(new DexClassProvider(dexFile));
+ return new ClassPath(providers, checkPackagePrivateAccess, oatVersion);
}
@Nonnull
public static ClassPath fromClassPath(Iterable<String> classPathDirs, Iterable<String> classPath, DexFile dexFile,
int api, boolean checkPackagePrivateAccess, boolean experimental,
int oatVersion) {
- ArrayList<DexFile> dexFiles = Lists.newArrayList();
+ List<ClassProvider> providers = Lists.newArrayList();
for (String classPathEntry: classPath) {
- dexFiles.addAll(loadClassPathEntry(classPathDirs, classPathEntry, api, experimental));
+ List<? extends DexFile> classPathDexFiles =
+ loadClassPathEntry(classPathDirs, classPathEntry, api, experimental);
+ for (DexFile classPathDexFile: classPathDexFiles) {
+ providers.add(new DexClassProvider(classPathDexFile));
+ }
}
- dexFiles.add(dexFile);
- return new ClassPath(dexFiles, checkPackagePrivateAccess, oatVersion);
+ providers.add(new DexClassProvider(dexFile));
+ return new ClassPath(providers, checkPackagePrivateAccess, oatVersion);
}
private static final Pattern dalvikCacheOdexPattern = Pattern.compile("@([^@]+)@classes.dex$");
diff --git a/dexlib2/src/main/java/org/jf/dexlib2/analysis/ClassProvider.java b/dexlib2/src/main/java/org/jf/dexlib2/analysis/ClassProvider.java
new file mode 100644
index 00000000..7c823ff0
--- /dev/null
+++ b/dexlib2/src/main/java/org/jf/dexlib2/analysis/ClassProvider.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.jf.dexlib2.analysis;
+
+import org.jf.dexlib2.iface.ClassDef;
+
+import javax.annotation.Nullable;
+
+public interface ClassProvider {
+ @Nullable ClassDef getClassDef(String type);
+}
diff --git a/dexlib2/src/main/java/org/jf/dexlib2/analysis/DexClassProvider.java b/dexlib2/src/main/java/org/jf/dexlib2/analysis/DexClassProvider.java
new file mode 100644
index 00000000..c460cc3f
--- /dev/null
+++ b/dexlib2/src/main/java/org/jf/dexlib2/analysis/DexClassProvider.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.jf.dexlib2.analysis;
+
+import com.google.common.collect.Maps;
+import org.jf.dexlib2.iface.ClassDef;
+import org.jf.dexlib2.iface.DexFile;
+
+import javax.annotation.Nullable;
+import java.util.Map;
+
+public class DexClassProvider implements ClassProvider {
+ private final DexFile dexFile;
+ private Map<String, ClassDef> classMap = Maps.newHashMap();
+
+ public DexClassProvider(DexFile dexFile) {
+ this.dexFile = dexFile;
+
+ for (ClassDef classDef: dexFile.getClasses()) {
+ classMap.put(classDef.getType(), classDef);
+ }
+ }
+
+ @Nullable @Override public ClassDef getClassDef(String type) {
+ return classMap.get(type);
+ }
+}
diff --git a/dexlib2/src/test/java/org/jf/dexlib2/analysis/CommonSuperclassTest.java b/dexlib2/src/test/java/org/jf/dexlib2/analysis/CommonSuperclassTest.java
index 521290f0..3f1ee56d 100644
--- a/dexlib2/src/test/java/org/jf/dexlib2/analysis/CommonSuperclassTest.java
+++ b/dexlib2/src/test/java/org/jf/dexlib2/analysis/CommonSuperclassTest.java
@@ -54,7 +54,7 @@ public class CommonSuperclassTest {
private final ClassPath classPath;
public CommonSuperclassTest() throws IOException {
- classPath = new ClassPath(new ImmutableDexFile(Opcodes.forApi(19),
+ classPath = new ClassPath(new DexClassProvider(new ImmutableDexFile(Opcodes.forApi(19),
ImmutableSet.of(
TestUtils.makeClassDef("Ljava/lang/Object;", null),
TestUtils.makeClassDef("Ltest/one;", "Ljava/lang/Object;"),
@@ -89,7 +89,7 @@ public class CommonSuperclassTest {
TestUtils.makeClassDef("Liface/classsubsub4;", "Liface/classsub4;"),
TestUtils.makeClassDef("Liface/classsub1234;", "Ljava/lang/Object;", "Liface/sub1;",
"Liface/sub2;", "Liface/sub3;", "Liface/sub4;")
- )));
+ ))));
}
public void superclassTest(String commonSuperclass,
diff --git a/dexlib2/src/test/java/org/jf/dexlib2/analysis/util/SuperclassChainTest.java b/dexlib2/src/test/java/org/jf/dexlib2/analysis/util/SuperclassChainTest.java
index c9a9af95..84cd284b 100644
--- a/dexlib2/src/test/java/org/jf/dexlib2/analysis/util/SuperclassChainTest.java
+++ b/dexlib2/src/test/java/org/jf/dexlib2/analysis/util/SuperclassChainTest.java
@@ -36,6 +36,7 @@ import com.google.common.collect.ImmutableSet;
import junit.framework.Assert;
import org.jf.dexlib2.Opcodes;
import org.jf.dexlib2.analysis.ClassPath;
+import org.jf.dexlib2.analysis.DexClassProvider;
import org.jf.dexlib2.analysis.TestUtils;
import org.jf.dexlib2.analysis.TypeProto;
import org.jf.dexlib2.iface.ClassDef;
@@ -46,7 +47,6 @@ import java.io.IOException;
public class SuperclassChainTest {
-
@Test
public void testGetSuperclassChain() throws IOException {
ClassDef objectClassDef = TestUtils.makeClassDef("Ljava/lang/Object;", null);
@@ -57,7 +57,7 @@ public class SuperclassChainTest {
ImmutableSet<ClassDef> classes = ImmutableSet.<ClassDef>of(
objectClassDef, oneClassDef, twoClassDef, threeClassDef);
- ClassPath classPath = new ClassPath(new ImmutableDexFile(Opcodes.forApi(19), classes));
+ ClassPath classPath = new ClassPath(new DexClassProvider(new ImmutableDexFile(Opcodes.forApi(19), classes)));
TypeProto objectClassProto = classPath.getClass("Ljava/lang/Object;");
TypeProto oneClassProto = classPath.getClass("Ltest/one;");
@@ -88,7 +88,7 @@ public class SuperclassChainTest {
ClassDef twoClassDef = TestUtils.makeClassDef("Ltest/two;", "Ltest/one;");
ClassDef threeClassDef = TestUtils.makeClassDef("Ltest/three;", "Ltest/two;");
ImmutableSet<ClassDef> classes = ImmutableSet.<ClassDef>of(twoClassDef, threeClassDef);
- ClassPath classPath = new ClassPath(new ImmutableDexFile(Opcodes.forApi(19), classes));
+ ClassPath classPath = new ClassPath(new DexClassProvider(new ImmutableDexFile(Opcodes.forApi(19), classes)));
TypeProto unknownClassProto = classPath.getUnknownClass();
TypeProto oneClassProto = classPath.getClass("Ltest/one;");