[core] RAII JNI interface (#444)

Co-authored-by: Wang Han <wanghan1995315@gmail.com>
This commit is contained in:
LoveSy 2021-04-03 19:35:39 +08:00 committed by GitHub
parent 6d056a40fd
commit 80bc9c0b35
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 216 additions and 174 deletions

View File

@ -122,6 +122,7 @@ namespace yahfa {
SDKVersion = sdkVersion; SDKVersion = sdkVersion;
jclass classExecutable = env->FindClass("java/lang/reflect/Executable"); jclass classExecutable = env->FindClass("java/lang/reflect/Executable");
fieldArtMethod = env->GetFieldID(classExecutable, "artMethod", "J"); fieldArtMethod = env->GetFieldID(classExecutable, "artMethod", "J");
env->DeleteLocalRef(classExecutable);
LOGI("init to SDK %d", sdkVersion); LOGI("init to SDK %d", sdkVersion);
switch (sdkVersion) { switch (sdkVersion) {
case __ANDROID_API_S__: case __ANDROID_API_S__:

View File

@ -25,6 +25,7 @@
#include <sys/mman.h> #include <sys/mman.h>
#include "config.h" #include "config.h"
#include "native_hook.h" #include "native_hook.h"
#include <concepts>
#define _uintval(p) reinterpret_cast<uintptr_t>(p) #define _uintval(p) reinterpret_cast<uintptr_t>(p)
#define _ptr(p) reinterpret_cast<void *>(p) #define _ptr(p) reinterpret_cast<void *>(p)
@ -140,9 +141,8 @@ namespace lspd {
}; };
template<typename Class, typename Return, typename T, typename... Args> template<typename Class, typename Return, typename T, typename... Args>
requires (std::is_same_v<T, void> || std::is_same_v<Class, T>)
inline static auto memfun_cast(Return (*func)(T *, Args...)) { inline static auto memfun_cast(Return (*func)(T *, Args...)) {
static_assert(std::is_same_v<T, void> || std::is_same_v<Class, T>,
"Not viable cast");
union { union {
Return (Class::*f)(Args...); Return (Class::*f)(Args...);
@ -155,8 +155,7 @@ namespace lspd {
return u.f; return u.f;
} }
template<typename T, typename Return, typename... Args, template<std::same_as<void> T, typename Return, typename... Args>
typename = std::enable_if_t<!std::is_same_v<T, void>>>
inline auto memfun_cast(Return (*func)(T *, Args...)) { inline auto memfun_cast(Return (*func)(T *, Args...)) {
return memfun_cast<T>(func); return memfun_cast<T>(func);
} }
@ -203,7 +202,7 @@ namespace lspd {
struct Hooker<Ret(Args...), tstring<cs...>> { struct Hooker<Ret(Args...), tstring<cs...>> {
inline static Ret (*backup)(Args...) = nullptr; inline static Ret (*backup)(Args...) = nullptr;
inline static constexpr const char sym[sizeof...(cs) + 1] = {cs..., '\0'}; inline static constexpr const char *sym = tstring<cs...>::c_str();
}; };
template<typename, typename> template<typename, typename>
@ -211,10 +210,16 @@ namespace lspd {
template<typename Ret, typename This, typename... Args, char... cs> template<typename Ret, typename This, typename... Args, char... cs>
struct MemHooker<Ret(This, Args...), tstring<cs...>> { struct MemHooker<Ret(This, Args...), tstring<cs...>> {
inline static MemberFunction<Ret(Args...)> backup; inline static MemberFunction<Ret(Args...)> backup;
inline static constexpr const char sym[sizeof...(cs) + 1] = {cs..., '\0'}; inline static constexpr const char *sym = tstring<cs...>::c_str();
}; };
template<typename T> template<typename T>
concept HookerType = requires(T a) {
a.backup;
a.replace;
};
template<HookerType T>
inline static bool HookSymNoHandle(void *original, T &arg) { inline static bool HookSymNoHandle(void *original, T &arg) {
if (original) { if (original) {
if constexpr(is_instance<decltype(arg.backup), MemberFunction>::value) { if constexpr(is_instance<decltype(arg.backup), MemberFunction>::value) {
@ -231,13 +236,13 @@ namespace lspd {
} }
} }
template<typename T> template<HookerType T>
inline static bool HookSym(void *handle, T &arg) { inline static bool HookSym(void *handle, T &arg) {
auto original = Dlsym(handle, arg.sym); auto original = Dlsym(handle, arg.sym);
return HookSymNoHandle(original, arg); return HookSymNoHandle(original, arg);
} }
template<typename T, typename...Args> template<HookerType T, HookerType...Args>
inline static bool HookSyms(void *handle, T &first, Args &...rest) { inline static bool HookSyms(void *handle, T &first, Args &...rest) {
if (!(HookSym(handle, first) || ... || HookSym(handle, rest))) { if (!(HookSym(handle, first) || ... || HookSym(handle, rest))) {
LOGW("Hook Fails: %s", first.sym); LOGW("Hook Fails: %s", first.sym);

View File

@ -24,6 +24,7 @@
#include "macros.h" #include "macros.h"
#include <string> #include <string>
#include "logging.h" #include "logging.h"
#include "base/object.h"
#define JNI_START JNIEnv *env, [[maybe_unused]] jclass clazz #define JNI_START JNIEnv *env, [[maybe_unused]] jclass clazz
@ -78,6 +79,9 @@ private:
}; };
template<typename T> template<typename T>
concept JObject = std::is_base_of_v<std::remove_pointer_t<jobject>, std::remove_pointer_t<T>>;
template<JObject T>
class ScopedLocalRef { class ScopedLocalRef {
public: public:
ScopedLocalRef(JNIEnv *env, T localRef) : mEnv(env), mLocalRef(localRef) { ScopedLocalRef(JNIEnv *env, T localRef) : mEnv(env), mLocalRef(localRef) {
@ -86,6 +90,10 @@ public:
ScopedLocalRef(ScopedLocalRef &&s) noexcept: mEnv(s.mEnv), mLocalRef(s.release()) { ScopedLocalRef(ScopedLocalRef &&s) noexcept: mEnv(s.mEnv), mLocalRef(s.release()) {
} }
template<JObject U>
ScopedLocalRef(ScopedLocalRef<U> &&s) noexcept: mEnv(s.mEnv), mLocalRef((T) s.release()) {
}
explicit ScopedLocalRef(JNIEnv *env) : mEnv(env), mLocalRef(nullptr) { explicit ScopedLocalRef(JNIEnv *env) : mEnv(env), mLocalRef(nullptr) {
} }
@ -93,18 +101,18 @@ public:
reset(); reset();
} }
void reset(T ptr = NULL) { void reset(T ptr = nullptr) {
if (ptr != mLocalRef) { if (ptr != mLocalRef) {
if (mLocalRef != NULL) { if (mLocalRef != nullptr) {
mEnv->DeleteLocalRef(mLocalRef); mEnv->DeleteLocalRef(mLocalRef);
} }
mLocalRef = ptr; mLocalRef = ptr;
} }
} }
T release() __attribute__((warn_unused_result)) { [[nodiscard]] T release() {
T localRef = mLocalRef; T localRef = mLocalRef;
mLocalRef = NULL; mLocalRef = nullptr;
return localRef; return localRef;
} }
@ -123,26 +131,28 @@ public:
return *this; return *this;
} }
// Allows "if (scoped_ref == nullptr)"
bool operator==(std::nullptr_t) const {
return mLocalRef == nullptr;
}
// Allows "if (scoped_ref != nullptr)"
bool operator!=(std::nullptr_t) const {
return mLocalRef != nullptr;
}
operator bool() const { operator bool() const {
return mLocalRef; return mLocalRef;
} }
template<JObject U>
friend
class ScopedLocalRef;
private: private:
JNIEnv *mEnv; JNIEnv *mEnv;
T mLocalRef; T mLocalRef;
DISALLOW_COPY_AND_ASSIGN(ScopedLocalRef); DISALLOW_COPY_AND_ASSIGN(ScopedLocalRef);
}; };
template<typename T, typename U>
concept ScopeOrRaw = std::is_same_v<T, U> || std::is_same_v<ScopedLocalRef<T>, U>;
template<typename T>
concept ScopeOrClass = ScopeOrRaw<jclass, T>;
template<typename T>
concept ScopeOrObject = ScopeOrRaw<jobject, T>;
inline ScopedLocalRef<jstring> ClearException(JNIEnv *env) { inline ScopedLocalRef<jstring> ClearException(JNIEnv *env) {
if (auto exception = env->ExceptionOccurred()) { if (auto exception = env->ExceptionOccurred()) {
env->ExceptionClear(); env->ExceptionClear();
@ -157,15 +167,24 @@ inline ScopedLocalRef<jstring> ClearException(JNIEnv *env) {
template<typename T> template<typename T>
[[maybe_unused]] [[maybe_unused]]
inline auto unwrap_sv(T &&x) { inline auto unwrap_scope(T &&x) {
if constexpr (std::is_same_v<std::decay_t<T>, std::string_view>) return x.data(); if constexpr (std::is_same_v<std::decay_t<T>, std::string_view>) return x.data();
else if constexpr (lspd::is_instance<std::decay_t<T>, ScopedLocalRef>::value) return x.get();
else return std::forward<T>(x); else return std::forward<T>(x);
} }
template<typename Func, typename ...Args> template<typename T>
[[maybe_unused]] [[maybe_unused]]
inline auto JNI_SafeInvoke(JNIEnv *env, Func f, Args &&... args) { inline auto wrap_scope(JNIEnv *env, T &&x) {
static_assert(std::is_member_function_pointer_v<Func>); if constexpr (std::is_convertible_v<T, jobject>) {
return ScopedLocalRef(env, std::forward<T>(x));
} else return x;
}
template<typename Func, typename ...Args>
requires(std::is_function_v<Func>)
[[maybe_unused]]
inline auto JNI_SafeInvoke(JNIEnv *env, Func JNIEnv::*f, Args &&... args) {
struct finally { struct finally {
finally(JNIEnv *env) : env_(env) {} finally(JNIEnv *env) : env_(env) {}
@ -178,7 +197,10 @@ inline auto JNI_SafeInvoke(JNIEnv *env, Func f, Args &&... args) {
JNIEnv *env_; JNIEnv *env_;
} _(env); } _(env);
return (env->*f)(unwrap_sv(std::forward<Args>(args))...); if constexpr (!std::is_same_v<void, std::invoke_result_t<Func, decltype(unwrap_scope(
std::forward<Args>(args)))...>>)
return wrap_scope(env, (env->*f)(unwrap_scope(std::forward<Args>(args))...));
else (env->*f)(unwrap_scope(std::forward<Args>(args))...);
} }
[[maybe_unused]] [[maybe_unused]]
@ -186,93 +208,118 @@ inline auto JNI_FindClass(JNIEnv *env, std::string_view name) {
return JNI_SafeInvoke(env, &JNIEnv::FindClass, name); return JNI_SafeInvoke(env, &JNIEnv::FindClass, name);
} }
template<ScopeOrObject Object>
[[maybe_unused]] [[maybe_unused]]
inline auto JNI_GetObjectClass(JNIEnv *env, jobject obj) { inline auto JNI_GetObjectClass(JNIEnv *env, const Object &obj) {
return JNI_SafeInvoke(env, &JNIEnv::GetObjectClass, obj); return JNI_SafeInvoke(env, &JNIEnv::GetObjectClass, obj);
} }
template<ScopeOrClass Class>
[[maybe_unused]] [[maybe_unused]]
inline auto JNI_GetFieldID(JNIEnv *env, jclass clazz, std::string_view name, std::string_view sig) { inline auto
JNI_GetFieldID(JNIEnv *env, const Class &clazz, std::string_view name, std::string_view sig) {
return JNI_SafeInvoke(env, &JNIEnv::GetFieldID, clazz, name, sig); return JNI_SafeInvoke(env, &JNIEnv::GetFieldID, clazz, name, sig);
} }
template<ScopeOrClass Class>
[[maybe_unused]] [[maybe_unused]]
inline auto JNI_GetObjectField(JNIEnv *env, jclass clazz, jfieldID fieldId) { inline auto JNI_GetObjectField(JNIEnv *env, const Class &clazz, jfieldID fieldId) {
return JNI_SafeInvoke(env, &JNIEnv::GetObjectField, clazz, fieldId); return JNI_SafeInvoke(env, &JNIEnv::GetObjectField, clazz, fieldId);
} }
template<ScopeOrClass Class>
[[maybe_unused]] [[maybe_unused]]
inline auto inline auto
JNI_GetMethodID(JNIEnv *env, jclass clazz, std::string_view name, std::string_view sig) { JNI_GetMethodID(JNIEnv *env, const Class &clazz, std::string_view name, std::string_view sig) {
return JNI_SafeInvoke(env, &JNIEnv::GetMethodID, clazz, name, sig); return JNI_SafeInvoke(env, &JNIEnv::GetMethodID, clazz, name, sig);
} }
template<typename ...Args> template<ScopeOrObject Object, typename ...Args>
[[maybe_unused]] [[maybe_unused]]
inline auto JNI_CallObjectMethod(JNIEnv *env, jobject obj, Args &&... args) { inline auto JNI_CallObjectMethod(JNIEnv *env, const Object &obj, Args &&... args) {
return JNI_SafeInvoke(env, &JNIEnv::CallObjectMethod, obj, std::forward<Args>(args)...); return JNI_SafeInvoke(env, &JNIEnv::CallObjectMethod, obj, std::forward<Args>(args)...);
} }
template<typename ...Args> template<ScopeOrObject Object, typename ...Args>
[[maybe_unused]] [[maybe_unused]]
inline auto JNI_CallVoidMethod(JNIEnv *env, jobject obj, Args &&...args) { inline auto JNI_CallVoidMethod(JNIEnv *env, const Object &obj, Args &&...args) {
return JNI_SafeInvoke(env, &JNIEnv::CallVoidMethod, obj, std::forward<Args>(args)...); return JNI_SafeInvoke(env, &JNIEnv::CallVoidMethod, obj, std::forward<Args>(args)...);
} }
template<typename ...Args> template<ScopeOrObject Object, typename ...Args>
[[maybe_unused]] [[maybe_unused]]
inline auto JNI_CallBooleanMethod(JNIEnv *env, jobject obj, Args &&...args) { inline auto JNI_CallBooleanMethod(JNIEnv *env, const Object &obj, Args &&...args) {
return JNI_SafeInvoke(env, &JNIEnv::CallBooleanMethod, obj, std::forward<Args>(args)...); return JNI_SafeInvoke(env, &JNIEnv::CallBooleanMethod, obj, std::forward<Args>(args)...);
} }
template<ScopeOrClass Class>
[[maybe_unused]] [[maybe_unused]]
inline auto inline auto
JNI_GetStaticFieldID(JNIEnv *env, jclass clazz, std::string_view name, std::string_view sig) { JNI_GetStaticFieldID(JNIEnv *env, const Class &clazz, std::string_view name, std::string_view sig) {
return JNI_SafeInvoke(env, &JNIEnv::GetStaticFieldID, clazz, name, sig); return JNI_SafeInvoke(env, &JNIEnv::GetStaticFieldID, clazz, name, sig);
} }
template<ScopeOrClass Class>
[[maybe_unused]] [[maybe_unused]]
inline auto JNI_GetStaticObjectField(JNIEnv *env, jclass clazz, jfieldID fieldId) { inline auto JNI_GetStaticObjectField(JNIEnv *env, const Class &clazz, jfieldID fieldId) {
return JNI_SafeInvoke(env, &JNIEnv::GetStaticObjectField, clazz, fieldId); return JNI_SafeInvoke(env, &JNIEnv::GetStaticObjectField, clazz, fieldId);
} }
template<ScopeOrClass Class>
[[maybe_unused]] [[maybe_unused]]
inline auto inline auto
JNI_GetStaticMethodID(JNIEnv *env, jclass clazz, std::string_view name, std::string_view sig) { JNI_GetStaticMethodID(JNIEnv *env, const Class &clazz, std::string_view name,
std::string_view sig) {
return JNI_SafeInvoke(env, &JNIEnv::GetStaticMethodID, clazz, name, sig); return JNI_SafeInvoke(env, &JNIEnv::GetStaticMethodID, clazz, name, sig);
} }
template<typename ...Args> template<ScopeOrClass Class, typename ...Args>
[[maybe_unused]] [[maybe_unused]]
inline auto JNI_CallStaticVoidMethod(JNIEnv *env, jclass clazz, Args &&...args) { inline auto JNI_CallStaticVoidMethod(JNIEnv *env, const Class &clazz, Args &&...args) {
return JNI_SafeInvoke(env, &JNIEnv::CallStaticVoidMethod, clazz, std::forward<Args>(args)...); return JNI_SafeInvoke(env, &JNIEnv::CallStaticVoidMethod, clazz, std::forward<Args>(args)...);
} }
template<typename ...Args> template<ScopeOrClass Class, typename ...Args>
[[maybe_unused]] [[maybe_unused]]
inline auto JNI_CallStaticObjectMethod(JNIEnv *env, jclass clazz, Args &&...args) { inline auto JNI_CallStaticObjectMethod(JNIEnv *env, const Class &clazz, Args &&...args) {
return JNI_SafeInvoke(env, &JNIEnv::CallStaticObjectMethod, clazz, std::forward<Args>(args)...); return JNI_SafeInvoke(env, &JNIEnv::CallStaticObjectMethod, clazz, std::forward<Args>(args)...);
} }
template<typename ...Args> template<ScopeOrClass Class, typename ...Args>
[[maybe_unused]] [[maybe_unused]]
inline auto JNI_CallStaticIntMethod(JNIEnv *env, jclass clazz, Args &&...args) { inline auto JNI_CallStaticIntMethod(JNIEnv *env, const Class &clazz, Args &&...args) {
return JNI_SafeInvoke(env, &JNIEnv::CallStaticIntMethod, clazz, std::forward<Args>(args)...); return JNI_SafeInvoke(env, &JNIEnv::CallStaticIntMethod, clazz, std::forward<Args>(args)...);
} }
template<ScopeOrRaw<jarray> Array>
[[maybe_unused]] [[maybe_unused]]
inline auto JNI_GetArrayLength(JNIEnv *env, jarray array) { inline auto JNI_GetArrayLength(JNIEnv *env, const Array &array) {
return JNI_SafeInvoke(env, &JNIEnv::GetArrayLength, array); return JNI_SafeInvoke(env, &JNIEnv::GetArrayLength, array);
} }
template<typename ...Args> template<ScopeOrClass Class, typename ...Args>
[[maybe_unused]] [[maybe_unused]]
inline auto JNI_NewObject(JNIEnv *env, jclass clazz, Args &&...args) { inline auto JNI_NewObject(JNIEnv *env, const Class &clazz, Args &&...args) {
return JNI_SafeInvoke(env, &JNIEnv::NewObject, clazz, std::forward<Args>(args)...); return JNI_SafeInvoke(env, &JNIEnv::NewObject, clazz, std::forward<Args>(args)...);
} }
template<ScopeOrClass Class>
[[maybe_unused]] [[maybe_unused]]
inline auto inline auto
JNI_RegisterNatives(JNIEnv *env, jclass clazz, const JNINativeMethod *methods, jint size) { JNI_RegisterNatives(JNIEnv *env, const Class &clazz, const JNINativeMethod *methods, jint size) {
return JNI_SafeInvoke(env, &JNIEnv::RegisterNatives, clazz, methods, size); return JNI_SafeInvoke(env, &JNIEnv::RegisterNatives, clazz, methods, size);
} }
template<typename T>
[[maybe_unused]]
inline auto JNI_NewGlobalRef(JNIEnv *env, T &&x) requires(std::is_convertible_v<T, jobject>){
return (T) env->NewGlobalRef(std::forward<T>(x));
}
template<typename T>
[[maybe_unused]]
inline auto
JNI_NewGlobalRef(JNIEnv *env, const ScopedLocalRef<T> &x) requires(
std::is_convertible_v<T, jobject>){
return (T) env->NewGlobalRef(x.get());
}

View File

@ -35,13 +35,12 @@ namespace lspd {
const JNINativeMethod *methods, const JNINativeMethod *methods,
jint method_count) { jint method_count) {
ScopedLocalRef clazz(env, auto clazz = Context::GetInstance()->FindClassFromCurrentLoader(env, class_name);
Context::GetInstance()->FindClassFromCurrentLoader(env, class_name));
if (clazz.get() == nullptr) { if (clazz.get() == nullptr) {
LOGF("Couldn't find class: %s", class_name); LOGF("Couldn't find class: %s", class_name);
return false; return false;
} }
return JNI_RegisterNatives(env, clazz.get(), methods, method_count); return JNI_RegisterNatives(env, clazz, methods, method_count);
} }
#if defined(__cplusplus) #if defined(__cplusplus)

View File

@ -42,11 +42,11 @@ namespace lspd {
template<char... chars> template<char... chars>
struct tstring : public std::integer_sequence<char, chars...> { struct tstring : public std::integer_sequence<char, chars...> {
constexpr const char *c_str() const { inline constexpr static const char *c_str() {
return str_; return str_;
} }
constexpr operator std::string_view() const { inline constexpr operator std::string_view() const {
return c_str(); return c_str();
} }

View File

@ -52,7 +52,7 @@ namespace lspd {
vm_->GetEnv((void **) (&env), JNI_VERSION_1_4); vm_->GetEnv((void **) (&env), JNI_VERSION_1_4);
art::JNIEnvExt env_ext(env); art::JNIEnvExt env_ext(env);
ScopedLocalRef clazz(env, env_ext.NewLocalRefer(class_ptr)); ScopedLocalRef clazz(env, env_ext.NewLocalRefer(class_ptr));
if (clazz != nullptr) { if (clazz) {
JNI_CallStaticVoidMethod(env, class_linker_class_, post_fixup_static_mid_, clazz.get()); JNI_CallStaticVoidMethod(env, class_linker_class_, post_fixup_static_mid_, clazz.get());
} }
} }
@ -74,48 +74,44 @@ namespace lspd {
} }
void Context::LoadDex(JNIEnv *env) { void Context::LoadDex(JNIEnv *env) {
jclass classloader = JNI_FindClass(env, "java/lang/ClassLoader"); auto classloader = JNI_FindClass(env, "java/lang/ClassLoader");
jmethodID getsyscl_mid = JNI_GetStaticMethodID( auto getsyscl_mid = JNI_GetStaticMethodID(
env, classloader, "getSystemClassLoader", "()Ljava/lang/ClassLoader;"); env, classloader, "getSystemClassLoader", "()Ljava/lang/ClassLoader;");
jobject sys_classloader = JNI_CallStaticObjectMethod(env, classloader, getsyscl_mid); auto sys_classloader = JNI_CallStaticObjectMethod(env, classloader, getsyscl_mid);
if (UNLIKELY(!sys_classloader)) { if (UNLIKELY(!sys_classloader)) {
LOGE("getSystemClassLoader failed!!!"); LOGE("getSystemClassLoader failed!!!");
return; return;
} }
jclass in_memory_classloader = JNI_FindClass(env, "dalvik/system/InMemoryDexClassLoader"); auto in_memory_classloader = JNI_FindClass(env, "dalvik/system/InMemoryDexClassLoader");
jmethodID initMid = JNI_GetMethodID(env, in_memory_classloader, "<init>", auto initMid = JNI_GetMethodID(env, in_memory_classloader, "<init>",
"(Ljava/nio/ByteBuffer;Ljava/lang/ClassLoader;)V"); "(Ljava/nio/ByteBuffer;Ljava/lang/ClassLoader;)V");
jclass byte_buffer_class = JNI_FindClass(env, "java/nio/ByteBuffer"); auto byte_buffer_class = JNI_FindClass(env, "java/nio/ByteBuffer");
auto dex_buffer = env->NewDirectByteBuffer(reinterpret_cast<void *>(dex.data()), auto dex_buffer = env->NewDirectByteBuffer(reinterpret_cast<void *>(dex.data()),
dex.size()); dex.size());
jobject my_cl = JNI_NewObject(env, in_memory_classloader, initMid, if (auto my_cl = JNI_NewObject(env, in_memory_classloader, initMid,
dex_buffer, sys_classloader); dex_buffer, sys_classloader)) {
env->DeleteLocalRef(classloader); inject_class_loader_ = JNI_NewGlobalRef(env, my_cl);
env->DeleteLocalRef(sys_classloader); } else {
env->DeleteLocalRef(in_memory_classloader);
env->DeleteLocalRef(byte_buffer_class);
if (UNLIKELY(my_cl == nullptr)) {
LOGE("InMemoryDexClassLoader creation failed!!!"); LOGE("InMemoryDexClassLoader creation failed!!!");
return; return;
} }
inject_class_loader_ = env->NewGlobalRef(my_cl); env->DeleteLocalRef(dex_buffer);
env->DeleteLocalRef(my_cl);
env->GetJavaVM(&vm_); env->GetJavaVM(&vm_);
} }
void Context::Init(JNIEnv *env) { void Context::Init(JNIEnv *env) {
class_linker_class_ = (jclass) env->NewGlobalRef( if (auto class_linker_class = FindClassFromCurrentLoader(env, kClassLinkerClassName)) {
FindClassFromCurrentLoader(env, kClassLinkerClassName)); class_linker_class_ = JNI_NewGlobalRef(env, class_linker_class);
}
post_fixup_static_mid_ = JNI_GetStaticMethodID(env, class_linker_class_, post_fixup_static_mid_ = JNI_GetStaticMethodID(env, class_linker_class_,
"onPostFixupStaticTrampolines", "onPostFixupStaticTrampolines",
"(Ljava/lang/Class;)V"); "(Ljava/lang/Class;)V");
entry_class_ = (jclass) (env->NewGlobalRef( if (auto entry_class = FindClassFromLoader(env, GetCurrentClassLoader(), kEntryClassName)) {
FindClassFromLoader(env, GetCurrentClassLoader(), kEntryClassName))); entry_class_ = JNI_NewGlobalRef(env, entry_class);
}
RegisterLogger(env); RegisterLogger(env);
RegisterResourcesHook(env); RegisterResourcesHook(env);
@ -125,44 +121,41 @@ namespace lspd {
RegisterNativeAPI(env); RegisterNativeAPI(env);
} }
jclass ScopedLocalRef<jclass>
Context::FindClassFromLoader(JNIEnv *env, jobject class_loader, std::string_view class_name) { Context::FindClassFromLoader(JNIEnv *env, jobject class_loader, std::string_view class_name) {
if (class_loader == nullptr) return nullptr; if (class_loader == nullptr) return {env, nullptr};
static auto clz = (jclass) env->NewGlobalRef( static auto clz = JNI_NewGlobalRef(env, JNI_FindClass(env, "dalvik/system/DexClassLoader"));
env->FindClass("dalvik/system/DexClassLoader"));
static jmethodID mid = JNI_GetMethodID(env, clz, "loadClass", static jmethodID mid = JNI_GetMethodID(env, clz, "loadClass",
"(Ljava/lang/String;)Ljava/lang/Class;"); "(Ljava/lang/String;)Ljava/lang/Class;");
jclass ret = nullptr;
if (!mid) { if (!mid) {
mid = JNI_GetMethodID(env, clz, "findClass", "(Ljava/lang/String;)Ljava/lang/Class;"); mid = JNI_GetMethodID(env, clz, "findClass", "(Ljava/lang/String;)Ljava/lang/Class;");
} }
if (LIKELY(mid)) { if (LIKELY(mid)) {
jobject target = JNI_CallObjectMethod(env, class_loader, mid, auto target = JNI_CallObjectMethod(env, class_loader, mid,
env->NewStringUTF(class_name.data())); env->NewStringUTF(class_name.data()));
if (target) { if (target) {
return (jclass) target; return target;
} }
} else { } else {
LOGE("No loadClass/findClass method found"); LOGE("No loadClass/findClass method found");
} }
LOGE("Class %s not found", class_name.data()); LOGE("Class %s not found", class_name.data());
return ret; return {env, nullptr};
} }
inline void Context::FindAndCall(JNIEnv *env, const char *method_name, template<typename ...Args>
const char *method_sig, ...) const { void
Context::FindAndCall(JNIEnv *env, std::string_view method_name, std::string_view method_sig,
Args &&... args) const {
if (UNLIKELY(!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.data());
return; return;
} }
jmethodID mid = JNI_GetStaticMethodID(env, entry_class_, method_name, method_sig); jmethodID mid = JNI_GetStaticMethodID(env, entry_class_, method_name, method_sig);
if (LIKELY(mid)) { if (LIKELY(mid)) {
va_list args; JNI_CallStaticVoidMethod(env, entry_class_, mid, std::forward<Args>(args)...);
va_start(args, method_sig);
env->CallStaticVoidMethodV(entry_class_, mid, args);
va_end(args);
} else { } else {
LOGE("method %s id is null", method_name); LOGE("method %s id is null", method_name.data());
} }
} }
@ -184,7 +177,7 @@ namespace lspd {
InstallInlineHooks(); InstallInlineHooks();
Init(env); Init(env);
FindAndCall(env, "forkSystemServerPost", "(Landroid/os/IBinder;)V", binder); FindAndCall(env, "forkSystemServerPost", "(Landroid/os/IBinder;)V", binder);
} } else skip_ = true;
} }
setAllowUnload(skip_); setAllowUnload(skip_);
} }
@ -221,7 +214,8 @@ namespace lspd {
void void
Context::OnNativeForkAndSpecializePost(JNIEnv *env) { Context::OnNativeForkAndSpecializePost(JNIEnv *env) {
const JUTFString process_name(env, nice_name_); const JUTFString process_name(env, nice_name_);
auto binder = skip_ ? nullptr : Service::instance()->RequestBinder(env, nice_name_); auto binder = skip_ ? ScopedLocalRef<jobject>{env, nullptr}
: Service::instance()->RequestBinder(env, nice_name_);
if (binder) { if (binder) {
LoadDex(env); LoadDex(env);
InstallInlineHooks(); InstallInlineHooks();

View File

@ -27,6 +27,7 @@
#include <tuple> #include <tuple>
#include <string_view> #include <string_view>
#include "utils.h" #include "utils.h"
#include "jni_helper.h"
namespace lspd { namespace lspd {
class Context { class Context {
@ -44,9 +45,7 @@ namespace lspd {
void CallOnPostFixupStaticTrampolines(void *class_ptr); void CallOnPostFixupStaticTrampolines(void *class_ptr);
void FindAndCall(JNIEnv *env, const char *method_name, const char *method_sig, ...) const; inline ScopedLocalRef<jclass> FindClassFromCurrentLoader(JNIEnv *env, std::string_view className) const {
inline jclass FindClassFromCurrentLoader(JNIEnv *env, std::string_view className) const {
return FindClassFromLoader(env, GetCurrentClassLoader(), className); return FindClassFromLoader(env, GetCurrentClassLoader(), className);
}; };
@ -78,10 +77,13 @@ namespace lspd {
void Init(JNIEnv *env); void Init(JNIEnv *env);
static jclass FindClassFromLoader(JNIEnv *env, jobject class_loader, static ScopedLocalRef<jclass> FindClassFromLoader(JNIEnv *env, jobject class_loader,
std::string_view class_name); std::string_view class_name);
static void setAllowUnload(bool unload); static void setAllowUnload(bool unload);
template<typename ...Args>
void FindAndCall(JNIEnv *env, std::string_view method_name, std::string_view method_sig, Args&&... args) const;
friend std::unique_ptr<Context> std::make_unique<Context>(); friend std::unique_ptr<Context> std::make_unique<Context>();
}; };

View File

@ -69,9 +69,10 @@ namespace lspd {
} }
LSP_DEF_NATIVE_METHOD(jboolean, ResourcesHook, initXResourcesNative) { LSP_DEF_NATIVE_METHOD(jboolean, ResourcesHook, initXResourcesNative) {
classXResources = Context::GetInstance()->FindClassFromCurrentLoader(env, if (auto classXResources_ = Context::GetInstance()->FindClassFromCurrentLoader(env,
kXResourcesClassName); kXResourcesClassName)) {
if (!classXResources) { classXResources = JNI_NewGlobalRef(env, classXResources_);
} else {
LOGE("Error while loading XResources class '%s':", kXResourcesClassName); LOGE("Error while loading XResources class '%s':", kXResourcesClassName);
return JNI_FALSE; return JNI_FALSE;
} }
@ -90,14 +91,13 @@ namespace lspd {
if (!PrepareSymbols()) { if (!PrepareSymbols()) {
return JNI_FALSE; return JNI_FALSE;
} }
classXResources = reinterpret_cast<jclass>(env->NewGlobalRef(classXResources));
return JNI_TRUE; return JNI_TRUE;
} }
// @ApiSensitive(Level.MIDDLE) // @ApiSensitive(Level.MIDDLE)
LSP_DEF_NATIVE_METHOD(jboolean, ResourcesHook, removeFinalFlagNative, jclass target_class) { LSP_DEF_NATIVE_METHOD(jboolean, ResourcesHook, removeFinalFlagNative, jclass target_class) {
if (target_class) { if (target_class) {
jclass class_clazz = JNI_FindClass(env, "java/lang/Class"); auto class_clazz = JNI_FindClass(env, "java/lang/Class");
jfieldID java_lang_Class_accessFlags = JNI_GetFieldID( jfieldID java_lang_Class_accessFlags = JNI_GetFieldID(
env, class_clazz, "accessFlags", "I"); env, class_clazz, "accessFlags", "I");
jint access_flags = env->GetIntField(target_class, java_lang_Class_accessFlags); jint access_flags = env->GetIntField(target_class, java_lang_Class_accessFlags);
@ -110,8 +110,8 @@ namespace lspd {
LSP_DEF_NATIVE_METHOD(jobject, ResourcesHook, buildDummyClassLoader, jobject parent, LSP_DEF_NATIVE_METHOD(jobject, ResourcesHook, buildDummyClassLoader, jobject parent,
jobject resource_super_class, jobject typed_array_super_class) { jobject resource_super_class, jobject typed_array_super_class) {
using namespace startop::dex; using namespace startop::dex;
static auto in_memory_classloader = (jclass) env->NewGlobalRef( static auto in_memory_classloader = JNI_NewGlobalRef(env, JNI_FindClass(env,
env->FindClass("dalvik/system/InMemoryDexClassLoader")); "dalvik/system/InMemoryDexClassLoader"));
static jmethodID initMid = JNI_GetMethodID(env, in_memory_classloader, "<init>", static jmethodID initMid = JNI_GetMethodID(env, in_memory_classloader, "<init>",
"(Ljava/nio/ByteBuffer;Ljava/lang/ClassLoader;)V"); "(Ljava/nio/ByteBuffer;Ljava/lang/ClassLoader;)V");
DexBuilder dex_file; DexBuilder dex_file;
@ -132,7 +132,7 @@ namespace lspd {
auto dex_buffer = env->NewDirectByteBuffer(const_cast<void *>(image.ptr()), image.size()); auto dex_buffer = env->NewDirectByteBuffer(const_cast<void *>(image.ptr()), image.size());
return JNI_NewObject(env, in_memory_classloader, initMid, return JNI_NewObject(env, in_memory_classloader, initMid,
dex_buffer, parent); dex_buffer, parent).release();
} }
LSP_DEF_NATIVE_METHOD(void, ResourcesHook, rewriteXmlReferencesNative, LSP_DEF_NATIVE_METHOD(void, ResourcesHook, rewriteXmlReferencesNative,

View File

@ -38,7 +38,7 @@ namespace lspd {
LSP_DEF_NATIVE_METHOD(jobject, Yahfa, findMethodNative, jclass targetClass, LSP_DEF_NATIVE_METHOD(jobject, Yahfa, findMethodNative, jclass targetClass,
jstring methodName, jstring methodSig) { jstring methodName, jstring methodSig) {
return yahfa::findMethodNative(env, clazz, targetClass, methodName, return yahfa::findMethodNative(env, clazz, targetClass, methodName,
methodSig); methodSig);
} }
LSP_DEF_NATIVE_METHOD(jboolean, Yahfa, backupAndHookNative, jobject target, LSP_DEF_NATIVE_METHOD(jboolean, Yahfa, backupAndHookNative, jobject target,
@ -60,8 +60,8 @@ namespace lspd {
LSP_DEF_NATIVE_METHOD(jclass, Yahfa, buildHooker, jobject app_class_loader, jclass return_class, LSP_DEF_NATIVE_METHOD(jclass, Yahfa, buildHooker, jobject app_class_loader, jclass return_class,
jobjectArray classes, jstring method_name) { jobjectArray classes, jstring method_name) {
static auto in_memory_classloader = (jclass) env->NewGlobalRef( static auto in_memory_classloader = JNI_NewGlobalRef(env, JNI_FindClass(env,
env->FindClass("dalvik/system/InMemoryDexClassLoader")); "dalvik/system/InMemoryDexClassLoader"));
static jmethodID initMid = JNI_GetMethodID(env, in_memory_classloader, "<init>", static jmethodID initMid = JNI_GetMethodID(env, in_memory_classloader, "<init>",
"(Ljava/nio/ByteBuffer;Ljava/lang/ClassLoader;)V"); "(Ljava/nio/ByteBuffer;Ljava/lang/ClassLoader;)V");
DexBuilder dex_file; DexBuilder dex_file;
@ -158,8 +158,9 @@ namespace lspd {
slicer::MemView image{dex_file.CreateImage()}; slicer::MemView image{dex_file.CreateImage()};
auto dex_buffer = env->NewDirectByteBuffer(const_cast<void *>(image.ptr()), image.size()); auto dex_buffer = env->NewDirectByteBuffer(const_cast<void *>(image.ptr()), image.size());
jobject my_cl = JNI_NewObject(env, in_memory_classloader, initMid, auto my_cl = JNI_NewObject(env, in_memory_classloader, initMid,
dex_buffer, app_class_loader); dex_buffer, app_class_loader);
env->DeleteLocalRef(dex_buffer);
static jmethodID mid = JNI_GetMethodID(env, in_memory_classloader, "loadClass", static jmethodID mid = JNI_GetMethodID(env, in_memory_classloader, "loadClass",
"(Ljava/lang/String;)Ljava/lang/Class;"); "(Ljava/lang/String;)Ljava/lang/Class;");
@ -167,10 +168,10 @@ namespace lspd {
mid = JNI_GetMethodID(env, in_memory_classloader, "findClass", mid = JNI_GetMethodID(env, in_memory_classloader, "findClass",
"(Ljava/lang/String;)Ljava/lang/Class;"); "(Ljava/lang/String;)Ljava/lang/Class;");
} }
jobject target = env->CallObjectMethod(my_cl, mid, env->NewStringUTF("LspHooker_")); auto target = JNI_CallObjectMethod(env, my_cl, mid, env->NewStringUTF("LspHooker_"));
// LOGD("Created %zd", image.size()); // LOGD("Created %zd", image.size());
if (target) { if (target) {
return (jclass) target; return (jclass) target.release();
} }
return nullptr; return nullptr;
} }

View File

@ -62,66 +62,64 @@ namespace lspd {
void Service::InitService(JNIEnv *env) { void Service::InitService(JNIEnv *env) {
if (LIKELY(initialized_)) return; if (LIKELY(initialized_)) return;
initialized_ = true;
// ServiceManager // ServiceManager
service_manager_class_ = env->FindClass("android/os/ServiceManager"); if (auto service_manager_class = JNI_FindClass(env, "android/os/ServiceManager"))
if (service_manager_class_) { service_manager_class_ = JNI_NewGlobalRef(env, service_manager_class);
service_manager_class_ = (jclass) env->NewGlobalRef(service_manager_class_); else return;
} else { get_service_method_ = JNI_GetStaticMethodID(env, service_manager_class_, "getService",
env->ExceptionClear(); "(Ljava/lang/String;)Landroid/os/IBinder;");
return; if (!get_service_method_) return;
}
get_service_method_ = env->GetStaticMethodID(service_manager_class_, "getService",
"(Ljava/lang/String;)Landroid/os/IBinder;");
if (!get_service_method_) {
env->ExceptionClear();
return;
}
// IBinder // IBinder
jclass ibinder_class = env->FindClass("android/os/IBinder"); if (auto ibinder_class = JNI_FindClass(env, "android/os/IBinder"))
transact_method_ = env->GetMethodID(ibinder_class, "transact", transact_method_ = JNI_GetMethodID(env, ibinder_class, "transact",
"(ILandroid/os/Parcel;Landroid/os/Parcel;I)Z"); "(ILandroid/os/Parcel;Landroid/os/Parcel;I)Z");
else return;
binder_class_ = env->FindClass("android/os/Binder"); if (auto binder_class = JNI_FindClass(env, "android/os/Binder"))
if (binder_class_) binder_class_ = (jclass) env->NewGlobalRef(binder_class_); binder_class_ = JNI_NewGlobalRef(env, binder_class);
binder_ctor_ = env->GetMethodID(binder_class_, "<init>", "()V"); else return;
binder_ctor_ = JNI_GetMethodID(env, binder_class_, "<init>", "()V");
// Parcel // Parcel
parcel_class_ = env->FindClass("android/os/Parcel"); if (auto parcel_class = JNI_FindClass(env, "android/os/Parcel"))
if (parcel_class_) parcel_class_ = (jclass) env->NewGlobalRef(parcel_class_); parcel_class_ = JNI_NewGlobalRef(env, parcel_class);
obtain_method_ = env->GetStaticMethodID(parcel_class_, "obtain", "()Landroid/os/Parcel;"); else return;
recycleMethod_ = env->GetMethodID(parcel_class_, "recycle", "()V"); obtain_method_ = JNI_GetStaticMethodID(env, parcel_class_, "obtain",
write_interface_token_method_ = env->GetMethodID(parcel_class_, "writeInterfaceToken", "()Landroid/os/Parcel;");
"(Ljava/lang/String;)V"); recycleMethod_ = JNI_GetMethodID(env, parcel_class_, "recycle", "()V");
write_int_method_ = env->GetMethodID(parcel_class_, "writeInt", "(I)V"); write_interface_token_method_ = JNI_GetMethodID(env, parcel_class_, "writeInterfaceToken",
write_string_method_ = env->GetMethodID(parcel_class_, "writeString", "(Ljava/lang/String;)V");
"(Ljava/lang/String;)V"); write_int_method_ = JNI_GetMethodID(env, parcel_class_, "writeInt", "(I)V");
write_strong_binder_method_ = env->GetMethodID(parcel_class_, "writeStrongBinder", write_string_method_ = JNI_GetMethodID(env, parcel_class_, "writeString",
"(Landroid/os/IBinder;)V"); "(Ljava/lang/String;)V");
read_exception_method_ = env->GetMethodID(parcel_class_, "readException", "()V"); write_strong_binder_method_ = JNI_GetMethodID(env, parcel_class_, "writeStrongBinder",
read_strong_binder_method_ = env->GetMethodID(parcel_class_, "readStrongBinder", "(Landroid/os/IBinder;)V");
"()Landroid/os/IBinder;"); read_exception_method_ = JNI_GetMethodID(env, parcel_class_, "readException", "()V");
read_strong_binder_method_ = JNI_GetMethodID(env, parcel_class_, "readStrongBinder",
"()Landroid/os/IBinder;");
// createStringArray_ = env->GetMethodID(parcel_class_, "createStringArray", // createStringArray_ = env->GetMethodID(parcel_class_, "createStringArray",
// "()[Ljava/lang/String;"); // "()[Ljava/lang/String;");
deadObjectExceptionClass_ = env->FindClass("android/os/DeadObjectException"); if (auto deadObjectExceptionClass = JNI_FindClass(env, "android/os/DeadObjectException"))
if (deadObjectExceptionClass_) deadObjectExceptionClass_ = JNI_NewGlobalRef(env, deadObjectExceptionClass);
deadObjectExceptionClass_ = (jclass) env->NewGlobalRef(deadObjectExceptionClass_); initialized_ = true;
} }
void Service::HookBridge(const Context &context, JNIEnv *env) { void Service::HookBridge(const Context &context, JNIEnv *env) {
static bool hooked = false; static bool hooked = false;
// This should only be ran once, so unlikely // This should only be ran once, so unlikely
if (UNLIKELY(hooked)) return; if (UNLIKELY(hooked)) return;
if (UNLIKELY(!initialized_)) return;
hooked = true; hooked = true;
bridge_service_class_ = context.FindClassFromCurrentLoader(env, kBridgeServiceClassName); if (auto bridge_service_class = context.FindClassFromCurrentLoader(env,
if (!bridge_service_class_) { kBridgeServiceClassName))
bridge_service_class_ = JNI_NewGlobalRef(env, bridge_service_class);
else {
LOGE("server class not found"); LOGE("server class not found");
return; return;
} }
bridge_service_class_ = (jclass) env->NewGlobalRef(bridge_service_class_);
exec_transact_replace_methodID_ = JNI_GetStaticMethodID(env, bridge_service_class_, exec_transact_replace_methodID_ = JNI_GetStaticMethodID(env, bridge_service_class_,
"execTransact", "execTransact",
"(IJJI)Z"); "(IJJI)Z");
@ -130,8 +128,8 @@ namespace lspd {
return; return;
} }
ScopedLocalRef binderClass(env, env->FindClass("android/os/Binder")); auto binderClass = JNI_FindClass(env, "android/os/Binder");
exec_transact_backup_methodID_ = JNI_GetMethodID(env, binderClass.get(), "execTransact", exec_transact_backup_methodID_ = JNI_GetMethodID(env, binderClass, "execTransact",
"(IJJI)Z"); "(IJJI)Z");
auto set_table_override = reinterpret_cast<void (*)( auto set_table_override = reinterpret_cast<void (*)(
JNINativeInterface *)>(Dlsym(handle_libart, JNINativeInterface *)>(Dlsym(handle_libart,
@ -151,10 +149,10 @@ namespace lspd {
LOGD("Done InitService"); LOGD("Done InitService");
} }
jobject Service::RequestBinder(JNIEnv *env, jstring nice_name) { ScopedLocalRef<jobject> Service::RequestBinder(JNIEnv *env, jstring nice_name) {
if (UNLIKELY(!initialized_)) { if (UNLIKELY(!initialized_)) {
LOGE("Service not initialized"); LOGE("Service not initialized");
return nullptr; return {env, nullptr};
} }
auto bridgeServiceName = env->NewStringUTF(BRIDGE_SERVICE_NAME.data()); auto bridgeServiceName = env->NewStringUTF(BRIDGE_SERVICE_NAME.data());
@ -162,7 +160,7 @@ namespace lspd {
get_service_method_, bridgeServiceName); get_service_method_, bridgeServiceName);
if (!bridgeService) { if (!bridgeService) {
LOGD("can't get %s", BRIDGE_SERVICE_NAME.data()); LOGD("can't get %s", BRIDGE_SERVICE_NAME.data());
return nullptr; return {env, nullptr};
} }
auto heart_beat_binder = JNI_NewObject(env, binder_class_, binder_ctor_); auto heart_beat_binder = JNI_NewObject(env, binder_class_, binder_ctor_);
@ -181,7 +179,7 @@ namespace lspd {
data, data,
reply, 0); reply, 0);
jobject service = nullptr; ScopedLocalRef<jobject> service = {env, nullptr};
if (res) { if (res) {
JNI_CallVoidMethod(env, reply, read_exception_method_); JNI_CallVoidMethod(env, reply, read_exception_method_);
service = JNI_CallObjectMethod(env, reply, read_strong_binder_method_); service = JNI_CallObjectMethod(env, reply, read_strong_binder_method_);
@ -189,25 +187,23 @@ namespace lspd {
JNI_CallVoidMethod(env, data, recycleMethod_); JNI_CallVoidMethod(env, data, recycleMethod_);
JNI_CallVoidMethod(env, reply, recycleMethod_); JNI_CallVoidMethod(env, reply, recycleMethod_);
if (service) { if (service) {
env->NewGlobalRef(heart_beat_binder); JNI_NewGlobalRef(env, heart_beat_binder);
} else {
env->DeleteLocalRef(heart_beat_binder);
} }
return service; return service;
} }
jobject Service::RequestBinderForSystemServer(JNIEnv *env) { ScopedLocalRef<jobject> Service::RequestBinderForSystemServer(JNIEnv *env) {
if (UNLIKELY(!initialized_ || !bridge_service_class_)) { if (UNLIKELY(!initialized_ || !bridge_service_class_)) {
LOGE("Service not initialized"); LOGE("Service not initialized");
return nullptr; return {env, nullptr};
} }
auto bridgeServiceName = env->NewStringUTF(SYSTEM_SERVER_BRIDGE_SERVICE_NAME.data()); auto bridgeServiceName = env->NewStringUTF(SYSTEM_SERVER_BRIDGE_SERVICE_NAME.data());
auto binder = JNI_CallStaticObjectMethod(env, service_manager_class_, auto binder = JNI_CallStaticObjectMethod(env, service_manager_class_,
get_service_method_, bridgeServiceName); get_service_method_, bridgeServiceName);
if (!binder) { if (!binder) {
LOGD("Fail to get binder for system server"); LOGD("Fail to get binder for system server");
return nullptr; return {env, nullptr};
} }
auto method = JNI_GetStaticMethodID(env, bridge_service_class_, auto method = JNI_GetStaticMethodID(env, bridge_service_class_,
"getApplicationServiceForSystemServer", "getApplicationServiceForSystemServer",
@ -216,9 +212,7 @@ namespace lspd {
auto app_binder = JNI_CallStaticObjectMethod(env, bridge_service_class_, method, binder, auto app_binder = JNI_CallStaticObjectMethod(env, bridge_service_class_, method, binder,
heart_beat_binder); heart_beat_binder);
if (app_binder) { if (app_binder) {
env->NewGlobalRef(heart_beat_binder); JNI_NewGlobalRef(env, heart_beat_binder);
} else {
env->DeleteLocalRef(heart_beat_binder);
} }
return app_binder; return app_binder;
} }

View File

@ -49,10 +49,9 @@ namespace lspd {
void InitService(JNIEnv *env); void InitService(JNIEnv *env);
void HookBridge(const Context& context, JNIEnv *env); void HookBridge(const Context& context, JNIEnv *env);
ScopedLocalRef<jobject> RequestBinder(JNIEnv *env, jstring nice_name);
jobject RequestBinder(JNIEnv *env, jstring nice_name); ScopedLocalRef<jobject> RequestBinderForSystemServer(JNIEnv *env);
jobject RequestBinderForSystemServer(JNIEnv *env);
private: private:
inline static std::unique_ptr<Service> instance_ = std::make_unique<Service>(); inline static std::unique_ptr<Service> instance_ = std::make_unique<Service>();