The open source OpenXR runtime
1// Copyright 2020, Collabora, Ltd.
2// SPDX-License-Identifier: BSL-1.0
3/*!
4 * @file
5 * @brief Implementation exposing Android-specific IPC client code to C.
6 * @author Rylie Pavlik <rylie.pavlik@collabora.com>
7 * @ingroup ipc_android
8 */
9
10#include "ipc_client_android.h"
11
12#include "org.freedesktop.monado.ipc.hpp"
13
14#include "xrt/xrt_config_android.h"
15#include "util/u_logging.h"
16
17#include "android/android_load_class.hpp"
18#include "android/android_looper.h"
19
20#include "wrap/android.app.h"
21
22using wrap::android::app::Activity;
23using wrap::org::freedesktop::monado::ipc::Client;
24using xrt::auxiliary::android::loadClassFromRuntimeApk;
25
26struct ipc_client_android
27{
28 ipc_client_android(struct _JavaVM *vm_, jobject act) : vm(vm_), activity(act) {}
29 ~ipc_client_android();
30 struct _JavaVM *vm;
31
32 Activity activity{};
33 Client client{nullptr};
34};
35
36ipc_client_android::~ipc_client_android()
37{
38
39 // Tell Java that native code is done with this.
40 try {
41 if (!client.isNull()) {
42 client.markAsDiscardedByNative();
43 }
44 } catch (std::exception const &e) {
45 // Must catch and ignore any exceptions in the destructor!
46 U_LOG_E("Failure while marking IPC client as discarded: %s", e.what());
47 }
48}
49
50struct ipc_client_android *
51ipc_client_android_create(struct _JavaVM *vm, void *activity)
52{
53
54 jni::init(vm);
55 try {
56 auto clazz = loadClassFromRuntimeApk((jobject)activity, Client::getFullyQualifiedTypeName());
57 if (clazz.isNull()) {
58 U_LOG_E("Could not load class '%s' from package '%s'", Client::getFullyQualifiedTypeName(),
59 XRT_ANDROID_PACKAGE);
60 return nullptr;
61 }
62
63 // Teach the wrapper our class before we start to use it.
64 Client::staticInitClass((jclass)clazz.object().getHandle());
65 std::unique_ptr<ipc_client_android> ret = std::make_unique<ipc_client_android>(vm, (jobject)activity);
66
67 ret->client = Client::construct(ret.get());
68
69 return ret.release();
70 } catch (std::exception const &e) {
71
72 U_LOG_E("Could not start IPC client class: %s", e.what());
73 return nullptr;
74 }
75}
76
77int
78ipc_client_android_blocking_connect(struct ipc_client_android *ica)
79{
80 try {
81 // Trick to avoid deadlock on main thread: only applicable to NativeActivity with app-glue.
82 // blockingConnect will block until binder is ready, the app-glue code will deadlock without this.
83 JavaVM *vm = ica->vm;
84 android_looper_poll_until_activity_resumed(vm, ica->activity.object().getHandle());
85 int fd = ica->client.blockingConnect(ica->activity, XRT_ANDROID_PACKAGE);
86 return fd;
87 } catch (std::exception const &e) {
88 U_LOG_E("Failure while connecting to IPC server: %s", e.what());
89 return -1;
90 }
91}
92
93
94void
95ipc_client_android_destroy(struct ipc_client_android **ptr_ica)
96{
97
98 if (ptr_ica == NULL) {
99 return;
100 }
101 struct ipc_client_android *ica = *ptr_ica;
102 if (ica == NULL) {
103 return;
104 }
105 try {
106 delete ica;
107 } catch (std::exception const &e) {
108 // Must catch and ignore any exceptions in the destructor!
109 U_LOG_E("Failure while destroying IPC clean: %s", e.what());
110 }
111 *ptr_ica = NULL;
112}