a/android: Base implementation of xrt_instance_android

Co-authored-by: Jarvis Huang <quic_jarvhuan@quicinc.com>
Part-of: <https://gitlab.freedesktop.org/monado/monado/-/merge_requests/1655>
This commit is contained in:
Rylie Pavlik 2021-04-09 16:31:00 -05:00
parent 3a7e98a51b
commit 28ec3246eb
3 changed files with 239 additions and 0 deletions

View file

@ -17,6 +17,8 @@ add_library(
android_custom_surface.h
android_globals.cpp
android_globals.h
android_instance_base.c
android_instance_base.h
android_lifecycle_callbacks.cpp
android_lifecycle_callbacks.h
android_load_class.cpp

View file

@ -0,0 +1,163 @@
// Copyright 2023, Qualcomm Innovation Center, Inc.
// Copyright 2021-2024, Collabora, Ltd.
// SPDX-License-Identifier: BSL-1.0
/*!
* @file
* @brief Basic xrt_instance_base implementation.
* @author Jarvis Huang
* @author Rylie Pavlik <rylie.pavlik@collabora.com>
* @ingroup aux_android
*/
#include "android_instance_base.h"
#include "android/android_globals.h"
#include "android/android_lifecycle_callbacks.h"
#include "util/u_logging.h"
#include "xrt/xrt_instance.h"
#include "xrt/xrt_android.h"
#include "xrt/xrt_results.h"
#include <jni.h>
#include <assert.h>
static inline struct android_instance_base *
android_instance_base(struct xrt_instance_android *xinst_android)
{
return (struct android_instance_base *)(xinst_android);
}
static inline const struct android_instance_base *
android_instance_base_const(const struct xrt_instance_android *xinst_android)
{
return (const struct android_instance_base *)(xinst_android);
}
static struct _JavaVM *
base_get_vm(const struct xrt_instance_android *xinst_android)
{
const struct android_instance_base *aib = android_instance_base_const(xinst_android);
return aib->vm;
}
static void *
base_get_context(const struct xrt_instance_android *xinst_android)
{
const struct android_instance_base *aib = android_instance_base_const(xinst_android);
return aib->context;
}
static xrt_result_t
base_register_activity_lifecycle_callback(struct xrt_instance_android *xinst_android,
xrt_android_lifecycle_event_handler_t callback,
enum xrt_android_lifecycle_event event_mask,
void *userdata)
{
struct android_instance_base *aib = android_instance_base(xinst_android);
int ret = 0;
if (aib->lifecycle_callbacks == NULL) {
U_LOG_I("No lifecycle callback container, instance is likely Service");
} else {
ret = android_lifecycle_callbacks_register_callback(aib->lifecycle_callbacks, callback, event_mask,
userdata);
}
// If it fails, the inner callback container threw on emplace_back. Should basically never happen,
// but technically an allocation error.
return ret == 0 ? XRT_SUCCESS : XRT_ERROR_ALLOCATION;
}
static xrt_result_t
base_remove_activity_lifecycle_callback(struct xrt_instance_android *xinst_android,
xrt_android_lifecycle_event_handler_t callback,
enum xrt_android_lifecycle_event event_mask,
void *userdata)
{
struct android_instance_base *aib = android_instance_base(xinst_android);
int ret = 0;
if (aib->lifecycle_callbacks != NULL) {
// We expect 1 to be returned, to remove the callback we previously added
ret = android_lifecycle_callbacks_remove_callback(aib->lifecycle_callbacks, callback, event_mask,
userdata);
}
return ret > 0 ? XRT_SUCCESS : XRT_ERROR_ANDROID;
}
xrt_result_t
android_instance_base_init(struct android_instance_base *aib,
struct xrt_instance *xinst,
const struct xrt_instance_info *ii)
{
struct _JavaVM *vm = ii->platform_info.vm;
void *context = ii->platform_info.context;
if (vm == NULL) {
U_LOG_E("Invalid Java VM - trying globals");
vm = android_globals_get_vm();
}
if (context == NULL) {
U_LOG_E("Invalid Context - trying globals");
context = android_globals_get_context();
}
if (vm == NULL) {
U_LOG_E("Invalid Java VM");
return XRT_ERROR_ANDROID;
}
if (context == NULL) {
U_LOG_E("Invalid context");
return XRT_ERROR_ANDROID;
}
JNIEnv *env = NULL;
if (vm->functions->AttachCurrentThread(&vm->functions, &env, NULL) != JNI_OK) {
U_LOG_E("Failed to attach thread");
return XRT_ERROR_ANDROID;
}
jobject global_context = (*env)->NewGlobalRef(env, context);
if (global_context == NULL) {
U_LOG_E("Failed to create global ref");
return XRT_ERROR_ANDROID;
}
xinst->android_instance = &aib->base;
aib->vm = vm;
aib->context = global_context;
aib->base.get_vm = base_get_vm;
aib->base.get_context = base_get_context;
aib->base.register_activity_lifecycle_callback = base_register_activity_lifecycle_callback;
aib->base.remove_activity_lifecycle_callback = base_remove_activity_lifecycle_callback;
// aib->base.register_surface_callback = base_register_surface_callback;
// aib->base.remove_surface_callback = base_remove_surface_callback;
aib->lifecycle_callbacks = android_lifecycle_callbacks_create(&aib->base);
if (aib->lifecycle_callbacks == NULL) {
return XRT_ERROR_ALLOCATION;
}
return XRT_SUCCESS;
}
void
android_instance_base_cleanup(struct android_instance_base *aib, struct xrt_instance *xinst)
{
assert(&(aib->base) == xinst->android_instance);
android_lifecycle_callbacks_destroy(&aib->lifecycle_callbacks);
if (aib->vm != NULL) {
JNIEnv *env = NULL;
if (aib->vm->functions->AttachCurrentThread(&aib->vm->functions, &env, NULL) == JNI_OK) {
(*env)->DeleteGlobalRef(env, aib->context);
}
}
xinst->android_instance = NULL;
}

View file

@ -0,0 +1,74 @@
// Copyright 2023, Qualcomm Innovation Center, Inc.
// Copyright 2020-2024, Collabora, Ltd.
// SPDX-License-Identifier: BSL-1.0
/*!
* @file
* @brief Base implementation of the @ref xrt_instance_android interface.
* @author Jarvis Huang
* @author Rylie Pavlik <rylie.pavlik@collabora.com>
* @ingroup aux_android
*/
#pragma once
#include "xrt/xrt_instance.h"
#include "xrt/xrt_android.h"
#ifdef __cplusplus
extern "C" {
#endif
struct _JavaVM;
struct android_lifecycle_callbacks;
/*!
* @brief A basic implementation of the @ref xrt_instance_android interface,
* a platform-specific "aspect" of @ref xrt_instance.
*
* Store nested in your @ref xrt_instance implementation (by value, not separately allocated),
* and call @ref android_instance_base_init in your instance creation and
* @ref android_instance_base_cleanup in instance destruction.
*
*/
struct android_instance_base
{
struct xrt_instance_android base;
struct _JavaVM *vm;
void *context;
struct android_lifecycle_callbacks *lifecycle_callbacks;
};
/*!
* @brief Initialize resources owned by @p android_instance_base and
* sets the @ref xrt_instance::android_instance pointer.
*
* @param aib The object to initialize.
* @param xinst The xrt_instance to update.
* @param vm The JavaVM pointer.
* @param activity The activity jobject, cast to a void pointer.
*
* @returns @ref XRT_SUCCESS on success, @ref XRT_ERROR_ALLOCATION if we could not allocate
* our required objects, and @ref XRT_ERROR_ANDROID if something goes very wrong with Java/JNI
* that should be impossible and likely indicates a logic error in the code.
*
* @public @memberof android_instance_base
*/
xrt_result_t
android_instance_base_init(struct android_instance_base *aib,
struct xrt_instance *xinst,
const struct xrt_instance_info *ii);
/*!
* @brief Release resources owned by @ref android_instance_base and unsets the aspect pointer
* - but does not free @p aib itself, since it is intended to be held by value.
*
* @param aib The object to de-initialize.
* @param xinst The xrt_instance to update.
*
* @public @memberof android_instance_base
*/
void
android_instance_base_cleanup(struct android_instance_base *aib, struct xrt_instance *xinst);
#ifdef __cplusplus
};
#endif