···991010#include "android_looper.h"
11111212-#include "android/android_globals.h"
1312#include "util/u_logging.h"
1413#include "wrap/android.app.h"
15141615#include <android_native_app_glue.h>
1716#include <android/looper.h>
18171919-#include <android/log.h>
2020-2118void
2222-android_looper_poll_until_activity_resumed()
1919+android_looper_poll_until_activity_resumed(struct _JavaVM *vm, void *activity)
2320{
2424- jni::init(android_globals_get_vm());
2525- wrap::android::app::Activity activity{(jobject)android_globals_get_activity()};
2626- if (!jni::env()->IsInstanceOf(activity.object().getHandle(),
2121+ jni::init(vm);
2222+ wrap::android::app::Activity activityObject{(jobject)activity};
2323+ if (!jni::env()->IsInstanceOf(activityObject.object().getHandle(),
2724 jni::Class("android/app/NativeActivity").getHandle())) {
2825 // skip if given activity is not android.app.NativeActivity
2926 U_LOG_I("Activity is not NativeActivity, skip");
···3128 }
32293330 // Activity is in resumed state if window is active. Check Activity#onPostResume for detail.
3434- if (!activity.getWindow().isNull() && activity.getWindow().call<bool>("isActive()Z")) {
3131+ if (!activityObject.getWindow().isNull() && activityObject.getWindow().call<bool>("isActive()Z")) {
3532 // Already in resume state, skip
3633 U_LOG_I("Activity is NativeActivity and already in resume state with window available, skip");
3734 return;
+3-1
src/xrt/auxiliary/android/android_looper.h
···1717extern "C" {
1818#endif
19192020+struct _JavaVM;
2121+2022/*!
2123 * Poll the looper until activity is in resume state.
2224 */
2325void
2424-android_looper_poll_until_activity_resumed();
2626+android_looper_poll_until_activity_resumed(struct _JavaVM *vm, void *activity);
25272628#ifdef __cplusplus
2729}
+6-1
src/xrt/ipc/android/ipc_client_android.cpp
···1515#include "util/u_logging.h"
16161717#include "android/android_load_class.hpp"
1818+#include "android/android_looper.h"
18191920#include "wrap/android.app.h"
2021···7677ipc_client_android_blocking_connect(struct ipc_client_android *ica)
7778{
7879 try {
8080+ // Trick to avoid deadlock on main thread: only applicable to NativeActivity with app-glue.
8181+ // blockingConnect will block until binder is ready, the app-glue code will deadlock without this.
8282+ JavaVM *vm = nullptr;
8383+ jni::env()->GetJavaVM(&vm);
8484+ android_looper_poll_until_activity_resumed(vm, ica->activity.object().getHandle());
7985 int fd = ica->client.blockingConnect(ica->activity, XRT_ANDROID_PACKAGE);
8086 return fd;
8187 } catch (std::exception const &e) {
8282- // Must catch and ignore any exceptions in the destructor!
8388 U_LOG_E("Failure while connecting to IPC server: %s", e.what());
8489 return -1;
8590 }
-3
src/xrt/state_trackers/oxr/oxr_instance.c
···27272828#ifdef XRT_OS_ANDROID
2929#include "android/android_globals.h"
3030-#include "android/android_looper.h"
3130#endif
32313332#include "oxr_objects.h"
···291290 createInfo, XR_TYPE_INSTANCE_CREATE_INFO_ANDROID_KHR, XrInstanceCreateInfoAndroidKHR);
292291 android_globals_store_vm_and_activity((struct _JavaVM *)create_info_android->applicationVM,
293292 create_info_android->applicationActivity);
294294- // Trick to avoid deadlock on main thread. Only works for NativeActivity with app-glue.
295295- android_looper_poll_until_activity_resumed();
296293#endif
297294298295