The open source OpenXR runtime
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
25static inline struct android_instance_base *
26android_instance_base(struct xrt_instance_android *xinst_android)
27{
28 return (struct android_instance_base *)(xinst_android);
29}
30
31static inline const struct android_instance_base *
32android_instance_base_const(const struct xrt_instance_android *xinst_android)
33{
34 return (const struct android_instance_base *)(xinst_android);
35}
36
37static struct _JavaVM *
38base_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
45static void *
46base_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
53static xrt_result_t
54base_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
73static xrt_result_t
74base_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
90xrt_result_t
91android_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
149void
150android_instance_base_cleanup(struct android_instance_base *aib, struct xrt_instance *xinst)
151{
152 if (xinst->android_instance == NULL) {
153 // Already cleaned up or never initialized.
154 return;
155 }
156
157 assert(&(aib->base) == xinst->android_instance);
158 android_lifecycle_callbacks_destroy(&aib->lifecycle_callbacks);
159
160 if (aib->vm != NULL) {
161 JNIEnv *env = NULL;
162 if (aib->vm->functions->AttachCurrentThread(&aib->vm->functions, &env, NULL) == JNI_OK) {
163 (*env)->DeleteGlobalRef(env, aib->context);
164 }
165 }
166
167 xinst->android_instance = NULL;
168}