Skip to content

Commit

Permalink
修复api30无法调用setHiddenApiExemptions的问题
Browse files Browse the repository at this point in the history
  • Loading branch information
wyouflf committed Aug 24, 2020
1 parent 10437f7 commit b6f9eb2
Show file tree
Hide file tree
Showing 8 changed files with 123 additions and 17 deletions.
1 change: 1 addition & 0 deletions settings.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ include ':main'
include ':xplugin'
include ':module1'
include ':module2'
include ':temp'
1 change: 1 addition & 0 deletions temp/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/build
20 changes: 20 additions & 0 deletions temp/build.gradle
Original file line number Diff line number Diff line change
@@ -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
}
}
}
5 changes: 5 additions & 0 deletions temp/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<manifest package="org.xplugin.core.util">

<application />

</manifest>
30 changes: 30 additions & 0 deletions temp/src/main/java/org/xplugin/core/util/BootstrapClass.java
Original file line number Diff line number Diff line change
@@ -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;
}
}
1 change: 0 additions & 1 deletion xplugin/src/main/java/org/xplugin/core/ctx/HostParentClassLoader.java
100755 → 100644
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
private Host host;

private HostParentClassLoader(Host host) {
PluginReflectUtil.init();
this.host = host;
// class loader结构:
// bootClassLoader <-- HostParentClassLoader <-- appClassLoader
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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);
Expand Down
80 changes: 64 additions & 16 deletions xplugin/src/main/java/org/xplugin/core/util/PluginReflectUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
}

Expand All @@ -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);
Expand Down Expand Up @@ -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;
}
}

0 comments on commit b6f9eb2

Please sign in to comment.