Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

jnipp: Upstream updates, including fixes for crashes. #286

Merged
merged 1 commit into from
Dec 8, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions changes/sdk/pr.286.gh.OpenXR-SDK-Source.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
- pr.285.gh.OpenXR-SDK-Source
---
Android loader: Update vendored jnipp project, including crash/exception fixes if an application manually attached or detached a thread.
18 changes: 18 additions & 0 deletions src/external/jnipp/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Copyright 2021, Collabora, Ltd.
#
# SPDX-License-Identifier: MIT

cmake_minimum_required(VERSION 3.10.2)
project(jnipp)

find_package(JNI REQUIRED)
include(CTest)

add_library(jnipp jnipp.cpp)
target_include_directories(
jnipp
PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}
PRIVATE ${JNI_INCLUDE_DIRS})
target_link_libraries(jnipp PUBLIC ${CMAKE_DL_LIBS})

add_subdirectory(tests)
55 changes: 29 additions & 26 deletions src/external/jnipp/jnipp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,13 @@ namespace jni
static std::atomic_bool isVm(false);
static JavaVM* javaVm = nullptr;

static bool getEnv(JavaVM *vm, JNIEnv **env) {
return vm->GetEnv((void **)env, JNI_VERSION_1_2) == JNI_OK;
}

static bool isAttached(JavaVM *vm) {
JNIEnv *env = nullptr;
return vm->GetEnv((void **)&env, JNI_VERSION_1_2) == JNI_OK;
return getEnv(vm, &env);
}
/**
Maintains the lifecycle of a JNIEnv.
Expand Down Expand Up @@ -63,7 +67,7 @@ namespace jni
if (vm == nullptr)
throw InitializationException("JNI not initialized");

if (!isAttached(vm))
if (!getEnv(vm, &_env))
{
#ifdef __ANDROID__
if (vm->AttachCurrentThread(&_env, nullptr) != 0)
Expand Down Expand Up @@ -368,20 +372,20 @@ namespace jni
return _handle == nullptr || env()->IsSameObject(_handle, nullptr);
}

template <> void Object::callMethod(method_t method, internal::value_t* args) const
void Object::callMethod(method_t method, internal::value_t* args, internal::ReturnTypeWrapper<void> const&) const
{
env()->CallVoidMethodA(_handle, method, (jvalue*) args);
handleJavaExceptions();
}

template <> bool Object::callMethod(method_t method, internal::value_t* args) const
bool Object::callMethod(method_t method, internal::value_t* args, internal::ReturnTypeWrapper<bool> const&) const
{
auto result = env()->CallBooleanMethodA(_handle, method, (jvalue*) args);
handleJavaExceptions();
return result != 0;
}

template <> bool Object::get(field_t field) const
bool Object::getFieldValue(field_t field, internal::ReturnTypeWrapper<bool> const&) const
{
return env()->GetBooleanField(_handle, field) != 0;
}
Expand All @@ -391,122 +395,122 @@ namespace jni
env()->SetBooleanField(_handle, field, value);
}

template <> byte_t Object::callMethod(method_t method, internal::value_t* args) const
byte_t Object::callMethod(method_t method, internal::value_t* args, internal::ReturnTypeWrapper<byte_t> const&) const
{
auto result = env()->CallByteMethodA(_handle, method, (jvalue*) args);
handleJavaExceptions();
return result;
}

template <> wchar_t Object::callMethod(method_t method, internal::value_t* args) const
wchar_t Object::callMethod(method_t method, internal::value_t* args, internal::ReturnTypeWrapper<wchar_t> const&) const
{
auto result = env()->CallCharMethodA(_handle, method, (jvalue*) args);
handleJavaExceptions();
return result;
}

template <> short Object::callMethod(method_t method, internal::value_t* args) const
short Object::callMethod(method_t method, internal::value_t* args, internal::ReturnTypeWrapper<short> const&) const
{
auto result = env()->CallShortMethodA(_handle, method, (jvalue*) args);
handleJavaExceptions();
return result;
}

template <> int Object::callMethod(method_t method, internal::value_t* args) const
int Object::callMethod(method_t method, internal::value_t* args, internal::ReturnTypeWrapper<int> const&) const
{
auto result = env()->CallIntMethodA(_handle, method, (jvalue*) args);
handleJavaExceptions();
return result;
}

template <> long long Object::callMethod(method_t method, internal::value_t* args) const
long long Object::callMethod(method_t method, internal::value_t* args, internal::ReturnTypeWrapper<long long> const&) const
{
auto result = env()->CallLongMethodA(_handle, method, (jvalue*) args);
handleJavaExceptions();
return result;
}

template <> float Object::callMethod(method_t method, internal::value_t* args) const
float Object::callMethod(method_t method, internal::value_t* args, internal::ReturnTypeWrapper<float> const&) const
{
auto result = env()->CallFloatMethodA(_handle, method, (jvalue*) args);
handleJavaExceptions();
return result;
}

template <> double Object::callMethod(method_t method, internal::value_t* args) const
double Object::callMethod(method_t method, internal::value_t* args, internal::ReturnTypeWrapper<double> const&) const
{
auto result = env()->CallDoubleMethodA(_handle, method, (jvalue*) args);
handleJavaExceptions();
return result;
}

template <> std::string Object::callMethod(method_t method, internal::value_t* args) const
std::string Object::callMethod(method_t method, internal::value_t* args, internal::ReturnTypeWrapper<std::string> const&) const
{
auto result = env()->CallObjectMethodA(_handle, method, (jvalue*) args);
handleJavaExceptions();
return toString(result);
}

template <> std::wstring Object::callMethod(method_t method, internal::value_t* args) const
std::wstring Object::callMethod(method_t method, internal::value_t* args, internal::ReturnTypeWrapper<std::wstring> const&) const
{
auto result = env()->CallObjectMethodA(_handle, method, (jvalue*) args);
handleJavaExceptions();
return toWString(result);
}

template <> jni::Object Object::callMethod(method_t method, internal::value_t* args) const
jni::Object Object::callMethod(method_t method, internal::value_t* args, internal::ReturnTypeWrapper<jni::Object> const&) const
{
auto result = env()->CallObjectMethodA(_handle, method, (jvalue*) args);
handleJavaExceptions();
return Object(result, DeleteLocalInput);
}

template <> byte_t Object::get(field_t field) const
byte_t Object::getFieldValue(field_t field, internal::ReturnTypeWrapper<byte_t> const&) const
{
return env()->GetByteField(_handle, field);
}

template <> wchar_t Object::get(field_t field) const
wchar_t Object::getFieldValue(field_t field, internal::ReturnTypeWrapper<wchar_t> const&) const
{
return env()->GetCharField(_handle, field);
}

template <> short Object::get(field_t field) const
short Object::getFieldValue(field_t field, internal::ReturnTypeWrapper<short> const&) const
{
return env()->GetShortField(_handle, field);
}

template <> int Object::get(field_t field) const
int Object::getFieldValue(field_t field, internal::ReturnTypeWrapper<int> const&) const
{
return env()->GetIntField(_handle, field);
}

template <> long long Object::get(field_t field) const
long long Object::getFieldValue(field_t field, internal::ReturnTypeWrapper<long long> const&) const
{
return env()->GetLongField(_handle, field);
}

template <> float Object::get(field_t field) const
float Object::getFieldValue(field_t field, internal::ReturnTypeWrapper<float> const&) const
{
return env()->GetFloatField(_handle, field);
}

template <> double Object::get(field_t field) const
double Object::getFieldValue(field_t field, internal::ReturnTypeWrapper<double> const&) const
{
return env()->GetDoubleField(_handle, field);
}

template <> std::string Object::get(field_t field) const
std::string Object::getFieldValue(field_t field, internal::ReturnTypeWrapper<std::string> const&) const
{
return toString(env()->GetObjectField(_handle, field));
}

template <> std::wstring Object::get(field_t field) const
std::wstring Object::getFieldValue(field_t field, internal::ReturnTypeWrapper<std::wstring> const&) const
{
return toWString(env()->GetObjectField(_handle, field));
}

template <> Object Object::get(field_t field) const
Object Object::getFieldValue(field_t field, internal::ReturnTypeWrapper<Object> const&) const
{
return Object(env()->GetObjectField(_handle, field), DeleteLocalInput);
}
Expand Down Expand Up @@ -1475,7 +1479,6 @@ namespace jni
}

#else
fprintf(stderr, "opening %s\n", path.c_str());

void* lib = ::dlopen(path.c_str(), RTLD_NOW | RTLD_GLOBAL);

Expand Down
49 changes: 45 additions & 4 deletions src/external/jnipp/jnipp.h
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,17 @@ namespace jni
value_t values[1];
};
long getArrayLength(jarray array);

/**
* @brief Used as a tag type for dispatching internally based on return type.
*
* @tparam T The type to wrap.
*/
template<typename T>
struct ReturnTypeWrapper
{
using type = T;
};
}

