Fix JNI ref leaks
This commit is contained in:
parent
3d863cb4c2
commit
c4978b7344
|
|
@ -123,6 +123,11 @@ public class Main implements KeepAll {
|
||||||
return edxpImplRef.get();
|
return edxpImplRef.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@EdxpImpl.Variant
|
||||||
|
public static synchronized int getEdxpVariant() {
|
||||||
|
return getEdxpImpl().getVariant();
|
||||||
|
}
|
||||||
|
|
||||||
private static void loadEdxpImpls() {
|
private static void loadEdxpImpls() {
|
||||||
AccessController.doPrivileged(new PrivilegedAction<Void>() {
|
AccessController.doPrivileged(new PrivilegedAction<Void>() {
|
||||||
public Void run() {
|
public Void run() {
|
||||||
|
|
@ -133,7 +138,7 @@ public class Main implements KeepAll {
|
||||||
iterator.next();
|
iterator.next();
|
||||||
}
|
}
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
// Do nothing
|
Utils.logE("error when loadEdxpImpls", t);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,10 +3,10 @@ import org.gradle.internal.os.OperatingSystem
|
||||||
|
|
||||||
apply plugin: 'com.android.library'
|
apply plugin: 'com.android.library'
|
||||||
|
|
||||||
version "v0.4.4.0_alpha"
|
version "v0.4.4.1_alpha"
|
||||||
|
|
||||||
ext {
|
ext {
|
||||||
versionCode = "4400"
|
versionCode = "4410"
|
||||||
module_name = "EdXposed"
|
module_name = "EdXposed"
|
||||||
jar_dest_dir = "${projectDir}/template_override/system/framework/"
|
jar_dest_dir = "${projectDir}/template_override/system/framework/"
|
||||||
is_windows = OperatingSystem.current().isWindows()
|
is_windows = OperatingSystem.current().isWindows()
|
||||||
|
|
|
||||||
|
|
@ -85,7 +85,11 @@ ALWAYS_INLINE static int ClearException(JNIEnv *env) {
|
||||||
|
|
||||||
#define JNI_CallStaticObjectMethod(env, obj, ...) \
|
#define JNI_CallStaticObjectMethod(env, obj, ...) \
|
||||||
env->CallStaticObjectMethod(obj, __VA_ARGS__); \
|
env->CallStaticObjectMethod(obj, __VA_ARGS__); \
|
||||||
if (ClearException(env)) LOGE("CallStaticVoidMethod " #obj " " #__VA_ARGS__);
|
if (ClearException(env)) LOGE("CallStaticObjectMethod " #obj " " #__VA_ARGS__);
|
||||||
|
|
||||||
|
#define JNI_CallStaticIntMethod(env, obj, ...) \
|
||||||
|
env->CallStaticIntMethod(obj, __VA_ARGS__); \
|
||||||
|
if (ClearException(env)) LOGE("CallStaticIntMethod " #obj " " #__VA_ARGS__);
|
||||||
|
|
||||||
#define JNI_GetArrayLength(env, array) \
|
#define JNI_GetArrayLength(env, array) \
|
||||||
env->GetArrayLength(array); \
|
env->GetArrayLength(array); \
|
||||||
|
|
|
||||||
|
|
@ -13,16 +13,25 @@ namespace art {
|
||||||
return NewLocalRefSym(env, mirror_ptr);
|
return NewLocalRefSym(env, mirror_ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CREATE_FUNC_SYMBOL_ENTRY(void, DeleteLocalRef, void *env, jobject obj) {
|
||||||
|
DeleteLocalRefSym(env, obj);
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
JNIEnvExt(void *thiz) : HookedObject(thiz) {}
|
JNIEnvExt(void *thiz) : HookedObject(thiz) {}
|
||||||
|
|
||||||
static void Setup(void *handle, HookFunType hook_func) {
|
static void Setup(void *handle, HookFunType hook_func) {
|
||||||
RETRIEVE_FUNC_SYMBOL(NewLocalRef, "_ZN3art9JNIEnvExt11NewLocalRefEPNS_6mirror6ObjectE");
|
RETRIEVE_FUNC_SYMBOL(NewLocalRef, "_ZN3art9JNIEnvExt11NewLocalRefEPNS_6mirror6ObjectE");
|
||||||
|
RETRIEVE_FUNC_SYMBOL(DeleteLocalRef, "_ZN3art9JNIEnvExt14DeleteLocalRefEP8_jobject");
|
||||||
}
|
}
|
||||||
|
|
||||||
jobject NewLocalRefer(void *mirror_ptr) {
|
jobject NewLocalRefer(void *mirror_ptr) {
|
||||||
return NewLocalRef(thiz_, mirror_ptr);
|
return NewLocalRef(thiz_, mirror_ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DeleteLocalRef(jobject obj) {
|
||||||
|
DeleteLocalRef(thiz_, obj);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -33,13 +33,14 @@ namespace edxp {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Context::CallOnPostFixupStaticTrampolines(void *class_ptr) {
|
void Context::CallOnPostFixupStaticTrampolines(void *class_ptr) {
|
||||||
if (post_fixup_static_mid_ != nullptr) {
|
if (UNLIKELY(!post_fixup_static_mid_ || !class_linker_class_)) {
|
||||||
JNIEnv *env;
|
return;
|
||||||
vm_->GetEnv((void **) (&env), JNI_VERSION_1_4);
|
|
||||||
art::JNIEnvExt env_ext(env);
|
|
||||||
jobject clazz = env_ext.NewLocalRefer(class_ptr);
|
|
||||||
JNI_CallStaticVoidMethod(env, class_linker_class_, post_fixup_static_mid_, clazz);
|
|
||||||
}
|
}
|
||||||
|
JNIEnv *env;
|
||||||
|
vm_->GetEnv((void **) (&env), JNI_VERSION_1_4);
|
||||||
|
art::JNIEnvExt env_ext(env);
|
||||||
|
ScopedLocalRef clazz(env, env_ext.NewLocalRefer(class_ptr));
|
||||||
|
JNI_CallStaticVoidMethod(env, class_linker_class_, post_fixup_static_mid_, clazz.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Context::LoadDexAndInit(JNIEnv *env, const char *dex_path) {
|
void Context::LoadDexAndInit(JNIEnv *env, const char *dex_path) {
|
||||||
|
|
@ -60,12 +61,22 @@ namespace edxp {
|
||||||
"(Ljava/lang/String;Ljava/lang/String;Ljava/lang/ClassLoader;)V");
|
"(Ljava/lang/String;Ljava/lang/String;Ljava/lang/ClassLoader;)V");
|
||||||
jobject my_cl = JNI_NewObject(env, path_classloader, initMid, env->NewStringUTF(dex_path),
|
jobject my_cl = JNI_NewObject(env, path_classloader, initMid, env->NewStringUTF(dex_path),
|
||||||
nullptr, sys_classloader);
|
nullptr, sys_classloader);
|
||||||
if (UNLIKELY(!my_cl)) {
|
|
||||||
|
env->DeleteLocalRef(classloader);
|
||||||
|
env->DeleteLocalRef(sys_classloader);
|
||||||
|
env->DeleteLocalRef(path_classloader);
|
||||||
|
|
||||||
|
if (UNLIKELY(my_cl == nullptr)) {
|
||||||
LOG(ERROR) << "PathClassLoader creation failed!!!";
|
LOG(ERROR) << "PathClassLoader creation failed!!!";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO clear up all these global refs if blacklisted?
|
||||||
|
|
||||||
inject_class_loader_ = env->NewGlobalRef(my_cl);
|
inject_class_loader_ = env->NewGlobalRef(my_cl);
|
||||||
|
|
||||||
|
env->DeleteLocalRef(my_cl);
|
||||||
|
|
||||||
// initialize pending methods related
|
// initialize pending methods related
|
||||||
env->GetJavaVM(&vm_);
|
env->GetJavaVM(&vm_);
|
||||||
class_linker_class_ = (jclass) env->NewGlobalRef(
|
class_linker_class_ = (jclass) env->NewGlobalRef(
|
||||||
|
|
@ -84,22 +95,36 @@ namespace edxp {
|
||||||
RegisterArtHeap(env);
|
RegisterArtHeap(env);
|
||||||
RegisterEdxpYahfa(env);
|
RegisterEdxpYahfa(env);
|
||||||
|
|
||||||
|
// must call entry class's methods after all native methods registered
|
||||||
|
if (LIKELY(entry_class_)) {
|
||||||
|
jmethodID get_variant_mid = JNI_GetStaticMethodID(env, entry_class_,
|
||||||
|
"getEdxpVariant", "()I");
|
||||||
|
if (LIKELY(get_variant_mid)) {
|
||||||
|
int variant = JNI_CallStaticIntMethod(env, entry_class_, get_variant_mid);
|
||||||
|
variant_ = static_cast<Variant>(variant);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
initialized_ = true;
|
initialized_ = true;
|
||||||
|
|
||||||
//for SandHook variant
|
if (variant_ == SANDHOOK) {
|
||||||
ScopedDlHandle sandhook_handle(kLibSandHookPath.c_str());
|
//for SandHook variant
|
||||||
if (!sandhook_handle.IsValid()) {
|
ScopedDlHandle sandhook_handle(kLibSandHookPath.c_str());
|
||||||
return;
|
if (!sandhook_handle.IsValid()) {
|
||||||
}
|
return;
|
||||||
typedef bool *(*TYPE_JNI_LOAD)(JNIEnv *, jclass, jclass);
|
}
|
||||||
auto jni_load = sandhook_handle.DlSym<TYPE_JNI_LOAD>("JNI_Load_Ex");
|
typedef bool *(*TYPE_JNI_LOAD)(JNIEnv *, jclass, jclass);
|
||||||
jclass sandhook_class = FindClassFromLoader(env, kSandHookClassName);
|
auto jni_load = sandhook_handle.DlSym<TYPE_JNI_LOAD>("JNI_Load_Ex");
|
||||||
jclass nevercall_class = FindClassFromLoader(env, kSandHookNeverCallClassName);
|
ScopedLocalRef sandhook_class(env, FindClassFromLoader(env, kSandHookClassName));
|
||||||
if (!sandhook_class || !nevercall_class) { // fail-fast
|
ScopedLocalRef nevercall_class(env,
|
||||||
return;
|
FindClassFromLoader(env, kSandHookNeverCallClassName));
|
||||||
}
|
if (sandhook_class == nullptr || nevercall_class == nullptr) { // fail-fast
|
||||||
if (!jni_load(env, sandhook_class, nevercall_class)) {
|
return;
|
||||||
LOGE("SandHook: HookEntry class error. %d", getpid());
|
}
|
||||||
|
if (!jni_load(env, sandhook_class.get(), nevercall_class.get())) {
|
||||||
|
LOGE("SandHook: HookEntry class error. %d", getpid());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -136,7 +161,7 @@ namespace edxp {
|
||||||
|
|
||||||
inline void Context::FindAndCall(JNIEnv *env, const char *method_name,
|
inline void Context::FindAndCall(JNIEnv *env, const char *method_name,
|
||||||
const char *method_sig, ...) const {
|
const char *method_sig, ...) const {
|
||||||
if (!entry_class_) {
|
if (UNLIKELY(!entry_class_)) {
|
||||||
LOGE("cannot call method %s, entry class is null", method_name);
|
LOGE("cannot call method %s, entry class is null", method_name);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -235,8 +260,7 @@ namespace edxp {
|
||||||
if (res == 0) {
|
if (res == 0) {
|
||||||
PrepareJavaEnv(env);
|
PrepareJavaEnv(env);
|
||||||
FindAndCall(env, "forkAndSpecializePost", "(ILjava/lang/String;Ljava/lang/String;)V",
|
FindAndCall(env, "forkAndSpecializePost", "(ILjava/lang/String;Ljava/lang/String;)V",
|
||||||
res,
|
res, app_data_dir_, nice_name_);
|
||||||
app_data_dir_, nice_name_);
|
|
||||||
} else {
|
} else {
|
||||||
// in zygote process, res is child zygote pid
|
// in zygote process, res is child zygote pid
|
||||||
// don't print log here, see https://github.com/RikkaApps/Riru/blob/77adfd6a4a6a81bfd20569c910bc4854f2f84f5e/riru-core/jni/main/jni_native_method.cpp#L55-L66
|
// don't print log here, see https://github.com/RikkaApps/Riru/blob/77adfd6a4a6a81bfd20569c910bc4854f2f84f5e/riru-core/jni/main/jni_native_method.cpp#L55-L66
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,13 @@ namespace edxp {
|
||||||
|
|
||||||
#define SYSTEM_SERVER_DATA_DIR "/data/user/0/android"
|
#define SYSTEM_SERVER_DATA_DIR "/data/user/0/android"
|
||||||
|
|
||||||
|
enum Variant {
|
||||||
|
NONE = 0,
|
||||||
|
YAHFA = 1,
|
||||||
|
SANDHOOK = 2,
|
||||||
|
WHALE = 3
|
||||||
|
};
|
||||||
|
|
||||||
class Context {
|
class Context {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
@ -52,6 +59,7 @@ namespace edxp {
|
||||||
private:
|
private:
|
||||||
static Context *instance_;
|
static Context *instance_;
|
||||||
bool initialized_ = false;
|
bool initialized_ = false;
|
||||||
|
Variant variant_ = NONE;
|
||||||
jobject inject_class_loader_ = nullptr;
|
jobject inject_class_loader_ = nullptr;
|
||||||
jclass entry_class_ = nullptr;
|
jclass entry_class_ = nullptr;
|
||||||
jstring app_data_dir_ = nullptr;
|
jstring app_data_dir_ = nullptr;
|
||||||
|
|
|
||||||
|
|
@ -62,13 +62,12 @@ namespace edxp {
|
||||||
hook_func = reinterpret_cast<HookFunType>(hook_func_symbol);
|
hook_func = reinterpret_cast<HookFunType>(hook_func_symbol);
|
||||||
|
|
||||||
if (api_level >= ANDROID_P) {
|
if (api_level >= ANDROID_P) {
|
||||||
void *handle = DlOpen(kLibDlPath.c_str());
|
ScopedDlHandle dl_handle(kLibDlPath.c_str());
|
||||||
|
void *handle = dl_handle.Get();
|
||||||
HOOK_FUNC(mydlopen, "__loader_dlopen");
|
HOOK_FUNC(mydlopen, "__loader_dlopen");
|
||||||
dlclose(handle);
|
|
||||||
} else {
|
} else {
|
||||||
void *art_handle = DlOpen(kLibArtPath.c_str());
|
ScopedDlHandle art_handle(kLibArtPath.c_str());
|
||||||
InstallArtHooks(art_handle);
|
InstallArtHooks(art_handle.Get());
|
||||||
dlclose(art_handle);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#!/system/bin/sh
|
#!/system/bin/sh
|
||||||
|
|
||||||
EDXP_VERSION="0.4.4.0_alpha (4400)"
|
EDXP_VERSION="0.4.4.1_alpha (4410)"
|
||||||
ANDROID_SDK=`getprop ro.build.version.sdk`
|
ANDROID_SDK=`getprop ro.build.version.sdk`
|
||||||
BUILD_DESC=`getprop ro.build.description`
|
BUILD_DESC=`getprop ro.build.description`
|
||||||
PRODUCT=`getprop ro.build.product`
|
PRODUCT=`getprop ro.build.product`
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue