diff options
author | Philip P. Moltmann <moltmann@google.com> | 2017-11-20 09:38:54 -0800 |
---|---|---|
committer | Philip P. Moltmann <moltmann@google.com> | 2017-12-12 12:50:10 -0800 |
commit | 171f097997993b84053f643dc275ce66364315ca (patch) | |
tree | ff5169be265d1ee674c4bd7748d52ca15b5ce20a /dexmaker | |
parent | 61a444d2c7f6c6a81ca2bf54958b02b7cdc81c04 (diff) | |
download | dexmaker-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.gradle | 2 | ||||
-rw-r--r-- | dexmaker/src/main/java/com/android/dx/Code.java | 21 | ||||
-rw-r--r-- | dexmaker/src/main/java/com/android/dx/DexMaker.java | 31 | ||||
-rw-r--r-- | dexmaker/src/main/java/com/android/dx/MethodId.java | 10 | ||||
-rw-r--r-- | dexmaker/src/main/java/com/android/dx/TypeId.java | 4 | ||||
-rw-r--r-- | dexmaker/src/main/java/com/android/dx/stock/ProxyBuilder.java | 68 |
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 "<init>" 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 "<init>" if this is a constructor + * or "<clinit>" 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; |