Skip to content

Commit

Permalink
chore: optimize native library loading logic
Browse files Browse the repository at this point in the history
  • Loading branch information
cinit committed Jul 18, 2023
1 parent 745ee7f commit 3017a8e
Showing 1 changed file with 63 additions and 40 deletions.
103 changes: 63 additions & 40 deletions app/src/main/java/io/github/qauxv/util/Natives.java
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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<String> abis = getAbiForLibrary();
String modulePath = HookEntry.getModulePath();
loadNativeLibraryInHost(ctx, modulePath, abis);
} catch (ClassNotFoundException e) {
// not in host process, ignore
System.loadLibrary("qauxv");
Expand All @@ -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<String> abis) throws UnsatisfiedLinkError {
Iterator<String> 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;
Expand Down Expand Up @@ -338,17 +356,22 @@ static File extractNativeLibrary(Context ctx, String libraryName, String abi) th
return soFile;
}

public static String getAbiForLibrary() {
public static List<String> 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<String> result = new ArrayList<>(2);
List<String> 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;
}
}
}

0 comments on commit 3017a8e

Please sign in to comment.