The open source OpenXR runtime

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>

+239
+2
src/xrt/auxiliary/android/CMakeLists.txt
··· 17 17 android_custom_surface.h 18 18 android_globals.cpp 19 19 android_globals.h 20 + android_instance_base.c 21 + android_instance_base.h 20 22 android_lifecycle_callbacks.cpp 21 23 android_lifecycle_callbacks.h 22 24 android_load_class.cpp
+163
src/xrt/auxiliary/android/android_instance_base.c
··· 1 + // Copyright 2023, Qualcomm Innovation Center, Inc. 2 + // Copyright 2021-2024, Collabora, Ltd. 3 + // SPDX-License-Identifier: BSL-1.0 4 + /*! 5 + * @file 6 + * @brief Basic xrt_instance_base implementation. 7 + * @author Jarvis Huang 8 + * @author Rylie Pavlik <rylie.pavlik@collabora.com> 9 + * @ingroup aux_android 10 + */ 11 + 12 + #include "android_instance_base.h" 13 + 14 + #include "android/android_globals.h" 15 + #include "android/android_lifecycle_callbacks.h" 16 + #include "util/u_logging.h" 17 + #include "xrt/xrt_instance.h" 18 + #include "xrt/xrt_android.h" 19 + #include "xrt/xrt_results.h" 20 + 21 + #include <jni.h> 22 + #include <assert.h> 23 + 24 + 25 + static inline struct android_instance_base * 26 + android_instance_base(struct xrt_instance_android *xinst_android) 27 + { 28 + return (struct android_instance_base *)(xinst_android); 29 + } 30 + 31 + static inline const struct android_instance_base * 32 + android_instance_base_const(const struct xrt_instance_android *xinst_android) 33 + { 34 + return (const struct android_instance_base *)(xinst_android); 35 + } 36 + 37 + static struct _JavaVM * 38 + base_get_vm(const struct xrt_instance_android *xinst_android) 39 + { 40 + 41 + const struct android_instance_base *aib = android_instance_base_const(xinst_android); 42 + return aib->vm; 43 + } 44 + 45 + static void * 46 + base_get_context(const struct xrt_instance_android *xinst_android) 47 + { 48 + 49 + const struct android_instance_base *aib = android_instance_base_const(xinst_android); 50 + return aib->context; 51 + } 52 + 53 + static xrt_result_t 54 + base_register_activity_lifecycle_callback(struct xrt_instance_android *xinst_android, 55 + xrt_android_lifecycle_event_handler_t callback, 56 + enum xrt_android_lifecycle_event event_mask, 57 + void *userdata) 58 + { 59 + struct android_instance_base *aib = android_instance_base(xinst_android); 60 + int ret = 0; 61 + if (aib->lifecycle_callbacks == NULL) { 62 + U_LOG_I("No lifecycle callback container, instance is likely Service"); 63 + } else { 64 + ret = android_lifecycle_callbacks_register_callback(aib->lifecycle_callbacks, callback, event_mask, 65 + userdata); 66 + } 67 + // If it fails, the inner callback container threw on emplace_back. Should basically never happen, 68 + // but technically an allocation error. 69 + return ret == 0 ? XRT_SUCCESS : XRT_ERROR_ALLOCATION; 70 + } 71 + 72 + 73 + static xrt_result_t 74 + base_remove_activity_lifecycle_callback(struct xrt_instance_android *xinst_android, 75 + xrt_android_lifecycle_event_handler_t callback, 76 + enum xrt_android_lifecycle_event event_mask, 77 + void *userdata) 78 + { 79 + struct android_instance_base *aib = android_instance_base(xinst_android); 80 + int ret = 0; 81 + if (aib->lifecycle_callbacks != NULL) { 82 + // We expect 1 to be returned, to remove the callback we previously added 83 + ret = android_lifecycle_callbacks_remove_callback(aib->lifecycle_callbacks, callback, event_mask, 84 + userdata); 85 + } 86 + 87 + return ret > 0 ? XRT_SUCCESS : XRT_ERROR_ANDROID; 88 + } 89 + 90 + xrt_result_t 91 + android_instance_base_init(struct android_instance_base *aib, 92 + struct xrt_instance *xinst, 93 + const struct xrt_instance_info *ii) 94 + { 95 + struct _JavaVM *vm = ii->platform_info.vm; 96 + void *context = ii->platform_info.context; 97 + 98 + if (vm == NULL) { 99 + U_LOG_E("Invalid Java VM - trying globals"); 100 + vm = android_globals_get_vm(); 101 + } 102 + 103 + if (context == NULL) { 104 + U_LOG_E("Invalid Context - trying globals"); 105 + context = android_globals_get_context(); 106 + } 107 + 108 + if (vm == NULL) { 109 + U_LOG_E("Invalid Java VM"); 110 + return XRT_ERROR_ANDROID; 111 + } 112 + 113 + if (context == NULL) { 114 + U_LOG_E("Invalid context"); 115 + return XRT_ERROR_ANDROID; 116 + } 117 + 118 + JNIEnv *env = NULL; 119 + if (vm->functions->AttachCurrentThread(&vm->functions, &env, NULL) != JNI_OK) { 120 + U_LOG_E("Failed to attach thread"); 121 + return XRT_ERROR_ANDROID; 122 + } 123 + 124 + jobject global_context = (*env)->NewGlobalRef(env, context); 125 + if (global_context == NULL) { 126 + U_LOG_E("Failed to create global ref"); 127 + return XRT_ERROR_ANDROID; 128 + } 129 + 130 + xinst->android_instance = &aib->base; 131 + aib->vm = vm; 132 + aib->context = global_context; 133 + aib->base.get_vm = base_get_vm; 134 + aib->base.get_context = base_get_context; 135 + aib->base.register_activity_lifecycle_callback = base_register_activity_lifecycle_callback; 136 + aib->base.remove_activity_lifecycle_callback = base_remove_activity_lifecycle_callback; 137 + 138 + // aib->base.register_surface_callback = base_register_surface_callback; 139 + // aib->base.remove_surface_callback = base_remove_surface_callback; 140 + 141 + aib->lifecycle_callbacks = android_lifecycle_callbacks_create(&aib->base); 142 + 143 + if (aib->lifecycle_callbacks == NULL) { 144 + return XRT_ERROR_ALLOCATION; 145 + } 146 + return XRT_SUCCESS; 147 + } 148 + 149 + void 150 + android_instance_base_cleanup(struct android_instance_base *aib, struct xrt_instance *xinst) 151 + { 152 + assert(&(aib->base) == xinst->android_instance); 153 + android_lifecycle_callbacks_destroy(&aib->lifecycle_callbacks); 154 + 155 + if (aib->vm != NULL) { 156 + JNIEnv *env = NULL; 157 + if (aib->vm->functions->AttachCurrentThread(&aib->vm->functions, &env, NULL) == JNI_OK) { 158 + (*env)->DeleteGlobalRef(env, aib->context); 159 + } 160 + } 161 + 162 + xinst->android_instance = NULL; 163 + }
+74
src/xrt/auxiliary/android/android_instance_base.h
··· 1 + // Copyright 2023, Qualcomm Innovation Center, Inc. 2 + // Copyright 2020-2024, Collabora, Ltd. 3 + // SPDX-License-Identifier: BSL-1.0 4 + /*! 5 + * @file 6 + * @brief Base implementation of the @ref xrt_instance_android interface. 7 + * @author Jarvis Huang 8 + * @author Rylie Pavlik <rylie.pavlik@collabora.com> 9 + * @ingroup aux_android 10 + */ 11 + #pragma once 12 + 13 + #include "xrt/xrt_instance.h" 14 + #include "xrt/xrt_android.h" 15 + 16 + #ifdef __cplusplus 17 + extern "C" { 18 + #endif 19 + 20 + struct _JavaVM; 21 + struct android_lifecycle_callbacks; 22 + 23 + /*! 24 + * @brief A basic implementation of the @ref xrt_instance_android interface, 25 + * a platform-specific "aspect" of @ref xrt_instance. 26 + * 27 + * Store nested in your @ref xrt_instance implementation (by value, not separately allocated), 28 + * and call @ref android_instance_base_init in your instance creation and 29 + * @ref android_instance_base_cleanup in instance destruction. 30 + * 31 + */ 32 + struct android_instance_base 33 + { 34 + struct xrt_instance_android base; 35 + struct _JavaVM *vm; 36 + void *context; 37 + struct android_lifecycle_callbacks *lifecycle_callbacks; 38 + }; 39 + 40 + /*! 41 + * @brief Initialize resources owned by @p android_instance_base and 42 + * sets the @ref xrt_instance::android_instance pointer. 43 + * 44 + * @param aib The object to initialize. 45 + * @param xinst The xrt_instance to update. 46 + * @param vm The JavaVM pointer. 47 + * @param activity The activity jobject, cast to a void pointer. 48 + * 49 + * @returns @ref XRT_SUCCESS on success, @ref XRT_ERROR_ALLOCATION if we could not allocate 50 + * our required objects, and @ref XRT_ERROR_ANDROID if something goes very wrong with Java/JNI 51 + * that should be impossible and likely indicates a logic error in the code. 52 + * 53 + * @public @memberof android_instance_base 54 + */ 55 + xrt_result_t 56 + android_instance_base_init(struct android_instance_base *aib, 57 + struct xrt_instance *xinst, 58 + const struct xrt_instance_info *ii); 59 + 60 + /*! 61 + * @brief Release resources owned by @ref android_instance_base and unsets the aspect pointer 62 + * - but does not free @p aib itself, since it is intended to be held by value. 63 + * 64 + * @param aib The object to de-initialize. 65 + * @param xinst The xrt_instance to update. 66 + * 67 + * @public @memberof android_instance_base 68 + */ 69 + void 70 + android_instance_base_cleanup(struct android_instance_base *aib, struct xrt_instance *xinst); 71 + 72 + #ifdef __cplusplus 73 + }; 74 + #endif