Ocean
Loading...
Searching...
No Matches
NativeInterfaceManager.h
Go to the documentation of this file.
1/*
2 * Copyright (c) Meta Platforms, Inc. and affiliates.
3 *
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 */
7
8#ifndef META_OCEAN_PLATFORM_ANDROID_NATIVE_INTERFACE_MANAGER_H
9#define META_OCEAN_PLATFORM_ANDROID_NATIVE_INTERFACE_MANAGER_H
10
12
13#include "ocean/base/Lock.h"
15
16#include <atomic>
17
18namespace Ocean
19{
20
21namespace Platform
22{
23
24namespace Android
25{
26
27/**
28 * This class implements the manager of the java native interface as singleton.
29 * The manager holds the Java virtual machine and provides the JNI environment of any thread.
30 * The manager can be used from any thread, threads are attached to the virtual machine on demand and are detached again when the thread ends.
31 * Threads created by Java are attached already and are never detached by this manager.
32 * The following code example shows the usage of this manager:
33 * @code
34 * using namespace Ocean::Platform::Android;
35 *
36 * // the virtual machine is set once, commonly in JNI_OnLoad()
37 * jint JNI_OnLoad(JavaVM* virtualMachine, void* reserved)
38 * {
39 * NativeInterfaceManager::get().setVirtualMachine(virtualMachine);
40 *
41 * return JNI_VERSION_1_6;
42 * }
43 *
44 * // afterwards, the environment can be accessed from any thread
45 * void functionRunningOnAnyThread()
46 * {
47 * JNIEnv* jniEnv = NativeInterfaceManager::get().environment();
48 *
49 * if (jniEnv == nullptr)
50 * {
51 * return;
52 * }
53 *
54 * // the environment must be used on this thread only, never hand it to another thread
55 * }
56 *
57 * // within a JNI function the environment is provided already, and can simply be used or forwarded
58 * extern "C" void Java_com_meta_ocean_Example_doSomething(JNIEnv* jniEnv, jobject javaThis)
59 * {
60 * // 'jniEnv' is the environment of the calling thread, the manager would return the same environment
61 * ocean_assert(!NativeInterfaceManager::get().isValid() || jniEnv == NativeInterfaceManager::get().environment());
62 * }
63 * @endcode
64 * @ingroup platformandroid
65 */
66class OCEAN_PLATFORM_ANDROID_EXPORT NativeInterfaceManager : public Singleton<NativeInterfaceManager>
67{
69
70 protected:
71
72 /**
73 * This class implements the attachment of one individual thread to a Java virtual machine.
74 * The object is intended to be used as thread-local object only, so that the thread is detached when the thread ends.
75 * Threads created by Java are attached already and are never detached by this object.
76 */
78 {
79 public:
80
81 /**
82 * Creates a new object and attaches the calling thread if the thread is not attached already.
83 * @param javaVM The Java virtual machine to which the calling thread will be attached
84 */
85 explicit ScopedThreadAttachment(JavaVM& javaVM);
86
87 /**
88 * Destructs this object and detaches the thread if this object has attached the thread.
89 */
91
92 /**
93 * Returns the JNI environment of the thread which has created this object.
94 * @param javaVM The Java virtual machine which has been provided when this object was created
95 * @return The JNI environment of the thread, nullptr if the thread could not be attached
96 */
97 inline JNIEnv* jniEnv(JavaVM& javaVM) const;
98
99 protected:
100
101 /**
102 * Disabled copy constructor.
103 * @param scopedThreadAttachment Object which would be copied
104 */
105 ScopedThreadAttachment(const ScopedThreadAttachment& scopedThreadAttachment) = delete;
106
107 /**
108 * Disabled copy operator.
109 * @param scopedThreadAttachment Object which would be copied
110 * @return Reference to this object
111 */
112 ScopedThreadAttachment& operator=(const ScopedThreadAttachment& scopedThreadAttachment) = delete;
113
114 protected:
115
116 /// The Java virtual machine to which this object has attached the thread, nullptr if this object has not attached the thread.
117 JavaVM* attachedJavaVM_ = nullptr;
118
119 /// The JNI environment of the thread, nullptr if the environment has not been determined yet.
120 JNIEnv* jniEnv_ = nullptr;
121 };
122
123 public:
124
125 /**
126 * Returns the JNI virtual machine object.
127 * @return The JNI virtual machine object, nullptr if not set
128 * @see isValid().
129 */
130 JavaVM* virtualMachine() const;
131
132 /**
133 * Returns the java native interface environment object for the current calling thread.
134 * The thread is attached to the virtual machine on demand, as a daemon thread, and is detached automatically when the thread ends.
135 * The environment is determined once per thread and is cached afterwards.
136 * Beware: The environment must be used on the calling thread only, it must never be stored or handed to another thread.
137 * Beware: Whenever other code detaches the thread, e.g., an explicit DetachCurrentThread() or a ScopedJNIEnvironment which has attached the thread itself, the environment becomes invalid.
138 * Beware: FindClass() resolves class names with the class loader of the Java code on the stack.
139 * A thread attached by this manager has no Java code on the stack, so that platform classes can be resolved but no classes of the application.
140 * Resolve application classes on a thread which has been called from Java, and keep the class as a global reference.
141 * @return JNI environment object, nullptr if the virtual machine is unknown or if the thread could not be attached
142 * @see isValid().
143 */
144 JNIEnv* environment();
145
146 /**
147 * Returns the current activity.
148 * Beware: The reference is owned by this manager, a concurrent setCurrentActivity() may release it.
149 * @return The current activity, may be nullptr if no activity is set
150 * @see setCurrentActivity().
151 */
152 jobject currentActivity() const;
153
154 /**
155 * Sets the virtual machine object of this manager.
156 * The virtual machine can be set once only, providing the same virtual machine again succeeds without any change.
157 * @param virtualMachine Virtual machine to be set, must be valid
158 * @return True, if succeeded; False, if a different virtual machine is set already
159 * @see isValid().
160 */
161 bool setVirtualMachine(JavaVM* virtualMachine);
162
163 /**
164 * Sets or changes the current activity.
165 * This manager creates and owns its own global reference, the caller keeps the ownership of the provided reference.
166 * Therefore, the reference can be a local reference as well as a global reference like ANativeActivity::clazz.
167 * @param activity The current activity to be set or updated, can be nullptr to remove the previously set activity
168 * @see currentActivity().
169 */
170 void setCurrentActivity(jobject activity);
171
172 /**
173 * Returns whether the virtual machine of this manager is set.
174 * @return True, if so
175 * @see setVirtualMachine().
176 */
177 bool isValid() const;
178
179 protected:
180
181 /**
182 * Creates a new manager object.
183 * This object will be created indirectly by the singleton object.
184 * @see Singleton::get().
185 */
187
188 /**
189 * Destructs a manager object.
190 */
192
193 protected:
194
195 /// Manager lock, protecting the current activity only.
196 mutable Lock lock_;
197
198 /// JNI virtual machine object, atomic so that the environment can be determined without a lock.
199 std::atomic<JavaVM*> virtualMachine_ = nullptr;
200
201 /// The global reference to the JNI object of the current activity which is owned by this manager, nullptr if not set.
202 jobject currentActivity_ = nullptr;
203};
204
206{
207#ifdef OCEAN_DEBUG
208 {
209 // the environment becomes invalid whenever other code detaches the thread, this cannot be detected in release builds
210 JNIEnv* debugJniEnv = nullptr;
211 javaVM.GetEnv((void**)(&debugJniEnv), JNI_VERSION_1_6);
212
213 if (jniEnv_ != nullptr)
214 {
215 ocean_assert(debugJniEnv == jniEnv_ && "The thread has been detached by other code!");
216 }
217 }
218#else
219 OCEAN_SUPPRESS_UNUSED_WARNING(javaVM);
220#endif // OCEAN_DEBUG
221
222 return jniEnv_;
223}
224
225}
226
227}
228
229}
230
231#endif // META_OCEAN_PLATFORM_ANDROID_NATIVE_INTERFACE_MANAGER_H
This class implements a recursive lock object.
Definition Lock.h:31
This class implements the attachment of one individual thread to a Java virtual machine.
Definition NativeInterfaceManager.h:78
~ScopedThreadAttachment()
Destructs this object and detaches the thread if this object has attached the thread.
JNIEnv * jniEnv_
The JNI environment of the thread, nullptr if the environment has not been determined yet.
Definition NativeInterfaceManager.h:120
ScopedThreadAttachment(JavaVM &javaVM)
Creates a new object and attaches the calling thread if the thread is not attached already.
ScopedThreadAttachment & operator=(const ScopedThreadAttachment &scopedThreadAttachment)=delete
Disabled copy operator.
ScopedThreadAttachment(const ScopedThreadAttachment &scopedThreadAttachment)=delete
Disabled copy constructor.
JNIEnv * jniEnv(JavaVM &javaVM) const
Returns the JNI environment of the thread which has created this object.
Definition NativeInterfaceManager.h:205
This class implements the manager of the java native interface as singleton.
Definition NativeInterfaceManager.h:67
bool setVirtualMachine(JavaVM *virtualMachine)
Sets the virtual machine object of this manager.
bool isValid() const
Returns whether the virtual machine of this manager is set.
JavaVM * virtualMachine() const
Returns the JNI virtual machine object.
jobject currentActivity() const
Returns the current activity.
NativeInterfaceManager()
Creates a new manager object.
Lock lock_
Manager lock, protecting the current activity only.
Definition NativeInterfaceManager.h:196
JNIEnv * environment()
Returns the java native interface environment object for the current calling thread.
void setCurrentActivity(jobject activity)
Sets or changes the current activity.
virtual ~NativeInterfaceManager()
Destructs a manager object.
This template class is the base class for all singleton objects.
Definition Singleton.h:71
The namespace covering the entire Ocean framework.
Definition Accessor.h:15