2020-04-19 23:04:05 +02:00
|
|
|
// SPDX-License-Identifier: MPL-2.0
|
2020-03-27 20:36:02 +01:00
|
|
|
// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
|
|
|
|
2019-12-05 16:35:34 +01:00
|
|
|
#include "jvm.h"
|
|
|
|
|
|
|
|
namespace skyline {
|
2020-10-17 13:38:27 +02:00
|
|
|
/*
|
|
|
|
* @brief A thread-local wrapper over JNIEnv and JavaVM which automatically handles attaching and detaching threads
|
|
|
|
*/
|
|
|
|
struct JniEnvironment {
|
2020-11-03 10:44:09 +01:00
|
|
|
JNIEnv *env{};
|
2020-10-17 13:38:27 +02:00
|
|
|
static inline JavaVM *vm{};
|
|
|
|
bool attached{};
|
|
|
|
|
2020-11-03 10:44:09 +01:00
|
|
|
void Initialize(JNIEnv *environment) {
|
2020-10-17 13:38:27 +02:00
|
|
|
env = environment;
|
|
|
|
if (env->GetJavaVM(&vm) < 0)
|
|
|
|
throw exception("Cannot get JavaVM from environment");
|
2020-11-03 10:44:09 +01:00
|
|
|
attached = true;
|
2020-10-17 13:38:27 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
JniEnvironment() {
|
2020-11-03 10:44:09 +01:00
|
|
|
if (vm && !attached) {
|
2020-10-17 13:38:27 +02:00
|
|
|
vm->AttachCurrentThread(&env, nullptr);
|
|
|
|
attached = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
~JniEnvironment() {
|
|
|
|
if (vm && attached)
|
|
|
|
vm->DetachCurrentThread();
|
|
|
|
}
|
|
|
|
|
|
|
|
operator JNIEnv *() {
|
2020-11-03 10:44:09 +01:00
|
|
|
if (!attached)
|
|
|
|
throw exception("Not attached");
|
2020-10-17 13:38:27 +02:00
|
|
|
return env;
|
|
|
|
}
|
|
|
|
|
2020-11-03 10:44:09 +01:00
|
|
|
JNIEnv *operator->() {
|
|
|
|
if (!attached)
|
|
|
|
throw exception("Not attached");
|
2020-10-17 13:38:27 +02:00
|
|
|
return env;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
thread_local inline JniEnvironment env;
|
|
|
|
|
2020-09-05 01:06:07 +02:00
|
|
|
JvmManager::JvmManager(JNIEnv *environ, jobject instance) : instance(environ->NewGlobalRef(instance)), instanceClass(reinterpret_cast<jclass>(environ->NewGlobalRef(environ->GetObjectClass(instance)))), initializeControllersId(environ->GetMethodID(instanceClass, "initializeControllers", "()V")), vibrateDeviceId(environ->GetMethodID(instanceClass, "vibrateDevice", "(I[J[I)V")), clearVibrationDeviceId(environ->GetMethodID(instanceClass, "clearVibrationDevice", "(I)V")) {
|
2020-11-03 10:44:09 +01:00
|
|
|
env.Initialize(environ);
|
2019-12-26 19:10:29 +01:00
|
|
|
}
|
|
|
|
|
2020-09-05 01:06:07 +02:00
|
|
|
JvmManager::~JvmManager() {
|
|
|
|
env->DeleteGlobalRef(instanceClass);
|
|
|
|
env->DeleteGlobalRef(instance);
|
|
|
|
}
|
|
|
|
|
2020-01-11 05:52:25 +01:00
|
|
|
JNIEnv *JvmManager::GetEnv() {
|
2019-12-26 19:10:29 +01:00
|
|
|
return env;
|
|
|
|
}
|
2019-12-05 16:35:34 +01:00
|
|
|
|
|
|
|
jobject JvmManager::GetField(const char *key, const char *signature) {
|
|
|
|
return env->GetObjectField(instance, env->GetFieldID(instanceClass, key, signature));
|
|
|
|
}
|
|
|
|
|
|
|
|
bool JvmManager::CheckNull(const char *key, const char *signature) {
|
|
|
|
return env->IsSameObject(env->GetObjectField(instance, env->GetFieldID(instanceClass, key, signature)), nullptr);
|
|
|
|
}
|
2019-12-26 19:10:29 +01:00
|
|
|
|
2020-01-11 05:52:25 +01:00
|
|
|
bool JvmManager::CheckNull(jobject &object) {
|
2019-12-26 19:10:29 +01:00
|
|
|
return env->IsSameObject(object, nullptr);
|
|
|
|
}
|
2020-08-21 13:14:27 +02:00
|
|
|
|
|
|
|
void JvmManager::InitializeControllers() {
|
|
|
|
env->CallVoidMethod(instance, initializeControllersId);
|
|
|
|
}
|
2020-09-05 01:06:07 +02:00
|
|
|
|
2020-09-25 02:05:12 +02:00
|
|
|
void JvmManager::VibrateDevice(jint index, const span<jlong> &timings, const span<jint> &litudes) {
|
2020-09-26 07:17:57 +02:00
|
|
|
auto jTimings{env->NewLongArray(timings.size())};
|
2020-09-05 01:06:07 +02:00
|
|
|
env->SetLongArrayRegion(jTimings, 0, timings.size(), timings.data());
|
2020-09-26 07:17:57 +02:00
|
|
|
auto jAmplitudes{env->NewIntArray(amplitudes.size())};
|
2020-09-05 01:06:07 +02:00
|
|
|
env->SetIntArrayRegion(jAmplitudes, 0, amplitudes.size(), amplitudes.data());
|
|
|
|
|
|
|
|
env->CallVoidMethod(instance, vibrateDeviceId, index, jTimings, jAmplitudes);
|
|
|
|
|
|
|
|
env->DeleteLocalRef(jTimings);
|
|
|
|
env->DeleteLocalRef(jAmplitudes);
|
|
|
|
}
|
|
|
|
|
|
|
|
void JvmManager::ClearVibrationDevice(jint index) {
|
|
|
|
env->CallVoidMethod(instance, clearVibrationDeviceId, index);
|
|
|
|
}
|
2019-12-05 16:35:34 +01:00
|
|
|
}
|