aboutsummaryrefslogtreecommitdiff
path: root/dexmaker
diff options
context:
space:
mode:
authorPhilip P. Moltmann <moltmann@google.com>2018-05-21 19:15:56 +0000
committerPhilip P. Moltmann <moltmann@google.com>2018-05-21 13:09:05 -0700
commit314cb2efb7b1d8d9b584a6e0bd82727168cfd181 (patch)
tree3b848189d1bc1a2238caf1d1285953232c35806a /dexmaker
parent8738f6764b9f61eb11ad678cad6d9434b4133731 (diff)
downloaddexmaker-pie-qpr1-s1-release.tar.gz
This reverts commit 8738f6764b9f61eb11ad678cad6d9434b4133731. Reason for revert: This was only a temporary revert. Now that the real issue is fixed, we can submit this again Bug: 80041014 Test: vts-tradefed run host --class com.android.tradefed.device.metric.VtsCoverageCollectorTest atest CtsActivityManagerDeviceTestCases atest CtsInputMethodTestCases Change-Id: I8d0ac45e3fe73c1870cf08f989b6d39f09923183
Diffstat (limited to 'dexmaker')
-rw-r--r--dexmaker/src/main/java/com/android/dx/DexMaker.java44
-rw-r--r--dexmaker/src/main/java/com/android/dx/stock/ProxyBuilder.java14
2 files changed, 58 insertions, 0 deletions
diff --git a/dexmaker/src/main/java/com/android/dx/DexMaker.java b/dexmaker/src/main/java/com/android/dx/DexMaker.java
index 02baa9b..755c9fa 100644
--- a/dexmaker/src/main/java/com/android/dx/DexMaker.java
+++ b/dexmaker/src/main/java/com/android/dx/DexMaker.java
@@ -49,6 +49,8 @@ import static com.android.dx.rop.code.AccessFlags.ACC_CONSTRUCTOR;
import static java.lang.reflect.Modifier.PRIVATE;
import static java.lang.reflect.Modifier.STATIC;
+import android.util.Log;
+
/**
* Generates a <strong>D</strong>alvik <strong>EX</strong>ecutable (dex)
* file for execution on Android. Dex files define classes and interfaces,
@@ -196,9 +198,12 @@ import static java.lang.reflect.Modifier.STATIC;
* }</pre>
*/
public final class DexMaker {
+ private static final String LOG_TAG = DexMaker.class.getSimpleName();
+
private final Map<TypeId<?>, TypeDeclaration> types = new LinkedHashMap<>();
private ClassLoader sharedClassLoader;
private DexFile outputDex;
+ private boolean markAsTrusted;
/**
* Creates a new {@code DexMaker} instance, which can be used to create a
@@ -359,12 +364,51 @@ public final class DexMaker {
return "Generated_" + checksum +".jar";
}
+ /**
+ * Set shared class loader to use.
+ *
+ * <p>If a class wants to call package private methods of another class they need to share a
+ * class loader. One common case for this requirement is a mock class wanting to mock package
+ * private methods of the original class.
+ *
+ * @param classLoader the class loader the new class should be loaded by
+ */
public void setSharedClassLoader(ClassLoader classLoader) {
this.sharedClassLoader = classLoader;
}
+ public void markAsTrusted() {
+ this.markAsTrusted = true;
+ }
+
private ClassLoader generateClassLoader(File result, File dexCache, ClassLoader parent) {
try {
+ // Try to load the class so that it can call hidden APIs. This is required for spying
+ // on system classes as real-methods of these classes might call blacklisted APIs
+ if (markAsTrusted) {
+ try {
+ if (sharedClassLoader != null) {
+ ClassLoader loader = parent != null ? parent : sharedClassLoader;
+ loader.getClass().getMethod("addDexPath", String.class,
+ Boolean.TYPE).invoke(loader, result.getPath(), true);
+ return loader;
+ } else {
+ return (ClassLoader) Class.forName("dalvik.system.BaseDexClassLoader")
+ .getConstructor(String.class, File.class, String.class,
+ ClassLoader.class, Boolean.TYPE)
+ .newInstance(result.getPath(), dexCache.getAbsoluteFile(), null,
+ parent, true);
+ }
+ } catch (InvocationTargetException e) {
+ if (e.getCause() instanceof SecurityException) {
+ Log.i(LOG_TAG, "Cannot allow to call blacklisted super methods. This might "
+ + "break spying on system classes.", e.getCause());
+ } else {
+ throw e;
+ }
+ }
+ }
+
if (sharedClassLoader != null) {
ClassLoader loader = parent != null ? parent : sharedClassLoader;
loader.getClass().getMethod("addDexPath", String.class).invoke(loader,
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 1363894..053fb16 100644
--- a/dexmaker/src/main/java/com/android/dx/stock/ProxyBuilder.java
+++ b/dexmaker/src/main/java/com/android/dx/stock/ProxyBuilder.java
@@ -47,6 +47,8 @@ import static java.lang.reflect.Modifier.PRIVATE;
import static java.lang.reflect.Modifier.PUBLIC;
import static java.lang.reflect.Modifier.STATIC;
+import android.os.Build;
+
/**
* Creates dynamic proxies of concrete classes.
* <p>
@@ -301,6 +303,18 @@ public final class ProxyBuilder<T> {
if (sharedClassLoader) {
dexMaker.setSharedClassLoader(baseClass.getClassLoader());
}
+ if (Build.VERSION.SDK_INT >= 28) {
+ // The proxied class might have blacklisted methods. Blacklisting methods (and fields)
+ // is a new feature of Android P:
+ //
+ // https://android-developers.googleblog.com/2018/02/
+ // improving-stability-by-reducing-usage.html
+ //
+ // The newly generated class might not be allowed to call methods of the proxied class
+ // if it is not trusted. As it is not clear which classes have blacklisted methods, mark
+ // all generated classes as trusted.
+ dexMaker.markAsTrusted();
+ }
ClassLoader classLoader = dexMaker.generateAndLoad(parentClassLoader, dexCache);
try {
proxyClass = loadClass(classLoader, generatedName);