mirror of
https://gitlab.freedesktop.org/monado/monado.git
synced 2025-01-01 12:46:12 +00:00
ipc/android: Avoid deadlock on Android
This commit is contained in:
parent
13f7fa3b82
commit
210a6908cd
|
@ -12,6 +12,8 @@ set(ANDROID_SOURCE_FILES
|
|||
android/android_globals.h
|
||||
android/android_load_class.cpp
|
||||
android/android_load_class.hpp
|
||||
android/android_looper.c
|
||||
android/android_looper.h
|
||||
android/org.freedesktop.monado.auxiliary.cpp
|
||||
android/org.freedesktop.monado.auxiliary.hpp
|
||||
android/org.freedesktop.monado.auxiliary.impl.hpp
|
||||
|
@ -320,10 +322,13 @@ endif()
|
|||
|
||||
|
||||
if(ANDROID)
|
||||
add_library(android_app_glue STATIC
|
||||
${ANDROID_NDK}/sources/android/native_app_glue/android_native_app_glue.c)
|
||||
target_include_directories(android_app_glue PUBLIC ${ANDROID_NDK}/sources/android/native_app_glue)
|
||||
add_library(aux_android STATIC ${ANDROID_SOURCE_FILES})
|
||||
target_link_libraries(aux_android
|
||||
PUBLIC aux_util
|
||||
PRIVATE ${ANDROID_LIBRARY} ${ANDROID_LOG_LIBRARY} xrt-external-jni-wrap xrt-external-jnipp
|
||||
PRIVATE ${ANDROID_LIBRARY} ${ANDROID_LOG_LIBRARY} xrt-external-jni-wrap xrt-external-jnipp android_app_glue
|
||||
)
|
||||
target_link_libraries(aux_vk PUBLIC aux_android)
|
||||
endif()
|
||||
|
|
31
src/xrt/auxiliary/android/android_looper.c
Normal file
31
src/xrt/auxiliary/android/android_looper.c
Normal file
|
@ -0,0 +1,31 @@
|
|||
// Copyright 2021, Qualcomm Innovation Center, Inc.
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
/*!
|
||||
* @file
|
||||
* @brief Implementation of android looper functions.
|
||||
* @author Jarvis Huang
|
||||
* @ingroup aux_android
|
||||
*/
|
||||
|
||||
#include "android_looper.h"
|
||||
|
||||
#include "util/u_logging.h"
|
||||
|
||||
#include <android_native_app_glue.h>
|
||||
#include <android/looper.h>
|
||||
|
||||
void
|
||||
android_looper_poll_until_activity_resumed()
|
||||
{
|
||||
struct android_poll_source *source;
|
||||
// Can we assume that activity already resumed if polling is failed?
|
||||
while (ALooper_pollAll(-1, NULL, NULL, (void **)&source) == LOOPER_ID_MAIN) {
|
||||
if (source) {
|
||||
source->process(source->app, source);
|
||||
if (source->app->activityState == APP_CMD_RESUME && source->app->window) {
|
||||
U_LOG_I("Activity is in resume state and window is ready now");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
30
src/xrt/auxiliary/android/android_looper.h
Normal file
30
src/xrt/auxiliary/android/android_looper.h
Normal file
|
@ -0,0 +1,30 @@
|
|||
// Copyright 2021, Qualcomm Innovation Center, Inc.
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
/*!
|
||||
* @file
|
||||
* @brief Utility functions for android looper.
|
||||
* @author Jarvis Huang
|
||||
* @ingroup aux_android
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef XRT_OS_ANDROID
|
||||
|
||||
#include <cstdbool>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*!
|
||||
* Poll the looper until activity is in resume state.
|
||||
*/
|
||||
void
|
||||
android_looper_poll_until_activity_resumed();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // XRT_OS_ANDROID
|
|
@ -10,13 +10,17 @@
|
|||
#include "ipc_client_android.h"
|
||||
|
||||
#include "org.freedesktop.monado.ipc.hpp"
|
||||
#include "wrap/android.app.h"
|
||||
|
||||
|
||||
#include "xrt/xrt_config_android.h"
|
||||
#include "android/android_load_class.hpp"
|
||||
#include "util/u_logging.h"
|
||||
|
||||
#include "android/android_load_class.hpp"
|
||||
#include "android/android_looper.h"
|
||||
|
||||
#include "wrap/android.app.h"
|
||||
|
||||
#include <android/api-level.h>
|
||||
|
||||
using wrap::android::app::Activity;
|
||||
using wrap::org::freedesktop::monado::ipc::Client;
|
||||
using xrt::auxiliary::android::getAppInfo;
|
||||
|
@ -83,6 +87,11 @@ ipc_client_android_create(struct _JavaVM *vm, void *activity)
|
|||
int
|
||||
ipc_client_android_blocking_connect(struct ipc_client_android *ica)
|
||||
{
|
||||
// Before android Q, onServiceConnected always returns on main thread, which might cause deadlock.
|
||||
if (android_get_device_api_level() < __ANDROID_API_Q__) {
|
||||
android_looper_poll_until_activity_resumed();
|
||||
}
|
||||
|
||||
try {
|
||||
int fd = ica->client.blockingConnect(ica->activity, XRT_ANDROID_PACKAGE);
|
||||
return fd;
|
||||
|
|
|
@ -16,6 +16,7 @@ import android.content.Context;
|
|||
import android.content.Intent;
|
||||
import android.content.ServiceConnection;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Build;
|
||||
import android.os.IBinder;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.os.RemoteException;
|
||||
|
@ -32,6 +33,7 @@ import org.freedesktop.monado.auxiliary.NativeCounterpart;
|
|||
import org.freedesktop.monado.auxiliary.SystemUiController;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
/**
|
||||
* Provides the client-side code to initiate connection to Monado IPC service.
|
||||
|
@ -257,19 +259,30 @@ public class Client implements ServiceConnection {
|
|||
Log.e(TAG, "startForegroundService: Service " + intent.toString() + " does not exist!");
|
||||
return false;
|
||||
}
|
||||
if (!context.bindService(intent,
|
||||
this,
|
||||
Context.BIND_AUTO_CREATE
|
||||
| Context.BIND_IMPORTANT
|
||||
| Context.BIND_INCLUDE_CAPABILITIES
|
||||
| Context.BIND_ABOVE_CLIENT)) {
|
||||
Log.e(TAG, "bindService: Service " + intent.toString() + " could not be found to bind!");
|
||||
|
||||
if (!bindService(context, intent)) {
|
||||
Log.e(TAG,
|
||||
"bindService: Service " + intent.toString() + " could not be found to bind!");
|
||||
return false;
|
||||
}
|
||||
|
||||
// does not bind right away! This takes some time.
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean bindService(Context context, Intent intent) {
|
||||
boolean result;
|
||||
int flags = Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT | Context.BIND_ABOVE_CLIENT;
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
result = context.bindService(intent, flags | Context.BIND_INCLUDE_CAPABILITIES,
|
||||
Executors.newSingleThreadExecutor(), this);
|
||||
} else {
|
||||
result = context.bindService(intent, this, flags);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Some on-failure cleanup.
|
||||
*/
|
||||
|
|
Loading…
Reference in a new issue