zworld-em/Plugins/sentry-unreal/Source/Sentry/Private/Android/SentrySubsystemAndroid.cpp
2025-05-11 22:07:21 +08:00

303 lines
14 KiB
C++

// Copyright (c) 2022 Sentry. All Rights Reserved.
#include "SentrySubsystemAndroid.h"
#include "SentryEventAndroid.h"
#include "SentryBreadcrumbAndroid.h"
#include "SentryUserFeedbackAndroid.h"
#include "SentryUserAndroid.h"
#include "SentryTransactionAndroid.h"
#include "SentryTransactionContextAndroid.h"
#include "SentryTransactionOptionsAndroid.h"
#include "SentryIdAndroid.h"
#include "SentryDefines.h"
#include "SentryBeforeSendHandler.h"
#include "SentryTraceSampler.h"
#include "SentryEvent.h"
#include "SentrySettings.h"
#include "Callbacks/SentryScopeCallbackAndroid.h"
#include "Infrastructure/SentryConvertorsAndroid.h"
#include "Infrastructure/SentryJavaClasses.h"
#include "Utils/SentryFileUtils.h"
#include "Dom/JsonObject.h"
#include "Serialization/JsonSerializer.h"
void SentrySubsystemAndroid::InitWithSettings(const USentrySettings* settings, USentryBeforeSendHandler* beforeSendHandler, USentryTraceSampler* traceSampler)
{
TSharedPtr<FJsonObject> SettingsJson = MakeShareable(new FJsonObject);
SettingsJson->SetStringField(TEXT("dsn"), settings->Dsn);
SettingsJson->SetStringField(TEXT("release"), settings->OverrideReleaseName
? settings->Release
: settings->GetFormattedReleaseName());
SettingsJson->SetStringField(TEXT("environment"), settings->Environment);
SettingsJson->SetBoolField(TEXT("autoSessionTracking"), settings->EnableAutoSessionTracking);
SettingsJson->SetNumberField(TEXT("sessionTimeout"), settings->SessionTimeout);
SettingsJson->SetBoolField(TEXT("enableStackTrace"), settings->AttachStacktrace);
SettingsJson->SetBoolField(TEXT("debug"), settings->Debug);
SettingsJson->SetNumberField(TEXT("sampleRate"), settings->SampleRate);
SettingsJson->SetNumberField(TEXT("maxBreadcrumbs"), settings->MaxBreadcrumbs);
SettingsJson->SetBoolField(TEXT("attachScreenshot"), settings->AttachScreenshot);
SettingsJson->SetArrayField(TEXT("inAppInclude"), SentryConvertorsAndroid::StrinArrayToJsonArray(settings->InAppInclude));
SettingsJson->SetArrayField(TEXT("inAppExclude"), SentryConvertorsAndroid::StrinArrayToJsonArray(settings->InAppExclude));
SettingsJson->SetBoolField(TEXT("sendDefaultPii"), settings->SendDefaultPii);
SettingsJson->SetBoolField(TEXT("enableAnrTracking"), settings->EnableAppNotRespondingTracking);
SettingsJson->SetBoolField(TEXT("enableTracing"), settings->EnableTracing);
if(settings->EnableTracing && settings->SamplingType == ESentryTracesSamplingType::UniformSampleRate)
{
SettingsJson->SetNumberField(TEXT("tracesSampleRate"), settings->TracesSampleRate);
}
if(settings->EnableTracing && settings->SamplingType == ESentryTracesSamplingType::TracesSampler)
{
SettingsJson->SetNumberField(TEXT("tracesSampler"), (jlong)traceSampler);
}
FString SettingsJsonStr;
TSharedRef<TJsonWriter<>> JsonWriter = TJsonWriterFactory<>::Create(&SettingsJsonStr);
FJsonSerializer::Serialize(SettingsJson.ToSharedRef(), JsonWriter);
FSentryJavaObjectWrapper::CallStaticMethod<void>(SentryJavaClasses::SentryBridgeJava,
"init", "(Landroid/app/Activity;Ljava/lang/String;J)V",
FJavaWrapper::GameActivityThis,
*FSentryJavaObjectWrapper::GetJString(SettingsJsonStr),
(jlong)beforeSendHandler);
}
void SentrySubsystemAndroid::Close()
{
FSentryJavaObjectWrapper::CallStaticMethod<void>(SentryJavaClasses::Sentry, "close", "()V");
}
bool SentrySubsystemAndroid::IsEnabled()
{
return FSentryJavaObjectWrapper::CallStaticMethod<bool>(SentryJavaClasses::Sentry, "isEnabled", "()Z");
}
ESentryCrashedLastRun SentrySubsystemAndroid::IsCrashedLastRun()
{
ESentryCrashedLastRun unrealIsCrashed = ESentryCrashedLastRun::NotEvaluated;
switch (FSentryJavaObjectWrapper::CallStaticMethod<int>(SentryJavaClasses::SentryBridgeJava, "isCrashedLastRun", "()I"))
{
case -1:
unrealIsCrashed = ESentryCrashedLastRun::NotEvaluated;
break;
case 0:
unrealIsCrashed = ESentryCrashedLastRun::NotCrashed;
break;
case 1:
unrealIsCrashed = ESentryCrashedLastRun::Crashed;
break;
default:
UE_LOG(LogSentrySdk, Warning, TEXT("Unknown IsCrashedLastRun result. NotEvaluated will be returned."));
}
return unrealIsCrashed;
}
void SentrySubsystemAndroid::AddBreadcrumb(TSharedPtr<ISentryBreadcrumb> breadcrumb)
{
TSharedPtr<SentryBreadcrumbAndroid> breadcrumbAndroid = StaticCastSharedPtr<SentryBreadcrumbAndroid>(breadcrumb);
FSentryJavaObjectWrapper::CallStaticMethod<void>(SentryJavaClasses::Sentry, "addBreadcrumb", "(Lio/sentry/Breadcrumb;)V",
breadcrumbAndroid->GetJObject());
}
void SentrySubsystemAndroid::AddBreadcrumbWithParams(const FString& Message, const FString& Category, const FString& Type, const TMap<FString, FString>& Data, ESentryLevel Level)
{
TSharedPtr<SentryBreadcrumbAndroid> breadcrumbAndroid = MakeShareable(new SentryBreadcrumbAndroid());
breadcrumbAndroid->SetMessage(Message);
breadcrumbAndroid->SetCategory(Category);
breadcrumbAndroid->SetType(Type);
breadcrumbAndroid->SetData(Data);
breadcrumbAndroid->SetLevel(Level);
FSentryJavaObjectWrapper::CallStaticMethod<void>(SentryJavaClasses::Sentry, "addBreadcrumb", "(Lio/sentry/Breadcrumb;)V",
breadcrumbAndroid->GetJObject());
}
void SentrySubsystemAndroid::ClearBreadcrumbs()
{
FSentryJavaObjectWrapper::CallStaticMethod<void>(SentryJavaClasses::Sentry, "clearBreadcrumbs", "()V");
}
TSharedPtr<ISentryId> SentrySubsystemAndroid::CaptureMessage(const FString& message, ESentryLevel level)
{
auto id = FSentryJavaObjectWrapper::CallStaticObjectMethod<jobject>(SentryJavaClasses::Sentry, "captureMessage", "(Ljava/lang/String;Lio/sentry/SentryLevel;)Lio/sentry/protocol/SentryId;",
*FSentryJavaObjectWrapper::GetJString(message), SentryConvertorsAndroid::SentryLevelToNative(level)->GetJObject());
return MakeShareable(new SentryIdAndroid(*id));
}
TSharedPtr<ISentryId> SentrySubsystemAndroid::CaptureMessageWithScope(const FString& message, const FSentryScopeDelegate& onConfigureScope, ESentryLevel level)
{
int64 scopeCallbackId = SentryScopeCallbackAndroid::SaveDelegate(onConfigureScope);
auto id = FSentryJavaObjectWrapper::CallStaticObjectMethod<jobject>(SentryJavaClasses::SentryBridgeJava, "captureMessageWithScope", "(Ljava/lang/String;Lio/sentry/SentryLevel;J)Lio/sentry/protocol/SentryId;",
*FSentryJavaObjectWrapper::GetJString(message), SentryConvertorsAndroid::SentryLevelToNative(level)->GetJObject(), scopeCallbackId);
return MakeShareable(new SentryIdAndroid(*id));
}
TSharedPtr<ISentryId> SentrySubsystemAndroid::CaptureEvent(TSharedPtr<ISentryEvent> event)
{
TSharedPtr<SentryEventAndroid> eventAndroid = StaticCastSharedPtr<SentryEventAndroid>(event);
auto id = FSentryJavaObjectWrapper::CallStaticObjectMethod<jobject>(SentryJavaClasses::Sentry, "captureEvent", "(Lio/sentry/SentryEvent;)Lio/sentry/protocol/SentryId;",
eventAndroid->GetJObject());
return MakeShareable(new SentryIdAndroid(*id));
}
TSharedPtr<ISentryId> SentrySubsystemAndroid::CaptureEventWithScope(TSharedPtr<ISentryEvent> event, const FSentryScopeDelegate& onConfigureScope)
{
TSharedPtr<SentryEventAndroid> eventAndroid = StaticCastSharedPtr<SentryEventAndroid>(event);
int64 scopeCallbackId = SentryScopeCallbackAndroid::SaveDelegate(onConfigureScope);
auto id = FSentryJavaObjectWrapper::CallStaticObjectMethod<jobject>(SentryJavaClasses::SentryBridgeJava, "captureEventWithScope", "(Lio/sentry/SentryEvent;J)Lio/sentry/protocol/SentryId;",
eventAndroid->GetJObject(), scopeCallbackId);
return MakeShareable(new SentryIdAndroid(*id));
}
TSharedPtr<ISentryId> SentrySubsystemAndroid::CaptureException(const FString& type, const FString& message, int32 framesToSkip)
{
return nullptr;
}
TSharedPtr<ISentryId> SentrySubsystemAndroid::CaptureAssertion(const FString& type, const FString& message)
{
const int32 framesToSkip = 8;
// add marker tags specific for Unreal assertions
SetTag(TEXT("sentry_unreal_exception"), TEXT("assert"));
SetTag(TEXT("sentry_unreal_exception_skip_frames"), FString::Printf(TEXT("%d"), framesToSkip));
SetTag(TEXT("sentry_unreal_exception_type"), type);
SetTag(TEXT("sentry_unreal_exception_message"), message);
PLATFORM_BREAK();
return nullptr;
}
TSharedPtr<ISentryId> SentrySubsystemAndroid::CaptureEnsure(const FString& type, const FString& message)
{
auto id = FSentryJavaObjectWrapper::CallStaticObjectMethod<jobject>(SentryJavaClasses::SentryBridgeJava, "captureException", "(Ljava/lang/String;Ljava/lang/String;)Lio/sentry/protocol/SentryId;",
*FSentryJavaObjectWrapper::GetJString(type), *FSentryJavaObjectWrapper::GetJString(message));
return MakeShareable(new SentryIdAndroid(*id));
}
void SentrySubsystemAndroid::CaptureUserFeedback(TSharedPtr<ISentryUserFeedback> userFeedback)
{
TSharedPtr<SentryUserFeedbackAndroid> userFeedbackAndroid = StaticCastSharedPtr<SentryUserFeedbackAndroid>(userFeedback);
FSentryJavaObjectWrapper::CallStaticMethod<void>(SentryJavaClasses::Sentry, "captureUserFeedback", "(Lio/sentry/UserFeedback;)V",
userFeedbackAndroid->GetJObject());
}
void SentrySubsystemAndroid::SetUser(TSharedPtr<ISentryUser> user)
{
TSharedPtr<SentryUserAndroid> userAndroid = StaticCastSharedPtr<SentryUserAndroid>(user);
FSentryJavaObjectWrapper::CallStaticMethod<void>(SentryJavaClasses::Sentry, "setUser", "(Lio/sentry/protocol/User;)V",
userAndroid->GetJObject());
}
void SentrySubsystemAndroid::RemoveUser()
{
FSentryJavaObjectWrapper::CallStaticMethod<void>(SentryJavaClasses::Sentry, "setUser", "(Lio/sentry/protocol/User;)V", nullptr);
}
void SentrySubsystemAndroid::ConfigureScope(const FSentryScopeDelegate& onConfigureScope)
{
int64 scopeCallbackId = SentryScopeCallbackAndroid::SaveDelegate(onConfigureScope);
FSentryJavaObjectWrapper::CallStaticMethod<void>(SentryJavaClasses::SentryBridgeJava, "configureScope", "(J)V", scopeCallbackId);
}
void SentrySubsystemAndroid::SetContext(const FString& key, const TMap<FString, FString>& values)
{
FSentryJavaObjectWrapper::CallStaticMethod<void>(SentryJavaClasses::SentryBridgeJava, "setContext", "(Ljava/lang/String;Ljava/util/HashMap;)V",
*FSentryJavaObjectWrapper::GetJString(key), SentryConvertorsAndroid::StringMapToNative(values)->GetJObject());
}
void SentrySubsystemAndroid::SetTag(const FString& key, const FString& value)
{
FSentryJavaObjectWrapper::CallStaticMethod<void>(SentryJavaClasses::SentryBridgeJava, "setTag", "(Ljava/lang/String;Ljava/lang/String;)V",
*FSentryJavaObjectWrapper::GetJString(key), *FSentryJavaObjectWrapper::GetJString(value));
}
void SentrySubsystemAndroid::RemoveTag(const FString& key)
{
FSentryJavaObjectWrapper::CallStaticMethod<void>(SentryJavaClasses::SentryBridgeJava, "removeTag", "(Ljava/lang/String;)V",
*FSentryJavaObjectWrapper::GetJString(key));
}
void SentrySubsystemAndroid::SetLevel(ESentryLevel level)
{
FSentryJavaObjectWrapper::CallStaticMethod<void>(SentryJavaClasses::SentryBridgeJava, "setLevel", "(Lio/sentry/SentryLevel;)V",
SentryConvertorsAndroid::SentryLevelToNative(level)->GetJObject());
}
void SentrySubsystemAndroid::StartSession()
{
FSentryJavaObjectWrapper::CallStaticMethod<void>(SentryJavaClasses::Sentry, "startSession", "()V", nullptr);
}
void SentrySubsystemAndroid::EndSession()
{
FSentryJavaObjectWrapper::CallStaticMethod<void>(SentryJavaClasses::Sentry, "endSession", "()V", nullptr);
}
TSharedPtr<ISentryTransaction> SentrySubsystemAndroid::StartTransaction(const FString& name, const FString& operation)
{
auto transaction = FSentryJavaObjectWrapper::CallStaticObjectMethod<jobject>(SentryJavaClasses::Sentry, "startTransaction", "(Ljava/lang/String;Ljava/lang/String;)Lio/sentry/ITransaction;",
*FSentryJavaObjectWrapper::GetJString(name), *FSentryJavaObjectWrapper::GetJString(operation));
return MakeShareable(new SentryTransactionAndroid(*transaction));
}
TSharedPtr<ISentryTransaction> SentrySubsystemAndroid::StartTransactionWithContext(TSharedPtr<ISentryTransactionContext> context)
{
TSharedPtr<SentryTransactionContextAndroid> transactionContextAndroid = StaticCastSharedPtr<SentryTransactionContextAndroid>(context);
auto transaction = FSentryJavaObjectWrapper::CallStaticObjectMethod<jobject>(SentryJavaClasses::Sentry, "startTransaction", "(Lio/sentry/TransactionContext;)Lio/sentry/ITransaction;",
transactionContextAndroid->GetJObject());
return MakeShareable(new SentryTransactionAndroid(*transaction));
}
TSharedPtr<ISentryTransaction> SentrySubsystemAndroid::StartTransactionWithContextAndTimestamp(TSharedPtr<ISentryTransactionContext> context, int64 timestamp)
{
UE_LOG(LogSentrySdk, Log, TEXT("Setting transaction timestamp explicitly not supported on Android."));
return StartTransactionWithContext(context);
}
TSharedPtr<ISentryTransaction> SentrySubsystemAndroid::StartTransactionWithContextAndOptions(TSharedPtr<ISentryTransactionContext> context, const TMap<FString, FString>& options)
{
TSharedPtr<SentryTransactionContextAndroid> transactionContextAndroid = StaticCastSharedPtr<SentryTransactionContextAndroid>(context);
TSharedPtr<SentryTransactionOptionsAndroid> transactionOptionsAndroid = MakeShareable(new SentryTransactionOptionsAndroid());
transactionOptionsAndroid->SetCustomSamplingContext(options);
auto transaction = FSentryJavaObjectWrapper::CallStaticObjectMethod<jobject>(SentryJavaClasses::Sentry, "startTransaction", "(Lio/sentry/TransactionContext;Lio/sentry/TransactionOptions;)Lio/sentry/ITransaction;",
transactionContextAndroid->GetJObject(), transactionOptionsAndroid->GetJObject());
return MakeShareable(new SentryTransactionAndroid(*transaction));
}
TSharedPtr<ISentryTransactionContext> SentrySubsystemAndroid::ContinueTrace(const FString& sentryTrace, const TArray<FString>& baggageHeaders)
{
auto transactionContext = FSentryJavaObjectWrapper::CallStaticObjectMethod<jobject>(SentryJavaClasses::Sentry, "continueTrace", "(Ljava/lang/String;Ljava/util/List;)Lio/sentry/TransactionContext;",
*FSentryJavaObjectWrapper::GetJString(sentryTrace), SentryConvertorsAndroid::StringArrayToNative(baggageHeaders)->GetJObject());
return MakeShareable(new SentryTransactionContextAndroid(*transactionContext));
}