QGroundControl
Ground Control Station for MAVLink Drones
Loading...
Searching...
No Matches
AndroidInit.cc
Go to the documentation of this file.
1#include "AndroidInterface.h"
2#ifndef QGC_NO_SERIAL_LINK
3#include "AndroidSerial.h"
4#endif
5#include <QtCore/QJniEnvironment>
6#include <QtCore/QJniObject>
7#include <QtCore/QLoggingCategory>
8
9#include <atomic>
10
11#include "QGCLoggingCategory.h"
12
13QGC_LOGGING_CATEGORY(AndroidInitLog, "Android.AndroidInit");
14
15static std::atomic<jobject> _context{nullptr};
16static std::atomic<jobject> _class_loader{nullptr};
17static std::atomic<JavaVM*> _java_vm{nullptr};
18
19#ifdef QGC_GST_STREAMING
20
21#define QGC_JNI_EXPORT __attribute__((visibility("default")))
22
23extern "C"
24{
25 // Exported for GStreamer plugins (e.g. androidmedia) that are statically
26 // linked into the main binary and need Android platform access at runtime.
27
28 QGC_JNI_EXPORT jobject gst_android_get_application_context(void)
29 {
30 return _context.load(std::memory_order_acquire);
31 }
32
33 QGC_JNI_EXPORT jobject gst_android_get_application_class_loader(void)
34 {
35 return _class_loader.load(std::memory_order_acquire);
36 }
37
38 QGC_JNI_EXPORT JavaVM *gst_android_get_java_vm(void)
39 {
40 return _java_vm.load(std::memory_order_acquire);
41 }
42}
43
44#endif
45
46static jboolean jniInit(JNIEnv *env, jobject thiz)
47{
48 qCDebug(AndroidInitLog) << Q_FUNC_INFO;
49
50 const jclass context_cls = env->GetObjectClass(thiz);
51 if (!context_cls) {
52 return JNI_FALSE;
53 }
54
55 const jmethodID get_app_context_id = env->GetMethodID(context_cls, "getApplicationContext", "()Landroid/content/Context;");
56 env->DeleteLocalRef(context_cls);
57 if (QJniEnvironment::checkAndClearExceptions(env)) {
58 return JNI_FALSE;
59 }
60
61 const jobject app_context = env->CallObjectMethod(thiz, get_app_context_id);
62 if (QJniEnvironment::checkAndClearExceptions(env) || !app_context) {
63 return JNI_FALSE;
64 }
65
66 const jclass app_context_cls = env->GetObjectClass(app_context);
67 if (!app_context_cls) {
68 env->DeleteLocalRef(app_context);
69 return JNI_FALSE;
70 }
71
72 const jmethodID get_class_loader_id = env->GetMethodID(app_context_cls, "getClassLoader", "()Ljava/lang/ClassLoader;");
73 env->DeleteLocalRef(app_context_cls);
74 if (QJniEnvironment::checkAndClearExceptions(env)) {
75 env->DeleteLocalRef(app_context);
76 return JNI_FALSE;
77 }
78
79 const jobject class_loader = env->CallObjectMethod(app_context, get_class_loader_id);
80 if (QJniEnvironment::checkAndClearExceptions(env)) {
81 env->DeleteLocalRef(app_context);
82 return JNI_FALSE;
83 }
84
85 const jobject app_context_global = env->NewGlobalRef(app_context);
86 const jobject class_loader_global = env->NewGlobalRef(class_loader);
87
88 env->DeleteLocalRef(app_context);
89 env->DeleteLocalRef(class_loader);
90
91 if (!app_context_global || !class_loader_global || QJniEnvironment::checkAndClearExceptions(env)) {
92 if (app_context_global) {
93 env->DeleteGlobalRef(app_context_global);
94 }
95 if (class_loader_global) {
96 env->DeleteGlobalRef(class_loader_global);
97 }
98 return JNI_FALSE;
99 }
100
101 if (jobject old_context = _context.exchange(app_context_global, std::memory_order_acq_rel)) {
102 env->DeleteGlobalRef(old_context);
103 }
104 if (jobject old_class_loader = _class_loader.exchange(class_loader_global, std::memory_order_acq_rel)) {
105 env->DeleteGlobalRef(old_class_loader);
106 }
107
108 return JNI_TRUE;
109}
110
112{
113 qCDebug(AndroidInitLog) << Q_FUNC_INFO;
114
115 const JNINativeMethod javaMethods[] {
116 {"nativeInit", "()Z", reinterpret_cast<void *>(jniInit)},
117 };
118
119 QJniEnvironment jniEnv;
120 (void) jniEnv.checkAndClearExceptions();
121
122 jclass objectClass = jniEnv->FindClass(AndroidInterface::kJniQGCActivityClassName);
123 if (!objectClass) {
124 qCWarning(AndroidInitLog) << "Couldn't find class:" << AndroidInterface::kJniQGCActivityClassName;
125 (void) jniEnv.checkAndClearExceptions();
126 return JNI_ERR;
127 }
128
129 const jint val = jniEnv->RegisterNatives(objectClass, javaMethods, std::size(javaMethods));
130 jniEnv->DeleteLocalRef(objectClass);
131 if (val < 0) {
132 qCWarning(AndroidInitLog) << "Error registering methods:" << val;
133 (void) jniEnv.checkAndClearExceptions();
134 return JNI_ERR;
135 }
136
137 qCDebug(AndroidInitLog) << "Main Native Functions Registered";
138
139 (void) jniEnv.checkAndClearExceptions();
140
141 return JNI_OK;
142}
143
144jint JNI_OnLoad(JavaVM* vm, void*)
145{
146 qCDebug(AndroidInitLog) << Q_FUNC_INFO;
147
148 _java_vm.store(vm, std::memory_order_release);
149
150 JNIEnv *env;
151 if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
152 return JNI_ERR;
153 }
154
155 if (jniSetNativeMethods() != JNI_OK) {
156 return JNI_ERR;
157 }
158
160
161#ifndef QGC_NO_SERIAL_LINK
163#endif
164
165 QNativeInterface::QAndroidApplication::hideSplashScreen(333);
166
167 return JNI_VERSION_1_6;
168}
169
170void JNI_OnUnload(JavaVM* vm, void*)
171{
172 qCDebug(AndroidInitLog) << Q_FUNC_INFO;
173
174 JNIEnv* env = nullptr;
175 if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) == JNI_OK) {
176 if (jobject ctx = _context.exchange(nullptr, std::memory_order_acq_rel)) {
177 env->DeleteGlobalRef(ctx);
178 }
179 if (jobject cl = _class_loader.exchange(nullptr, std::memory_order_acq_rel)) {
180 env->DeleteGlobalRef(cl);
181 }
182 }
183
184 _java_vm.store(nullptr, std::memory_order_release);
185
186#ifndef QGC_NO_SERIAL_LINK
188#endif
189}
jint JNI_OnLoad(JavaVM *vm, void *)
void JNI_OnUnload(JavaVM *vm, void *)
static jboolean jniInit(JNIEnv *env, jobject thiz)
static std::atomic< jobject > _context
static std::atomic< JavaVM * > _java_vm
static std::atomic< jobject > _class_loader
static jint jniSetNativeMethods()
#define QGC_LOGGING_CATEGORY(name, categoryStr)
constexpr const char * kJniQGCActivityClassName
void setNativeMethods()