// 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 * @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 #include 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) { if (xinst->android_instance == NULL) { // Already cleaned up or never initialized. return; } 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; }