Wait GC to complete before each hook

This commit is contained in:
solohsu 2019-03-06 17:51:03 +08:00
parent 93cea40f85
commit 30e7dfd3d8
5 changed files with 67 additions and 10 deletions

View File

@ -129,4 +129,6 @@ public class Main implements KeepAll {
public static native long suspendAllThreads();
public static native void resumeAllThreads(long obj);
public static native int waitForGcToComplete(long thread);
}

View File

@ -1,5 +1,6 @@
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.util.Utils;
@ -11,6 +12,8 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.Set;
import de.robv.android.xposed.XposedHelpers;
import static com.elderdrivers.riru.xposed.Main.backupAndHookNative;
import static com.elderdrivers.riru.xposed.Main.findMethodNative;
@ -111,7 +114,14 @@ public class HookMain {
if (backup != null) {
HookMethodResolver.resolveMethod(hook, backup);
}
Runtime.getRuntime().gc();
// make sure GC completed before hook
Thread currentThread = Thread.currentThread();
int lastGcType = Main.waitForGcToComplete(
XposedHelpers.getLongField(currentThread, "nativePeer"));
if (lastGcType < 0) {
Utils.logW("waitForGcToComplete failed, using fallback");
Runtime.getRuntime().gc();
}
if (!backupAndHookNative(target, hook, backup)) {
throw new RuntimeException("Failed to hook " + target + " with " + hook);
}

View File

@ -52,6 +52,12 @@ void resumeAllThreads(JNIEnv *, jclass, jlong obj) {
resumeAll(reinterpret_cast<ScopedSuspendAll *>(obj));
}
int waitForGcToComplete(JNIEnv *, jclass, jlong thread) {
// if waitGc succeeded, it should return one of enum collector::GcType
int gcType = waitGc(0, reinterpret_cast<void *>(thread));
return gcType;
}
static JNINativeMethod hookMethods[] = {
{
"init",
@ -99,6 +105,9 @@ static JNINativeMethod hookMethods[] = {
},
{
"resumeAllThreads", "(J)V", (void *) resumeAllThreads
},
{
"waitForGcToComplete", "(J)I", (void *) waitForGcToComplete
}
};
@ -137,7 +146,7 @@ void loadDexAndInit(JNIEnv *env, const char *dexPath) {
jclass entry_class = findClassFromLoader(env, myClassLoader, ENTRY_CLASS_NAME);
if (NULL != entry_class) {
LOGD("HookEntry Class %p", entry_class);
env->RegisterNatives(entry_class, hookMethods, 13);
env->RegisterNatives(entry_class, hookMethods, 14);
isInited = true;
LOGD("RegisterNatives succeed for HookEntry.");
} else {

View File

@ -28,6 +28,8 @@ static void *(*instrCstBackup)(void *instru) = nullptr;
void (*deoptMethod)(void *, void *) = nullptr;
static void (*heapPreForkBackup)(void *) = nullptr;
bool my_runtimeInit(void *runtime, void *mapAddr) {
if (!runtimeInitBackup) {
LOGE("runtimeInitBackup is null");
@ -212,17 +214,49 @@ void hookRuntime(int api_level, void *artHandle, void (*hookFun)(void *, void *,
}
}
void (*suspendAll)(ScopedSuspendAll*, const char*, bool) = nullptr;
void (*resumeAll)(ScopedSuspendAll*) = nullptr;
void (*suspendAll)(ScopedSuspendAll *, const char *, bool) = nullptr;
void (*resumeAll)(ScopedSuspendAll *) = nullptr;
int (*waitGcInternal)(void *, int, void *) = nullptr;
void *heap_ = nullptr;
int waitGc(int gcCause, void *thread) {
if (!heap_) {
LOGE("heap_ is null");
return -1;
}
return (*waitGcInternal)(heap_, gcCause, thread);
}
static void myHeapPreFork(void *heap) {
heap_ = heap;
(*heapPreForkBackup)(heap);
}
void getSuspendSyms(int api_level, void *artHandle, void (*hookFun)(void *, void *, void **)) {
if (api_level < ANDROID_N) {
return;
if (api_level >= ANDROID_LOLLIPOP) {
waitGcInternal = reinterpret_cast<int (*)(void *, int, void *)>(dlsym(artHandle,
"_ZN3art2gc4Heap19WaitForGcToCompleteENS0_7GcCauseEPNS_6ThreadE"));
void *heapPreFork = dlsym(artHandle, "_ZN3art2gc4Heap13PreZygoteForkEv");
if (!heapPreFork) {
LOGE("can't find heapPreFork: %s", dlerror());
} else {
// a chance to get pointer of the heap
(*hookFun)(heapPreFork, reinterpret_cast<void *>(myHeapPreFork),
reinterpret_cast<void **>(&heapPreForkBackup));
LOGI("heapPreFork hooked.");
}
}
if (api_level >= ANDROID_N) {
suspendAll = reinterpret_cast<void (*)(ScopedSuspendAll *, const char *, bool)>(dlsym(
artHandle,
"_ZN3art16ScopedSuspendAllC2EPKcb"));
resumeAll = reinterpret_cast<void (*)(ScopedSuspendAll *)>(dlsym(artHandle,
"_ZN3art16ScopedSuspendAllD2Ev"));
}
suspendAll = reinterpret_cast<void (*)(ScopedSuspendAll*,const char*, bool)>(dlsym(artHandle,
"_ZN3art16ScopedSuspendAllC2EPKcb"));
resumeAll = reinterpret_cast<void (*)(ScopedSuspendAll*)>(dlsym(artHandle,
"_ZN3art16ScopedSuspendAllD2Ev"));
}
void install_inline_hooks() {

View File

@ -26,6 +26,8 @@ extern void (*suspendAll)(ScopedSuspendAll *, const char *, bool);
extern void (*resumeAll)(ScopedSuspendAll *);
extern int waitGc(int, void *);
void install_inline_hooks();
void deoptimize_method(JNIEnv *env, jclass clazz, jobject method);