Suspend all threads when doing hook stuffs to prevent crashes caused by GC

This commit is contained in:
solohsu 2019-02-28 18:05:01 +08:00
parent 9a0044b674
commit 2ac5eb19c9
5 changed files with 63 additions and 10 deletions

View File

@ -125,4 +125,8 @@ public class Main implements KeepAll {
public static native void reopenFilesAfterForkNative(); public static native void reopenFilesAfterForkNative();
public static native void deoptMethodNative(Object object); public static native void deoptMethodNative(Object object);
public static native long suspendAllThreads();
public static native void resumeAllThreads(long obj);
} }

View File

@ -1,5 +1,6 @@
package com.elderdrivers.riru.xposed.core; package com.elderdrivers.riru.xposed.core;
import com.elderdrivers.riru.xposed.Main;
import com.elderdrivers.riru.xposed.entry.hooker.OnePlusWorkAroundHooker; import com.elderdrivers.riru.xposed.entry.hooker.OnePlusWorkAroundHooker;
import com.elderdrivers.riru.xposed.util.Utils; import com.elderdrivers.riru.xposed.util.Utils;
@ -111,8 +112,13 @@ public class HookMain {
if (backup != null) { if (backup != null) {
HookMethodResolver.resolveMethod(hook, backup); HookMethodResolver.resolveMethod(hook, backup);
} }
if (!backupAndHookNative(target, hook, backup)) { long obj = Main.suspendAllThreads();
throw new RuntimeException("Failed to hook " + target + " with " + hook); try {
if (!backupAndHookNative(target, hook, backup)) {
throw new RuntimeException("Failed to hook " + target + " with " + hook);
}
} finally {
Main.resumeAllThreads(obj);
} }
} }

View File