/**
Expand Down Expand Up @@ -296,7 +307,7 @@ namespace jni
\return The method's return value.
*/
template <class TReturn>
TReturn call(method_t method) const { return callMethod<TReturn>(method, nullptr); }
TReturn call(method_t method) const { return callMethod(method, nullptr, internal::ReturnTypeWrapper<TReturn>{}); }

/**
Calls the method on this Object with the given name, and no arguments.
Expand Down Expand Up @@ -326,7 +337,7 @@ namespace jni
template <class TReturn, class... TArgs>
TReturn call(method_t method, const TArgs&... args) const {
internal::ArgArray<TArgs...> transform(args...);
return callMethod<TReturn>(method, transform.values);
return callMethod(method, transform.values, internal::ReturnTypeWrapper<TReturn>{});
}

/**
Expand Down Expand Up @@ -356,7 +367,11 @@ namespace jni
\return The field's value.
*/
template <class TType>
TType get(field_t field) const;
TType get(field_t field) const {
// If you get a compile error here, then you've asked for a type
// we don't know how to get from JNI directly.
return getFieldValue(field, internal::ReturnTypeWrapper<TType>{});
}

/**
Gets a field value from this Object. The field must belong to the
Expand Down Expand Up @@ -424,7 +439,33 @@ namespace jni
method_t getMethod(const char* name, const char* signature) const;
method_t getMethod(const char* nameAndSignature) const;
field_t getField(const char* name, const char* signature) const;
template <class TType> TType callMethod(method_t method, internal::value_t* values) const;

void callMethod(method_t method, internal::value_t* args, internal::ReturnTypeWrapper<void> const&) const;
bool callMethod(method_t method, internal::value_t* args, internal::ReturnTypeWrapper<bool> const&) const;
byte_t callMethod(method_t method, internal::value_t* args, internal::ReturnTypeWrapper<byte_t> const&) const;
wchar_t callMethod(method_t method, internal::value_t* args, internal::ReturnTypeWrapper<wchar_t> const&) const;
short callMethod(method_t method, internal::value_t* args, internal::ReturnTypeWrapper<short> const&) const;
int callMethod(method_t method, internal::value_t* args, internal::ReturnTypeWrapper<int> const&) const;
long long callMethod(method_t method, internal::value_t* args, internal::ReturnTypeWrapper<long long> const&) const;
float callMethod(method_t method, internal::value_t* args, internal::ReturnTypeWrapper<float> const&) const;
double callMethod(method_t method, internal::value_t* args, internal::ReturnTypeWrapper<double> const&) const;
std::string callMethod(method_t method, internal::value_t* args, internal::ReturnTypeWrapper<std::string> const&) const;
std::wstring callMethod(method_t method, internal::value_t* args, internal::ReturnTypeWrapper<std::wstring> const&) const;
jni::Object callMethod(method_t method, internal::value_t* args, internal::ReturnTypeWrapper<jni::Object> const&) const;


void getFieldValue(field_t field, internal::ReturnTypeWrapper<void> const&) const;
bool getFieldValue(field_t field, internal::ReturnTypeWrapper<bool> const&) const;
byte_t getFieldValue(field_t field, internal::ReturnTypeWrapper<byte_t> const&) const;
wchar_t getFieldValue(field_t field, internal::ReturnTypeWrapper<wchar_t> const&) const;
short getFieldValue(field_t field, internal::ReturnTypeWrapper<short> const&) const;
int getFieldValue(field_t field, internal::ReturnTypeWrapper<int> const&) const;
long long getFieldValue(field_t field, internal::ReturnTypeWrapper<long long> const&) const;
float getFieldValue(field_t field, internal::ReturnTypeWrapper<float> const&) const;
double getFieldValue(field_t field, internal::ReturnTypeWrapper<double> const&) const;
std::string getFieldValue(field_t field, internal::ReturnTypeWrapper<std::string> const&) const;
std::wstring getFieldValue(field_t field, internal::ReturnTypeWrapper<std::wstring> const&) const;
jni::Object getFieldValue(field_t field, internal::ReturnTypeWrapper<jni::Object> const&) const;

// Instance Variables
jobject _handle;
Expand Down
18 changes: 18 additions & 0 deletions src/external/jnipp/tests/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Copyright 2021, Collabora, Ltd.
#
# SPDX-License-Identifier: MIT

add_executable(main_test main.cpp testing.h)
target_link_libraries(main_test PRIVATE jnipp)
add_test(NAME main_test COMMAND main_test)

add_executable(external_create external_create.cpp testing.h)
target_link_libraries(external_create PUBLIC jnipp ${JNI_LIBRARIES})
target_include_directories(external_create PUBLIC ${JNI_INCLUDE_DIRS})
add_test(NAME external_create COMMAND external_create)


add_executable(external_detach external_detach.cpp testing.h)
target_link_libraries(external_detach PUBLIC jnipp ${JNI_LIBRARIES})
target_include_directories(external_detach PUBLIC ${JNI_INCLUDE_DIRS})
add_test(NAME external_detach COMMAND external_detach)
37 changes: 37 additions & 0 deletions src/external/jnipp/tests/external_create.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// Project Dependencies
#include <jni.h>
#include <jnipp.h>

// Standard Dependencies
#include <cmath>

// Local Dependencies
#include "testing.h"

/*
jni::Vm Tests
*/
TEST(Vm_externalCreateAndAttach) {
JNIEnv *env;
JavaVMInitArgs args = {};
args.version = JNI_VERSION_1_2;
JavaVM *javaVm{};
auto ret = JNI_CreateJavaVM(&javaVm, (void **)&env, &args);
ASSERT(ret == 0);

{
jni::init(env);
jni::Class cls("java/lang/String");
}
JavaVM *localVmPointer{};

ret = env->GetJavaVM(&localVmPointer);
ASSERT(ret == 0);
}

int main() {
// jni::Vm Tests
RUN_TEST(Vm_externalCreateAndAttach);

return 0;
}
34 changes: 34 additions & 0 deletions src/external/jnipp/tests/external_detach.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// Project Dependencies
#include <jni.h>
#include <jnipp.h>

// Standard Dependencies
#include <cmath>

// Local Dependencies
#include "testing.h"

/*
jni::Vm Tests
*/
TEST(Vm_externalDetach) {
jni::Vm vm;

jni::Class cls("java/lang/String");

JNIEnv *env = (JNIEnv *)jni::env();
JavaVM *localVmPointer{};

auto ret = env->GetJavaVM(&localVmPointer);
ASSERT(ret == 0);
ret = localVmPointer->DetachCurrentThread();
ASSERT(ret == 0);

ASSERT(1);
}

int main() {
// jni::Vm Tests
RUN_TEST(Vm_externalDetach);
return 0;
}
Loading