cpp_client_telemetry/lib/jni/LogManager_jni.cpp

686 строки
24 KiB
C++
Исходник Обычный вид История

2020-06-07 00:37:49 +03:00
#include "JniConvertors.hpp"
#include "LogManagerBase.hpp"
#include "WrapperLogManager.hpp"
#include "android/log.h"
2020-05-31 23:50:25 +03:00
using namespace MAT;
template <>
ILogManager* LogManagerBase<WrapperConfig>::instance{};
extern "C"
{
JNIEXPORT jlong JNICALL Java_com_microsoft_applications_events_LogManager_nativeInitializeWithoutTenantToken(
2020-05-31 23:50:25 +03:00
JNIEnv* /* env */,
jclass /* LogManager.class */)
{
ILogger* logger = WrapperLogManager::Initialize();
return reinterpret_cast<jlong>(logger);
}
2020-05-31 23:50:25 +03:00
JNIEXPORT jlong JNICALL Java_com_microsoft_applications_events_LogManager_nativeInitializeWithTenantToken(
2020-05-31 23:50:25 +03:00
JNIEnv* env,
jclass /* LogManager.class */,
jstring jTenantToken)
{
auto tenantToken = JStringToStdString(env, jTenantToken);
ILogger* logger = WrapperLogManager::Initialize(tenantToken);
return reinterpret_cast<jlong>(logger);
}
JNIEXPORT jint JNICALL Java_com_microsoft_applications_events_LogManager_nativeFlushAndTeardown(
2020-05-31 23:50:25 +03:00
JNIEnv* /* env */,
jclass /* LogManager.class */)
{
return static_cast<jint>(WrapperLogManager::FlushAndTeardown());
}
2020-05-31 23:50:25 +03:00
JNIEXPORT jint JNICALL Java_com_microsoft_applications_events_LogManager_nativeFlush(
2020-05-31 23:50:25 +03:00
JNIEnv* /* env */,
jclass /* this */)
{
return static_cast<jint>(WrapperLogManager::Flush());
}
2020-05-31 23:50:25 +03:00
JNIEXPORT jint JNICALL Java_com_microsoft_applications_events_LogManager_nativeUploadNow(
2020-05-31 23:50:25 +03:00
JNIEnv* /* env */,
jclass /* this */)
{
return static_cast<jint>(WrapperLogManager::UploadNow());
}
2020-05-31 23:50:25 +03:00
JNIEXPORT jint JNICALL Java_com_microsoft_applications_events_LogManager_nativePauseTransmission(
2020-05-31 23:50:25 +03:00
JNIEnv* /* env */,
jclass /* this */)
{
return static_cast<jint>(WrapperLogManager::PauseTransmission());
}
2020-05-31 23:50:25 +03:00
JNIEXPORT jint JNICALL Java_com_microsoft_applications_events_LogManager_nativeResumeTransmission(
2020-05-31 23:50:25 +03:00
JNIEnv* /* env */,
jclass /* this */)
{
return static_cast<jint>(WrapperLogManager::ResumeTransmission());
}
2020-05-31 23:50:25 +03:00
JNIEXPORT jint JNICALL Java_com_microsoft_applications_events_LogManager_nativeSetIntTransmitProfile(
2020-05-31 23:50:25 +03:00
JNIEnv* /* env */,
jclass /* this */,
jint jProfile)
{
return static_cast<jint>(WrapperLogManager::SetTransmitProfile(
2020-05-31 23:50:25 +03:00
static_cast<TransmitProfile>(jProfile)));
}
2020-05-31 23:50:25 +03:00
JNIEXPORT jint JNICALL Java_com_microsoft_applications_events_LogManager_nativeSetTransmitProfileString(
2020-05-31 23:50:25 +03:00
JNIEnv* env,
jclass /* this */,
jstring jstrProfile)
{
return static_cast<jint>(WrapperLogManager::SetTransmitProfile(JStringToStdString(env, jstrProfile)));
}
2020-05-31 23:50:25 +03:00
JNIEXPORT jint JNICALL Java_com_microsoft_applications_events_LogManager_nativeLoadTransmitProfilesString(
2020-05-31 23:50:25 +03:00
JNIEnv* env,
jclass /* this */,
jstring jstrProfilesJson)
{
return static_cast<jint>(WrapperLogManager::LoadTransmitProfiles(JStringToStdString(env, jstrProfilesJson)));
}
2020-05-31 23:50:25 +03:00
JNIEXPORT jint JNICALL Java_com_microsoft_applications_events_LogManager_nativeResetTransmitProfiles(
2020-05-31 23:50:25 +03:00
JNIEnv* /* env */,
jclass /* this */)
{
return static_cast<jint>(WrapperLogManager::ResetTransmitProfiles());
}
2020-05-31 23:50:25 +03:00
JNIEXPORT jstring JNICALL Java_com_microsoft_applications_events_LogManager_getTransmitProfileName(
2020-05-31 23:50:25 +03:00
JNIEnv* env,
jclass /* this */)
{
std::string profileName = WrapperLogManager::GetTransmitProfileName();
return static_cast<jstring>(env->NewStringUTF(profileName.c_str()));
}
2020-05-31 23:50:25 +03:00
JNIEXPORT jlong JNICALL Java_com_microsoft_applications_events_LogManager_nativeGetSemanticContext(
2020-05-31 23:50:25 +03:00
JNIEnv* env,
jclass /* this */)
{
return reinterpret_cast<jlong>(WrapperLogManager::GetSemanticContext());
}
2020-05-31 23:50:25 +03:00
JNIEXPORT jint JNICALL Java_com_microsoft_applications_events_LogManager_nativeSetContextStringValue(
2020-05-31 23:50:25 +03:00
JNIEnv* env,
jclass /* this */,
jstring jstrName,
jstring jstrValue,
jint piiKind)
{
auto name = JStringToStdString(env, jstrName);
auto value = JStringToStdString(env, jstrValue);
return static_cast<jint>(WrapperLogManager::SetContext(name, value, static_cast<PiiKind>(piiKind)));
}
JNIEXPORT jint JNICALL Java_com_microsoft_applications_events_LogManager_nativeSetContextIntValue(
2020-05-31 23:50:25 +03:00
JNIEnv* env,
jclass /* this */,
jstring jstrName,
jint jValue,
jint piiKind)
{
auto name = JStringToStdString(env, jstrName);
return static_cast<jint>(WrapperLogManager::SetContext(name, static_cast<int32_t>(jValue), static_cast<PiiKind>(piiKind)));
}
2020-05-31 23:50:25 +03:00
JNIEXPORT jint JNICALL Java_com_microsoft_applications_events_LogManager_nativeSetContextLongValue(
2020-05-31 23:50:25 +03:00
JNIEnv* env,
jclass /* this */,
jstring jstrName,
jlong jValue,
jint piiKind)
{
auto name = JStringToStdString(env, jstrName);
return static_cast<jint>(WrapperLogManager::SetContext(name, static_cast<int64_t>(jValue), static_cast<PiiKind>(piiKind)));
}
2020-05-31 23:50:25 +03:00
JNIEXPORT jint JNICALL Java_com_microsoft_applications_events_LogManager_nativeSetContextDoubleValue(
2020-05-31 23:50:25 +03:00
JNIEnv* env,
jclass /* this */,
jstring jstrName,
jdouble jValue,
jint piiKind)
{
auto name = JStringToStdString(env, jstrName);
return static_cast<jint>(WrapperLogManager::SetContext(name, static_cast<double>(jValue), static_cast<PiiKind>(piiKind)));
}
2020-05-31 23:50:25 +03:00
JNIEXPORT jint JNICALL Java_com_microsoft_applications_events_LogManager_nativeSetContextBoolValue(
2020-05-31 23:50:25 +03:00
JNIEnv* env,
jclass /* this */,
jstring jstrName,
jboolean jValue,
jint piiKind)
{
auto name = JStringToStdString(env, jstrName);
return static_cast<jint>(WrapperLogManager::SetContext(name, static_cast<bool>(jValue), static_cast<PiiKind>(piiKind)));
}
2020-05-31 23:50:25 +03:00
JNIEXPORT jint JNICALL Java_com_microsoft_applications_events_LogManager_nativeSetContextTimeTicksValue(
2020-05-31 23:50:25 +03:00
JNIEnv* env,
jclass /* this */,
jstring jstrName,
jlong jValue,
jint piiKind)
{
auto name = JStringToStdString(env, jstrName);
return static_cast<jint>(WrapperLogManager::SetContext(name, time_ticks_t(static_cast<uint64_t>(jValue)), static_cast<PiiKind>(piiKind)));
}
2020-05-31 23:50:25 +03:00
JNIEXPORT jint JNICALL Java_com_microsoft_applications_events_LogManager_nativeSetContextGuidValue(
2020-05-31 23:50:25 +03:00
JNIEnv* env,
jclass /* this */,
jstring jstrName,
jstring jstrValue,
jint piiKind)
{
auto name = JStringToStdString(env, jstrName);
auto value = JStringToStdString(env, jstrValue);
return static_cast<jint>(WrapperLogManager::SetContext(name, GUID_t(value.c_str()), static_cast<PiiKind>(piiKind)));
}
JNIEXPORT jlong JNICALL Java_com_microsoft_applications_events_LogManager_nativeGetLogger(
2020-05-31 23:50:25 +03:00
JNIEnv* /* env */,
jclass /* this */)
{
ILogger* logger = WrapperLogManager::GetLogger();
return reinterpret_cast<jlong>(logger);
}
2020-05-31 23:50:25 +03:00
JNIEXPORT jlong JNICALL Java_com_microsoft_applications_events_LogManager_nativeGetLoggerWithSource(
2020-05-31 23:50:25 +03:00
JNIEnv* env,
jclass /* this */,
jstring jstrSource)
{
auto source = JStringToStdString(env, jstrSource);
ILogger* logger = WrapperLogManager::GetLogger(source);
return reinterpret_cast<jlong>(logger);
}
JNIEXPORT jlong JNICALL Java_com_microsoft_applications_events_LogManager_nativeGetLoggerWithTenantTokenAndSource(
2020-05-31 23:50:25 +03:00
JNIEnv* env,
jclass /* this */,
jstring jstrTenantToken,
jstring jstrSource)
{
auto tenantToken = JStringToStdString(env, jstrTenantToken);
auto source = JStringToStdString(env, jstrSource);
ILogger* logger = WrapperLogManager::GetLogger(tenantToken, source);
return reinterpret_cast<jlong>(logger);
}
2020-05-31 23:50:25 +03:00
}
namespace
{
/**
* helper function: rethrow any exceptions from reverse-JNI calls
* @param env
*/
void rethrow(JNIEnv* env)
{
if (env->ExceptionCheck())
{
env->Throw(env->ExceptionOccurred());
throw std::runtime_error("JNI exception");
}
}
/**
* Smart object to manage PushLocalFrame/PopLocalFrame
*/
class FrameWrapper
{
JNIEnv* env;
size_t frameSize;
jobject* result = nullptr;
FrameWrapper() = delete;
public:
/*
* Constructor: takes JNIEnv* and the desired LocalStack frame depth
*/
FrameWrapper(JNIEnv* e, size_t s) :
env(e),
frameSize(s)
{
env->PushLocalFrame(frameSize);
rethrow(env);
}
/**
* Set the reference that will survive PopLocalFrame (as a new
* reference in the outer frame).
* @param r Object that should survive
* @return Previous result value
*/
jobject* setResult(jobject* r)
{
jobject* t = result;
result = r;
return t;
}
/**
* On destruction, pop the frame with an optional result object.
*/
virtual ~FrameWrapper()
{
jobject localRef = nullptr;
if (!!result)
{
localRef = *result;
}
localRef = env->PopLocalFrame(localRef);
rethrow(env);
if (!!result)
{
*result = localRef;
}
}
};
/**
* Enum of the types we know how to convert into a VariantMap or
* VariantArray.
*/
enum class ValueTypes
{
BOOLEAN,
LONG,
STRING,
VARIANT_MAP,
VARIANT_ARRAY
};
/**
* POD to record how we handle each known value type
*/
struct ValueInfo
{
/**
* JNI class reference for a known type
*/
jclass valueClass;
/**
* Method ID for the method to cast into the primitive type for
* Long or Boolean
*/
jmethodID castMethod;
};
static constexpr char lcClassName[] =
"com/microsoft/applications/events/ILogConfiguration";
struct VariantTranslator
{
std::map<ValueTypes, ValueInfo> classCache;
JNIEnv* env;
VariantTranslator() = delete;
VariantTranslator(JNIEnv* env) :
env(env)
{
ValueInfo vi;
vi.valueClass = env->FindClass("java/lang/Boolean");
rethrow(env);
vi.castMethod =
env->GetMethodID(vi.valueClass, "booleanValue", "()Z");
rethrow(env);
classCache[ValueTypes::BOOLEAN] = vi;
vi.valueClass = env->FindClass("java/lang/Long");
rethrow(env);
vi.castMethod =
env->GetMethodID(vi.valueClass, "longValue", "()J");
rethrow(env);
classCache[ValueTypes::LONG] = vi;
vi.valueClass = env->FindClass("java/lang/String");
rethrow(env);
vi.castMethod = nullptr;
classCache[ValueTypes::STRING] = vi;
vi.valueClass = env->FindClass(lcClassName);
rethrow(env);
vi.castMethod = nullptr;
classCache[ValueTypes::VARIANT_MAP] = vi;
vi.valueClass = env->FindClass("[Ljava/lang/Object;");
vi.castMethod = nullptr;
classCache[ValueTypes::VARIANT_ARRAY] = vi;
}
void translateVariantArray(VariantArray& array, jobjectArray value)
{
jsize count = env->GetArrayLength(value);
array.clear();
array.reserve(count);
for (jsize i = 0; i < count; ++i)
{
auto element = env->GetObjectArrayElement(value, i);
rethrow(env);
array.emplace_back(std::move(translateVariant(element)));
}
}
void translateVariantMap(VariantMap& variantMap, jobject configuration)
{
static std::map<ValueTypes, ValueInfo> classCache;
auto stringClass = env->FindClass("java/lang/String");
rethrow(env);
auto configClass = env->GetObjectClass(configuration);
auto gkaMethod =
env->GetMethodID(configClass,
"getKeyArray",
"()[Ljava/lang/String;");
rethrow(env);
jobjectArray keys = static_cast<jobjectArray>(env->CallObjectMethod(
configuration,
gkaMethod));
rethrow(env);
auto getMethod = env->GetMethodID(
configClass,
"getObject",
"(Ljava/lang/String;)Ljava/lang/Object;");
rethrow(env);
jsize keyCount = env->GetArrayLength(keys);
for (jsize i = 0; i < keyCount; ++i)
{
FrameWrapper wrapper(env, 32);
rethrow(env);
auto k = env->GetObjectArrayElement(keys, i);
rethrow(env);
if (k == nullptr)
{
__android_log_print(ANDROID_LOG_ERROR,
"MAE",
"Null configuration key");
continue;
}
if (!env->IsInstanceOf(k, stringClass))
{
__android_log_print(ANDROID_LOG_ERROR, "MAE",
"Configuration key is not a string");
continue;
}
auto key = static_cast<jstring>(k);
auto cstringKey = env->GetStringUTFChars(key, nullptr);
rethrow(env);
std::string stringKey(cstringKey);
env->ReleaseStringUTFChars(key, cstringKey);
auto value = env->CallObjectMethod(configuration, getMethod, key);
rethrow(env);
auto v = translateVariant(value);
auto emplace = variantMap.emplace(stringKey, std::move(v));
if (!emplace.second)
{
auto& it = emplace.first;
it->second.move(std::move(v));
}
} // for (... configuration keys)
}
Variant translateVariant(jobject value)
{
for (auto& kv : classCache)
{
if (env->IsInstanceOf(value, kv.second.valueClass))
{
switch (kv.first)
{
case ValueTypes::LONG:
{
auto longValue =
env->CallLongMethod(value,
kv.second.castMethod);
rethrow(env);
return Variant(longValue);
}
case ValueTypes::BOOLEAN:
{
auto booleanValue =
env->CallBooleanMethod(value,
kv.second.castMethod);
rethrow(env);
return Variant(booleanValue);
}
case ValueTypes::STRING:
{
auto s = static_cast<jstring>(value);
auto cString = env->GetStringUTFChars(
s,
nullptr);
rethrow(env);
std::string cppString(cString);
env->ReleaseStringUTFChars(s, cString);
return Variant(std::move(cppString));
}
case ValueTypes::VARIANT_MAP:
{
VariantMap subMap;
translateVariantMap(subMap, value);
return Variant(std::move(subMap));
}
case ValueTypes::VARIANT_ARRAY:
{
VariantArray subArray;
translateVariantArray(subArray,
static_cast<jobjectArray>(value));
return Variant(std::move(subArray));
}
default:
throw std::logic_error("Unknown enum value");
}
} // if class matches
} // for (... classCache){
auto actual = env->GetObjectClass(value);
auto meta = env->GetObjectClass(actual);
rethrow(env);
auto gnMethod =
env->GetMethodID(meta,
"getName",
"()Ljava/lang/String;");
rethrow(env);
auto jName =
static_cast<jstring>(env->CallObjectMethod(actual,
gnMethod));
auto cName = env->GetStringUTFChars(jName, nullptr);
std::string className(cName);
env->ReleaseStringUTFChars(jName, cName);
__android_log_print(ANDROID_LOG_ERROR,
"MAE",
"Unsupported class %s",
className.c_str());
auto errorClass = env->FindClass("java/lang/Error");
rethrow(env);
env->ThrowNew(errorClass, "Unsupported class");
MATSDK_THROW(std::logic_error("Unsupported class"));
}
};
struct ConfigConstructor
{
JNIEnv* env;
jobject boolTrue = nullptr;
jobject boolFalse = nullptr;
jclass doubleClass = nullptr;
jmethodID doubleInit = nullptr;
jclass longClass = nullptr;
jmethodID longInit = nullptr;
jclass objectClass = nullptr;
jclass configClass = nullptr;
jmethodID configInit = nullptr;
jmethodID setMethod = nullptr;
ConfigConstructor() = delete;
ConfigConstructor(JNIEnv* env)
{
this->env = env;
auto boolClass = env->FindClass("java/lang/Boolean");
rethrow(env);
auto truthField = env->GetStaticFieldID(boolClass, "TRUE", "Ljava/lang/Boolean;");
rethrow(env);
boolTrue = env->GetStaticObjectField(boolClass, truthField);
auto untruthField = env->GetStaticFieldID(boolClass, "FALSE", "Ljava/lang/Boolean;");
rethrow(env);
boolFalse = env->GetStaticObjectField(boolClass, untruthField);
doubleClass = env->FindClass("java/lang/Double");
rethrow(env);
doubleInit = env->GetMethodID(doubleClass, "<init>", "(D)V");
rethrow(env);
longClass = env->FindClass("java/lang/Long");
rethrow(env);
longInit = env->GetMethodID(longClass, "<init>", "(J)V");
rethrow(env);
objectClass = env->FindClass("java/lang/Object");
rethrow(env);
configClass = env->FindClass("com/microsoft/applications/events/LogManager$LogConfigurationImpl");
rethrow(env);
configInit = env->GetMethodID(configClass, "<init>", "()V");
rethrow(env);
setMethod = env->GetMethodID(configClass, "set", "(Ljava/lang/String;Ljava/lang/Object;)V");
rethrow(env);
}
jobject valueTranslate(Variant& variant)
{
jobject result = nullptr;
{
FrameWrapper frameWrapper(env, 8);
frameWrapper.setResult(&result);
switch (variant.type)
{
case Variant::Type::TYPE_BOOL:
{
bool const v = variant;
if (v)
{
result = boolTrue;
}
else
{
result = boolFalse;
}
break;
}
case Variant::Type::TYPE_DOUBLE:
{
jdouble const v = variant;
result = env->NewObject(doubleClass, doubleInit, v);
rethrow(env);
break;
}
case Variant::Type::TYPE_INT:
{
jlong const v = variant;
result = env->NewObject(longClass, longInit, v);
rethrow(env);
break;
}
case Variant::Type::TYPE_NULL:
break;
case Variant::Type::TYPE_OBJ:
{
VariantMap variantMap = variant;
result = mapTranslate(variantMap);
break;
}
case Variant::Type::TYPE_STRING:
case Variant::Type::TYPE_STRING2:
{
const char* v = variant;
result = env->NewStringUTF(v);
break;
}
case Variant::Type::TYPE_ARR:
{
VariantArray& variantArray = variant;
{
FrameWrapper
innerWrapper(env, variantArray.size() + 4);
auto array = env->NewObjectArray(variantArray.size(),
objectClass,
nullptr);
for (size_t i = 0; i < variantArray.size(); ++i)
{
jobject element = valueTranslate(variantArray[i]);
env->SetObjectArrayElement(array, i, element);
rethrow(env);
}
result = array;
innerWrapper.setResult(&result);
}
break;
}
default:
auto errorClass = env->FindClass("java/lang/Error");
rethrow(env);
env->ThrowNew(errorClass, "Unsupported class");
MATSDK_THROW(std::logic_error("Unsupported class"));
}
}
return result;
}
jobject mapTranslate(VariantMap& variantMap)
{
auto map = env->NewObject(configClass, configInit);
rethrow(env);
for (auto& kv : variantMap)
{
FrameWrapper frameWrapper(env, 8);
auto const& key = kv.first;
auto& value = kv.second;
auto keyString = env->NewStringUTF(key.c_str());
rethrow(env);
auto valueObject = valueTranslate(value);
env->CallVoidMethod(map, setMethod, keyString, valueObject);
rethrow(env);
}
return map;
}
};
}
extern "C" JNIEXPORT jlong JNICALL
Java_com_microsoft_applications_events_LogManager_nativeInitializeConfig(JNIEnv* env,
jclass clazz,
jstring tenant_token,
jobject configuration)
{
ILogConfiguration logConfiguration;
VariantTranslator variantTranslator(env);
variantTranslator.translateVariantMap(*logConfiguration, configuration);
std::string cereal;
Variant::serialize(*logConfiguration, cereal);
__android_log_print(ANDROID_LOG_INFO, "MAE", "Translated map: %s",
cereal.c_str());
auto tokenUTF = env->GetStringUTFChars(tenant_token, nullptr);
rethrow(env);
std::string token(tokenUTF);
env->ReleaseStringUTFChars(tenant_token, tokenUTF);
auto logger = WrapperLogManager::Initialize(token, logConfiguration);
return reinterpret_cast<jlong>(logger);
}
extern "C" JNIEXPORT jobject JNICALL
Java_com_microsoft_applications_events_LogManager_nativeGetLogConfiguration(
JNIEnv* env,
jclass /* LogManager.class */)
{
ConfigConstructor config(env);
return config.mapTranslate(*WrapperLogManager::GetLogConfiguration());
}