@ -20,13 +20,13 @@ jobject gInjectDexClassLoader;
static bool isInited = false; static bool isInited = false;
static FileDescriptorTable* gClosedFdTable = nullptr; static FileDescriptorTable *gClosedFdTable = nullptr;
void closeFilesBeforeForkNative(JNIEnv*, jclass) { void closeFilesBeforeForkNative(JNIEnv *, jclass) {
gClosedFdTable = FileDescriptorTable::Create(); gClosedFdTable = FileDescriptorTable::Create();
} }
void reopenFilesAfterForkNative(JNIEnv*, jclass) { void reopenFilesAfterForkNative(JNIEnv *, jclass) {
if (!gClosedFdTable) { if (!gClosedFdTable) {
LOGE("gClosedFdTable is null when reopening files"); LOGE("gClosedFdTable is null when reopening files");
return; return;
@ -36,6 +36,22 @@ void reopenFilesAfterForkNative(JNIEnv*, jclass) {
gClosedFdTable = nullptr; gClosedFdTable = nullptr;
} }
jlong suspendAllThreads(JNIEnv *, jclass) {
if (!suspendAll) {
return 0;
}
ScopedSuspendAll *suspendAllObj = (ScopedSuspendAll *) malloc(sizeof(ScopedSuspendAll));
suspendAll(suspendAllObj, "edxp_stop_gc", false);
return reinterpret_cast<jlong>(suspendAllObj);
}
void resumeAllThreads(JNIEnv *, jclass, jlong obj) {
if (!resumeAll) {
return;
}
resumeAll(reinterpret_cast<ScopedSuspendAll *>(obj));
}
static JNINativeMethod hookMethods[] = { static JNINativeMethod hookMethods[] = {
{ {
"init", "init",
@ -58,16 +74,22 @@ static JNINativeMethod hookMethods[] = {
(void *) Java_lab_galaxy_yahfa_HookMain_ensureMethodCached (void *) Java_lab_galaxy_yahfa_HookMain_ensureMethodCached
}, },
{ {
"getInstallerPkgName", "()Ljava/lang/String;", (void *)get_installer_pkg_name "getInstallerPkgName", "()Ljava/lang/String;", (void *) get_installer_pkg_name
}, },
{ {
"closeFilesBeforeForkNative", "()V", (void *)closeFilesBeforeForkNative "closeFilesBeforeForkNative", "()V", (void *) closeFilesBeforeForkNative
}, },
{ {
"reopenFilesAfterForkNative", "()V", (void *)reopenFilesAfterForkNative "reopenFilesAfterForkNative", "()V", (void *) reopenFilesAfterForkNative
}, },
{ {
"deoptMethodNative", "(Ljava/lang/Object;)V", (void *)deoptimize_method "deoptMethodNative", "(Ljava/lang/Object;)V", (void *) deoptimize_method
},
{
"suspendAllThreads", "()J", (void *) suspendAllThreads
},
{
"resumeAllThreads", "(J)V", (void *) resumeAllThreads
} }
}; };
@ -106,7 +128,7 @@ void loadDexAndInit(JNIEnv *env, const char *dexPath) {
jclass entry_class = findClassFromLoader(env, myClassLoader, ENTRY_CLASS_NAME); jclass entry_class = findClassFromLoader(env, myClassLoader, ENTRY_CLASS_NAME);
if (NULL != entry_class) { if (NULL != entry_class) {
LOGD("HookEntry Class %p", entry_class); LOGD("HookEntry Class %p", entry_class);
env->RegisterNatives(entry_class, hookMethods, 8); env->RegisterNatives(entry_class, hookMethods, 10);
isInited = true; isInited = true;
LOGD("RegisterNatives succeed for HookEntry."); LOGD("RegisterNatives succeed for HookEntry.");
} else { } else {

View File

@ -212,6 +212,19 @@ void hookRuntime(int api_level, void *artHandle, void (*hookFun)(void *, void *,
} }
} }
void (*suspendAll)(ScopedSuspendAll*, const char*, bool) = nullptr;
void (*resumeAll)(ScopedSuspendAll*) = nullptr;
void getSuspendSyms(int api_level, void *artHandle, void (*hookFun)(void *, void *, void **)) {
if (api_level < ANDROID_N) {
return;
}
suspendAll = reinterpret_cast<void (*)(ScopedSuspendAll*,const char*, bool)>(dlsym(artHandle,
"_ZN3art16ScopedSuspendAllC2EPKcb"));
resumeAll = reinterpret_cast<void (*)(ScopedSuspendAll*)>(dlsym(artHandle,
"_ZN3art16ScopedSuspendAllD2Ev"));
}
void install_inline_hooks() { void install_inline_hooks() {
if (inlineHooksInstalled) { if (inlineHooksInstalled) {
LOGI("inline hooks installed, skip"); LOGI("inline hooks installed, skip");
@ -243,6 +256,7 @@ void install_inline_hooks() {
} }
hookRuntime(api_level, artHandle, hookFun); hookRuntime(api_level, artHandle, hookFun);
hookInstrumentation(api_level, artHandle, hookFun); hookInstrumentation(api_level, artHandle, hookFun);
getSuspendSyms(api_level, artHandle, hookFun);
hookIsInSamePackage(api_level, artHandle, hookFun); hookIsInSamePackage(api_level, artHandle, hookFun);
if (disableHiddenAPIPolicyImpl(api_level, artHandle, hookFun)) { if (disableHiddenAPIPolicyImpl(api_level, artHandle, hookFun)) {
LOGI("disableHiddenAPIPolicyImpl done."); LOGI("disableHiddenAPIPolicyImpl done.");

View File

@ -19,6 +19,13 @@ static constexpr const char *kLibWhalePath = "/system/lib/libwhale.so";
static ret (*old_##func)(__VA_ARGS__); \ static ret (*old_##func)(__VA_ARGS__); \
static ret new_##func(__VA_ARGS__) static ret new_##func(__VA_ARGS__)
class ScopedSuspendAll {
};
extern void (*suspendAll)(ScopedSuspendAll *, const char *, bool);
extern void (*resumeAll)(ScopedSuspendAll *);
void install_inline_hooks(); void install_inline_hooks();
void deoptimize_method(JNIEnv *env, jclass clazz, jobject method); void deoptimize_method(JNIEnv *env, jclass clazz, jobject method);