From b6f9eb20feded9671c9ad6260362db26fd8597ac Mon Sep 17 00:00:00 2001 From: wyouflf Date: Mon, 24 Aug 2020 13:41:30 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8Dapi30=E6=97=A0=E6=B3=95?= =?UTF-8?q?=E8=B0=83=E7=94=A8setHiddenApiExemptions=E7=9A=84=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- settings.gradle | 1 + temp/.gitignore | 1 + temp/build.gradle | 20 +++++ temp/src/main/AndroidManifest.xml | 5 ++ .../org/xplugin/core/util/BootstrapClass.java | 30 +++++++ .../core/ctx/HostParentClassLoader.java | 1 - .../xplugin/core/msg/PluginInitializer.java | 2 + .../xplugin/core/util/PluginReflectUtil.java | 80 +++++++++++++++---- 8 files changed, 123 insertions(+), 17 deletions(-) create mode 100644 temp/.gitignore create mode 100644 temp/build.gradle create mode 100644 temp/src/main/AndroidManifest.xml create mode 100644 temp/src/main/java/org/xplugin/core/util/BootstrapClass.java mode change 100755 => 100644 xplugin/src/main/java/org/xplugin/core/ctx/HostParentClassLoader.java diff --git a/settings.gradle b/settings.gradle index 7283207..0a883e6 100644 --- a/settings.gradle +++ b/settings.gradle @@ -4,3 +4,4 @@ include ':main' include ':xplugin' include ':module1' include ':module2' +include ':temp' diff --git a/temp/.gitignore b/temp/.gitignore new file mode 100644 index 0000000..42afabf --- /dev/null +++ b/temp/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/temp/build.gradle b/temp/build.gradle new file mode 100644 index 0000000..86b02c3 --- /dev/null +++ b/temp/build.gradle @@ -0,0 +1,20 @@ +apply plugin: 'com.android.application' + +android { + compileSdkVersion 30 + buildToolsVersion "30.0.1" + + defaultConfig { + applicationId "org.xplugin.core.util" + minSdkVersion 19 + targetSdkVersion 30 + versionCode 1 + versionName "1.0" + } + + buildTypes { + release { + minifyEnabled false + } + } +} \ No newline at end of file diff --git a/temp/src/main/AndroidManifest.xml b/temp/src/main/AndroidManifest.xml new file mode 100644 index 0000000..7ac88c9 --- /dev/null +++ b/temp/src/main/AndroidManifest.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/temp/src/main/java/org/xplugin/core/util/BootstrapClass.java b/temp/src/main/java/org/xplugin/core/util/BootstrapClass.java new file mode 100644 index 0000000..76155bb --- /dev/null +++ b/temp/src/main/java/org/xplugin/core/util/BootstrapClass.java @@ -0,0 +1,30 @@ +package org.xplugin.core.util; + +import android.os.Build; + +import java.lang.reflect.Method; + +public final class BootstrapClass { + + public static boolean exemptHideApi() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { + try { + Method forName = Class.class.getDeclaredMethod("forName", String.class); + Method getDeclaredMethod = Class.class.getDeclaredMethod("getDeclaredMethod", String.class, Class[].class); + + Class vmRuntimeClass = (Class) forName.invoke(null, new Object[]{"dalvik.system.VMRuntime"}); + + Method getRuntime = (Method) getDeclaredMethod.invoke(vmRuntimeClass, "getRuntime", null); + Object sVmRuntime = getRuntime.invoke(null); + + Method setHiddenApiExemptions = (Method) getDeclaredMethod.invoke(vmRuntimeClass, "setHiddenApiExemptions", new Class[]{String[].class}); + Object ignoredHiddenMethodPrefix = new String[]{"L"}; // the method signature prefix, such as "Ldalvik/system", "Landroid" or even "L" + setHiddenApiExemptions.invoke(sVmRuntime, ignoredHiddenMethodPrefix); + return true; + } catch (Throwable ex) { + return false; + } + } + return true; + } +} \ No newline at end of file diff --git a/xplugin/src/main/java/org/xplugin/core/ctx/HostParentClassLoader.java b/xplugin/src/main/java/org/xplugin/core/ctx/HostParentClassLoader.java old mode 100755 new mode 100644 index 4df72e3..43ce7ac --- a/xplugin/src/main/java/org/xplugin/core/ctx/HostParentClassLoader.java +++ b/xplugin/src/main/java/org/xplugin/core/ctx/HostParentClassLoader.java @@ -24,7 +24,6 @@ private Host host; private HostParentClassLoader(Host host) { - PluginReflectUtil.init(); this.host = host; // class loader结构: // bootClassLoader <-- HostParentClassLoader <-- appClassLoader diff --git a/xplugin/src/main/java/org/xplugin/core/msg/PluginInitializer.java b/xplugin/src/main/java/org/xplugin/core/msg/PluginInitializer.java index df6e52c..c21e8c6 100644 --- a/xplugin/src/main/java/org/xplugin/core/msg/PluginInitializer.java +++ b/xplugin/src/main/java/org/xplugin/core/msg/PluginInitializer.java @@ -1,6 +1,7 @@ package org.xplugin.core.msg; import org.xplugin.core.install.Installer; +import org.xplugin.core.util.PluginReflectUtil; public final class PluginInitializer { private static PluginInitializer instance; @@ -12,6 +13,7 @@ public static void init() { if (instance == null) { synchronized (PluginInitializer.class) { if (instance == null) { + PluginReflectUtil.init(); instance = new PluginInitializer(); PluginMsgLooper looper = new PluginMsgLooper().start(); Installer.initHost(looper); diff --git a/xplugin/src/main/java/org/xplugin/core/util/PluginReflectUtil.java b/xplugin/src/main/java/org/xplugin/core/util/PluginReflectUtil.java index 473c19a..42186a6 100644 --- a/xplugin/src/main/java/org/xplugin/core/util/PluginReflectUtil.java +++ b/xplugin/src/main/java/org/xplugin/core/util/PluginReflectUtil.java @@ -6,18 +6,26 @@ import android.content.res.AssetManager; import android.os.Build; import android.text.TextUtils; +import android.util.Base64; +import org.xutils.common.util.IOUtil; import org.xutils.common.util.LogUtil; import org.xutils.x; +import java.io.File; +import java.io.FileOutputStream; import java.lang.reflect.Method; +import dalvik.system.DexFile; + public final class PluginReflectUtil { private static ReflectMethod addAssetPathMethod; private static ReflectMethod findClassMethod; private static String sWebViewResourcesDir; + private static final String DEX = "ZGV4CjAzNQDsLlmvTNJ0Qhlx+oWyv99KN2uwf6xMxpQMBwAAcAAAAHhWNBIAAAAAAAAAAGAGAAAkAAAAcAAAAA4AAAAAAQAABAAAADgBAAAGAAAAaAEAAAcAAACYAQAAAwAAANABAADcBAAAMAIAAJgDAACdAwAApQMAALUDAADBAwAA1gMAAOgDAADvAwAA8gMAAPUDAAD6AwAAFgQAACkEAAA9BAAAUQQAAG0EAACVBAAAugQAANUEAADeBAAA4QQAAO8EAAD9BAAAAAUAABQFAAApBQAAPgUAAFcFAABmBQAAbwUAAIIFAACOBQAAlgUAAK0FAAC2BQAAzgUAAAcAAAAKAAAACwAAAAwAAAANAAAADgAAAA8AAAAQAAAAEQAAABMAAAAWAAAAFwAAABgAAAAZAAAACQAAAAMAAACIAwAACQAAAAUAAACQAwAAEwAAAAkAAAAAAAAAFgAAAAoAAAAAAAAAAQAAABIAAAAHAAQAAgAAAAcABAADAAAABwAKAAYAAAAHAAAAFAAAAAcABAAVAAAAAgABAB0AAAADAAIAAQAAAAUAAAAfAAAABgACAAEAAAAGAAMAGwAAAAcAAgABAAAACAACAAEAAAAGAAAAEQAAAAMAAAAAAAAABAAAAAAAAAAoBgAAAAAAAAcAAAARAAAAAwAAAAAAAAAFAAAAAAAAADYGAABUBgAACAAAABEAAAADAAAAAAAAAP////8AAAAASgYAAAAAAAAIAAAAAwABAHQDAABuAAAAYAAAABIREwIcADQgaAASABwCAgAaAxwAIxQLABwFBABNBQQAbjAAADIEDAIcAwIAGgQdABIlI1YLABwHBABNBwYAHAcLAE0HBgFuMAAAQwYMAyMUDAAaBhoATQYEABIGbjACAGIEDAIfAgIAI1QMABoHHgBNBwQATQYEAW4wAgAjBAwEHwQFACMHDABuMAIAZAcMBCNVDAAaBiIATQYFACMWCwAcBw0ATQcGAE0GBQFuMAIAIwUMAh8CBQAaAwgAJBANAAMADAMjFQwATQMFAG4wAgBCBQ8BDwAPAQgAAABjAAEAAQBsAAEAAQABAAAAcAMAAAQAAABwEAEAAAAOAAEAAQABAAAAggMAAAQAAABwEAEAAAAOAAEAAQABAAAAAAAAAAQAAABwEAEAAAAOAAcADgAKAA6I4QEaEOKHxOGHAAYADgAAAAIAAAADAAwAAgAAAAQACwADMS4wAAY8aW5pdD4ADkFQUExJQ0FUSU9OX0lEAApCVUlMRF9UWVBFABNCb290c3RyYXBDbGFzcy5qYXZhABBCdWlsZENvbmZpZy5qYXZhAAVERUJVRwABSQABTAADTExMABpMYW5kcm9pZC9vcy9CdWlsZCRWRVJTSU9OOwARTGphdmEvbGFuZy9DbGFzczsAEkxqYXZhL2xhbmcvT2JqZWN0OwASTGphdmEvbGFuZy9TdHJpbmc7ABpMamF2YS9sYW5nL3JlZmxlY3QvTWV0aG9kOwAmTG9yZy94cGx1Z2luL2NvcmUvdXRpbC9Cb290c3RyYXBDbGFzczsAI0xvcmcveHBsdWdpbi9jb3JlL3V0aWwvQnVpbGRDb25maWc7ABlMb3JnL3hwbHVnaW4vY29yZS91dGlsL1I7AAdTREtfSU5UAAFWAAxWRVJTSU9OX0NPREUADFZFUlNJT05fTkFNRQABWgASW0xqYXZhL2xhbmcvQ2xhc3M7ABNbTGphdmEvbGFuZy9PYmplY3Q7ABNbTGphdmEvbGFuZy9TdHJpbmc7ABdkYWx2aWsuc3lzdGVtLlZNUnVudGltZQANZXhlbXB0SGlkZUFwaQAHZm9yTmFtZQARZ2V0RGVjbGFyZWRNZXRob2QACmdldFJ1bnRpbWUABmludm9rZQAVb3JnLnhwbHVnaW4uY29yZS51dGlsAAdyZWxlYXNlABZzZXRIaWRkZW5BcGlFeGVtcHRpb25zAFh+fkQ4eyJjb21waWxhdGlvbi1tb2RlIjoicmVsZWFzZSIsImhhcy1jaGVja3N1bXMiOmZhbHNlLCJtaW4tYXBpIjoxOSwidmVyc2lvbiI6IjIuMC44OCJ9AAAAAgADgYAEqAYBCbAEBQABAAEZARkBGQEZARkFgYAEwAYAAAEABoKABNgGBRcgFyEfBAEXAAAADgAAAAAAAAABAAAAAAAAAAEAAAAkAAAAcAAAAAIAAAAOAAAAAAEAAAMAAAAEAAAAOAEAAAQAAAAGAAAAaAEAAAUAAAAHAAAAmAEAAAYAAAADAAAA0AEAAAEgAAAEAAAAMAIAAAMgAAADAAAAcAMAAAEQAAACAAAAiAMAAAIgAAAkAAAAmAMAAAAgAAADAAAAKAYAAAUgAAABAAAAVAYAAAAQAAABAAAAYAYAAA=="; + private PluginReflectUtil() { } @@ -26,24 +34,15 @@ private PluginReflectUtil() { * 防止ReflectUtil在load时陷入findClass的死循环. */ public static void init() { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { - try { - Reflector clsReflector = Reflector.on(Class.class); - ReflectMethod forName = clsReflector.method("forName", String.class); - ReflectMethod getDeclaredMethod = clsReflector.method("getDeclaredMethod", String.class, Class[].class); - - Class vmRuntimeClass = forName.call("dalvik.system.VMRuntime"); - Method getRuntime = getDeclaredMethod.callByCaller(vmRuntimeClass, "getRuntime", null); - Object sVmRuntime = getRuntime.invoke(null); - - Method setHiddenApiExemptions = getDeclaredMethod.callByCaller(vmRuntimeClass, "setHiddenApiExemptions", new Class[]{String[].class}); - Object ignoredHiddenMethodPrefix = new String[]{"L"}; // the method signature prefix, such as "Ldalvik/system", "Landroid" or even "L" - setHiddenApiExemptions.invoke(sVmRuntime, ignoredHiddenMethodPrefix); - } catch (Throwable ex) { - LogUtil.e("reflect VMRuntime failed:", ex); - } + // 避免调用隐藏API的警告 + boolean exemptHideApi = false; + if (!exemptHideApi()) { + exemptHideApi = exemptHideApiByDexFile(); + } else { + exemptHideApi = true; } + LogUtil.d("exemptHideApi: " + exemptHideApi); try { addAssetPathMethod = Reflector.on(AssetManager.class).method("addAssetPath", String.class); @@ -137,4 +136,53 @@ public static String getWebViewResourcesDir() { return null; } + + private static boolean exemptHideApiByDexFile() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { + FileOutputStream fos = null; + File codeCacheDir = x.app().getCodeCacheDir(); + File code = new File(codeCacheDir, System.currentTimeMillis() + ".dex"); + try { + byte[] bytes = Base64.decode(DEX, Base64.NO_WRAP); + + fos = new FileOutputStream(code); + fos.write(bytes); + IOUtil.closeQuietly(fos); + + DexFile dexFile = new DexFile(code); + Class reflectUtilCls = dexFile.loadClass("org.xplugin.core.util.BootstrapClass", null); + Method exemptAll = reflectUtilCls.getDeclaredMethod("exemptHideApi"); + return (boolean) exemptAll.invoke(null); + } catch (Throwable ex) { + LogUtil.e(ex.getMessage(), ex); + return false; + } finally { + IOUtil.closeQuietly(fos); + IOUtil.deleteFileOrDir(code); + } + } + return true; + } + + private static boolean exemptHideApi() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { + try { + Method forName = Class.class.getDeclaredMethod("forName", String.class); + Method getDeclaredMethod = Class.class.getDeclaredMethod("getDeclaredMethod", String.class, Class[].class); + + Class vmRuntimeClass = (Class) forName.invoke(null, new Object[]{"dalvik.system.VMRuntime"}); + + Method getRuntime = (Method) getDeclaredMethod.invoke(vmRuntimeClass, "getRuntime", null); + Object sVmRuntime = getRuntime.invoke(null); + + Method setHiddenApiExemptions = (Method) getDeclaredMethod.invoke(vmRuntimeClass, "setHiddenApiExemptions", new Class[]{String[].class}); + Object ignoredHiddenMethodPrefix = new String[]{"L"}; // the method signature prefix, such as "Ldalvik/system", "Landroid" or even "L" + setHiddenApiExemptions.invoke(sVmRuntime, ignoredHiddenMethodPrefix); + return true; + } catch (Throwable ex) { + return false; + } + } + return true; + } } \ No newline at end of file