zworld-em/Plugins/sentry-unreal/Source/Sentry/Private/Android/Infrastructure/SentryJavaObjectWrapper.cpp

254 lines
7.5 KiB
C++
Raw Permalink Normal View History

2025-05-11 22:07:21 +08:00
// Copyright (c) 2022 Sentry. All Rights Reserved.
#include "SentryJavaObjectWrapper.h"
#include "Android/AndroidJNI.h"
FSentryJavaObjectWrapper::FSentryJavaObjectWrapper(FSentryJavaClass ClassData)
: Object(nullptr)
, Class(nullptr)
{
JNIEnv* JEnv = AndroidJavaEnv::GetJavaEnv();
ANSICHAR AnsiClassName[NAME_SIZE];
ClassData.Name.GetPlainANSIString(AnsiClassName);
if(ClassData.Type == ESentryJavaClassType::System)
Class = FJavaWrapper::FindClassGlobalRef(JEnv, AnsiClassName, false);
if(ClassData.Type == ESentryJavaClassType::External)
Class = AndroidJavaEnv::FindJavaClassGlobalRef(AnsiClassName);
check(Class);
}
FSentryJavaObjectWrapper::FSentryJavaObjectWrapper(FSentryJavaClass ClassData, const char* CtorSignature, ...)
: FSentryJavaObjectWrapper(ClassData)
{
JNIEnv* JEnv = AndroidJavaEnv::GetJavaEnv();
jmethodID Constructor = JEnv->GetMethodID(Class, "<init>", CtorSignature);
check(Constructor);
va_list Params;
va_start(Params, CtorSignature);
auto LocalObject = NewScopedJavaObject(JEnv, JEnv->NewObjectV(Class, Constructor, Params));
va_end(Params);
VerifyException();
check(LocalObject);
Object = JEnv->NewGlobalRef(*LocalObject);
}
FSentryJavaObjectWrapper::FSentryJavaObjectWrapper(FSentryJavaClass ClassData, jobject JavaClassInstance)
: FSentryJavaObjectWrapper(ClassData)
{
JNIEnv* JEnv = AndroidJavaEnv::GetJavaEnv();
if(!JEnv->IsInstanceOf(JavaClassInstance, Class))
{
verify(false && "Java class instance type doesn't match the specified class.");
}
Object = JEnv->NewGlobalRef(JavaClassInstance);
}
FSentryJavaObjectWrapper::~FSentryJavaObjectWrapper()
{
JNIEnv* JEnv = AndroidJavaEnv::GetJavaEnv();
if(Object)
JEnv->DeleteGlobalRef(Object);
if(Class)
JEnv->DeleteGlobalRef(Class);
}
FSentryJavaMethod FSentryJavaObjectWrapper::GetMethod(const char* MethodName, const char* FunctionSignature)
{
JNIEnv* JEnv = AndroidJavaEnv::GetJavaEnv();
FSentryJavaMethod Method;
Method.Method = JEnv->GetMethodID(Class, MethodName, FunctionSignature);
Method.Name = MethodName;
Method.Signature = FunctionSignature;
Method.IsStatic = false;
checkf(Method.Method, TEXT("Unable to find Java Method %s with Signature %s"), UTF8_TO_TCHAR(MethodName), UTF8_TO_TCHAR(FunctionSignature));
return Method;
}
FSentryJavaMethod FSentryJavaObjectWrapper::GetStaticMethod(FSentryJavaClass ClassData, const char* MethodName, const char* FunctionSignature)
{
FSentryJavaObjectWrapper StaticClass(ClassData);
JNIEnv* JEnv = AndroidJavaEnv::GetJavaEnv();
FSentryJavaMethod Method;
Method.Method = JEnv->GetStaticMethodID(StaticClass.Class, MethodName, FunctionSignature);
Method.Name = MethodName;
Method.Signature = FunctionSignature;
Method.IsStatic = true;
checkf(Method.Method, TEXT("Unable to find Java Method %s with Signature %s"), UTF8_TO_TCHAR(MethodName), UTF8_TO_TCHAR(FunctionSignature));
return Method;
}
jobject FSentryJavaObjectWrapper::GetJObject() const
{
check(Object);
return Object;
}
FScopedJavaObject<jstring> FSentryJavaObjectWrapper::GetJString(const FString& String)
{
JNIEnv* JEnv = AndroidJavaEnv::GetJavaEnv();
return FJavaHelper::ToJavaString(JEnv, String);
}
void FSentryJavaObjectWrapper::VerifyMethodCall(FSentryJavaMethod Method) const
{
if(Method.IsStatic && Object)
{
verify(false && "Calling static method using class instance is not allowed. Try CallStaticMethod/CallStaticObjectMethod instead.");
}
if(!Method.IsStatic && !Object)
{
verify(false && "Calling instance method in static context is not allowed. Check method config or try CallMethod/CallObjectMethod instead.");
}
}
void FSentryJavaObjectWrapper::VerifyException() const
{
JNIEnv* JEnv = AndroidJavaEnv::GetJavaEnv();
if (JEnv->ExceptionCheck())
{
JEnv->ExceptionDescribe();
JEnv->ExceptionClear();
verify(false && "Java JNI call failed with an exception.");
}
}
template<>
void FSentryJavaObjectWrapper::CallMethod<void>(FSentryJavaMethod Method, ...) const
{
va_list Params;
va_start(Params, Method);
CallMethodInternal<void>(Method, Params);
va_end(Params);
}
template<>
void FSentryJavaObjectWrapper::CallStaticMethod<void>(FSentryJavaClass ClassData, FSentryJavaMethod Method, ...)
{
FSentryJavaObjectWrapper StaticInst(ClassData);
va_list Params;
va_start(Params, Method);
StaticInst.CallMethodInternal<void>(Method, Params);
va_end(Params);
}
template<>
void FSentryJavaObjectWrapper::CallStaticMethod<void>(FSentryJavaClass ClassData, const char* MethodName, const char* FunctionSignature, ...)
{
FSentryJavaObjectWrapper StaticInst(ClassData);
FSentryJavaMethod Method = GetStaticMethod(ClassData, MethodName, FunctionSignature);
va_list Params;
va_start(Params, FunctionSignature);
StaticInst.CallMethodInternal<void>(Method, Params);
va_end(Params);
}
template<>
void FSentryJavaObjectWrapper::CallMethodInternal<void>(FSentryJavaMethod Method, va_list Params) const
{
VerifyMethodCall(Method);
JNIEnv* JEnv = AndroidJavaEnv::GetJavaEnv();
!Method.IsStatic
? JEnv->CallVoidMethodV(Object, Method.Method, Params)
: JEnv->CallStaticVoidMethodV(Class, Method.Method, Params);
VerifyException();
}
template<>
bool FSentryJavaObjectWrapper::CallMethodInternal<bool>(FSentryJavaMethod Method, va_list Params) const
{
VerifyMethodCall(Method);
JNIEnv* JEnv = AndroidJavaEnv::GetJavaEnv();
bool RetVal = !Method.IsStatic
? JEnv->CallBooleanMethodV(Object, Method.Method, Params)
: JEnv->CallStaticBooleanMethodV(Class, Method.Method, Params);
VerifyException();
return RetVal;
}
template<>
int FSentryJavaObjectWrapper::CallMethodInternal<int>(FSentryJavaMethod Method, va_list Params) const
{
VerifyMethodCall(Method);
JNIEnv* JEnv = AndroidJavaEnv::GetJavaEnv();
int RetVal = !Method.IsStatic
? JEnv->CallIntMethodV(Object, Method.Method, Params)
: JEnv->CallStaticIntMethodV(Class, Method.Method, Params);
VerifyException();
return RetVal;
}
template<>
int64 FSentryJavaObjectWrapper::CallMethodInternal<int64>(FSentryJavaMethod Method, va_list Params) const
{
VerifyMethodCall(Method);
JNIEnv* JEnv = AndroidJavaEnv::GetJavaEnv();
int64 RetVal = !Method.IsStatic
? JEnv->CallLongMethodV(Object, Method.Method, Params)
: JEnv->CallStaticLongMethodV(Class, Method.Method, Params);
VerifyException();
return RetVal;
}
template<>
FString FSentryJavaObjectWrapper::CallMethodInternal<FString>(FSentryJavaMethod Method, va_list Params) const
{
VerifyMethodCall(Method);
JNIEnv* JEnv = AndroidJavaEnv::GetJavaEnv();
jstring RetVal = !Method.IsStatic
? static_cast<jstring>(JEnv->CallObjectMethodV(Object, Method.Method, Params))
: static_cast<jstring>(JEnv->CallStaticObjectMethodV(Class, Method.Method, Params));
VerifyException();
auto Result = FJavaHelper::FStringFromLocalRef(JEnv, RetVal);
return Result;
}
template<>
FScopedJavaObject<jobject> FSentryJavaObjectWrapper::CallObjectMethodInternal<jobject>(FSentryJavaMethod Method, va_list Params) const
{
VerifyMethodCall(Method);
JNIEnv* JEnv = AndroidJavaEnv::GetJavaEnv();
jobject RetVal = !Method.IsStatic
? JEnv->CallObjectMethodV(Object, Method.Method, Params)
: JEnv->CallStaticObjectMethodV(Class, Method.Method, Params);
VerifyException();
return NewScopedJavaObject(JEnv, RetVal);
}
template<>
FScopedJavaObject<jobjectArray> FSentryJavaObjectWrapper::CallObjectMethodInternal<jobjectArray>(FSentryJavaMethod Method, va_list Params) const
{
VerifyMethodCall(Method);
JNIEnv* JEnv = AndroidJavaEnv::GetJavaEnv();
jobject RetVal = !Method.IsStatic
? JEnv->CallObjectMethodV(Object, Method.Method, Params)
: JEnv->CallStaticObjectMethodV(Class, Method.Method, Params);
VerifyException();
return NewScopedJavaObject(JEnv, (jobjectArray)RetVal);
}