aboutsummaryrefslogtreecommitdiff
path: root/dexmaker
diff options
context:
space:
mode:
authorPhilip P. Moltmann <moltmann@google.com>2017-11-20 09:38:54 -0800
committerPhilip P. Moltmann <moltmann@google.com>2017-12-12 12:50:10 -0800
commit171f097997993b84053f643dc275ce66364315ca (patch)
treeff5169be265d1ee674c4bd7748d52ca15b5ce20a /dexmaker
parent61a444d2c7f6c6a81ca2bf54958b02b7cdc81c04 (diff)
downloaddexmaker-171f097997993b84053f643dc275ce66364315ca.tar.gz
Update dexmaker to latest (master) state
This adds dexmaker-mockito-inline support and dexmaker-mockito-*-tests. Inline mocking will allow mocking of final methods/classes. Bug: 63538681 Test: cts-tradefed run cts-dev -m CtsMockingTestCases Change-Id: Id8b88639abe0a84642273eae43322df09068a782
Diffstat (limited to 'dexmaker')
-rw-r--r--dexmaker/build.gradle2
-rw-r--r--dexmaker/src/main/java/com/android/dx/Code.java21
-rw-r--r--dexmaker/src/main/java/com/android/dx/DexMaker.java31
-rw-r--r--dexmaker/src/main/java/com/android/dx/MethodId.java10
-rw-r--r--dexmaker/src/main/java/com/android/dx/TypeId.java4
-rw-r--r--dexmaker/src/main/java/com/android/dx/stock/ProxyBuilder.java68
6 files changed, 84 insertions, 52 deletions
diff --git a/dexmaker/build.gradle b/dexmaker/build.gradle
index eb337ec..73c9344 100644
--- a/dexmaker/build.gradle
+++ b/dexmaker/build.gradle
@@ -13,6 +13,4 @@ repositories {
dependencies {
compile 'com.jakewharton.android.repackaged:dalvik-dx:7.1.0_r7'
-
- testCompile 'junit:junit:4.12'
}
diff --git a/dexmaker/src/main/java/com/android/dx/Code.java b/dexmaker/src/main/java/com/android/dx/Code.java
index 721d659..715d2b4 100644
--- a/dexmaker/src/main/java/com/android/dx/Code.java
+++ b/dexmaker/src/main/java/com/android/dx/Code.java
@@ -534,13 +534,24 @@ public final class Code {
*/
public <T> void compare(Comparison comparison, Label trueLabel, Local<T> a, Local<T> b) {
adopt(trueLabel);
- // TODO: ops to compare with zero/null: just omit the 2nd local in StdTypeList.make()
Rop rop = comparison.rop(StdTypeList.make(a.type.ropType, b.type.ropType));
addInstruction(new PlainInsn(rop, sourcePosition, null,
RegisterSpecList.make(a.spec(), b.spec())), trueLabel);
}
/**
+ * Check if an int or reference equals to zero. If the comparison is true,
+ * execution jumps to {@code trueLabel}. If it is false, execution continues to
+ * the next instruction.
+ */
+ public <T> void compareZ(Comparison comparison, Label trueLabel, Local<?> a) {
+ adopt(trueLabel);
+ Rop rop = comparison.rop(StdTypeList.make(a.type.ropType));
+ addInstruction(new PlainInsn(rop, sourcePosition, null,
+ RegisterSpecList.make(a.spec())), trueLabel);
+ }
+
+ /**
* Compare floats or doubles. This stores -1 in {@code target} if {@code
* a < b}, 0 in {@code target} if {@code a == b} and 1 in target if {@code
* a > b}. This stores {@code nanValue} in {@code target} if either value
@@ -576,7 +587,7 @@ public final class Code {
* Copies the value in instance field {@code fieldId} of {@code instance} to
* {@code target}.
*/
- public <D, V> void iget(FieldId<D, V> fieldId, Local<V> target, Local<D> instance) {
+ public <D, V> void iget(FieldId<D, ? extends V> fieldId, Local<V> target, Local<D> instance) {
addInstruction(new ThrowingCstInsn(Rops.opGetField(target.type.ropType), sourcePosition,
RegisterSpecList.make(instance.spec()), catches, fieldId.constant));
moveResult(target, true);
@@ -586,7 +597,7 @@ public final class Code {
* Copies the value in {@code source} to the instance field {@code fieldId}
* of {@code instance}.
*/
- public <D, V> void iput(FieldId<D, V> fieldId, Local<D> instance, Local<V> source) {
+ public <D, V> void iput(FieldId<D, V> fieldId, Local<? extends D> instance, Local<? extends V> source) {
addInstruction(new ThrowingCstInsn(Rops.opPutField(source.type.ropType), sourcePosition,
RegisterSpecList.make(source.spec(), instance.spec()), catches, fieldId.constant));
}
@@ -594,7 +605,7 @@ public final class Code {
/**
* Copies the value in the static field {@code fieldId} to {@code target}.
*/
- public <V> void sget(FieldId<?, V> fieldId, Local<V> target) {
+ public <V> void sget(FieldId<?, ? extends V> fieldId, Local<V> target) {
addInstruction(new ThrowingCstInsn(Rops.opGetStatic(target.type.ropType), sourcePosition,
RegisterSpecList.EMPTY, catches, fieldId.constant));
moveResult(target, true);
@@ -603,7 +614,7 @@ public final class Code {
/**
* Copies the value in {@code source} to the static field {@code fieldId}.
*/
- public <V> void sput(FieldId<?, V> fieldId, Local<V> source) {
+ public <V> void sput(FieldId<?, V> fieldId, Local<? extends V> source) {
addInstruction(new ThrowingCstInsn(Rops.opPutStatic(source.type.ropType), sourcePosition,
RegisterSpecList.make(source.spec()), catches, fieldId.constant));
}
diff --git a/dexmaker/src/main/java/com/android/dx/DexMaker.java b/dexmaker/src/main/java/com/android/dx/DexMaker.java
index ee8d722..f10ad8e 100644
--- a/dexmaker/src/main/java/com/android/dx/DexMaker.java
+++ b/dexmaker/src/main/java/com/android/dx/DexMaker.java
@@ -31,14 +31,12 @@ import com.android.dx.rop.code.RopMethod;
import com.android.dx.rop.cst.CstString;
import com.android.dx.rop.cst.CstType;
import com.android.dx.rop.type.StdTypeList;
-import com.android.dx.stock.ProxyBuilder;
+
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Modifier;
-import dalvik.system.DexClassLoader;
-
import java.util.Arrays;
import java.util.Iterator;
import java.util.LinkedHashMap;
@@ -199,6 +197,7 @@ import static java.lang.reflect.Modifier.STATIC;
*/
public final class DexMaker {
private final Map<TypeId<?>, TypeDeclaration> types = new LinkedHashMap<>();
+ private ClassLoader sharedClassLoader;
/**
* Creates a new {@code DexMaker} instance, which can be used to create a
@@ -269,7 +268,7 @@ public final class DexMaker {
flags = (flags & ~Modifier.SYNCHRONIZED) | AccessFlags.ACC_DECLARED_SYNCHRONIZED;
}
- if (method.isConstructor()) {
+ if (method.isConstructor() || method.isStaticInitializer()) {
flags |= ACC_CONSTRUCTOR;
}
@@ -357,15 +356,16 @@ public final class DexMaker {
return "Generated_" + checksum +".jar";
}
- private ClassLoader generateClassLoader(ClassLoader classLoader, File result, File dexCache,
- ClassLoader parent) {
+ public void setSharedClassLoader(ClassLoader classLoader) {
+ this.sharedClassLoader = classLoader;
+ }
+
+ private ClassLoader generateClassLoader(File result, File dexCache, ClassLoader parent) {
try {
- boolean shareClassLoader = Boolean.parseBoolean(System.getProperty(
- "dexmaker.share_classloader", "false"));
- if (shareClassLoader) {
- ClassLoader loader = parent != null ? parent : classLoader;
+ if (sharedClassLoader != null) {
+ ClassLoader loader = parent != null ? parent : sharedClassLoader;
loader.getClass().getMethod("addDexPath", String.class).invoke(loader,
- result.getPath());
+ result.getPath());
return loader;
} else {
return (ClassLoader) Class.forName("dalvik.system.DexClassLoader")
@@ -411,11 +411,6 @@ public final class DexMaker {
* application's private data dir.
*/
public ClassLoader generateAndLoad(ClassLoader parent, File dexCache) throws IOException {
- return generateAndLoad(parent, parent, dexCache);
- }
-
- public ClassLoader generateAndLoad(ClassLoader classLoader, ClassLoader parent, File dexCache)
- throws IOException {
if (dexCache == null) {
String property = System.getProperty("dexmaker.dexcache");
if (property != null) {
@@ -433,7 +428,7 @@ public final class DexMaker {
// Check that the file exists. If it does, return a DexClassLoader and skip all
// the dex bytecode generation.
if (result.exists()) {
- return generateClassLoader(classLoader, result, dexCache, parent);
+ return generateClassLoader(result, dexCache, parent);
}
byte[] dex = generate();
@@ -453,7 +448,7 @@ public final class DexMaker {
jarOut.write(dex);
jarOut.closeEntry();
jarOut.close();
- return generateClassLoader(classLoader, result, dexCache, parent);
+ return generateClassLoader(result, dexCache, parent);
}
private static class TypeDeclaration {
diff --git a/dexmaker/src/main/java/com/android/dx/MethodId.java b/dexmaker/src/main/java/com/android/dx/MethodId.java
index 746d73e..d891b97 100644
--- a/dexmaker/src/main/java/com/android/dx/MethodId.java
+++ b/dexmaker/src/main/java/com/android/dx/MethodId.java
@@ -66,7 +66,15 @@ public final class MethodId<D, R> {
}
/**
- * Returns the method's name. This is "&lt;init&gt;" if this is a constructor.
+ * Returns true if this method is the static initializer for its declaring class.
+ */
+ public boolean isStaticInitializer() {
+ return name.equals("<clinit>");
+ }
+
+ /**
+ * Returns the method's name. This is "&lt;init&gt;" if this is a constructor
+ * or "&lt;clinit&gt;" if a static initializer
*/
public String getName() {
return name;
diff --git a/dexmaker/src/main/java/com/android/dx/TypeId.java b/dexmaker/src/main/java/com/android/dx/TypeId.java
index de96028..7131f33 100644
--- a/dexmaker/src/main/java/com/android/dx/TypeId.java
+++ b/dexmaker/src/main/java/com/android/dx/TypeId.java
@@ -123,6 +123,10 @@ public final class TypeId<T> {
return new MethodId<>(this, VOID, "<init>", new TypeList(parameters));
}
+ public MethodId<T, Void> getStaticInitializer() {
+ return new MethodId<>(this, VOID, "<clinit>", new TypeList(new TypeId[0]));
+ }
+
public <R> MethodId<T, R> getMethod(TypeId<R> returnType, String name, TypeId<?>... parameters) {
return new MethodId<>(this, returnType, name, new TypeList(parameters));
}
diff --git a/dexmaker/src/main/java/com/android/dx/stock/ProxyBuilder.java b/dexmaker/src/main/java/com/android/dx/stock/ProxyBuilder.java
index b618c84..1363894 100644
--- a/dexmaker/src/main/java/com/android/dx/stock/ProxyBuilder.java
+++ b/dexmaker/src/main/java/com/android/dx/stock/ProxyBuilder.java
@@ -140,6 +140,8 @@ public final class ProxyBuilder<T> {
private Class<?>[] constructorArgTypes = new Class[0];
private Object[] constructorArgValues = new Object[0];
private Set<Class<?>> interfaces = new HashSet<>();
+ private Method[] methods;
+ private boolean sharedClassLoader;
private ProxyBuilder(Class<T> clazz) {
baseClass = clazz;
@@ -195,6 +197,16 @@ public final class ProxyBuilder<T> {
return this;
}
+ public ProxyBuilder<T> onlyMethods(Method[] methods) {
+ this.methods = methods;
+ return this;
+ }
+
+ public ProxyBuilder<T> withSharedClassLoader() {
+ this.sharedClassLoader = true;
+ return this;
+ }
+
/**
* Create a new instance of the class to proxy.
*
@@ -249,12 +261,10 @@ public final class ProxyBuilder<T> {
@SuppressWarnings("unchecked")
Class<? extends T> proxyClass = (Class) generatedProxyClasses.get(baseClass);
if (proxyClass != null) {
- boolean shareClassLoader = Boolean.parseBoolean(System.getProperty(
- "dexmaker.share_classloader", "false"));
boolean validClassLoader;
- if (shareClassLoader) {
- ClassLoader parent = parentClassLoader != null ? parentClassLoader
- : baseClass.getClassLoader();
+ if (sharedClassLoader) {
+ ClassLoader parent = parentClassLoader != null ? parentClassLoader : baseClass
+ .getClassLoader();
validClassLoader = proxyClass.getClassLoader() == parent;
} else {
validClassLoader = proxyClass.getClassLoader().getParent() == parentClassLoader;
@@ -270,11 +280,28 @@ public final class ProxyBuilder<T> {
TypeId<? extends T> generatedType = TypeId.get("L" + generatedName + ";");
TypeId<T> superType = TypeId.get(baseClass);
generateConstructorsAndFields(dexMaker, generatedType, superType, baseClass);
- Method[] methodsToProxy = getMethodsToProxyRecursive();
+
+ Method[] methodsToProxy;
+ if (methods == null) {
+ methodsToProxy = getMethodsToProxyRecursive();
+ } else {
+ methodsToProxy = methods;
+ }
+
+ // Sort the results array so that they are in a deterministic fashion.
+ Arrays.sort(methodsToProxy, new Comparator<Method>() {
+ @Override
+ public int compare(Method method1, Method method2) {
+ return method1.toString().compareTo(method2.toString());
+ }
+ });
+
generateCodeForAllMethods(dexMaker, generatedType, methodsToProxy, superType);
dexMaker.declare(generatedType, generatedName + ".generated", PUBLIC, superType, getInterfacesAsTypeIds());
- ClassLoader classLoader = dexMaker.generateAndLoad(baseClass.getClassLoader(),
- parentClassLoader, dexCache);
+ if (sharedClassLoader) {
+ dexMaker.setSharedClassLoader(baseClass.getClassLoader());
+ }
+ ClassLoader classLoader = dexMaker.generateAndLoad(parentClassLoader, dexCache);
try {
proxyClass = loadClass(classLoader, generatedName);
} catch (IllegalAccessError e) {
@@ -654,22 +681,11 @@ public final class ProxyBuilder<T> {
results[i++] = entry.originalMethod;
}
- // Sort the results array so that they are returned by this method
- // in a deterministic fashion.
- Arrays.sort(results, new Comparator<Method>() {
- @Override
- public int compare(Method method1, Method method2) {
- return method1.toString().compareTo(method2.toString());
- }
- });
-
return results;
}
private void getMethodsToProxy(Set<MethodSetEntry> sink, Set<MethodSetEntry> seenFinalMethods,
Class<?> c) {
- boolean shareClassLoader = Boolean.parseBoolean(System.getProperty(
- "dexmaker.share_classloader", "false"));
for (Method method : c.getDeclaredMethods()) {
if ((method.getModifiers() & Modifier.FINAL) != 0) {
// Skip final methods, we can't override them. We
@@ -687,8 +703,8 @@ public final class ProxyBuilder<T> {
continue;
}
if (!Modifier.isPublic(method.getModifiers())
- && !Modifier.isProtected(method.getModifiers())
- && (!shareClassLoader || Modifier.isPrivate(method.getModifiers()))) {
+ && !Modifier.isProtected(method.getModifiers())
+ && (!sharedClassLoader || Modifier.isPrivate(method.getModifiers()))) {
// Skip private methods, since they are invoked through direct
// invocation (as opposed to virtual). Therefore, it would not
// be possible to intercept any private method defined inside
@@ -820,11 +836,11 @@ public final class ProxyBuilder<T> {
* another. For these purposes, we consider two methods to be equal if they have the same
* name, return type, and parameter types.
*/
- private static class MethodSetEntry {
- private final String name;
- private final Class<?>[] paramTypes;
- private final Class<?> returnType;
- private final Method originalMethod;
+ public static class MethodSetEntry {
+ public final String name;
+ public final Class<?>[] paramTypes;
+ public final Class<?> returnType;
+ public final Method originalMethod;
public MethodSetEntry(Method method) {
originalMethod = method;