diff --git a/app/src/main/java/io/github/qauxv/util/Natives.java b/app/src/main/java/io/github/qauxv/util/Natives.java index 30fcc206c0..b673f10f25 100644 --- a/app/src/main/java/io/github/qauxv/util/Natives.java +++ b/app/src/main/java/io/github/qauxv/util/Natives.java @@ -39,7 +39,9 @@ import java.io.InputStream; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import java.util.ArrayList; import java.util.Arrays; +import java.util.Iterator; import java.util.List; public class Natives { @@ -213,52 +215,18 @@ private static void registerNativeLibEntry(String soTailingName) { } } - @SuppressLint("UnsafeDynamicallyLoadedCode") public static void load(Context ctx) throws LinkageError { try { getpagesize(); return; } catch (UnsatisfiedLinkError ignored) { } - String abi = getAbiForLibrary(); try { Class.forName(HybridClassLoader.getXposedBridgeClassName()); // in host process - try { - String modulePath = HookEntry.getModulePath(); - if (modulePath != null) { - // try direct memory map - System.load(modulePath + "!/lib/" + abi + "/libqauxv.so"); - Log.d("dlopen by mmap success"); - } - } catch (UnsatisfiedLinkError e1) { - throwIfJniError(e1); - // direct memory map load failed, extract and dlopen - File libname = extractNativeLibrary(ctx, "qauxv", abi); - registerNativeLibEntry(libname.getName()); - try { - System.load(libname.getAbsolutePath()); - Log.d("dlopen by extract success"); - } catch (UnsatisfiedLinkError e3) { - throwIfJniError(e3); - // give enough information to help debug - // Is this CPU_ABI bad? - Log.e("Build.SDK_INT=" + VERSION.SDK_INT); - Log.e("Build.CPU_ABI is: " + Build.CPU_ABI); - Log.e("Build.CPU_ABI2 is: " + Build.CPU_ABI2); - Log.e("Build.SUPPORTED_ABIS is: " + Arrays.toString(Build.SUPPORTED_ABIS)); - Log.e("Build.SUPPORTED_32_BIT_ABIS is: " + Arrays.toString(Build.SUPPORTED_32_BIT_ABIS)); - Log.e("Build.SUPPORTED_64_BIT_ABIS is: " + Arrays.toString(Build.SUPPORTED_64_BIT_ABIS)); - // check whether this is a 64-bit ART runtime - Log.e("Process.is64bit is: " + Process.is64Bit()); - StructUtsname uts = Os.uname(); - Log.e("uts.machine is: " + uts.machine); - Log.e("uts.version is: " + uts.version); - Log.e("uts.sysname is: " + uts.sysname); - // panic, this is a bug - throw e3; - } - } + List abis = getAbiForLibrary(); + String modulePath = HookEntry.getModulePath(); + loadNativeLibraryInHost(ctx, modulePath, abis); } catch (ClassNotFoundException e) { // not in host process, ignore System.loadLibrary("qauxv"); @@ -280,6 +248,56 @@ public static void load(Context ctx) throws LinkageError { MMKV.mmkvWithID("global_cache", MMKV.MULTI_PROCESS_MODE); } + @SuppressLint("UnsafeDynamicallyLoadedCode") + private static void loadNativeLibraryInHost(Context ctx, String modulePath, List abis) throws UnsatisfiedLinkError { + Iterator it = abis.iterator(); + if (modulePath != null && modulePath.length() > 0 && new File(modulePath).exists()) { + // try direct memory map + while (it.hasNext()) { + String abi = it.next(); + try { + System.load(modulePath + "!/lib/" + abi + "/libqauxv.so"); + Log.d("dlopen by mmap success"); + return; + } catch (UnsatisfiedLinkError e1) { + throwIfJniError(e1); + String errMsg = e1.getMessage(); + if (errMsg != null && errMsg.contains(" EM_")) { + // linker or native bridge is complaining about the ELF machine type, try next + } else { + // older linker doesn't support memory map, try extract and dlopen + break; + } + } + } + } + // direct memory map load failed, extract and dlopen + File libname = extractNativeLibrary(ctx, "qauxv", abis.get(0)); + registerNativeLibEntry(libname.getName()); + try { + System.load(libname.getAbsolutePath()); + Log.d("dlopen by extract success"); + } catch (UnsatisfiedLinkError e3) { + throwIfJniError(e3); + // give enough information to help debug + // Is this CPU_ABI bad? + Log.e("Build.SDK_INT=" + VERSION.SDK_INT); + Log.e("Build.CPU_ABI is: " + Build.CPU_ABI); + Log.e("Build.CPU_ABI2 is: " + Build.CPU_ABI2); + Log.e("Build.SUPPORTED_ABIS is: " + Arrays.toString(Build.SUPPORTED_ABIS)); + Log.e("Build.SUPPORTED_32_BIT_ABIS is: " + Arrays.toString(Build.SUPPORTED_32_BIT_ABIS)); + Log.e("Build.SUPPORTED_64_BIT_ABIS is: " + Arrays.toString(Build.SUPPORTED_64_BIT_ABIS)); + // check whether this is a 64-bit ART runtime + Log.e("Process.is64bit is: " + Process.is64Bit()); + StructUtsname uts = Os.uname(); + Log.e("uts.machine is: " + uts.machine); + Log.e("uts.version is: " + uts.version); + Log.e("uts.sysname is: " + uts.sysname); + // panic, this is a bug + throw e3; + } + } + private static void throwIfJniError(UnsatisfiedLinkError error) { if (error.getMessage() != null && error.getMessage().contains("JNI_ERR")) { throw error; @@ -338,17 +356,22 @@ static File extractNativeLibrary(Context ctx, String libraryName, String abi) th return soFile; } - public static String getAbiForLibrary() { + public static List getAbiForLibrary() { String[] supported = Process.is64Bit() ? Build.SUPPORTED_64_BIT_ABIS : Build.SUPPORTED_32_BIT_ABIS; if (supported == null || supported.length == 0) { throw new IllegalStateException("No supported ABI in this device"); } + List result = new ArrayList<>(2); List abis = Arrays.asList("armeabi-v7a", "arm64-v8a", "x86", "x86_64"); for (String abi : supported) { if (abis.contains(abi)) { - return abi; + result.add(abi); } } - throw new IllegalStateException("No supported ABI in " + Arrays.toString(supported)); + if (result.isEmpty()) { + throw new IllegalStateException("No supported ABI in " + Arrays.toString(supported)); + } else { + return result; + } } }