[core] Update JNI helper (#440)

This commit is contained in:
LoveSy 2021-04-01 18:17:39 +08:00 committed by GitHub
parent eecef24179
commit a384697655
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 188 additions and 129 deletions

View File

@ -91,20 +91,14 @@ public class LogsActivity extends BaseActivity {
e.printStackTrace(); e.printStackTrace();
} }
AsyncTask.THREAD_POOL_EXECUTOR.execute(() -> { AsyncTask.THREAD_POOL_EXECUTOR.execute(() -> {
try { try (var os = getContentResolver().openOutputStream(uri)) {
OutputStream os = getContentResolver().openOutputStream(uri);
if (os == null) {
return;
}
ParcelFileDescriptor parcelFileDescriptor = ConfigManager.getLogs(verbose); ParcelFileDescriptor parcelFileDescriptor = ConfigManager.getLogs(verbose);
if (parcelFileDescriptor == null) { if (parcelFileDescriptor == null) {
os.close();
return; return;
} }
InputStream is = new FileInputStream(parcelFileDescriptor.getFileDescriptor()); try (var is = new FileInputStream(parcelFileDescriptor.getFileDescriptor())) {
FileUtils.copy(is, os); FileUtils.copy(is, os);
os.close(); }
is.close();
} catch (Exception e) { } catch (Exception e) {
Snackbar.make(binding.snackbar, getResources().getString(R.string.logs_save_failed) + "\n" + e.getMessage(), Snackbar.LENGTH_LONG).show(); Snackbar.make(binding.snackbar, getResources().getString(R.string.logs_save_failed) + "\n" + e.getMessage(), Snackbar.LENGTH_LONG).show();
} }
@ -252,9 +246,7 @@ public class LogsActivity extends BaseActivity {
now.get(Calendar.DAY_OF_MONTH), now.get(Calendar.HOUR_OF_DAY), now.get(Calendar.DAY_OF_MONTH), now.get(Calendar.HOUR_OF_DAY),
now.get(Calendar.MINUTE), now.get(Calendar.SECOND)); now.get(Calendar.MINUTE), now.get(Calendar.SECOND));
File cacheFile = new File(getCacheDir(), filename); File cacheFile = new File(getCacheDir(), filename);
try { try (var os = new FileOutputStream(cacheFile); var is = new FileInputStream(parcelFileDescriptor.getFileDescriptor())) {
OutputStream os = new FileOutputStream(cacheFile);
InputStream is = new FileInputStream(parcelFileDescriptor.getFileDescriptor());
FileUtils.copy(is, os); FileUtils.copy(is, os);
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();

View File

@ -44,7 +44,7 @@ val androidTargetSdkVersion by extra(30)
val androidMinSdkVersion by extra(27) val androidMinSdkVersion by extra(27)
val androidBuildToolsVersion by extra("30.0.3") val androidBuildToolsVersion by extra("30.0.3")
val androidCompileSdkVersion by extra(30) val androidCompileSdkVersion by extra(30)
val androidCompileNdkVersion by extra("22.0.7026061") val androidCompileNdkVersion by extra("22.1.7171670")
val androidSourceCompatibility by extra(JavaVersion.VERSION_11) val androidSourceCompatibility by extra(JavaVersion.VERSION_11)
val androidTargetCompatibility by extra(JavaVersion.VERSION_11) val androidTargetCompatibility by extra(JavaVersion.VERSION_11)
val apiCode by extra(93) val apiCode by extra(93)

View File

@ -27,107 +27,6 @@
#define JNI_START JNIEnv *env, [[maybe_unused]] jclass clazz #define JNI_START JNIEnv *env, [[maybe_unused]] jclass clazz
ALWAYS_INLINE static void JNIExceptionClear(JNIEnv *env) {
if (env->ExceptionCheck()) {
env->ExceptionClear();
}
}
ALWAYS_INLINE static bool JNIExceptionCheck(JNIEnv *env) {
if (env->ExceptionCheck()) {
jthrowable e = env->ExceptionOccurred();
env->Throw(e);
env->DeleteLocalRef(e);
return true;
}
return false;
}
ALWAYS_INLINE static void JNIExceptionClearAndDescribe(JNIEnv *env) {
if (env->ExceptionCheck()) {
env->ExceptionDescribe();
env->ExceptionClear();
}
}
ALWAYS_INLINE static int ClearException(JNIEnv *env) {
jthrowable exception = env->ExceptionOccurred();
if (exception != nullptr) {
env->ExceptionDescribe();
env->ExceptionClear();
return true;
}
return false;
}
#define JNI_FindClass(env, name) \
env->FindClass(name); \
if (ClearException(env)) LOGE("FindClass " #name)
#define JNI_GetObjectClass(env, obj) \
env->GetObjectClass(obj); \
if (ClearException(env)) LOGE("GetObjectClass " #obj)
#define JNI_GetFieldID(env, class, name, sig) \
env->GetFieldID(class, name, sig); \
if (ClearException(env)) LOGE("GetFieldID " #name)
#define JNI_GetObjectField(env, class, fieldId) \
env->GetObjectField(class, fieldId); \
if (ClearException(env)) LOGE("GetObjectField " #fieldId)
#define JNI_GetMethodID(env, class, name, sig) \
env->GetMethodID(class, name, sig); \
//if (ClearException(env)) LOGE("GetMethodID " #name)
#define JNI_CallObjectMethod(env, obj, ...) \
env->CallObjectMethod(obj, __VA_ARGS__); \
if (ClearException(env)) LOGE("CallObjectMethod " #obj " " #__VA_ARGS__)
#define JNI_CallVoidMethod(env, obj, ...) \
env->CallVoidMethod(obj, __VA_ARGS__); \
if (ClearException(env)) LOGE("CallVoidMethod " #obj " " #__VA_ARGS__)
#define JNI_CallBooleanMethod(env, obj, ...) \
env->CallBooleanMethod(obj, __VA_ARGS__); \
if (ClearException(env)) LOGE("CallVoidMethod " #obj " " #__VA_ARGS__)
#define JNI_GetStaticFieldID(env, class, name, sig) \
env->GetStaticFieldID(class, name, sig); \
if (ClearException(env)) LOGE("GetStaticFieldID " #name " " #sig)
#define JNI_GetStaticObjectField(env, class, fieldId) \
env->GetStaticObjectField(class, fieldId); \
if (ClearException(env)) LOGE("GetStaticObjectField " #fieldId)
#define JNI_GetStaticMethodID(env, class, name, sig) \
env->GetStaticMethodID(class, name, sig); \
if (ClearException(env)) LOGE("GetStaticMethodID " #name)
#define JNI_CallStaticVoidMethod(env, obj, ...) \
env->CallStaticVoidMethod(obj, __VA_ARGS__); \
if (ClearException(env)) LOGE("CallStaticVoidMethod " #obj " " #__VA_ARGS__)
#define JNI_CallStaticObjectMethod(env, obj, ...) \
env->CallStaticObjectMethod(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) \
env->GetArrayLength(array); \
if (ClearException(env)) LOGE("GetArrayLength " #array)
#define JNI_NewObject(env, class, ...) \
env->NewObject(class, __VA_ARGS__); \
if (ClearException(env)) LOGE("NewObject " #class " " #__VA_ARGS__)
#define JNI_RegisterNatives(env, class, methods, size) \
env->RegisterNatives(class, methods, size); \
if (ClearException(env)) LOGE("RegisterNatives " #class)
class JUTFString { class JUTFString {
public: public:
inline JUTFString(JNIEnv *env, jstring jstr) : JUTFString(env, jstr, nullptr) { inline JUTFString(JNIEnv *env, jstring jstr) : JUTFString(env, jstr, nullptr) {
@ -181,15 +80,19 @@ private:
template<typename T> template<typename 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) {
} }
ScopedLocalRef(ScopedLocalRef&& s) noexcept : mEnv(s.mEnv), mLocalRef(s.release()) {
ScopedLocalRef(ScopedLocalRef &&s) noexcept: mEnv(s.mEnv), mLocalRef(s.release()) {
} }
explicit ScopedLocalRef(JNIEnv* env) : mEnv(env), mLocalRef(nullptr) {
explicit ScopedLocalRef(JNIEnv *env) : mEnv(env), mLocalRef(nullptr) {
} }
~ScopedLocalRef() { ~ScopedLocalRef() {
reset(); reset();
} }
void reset(T ptr = NULL) { void reset(T ptr = NULL) {
if (ptr != mLocalRef) { if (ptr != mLocalRef) {
if (mLocalRef != NULL) { if (mLocalRef != NULL) {
@ -198,34 +101,198 @@ public:
mLocalRef = ptr; mLocalRef = ptr;
} }
} }
T release() __attribute__((warn_unused_result)) { T release() __attribute__((warn_unused_result)) {
T localRef = mLocalRef; T localRef = mLocalRef;
mLocalRef = NULL; mLocalRef = NULL;
return localRef; return localRef;
} }
T get() const { T get() const {
return mLocalRef; return mLocalRef;
} }
// We do not expose an empty constructor as it can easily lead to errors // We do not expose an empty constructor as it can easily lead to errors
// using common idioms, e.g.: // using common idioms, e.g.:
// ScopedLocalRef<...> ref; // ScopedLocalRef<...> ref;
// ref.reset(...); // ref.reset(...);
// Move assignment operator. // Move assignment operator.
ScopedLocalRef& operator=(ScopedLocalRef&& s) noexcept { ScopedLocalRef &operator=(ScopedLocalRef &&s) noexcept {
reset(s.release()); reset(s.release());
mEnv = s.mEnv; mEnv = s.mEnv;
return *this; return *this;
} }
// Allows "if (scoped_ref == nullptr)" // Allows "if (scoped_ref == nullptr)"
bool operator==(std::nullptr_t) const { bool operator==(std::nullptr_t) const {
return mLocalRef == nullptr; return mLocalRef == nullptr;
} }
// Allows "if (scoped_ref != nullptr)" // Allows "if (scoped_ref != nullptr)"
bool operator!=(std::nullptr_t) const { bool operator!=(std::nullptr_t) const {
return mLocalRef != nullptr; return mLocalRef != nullptr;
} }
private: private:
JNIEnv* mEnv; JNIEnv *mEnv;
T mLocalRef; T mLocalRef;
DISALLOW_COPY_AND_ASSIGN(ScopedLocalRef); DISALLOW_COPY_AND_ASSIGN(ScopedLocalRef);
}; };
[[maybe_unused]]
inline void JNIExceptionClear(JNIEnv *env) {
if (env->ExceptionCheck()) {
env->ExceptionClear();
}
}
[[maybe_unused]]
inline bool JNIExceptionCheck(JNIEnv *env) {
if (env->ExceptionCheck()) {
jthrowable e = env->ExceptionOccurred();
env->Throw(e);
env->DeleteLocalRef(e);
return true;
}
return false;
}
[[maybe_unused]]
inline void JNIExceptionClearAndDescribe(JNIEnv *env) {
if (env->ExceptionCheck()) {
env->ExceptionDescribe();
env->ExceptionClear();
}
}
inline jstring ClearException(JNIEnv *env) {
static jmethodID toString = env->GetMethodID(env->FindClass("java/lang/Object"), "toString",
"()Ljava/lang/String;");
if (auto exception = env->ExceptionOccurred()) {
env->ExceptionClear();
return (jstring) env->CallObjectMethod(exception, toString);
}
return nullptr;
}
template<typename T>
[[maybe_unused]]
inline auto unwrap_sv(T &&x) {
if constexpr (std::is_same_v<std::decay_t<T>, std::string_view>) return x.data();
else return std::forward<T>(x);
}
template<typename Func, typename ...Args>
[[maybe_unused]]
inline auto JNI_SafeInvoke(JNIEnv *env, Func f, Args &&... args) {
static_assert(std::is_member_function_pointer_v<Func>);
struct finally {
finally(JNIEnv *env) : env_(env) {}
~finally() {
if (auto exception = ClearException(env_)) {
LOGE("%s", JUTFString(env_, exception).get());
}
}
JNIEnv *env_;
} _(env);
return (env->*f)(unwrap_sv(std::forward<Args>(args))...);
}
[[maybe_unused]]
inline auto JNI_FindClass(JNIEnv *env, std::string_view name) {
return JNI_SafeInvoke(env, &JNIEnv::FindClass, name);
}
[[maybe_unused]]
inline auto JNI_GetObjectClass(JNIEnv *env, jobject obj) {
return JNI_SafeInvoke(env, &JNIEnv::GetObjectClass, obj);
}
[[maybe_unused]]
inline auto JNI_GetFieldID(JNIEnv *env, jclass clazz, std::string_view name, std::string_view sig) {
return JNI_SafeInvoke(env, &JNIEnv::GetFieldID, clazz, name, sig);
}
[[maybe_unused]]
inline auto JNI_GetObjectField(JNIEnv *env, jclass clazz, jfieldID fieldId) {
return JNI_SafeInvoke(env, &JNIEnv::GetObjectField, clazz, fieldId);
}
[[maybe_unused]]
inline auto
JNI_GetMethodID(JNIEnv *env, jclass clazz, std::string_view name, std::string_view sig) {
return JNI_SafeInvoke(env, &JNIEnv::GetMethodID, clazz, name, sig);
}
template<typename ...Args>
[[maybe_unused]]
inline auto JNI_CallObjectMethod(JNIEnv *env, jobject obj, Args &&... args) {
return JNI_SafeInvoke(env, &JNIEnv::CallObjectMethod, obj, std::forward<Args>(args)...);
}
template<typename ...Args>
[[maybe_unused]]
inline auto JNI_CallVoidMethod(JNIEnv *env, jobject obj, Args &&...args) {
return JNI_SafeInvoke(env, &JNIEnv::CallVoidMethod, obj, std::forward<Args>(args)...);
}
template<typename ...Args>
[[maybe_unused]]
inline auto JNI_CallBooleanMethod(JNIEnv *env, jobject obj, Args &&...args) {
return JNI_SafeInvoke(env, &JNIEnv::CallBooleanMethod, obj, std::forward<Args>(args)...);
}
[[maybe_unused]]
inline auto
JNI_GetStaticFieldID(JNIEnv *env, jclass clazz, std::string_view name, std::string_view sig) {
return JNI_SafeInvoke(env, &JNIEnv::GetStaticFieldID, clazz, name, sig);
}
[[maybe_unused]]
inline auto JNI_GetStaticObjectField(JNIEnv *env, jclass clazz, jfieldID fieldId) {
return JNI_SafeInvoke(env, &JNIEnv::GetStaticObjectField, clazz, fieldId);
}
[[maybe_unused]]
inline auto
JNI_GetStaticMethodID(JNIEnv *env, jclass clazz, std::string_view name, std::string_view sig) {
return JNI_SafeInvoke(env, &JNIEnv::GetStaticMethodID, clazz, name, sig);
}
template<typename ...Args>
[[maybe_unused]]
inline auto JNI_CallStaticVoidMethod(JNIEnv *env, jclass clazz, Args &&...args) {
return JNI_SafeInvoke(env, &JNIEnv::CallStaticVoidMethod, clazz, std::forward<Args>(args)...);
}
template<typename ...Args>
[[maybe_unused]]
inline auto JNI_CallStaticObjectMethod(JNIEnv *env, jclass clazz, Args &&...args) {
return JNI_SafeInvoke(env, &JNIEnv::CallStaticObjectMethod, clazz, std::forward<Args>(args)...);
}
template<typename ...Args>
[[maybe_unused]]
inline auto JNI_CallStaticIntMethod(JNIEnv *env, jclass clazz, Args &&...args) {
return JNI_SafeInvoke(env, &JNIEnv::CallStaticIntMethod, clazz, std::forward<Args>(args)...);
}
[[maybe_unused]]
inline auto JNI_GetArrayLength(JNIEnv *env, jarray array) {
return JNI_SafeInvoke(env, &JNIEnv::GetArrayLength, array);
}
template<typename ...Args>
[[maybe_unused]]
inline auto JNI_NewObject(JNIEnv *env, jclass clazz, Args &&...args) {
return JNI_SafeInvoke(env, &JNIEnv::NewObject, clazz, std::forward<Args>(args)...);
}
[[maybe_unused]]
inline auto
JNI_RegisterNatives(JNIEnv *env, jclass clazz, const JNINativeMethod *methods, jint size) {
return JNI_SafeInvoke(env, &JNIEnv::RegisterNatives, clazz, methods, size);
}

View File

@ -35,14 +35,15 @@ namespace lspd {
const JNINativeMethod *methods, const JNINativeMethod *methods,
jint method_count) { jint method_count) {
ScopedLocalRef<jclass> clazz(env, ScopedLocalRef clazz(env,
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.get(), methods, method_count);
} }
#if defined(__cplusplus) #if defined(__cplusplus)
#define _NATIVEHELPER_JNI_MACRO_CAST(to) \ #define _NATIVEHELPER_JNI_MACRO_CAST(to) \
reinterpret_cast<to> reinterpret_cast<to>
@ -60,7 +61,7 @@ namespace lspd {
#endif #endif
#ifndef LSP_DEF_NATIVE_METHOD #ifndef LSP_DEF_NATIVE_METHOD
#define LSP_DEF_NATIVE_METHOD(ret, className, functionName, ...) \ #define LSP_DEF_NATIVE_METHOD(ret, className, functionName, ...) \
extern "C" ret Java_org_lsposed_lspd_nativebridge_## className ## _ ## functionName (JNI_START, ## __VA_ARGS__) extern "C" ret Java_org_lsposed_lspd_nativebridge_## className ## _ ## functionName (JNI_START, ## __VA_ARGS__)
#endif #endif

View File

@ -130,7 +130,7 @@ namespace lspd {
return; return;
} }
ScopedLocalRef<jclass> binderClass(env, env->FindClass("android/os/Binder")); ScopedLocalRef binderClass(env, env->FindClass("android/os/Binder"));
exec_transact_backup_methodID_ = JNI_GetMethodID(env, binderClass.get(), "execTransact", exec_transact_backup_methodID_ = JNI_GetMethodID(env, binderClass.get(), "execTransact",
"(IJJI)Z"); "(IJJI)Z");
auto set_table_override = reinterpret_cast<void (*)( auto set_table_override = reinterpret_cast<void (*)(
@ -183,10 +183,8 @@ namespace lspd {
jobject service = nullptr; jobject service = nullptr;
if (res) { if (res) {
env->CallVoidMethod(reply, read_exception_method_); JNI_CallVoidMethod(env, reply, read_exception_method_);
if (!ClearException(env)) { service = JNI_CallObjectMethod(env, reply, read_strong_binder_method_);
service = JNI_CallObjectMethod(env, reply, read_strong_binder_method_);
}
} }
JNI_CallVoidMethod(env, data, recycleMethod_); JNI_CallVoidMethod(env, data, recycleMethod_);
JNI_CallVoidMethod(env, reply, recycleMethod_); JNI_CallVoidMethod(env, reply, recycleMethod_);

View File

@ -265,7 +265,8 @@ public class BridgeService {
try { try {
String processName = data.readString(); String processName = data.readString();
IBinder heartBeat = data.readStrongBinder(); IBinder heartBeat = data.readStrongBinder();
binder = service.requestApplicationService(Binder.getCallingUid(), Binder.getCallingPid(), processName, heartBeat).asBinder(); var applicationService = service.requestApplicationService(Binder.getCallingUid(), Binder.getCallingPid(), processName, heartBeat);
if (applicationService != null) binder = service.asBinder();
} catch (RemoteException e) { } catch (RemoteException e) {
Log.e(TAG, Log.getStackTraceString(e)); Log.e(TAG, Log.getStackTraceString(e));
} }