diff options
author | Philip P. Moltmann <moltmann@google.com> | 2018-05-21 19:15:56 +0000 |
---|---|---|
committer | Philip P. Moltmann <moltmann@google.com> | 2018-05-21 13:09:05 -0700 |
commit | 314cb2efb7b1d8d9b584a6e0bd82727168cfd181 (patch) | |
tree | 3b848189d1bc1a2238caf1d1285953232c35806a /dexmaker | |
parent | 8738f6764b9f61eb11ad678cad6d9434b4133731 (diff) | |
download | dexmaker-pie-qpr1-s1-release.tar.gz |
DO NOT MERGE: Revert "DO NOT MERGE: Revert "Allow mocks to call blackisted APIs""android-9.0.0_r35android-9.0.0_r34android-9.0.0_r33android-9.0.0_r32android-9.0.0_r31android-9.0.0_r30android-9.0.0_r22android-9.0.0_r21android-9.0.0_r20android-9.0.0_r19android-9.0.0_r16android-9.0.0_r12android-9.0.0_r11pie-qpr2-releasepie-qpr1-s3-releasepie-qpr1-s2-releasepie-qpr1-s1-releasepie-qpr1-releasepie-dr1-releasepie-dr1-devpie-dev
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.java | 44 | ||||
-rw-r--r-- | dexmaker/src/main/java/com/android/dx/stock/ProxyBuilder.java | 14 |
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); |