8#include <QtCore/QThread>
9#include <QtCore/QThreadStorage>
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
44 QtAndroidPrivate::javaVM()->DetachCurrentThread();
48Q_GLOBAL_STATIC(QThreadStorage<QJniEnvironmentPrivateTLS *>, jniEnvTLS)
52
53
54QJniEnvironment::QJniEnvironment()
55 : d(
new QJniEnvironmentPrivate{})
57 d->jniEnv = getJniEnv();
61
62
63
64
65JNIEnv *QJniEnvironment::getJniEnv()
67 JNIEnv *jniEnv =
nullptr;
69 JavaVM *vm = QtAndroidPrivate::javaVM();
70 const jint ret = vm->GetEnv((
void**)&jniEnv, JNI_VERSION_1_6);
72 if (ret == JNI_EDETACHED) {
73 const QByteArray threadName = QThread::currentThread()->objectName().toUtf8();
74 JavaVMAttachArgs args = { JNI_VERSION_1_6,
75 threadName.isEmpty() ?
"QtThread" : threadName.constData(),
78 if (vm->AttachCurrentThread(&jniEnv, &args) == JNI_OK) {
79 if (!jniEnvTLS->hasLocalData())
80 jniEnvTLS->setLocalData(
new QJniEnvironmentPrivateTLS);
87
88
89
90
91
92QJniEnvironment::~QJniEnvironment()
94 checkAndClearExceptions();
98
99
100
101
102bool QJniEnvironment::isValid()
const
108
109
110JNIEnv *QJniEnvironment::operator->()
const
116
117
118JNIEnv &QJniEnvironment::operator*()
const
124
125
126JNIEnv *QJniEnvironment::jniEnv()
const
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158jclass QJniEnvironment::findClass(
const char *className)
160 return QtAndroidPrivate::findClass(className, d->jniEnv);
164
165
166
167
168
169
170
171
172
173
174jmethodID QJniEnvironment::findMethod(jclass clazz,
const char *methodName,
const char *signature)
177 jmethodID id = d->jniEnv->GetMethodID(clazz, methodName, signature);
178 if (!checkAndClearExceptions(d->jniEnv))
186
187
188
189
190
191
192
193
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218jmethodID QJniEnvironment::findStaticMethod(jclass clazz,
const char *methodName,
const char *signature)
221 jmethodID id = d->jniEnv->GetStaticMethodID(clazz, methodName, signature);
222 if (!checkAndClearExceptions(d->jniEnv))
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
250
251
252
253
254
255
256
257
258
259
260jfieldID QJniEnvironment::findField(jclass clazz,
const char *fieldName,
const char *signature)
263 jfieldID id = d->jniEnv->GetFieldID(clazz, fieldName, signature);
264 if (!checkAndClearExceptions())
272
273
274
275
276
277
278
279
282
283
284
285
286
287
288
289
290
291
292jfieldID QJniEnvironment::findStaticField(jclass clazz,
const char *fieldName,
const char *signature)
295 jfieldID id = d->jniEnv->GetStaticFieldID(clazz, fieldName, signature);
296 if (!checkAndClearExceptions())
304
305
306
307
308
309
310
311
314
315
316
317
318JavaVM *QJniEnvironment::javaVM()
320 return QtAndroidPrivate::javaVM();
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369bool QJniEnvironment::registerNativeMethods(
const char *className,
const JNINativeMethod methods[],
372 const jclass clazz = findClass(className);
377 return registerNativeMethods(clazz, methods, size);
381
382
383
384
385
386
388#if QT_DEPRECATED_SINCE(6
, 2
)
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413bool QJniEnvironment::registerNativeMethods(
const char *className, JNINativeMethod methods[],
416 return registerNativeMethods(className,
const_cast<
const JNINativeMethod*>(methods), size);
420
421
422
423
424
425
426
427
428
429
430
431
432bool QJniEnvironment::registerNativeMethods(jclass clazz,
const JNINativeMethod methods[],
435 if (d->jniEnv->RegisterNatives(clazz, methods, size) < 0) {
436 checkAndClearExceptions();
443
444
445
446
447
448
451
452
453
454
455
456
459
460
461
462
463
464
465
466
467
468
469
470
471bool QJniEnvironment::checkAndClearExceptions(QJniEnvironment::OutputMode outputMode)
473 return checkAndClearExceptions(d->jniEnv, outputMode);
478 QString exceptionMessage(JNIEnv *env, jthrowable exception)
483 auto logError = []() {
484 qWarning() <<
"QJniEnvironment: a null object returned or an exception occurred while "
485 "fetching a prior exception message";
488 auto checkAndClear = [env]() {
489 if (Q_UNLIKELY(env->ExceptionCheck())) {
490 env->ExceptionClear();
496 const jclass logClazz = env->FindClass(
"android/util/Log");
497 if (checkAndClear() || !logClazz) {
502 const jmethodID methodId = env->GetStaticMethodID(logClazz,
"getStackTraceString",
503 "(Ljava/lang/Throwable;)Ljava/lang/String;");
504 if (checkAndClear() || !methodId) {
510 value.l =
static_cast<jobject>(exception);
511 const jobject messageObj = env->CallStaticObjectMethodA(logClazz, methodId, &value);
512 const jstring jmessage =
static_cast<jstring>(messageObj);
516 char const *utfMessage = env->GetStringUTFChars(jmessage, 0);
517 const QString message = QString::fromUtf8(utfMessage);
519 env->ReleaseStringUTFChars(jmessage, utfMessage);
526
527
528
529
530
531
532
533
534
535
536
537bool QJniEnvironment::checkAndClearExceptions(JNIEnv *env, QJniEnvironment::OutputMode outputMode)
539 if (Q_UNLIKELY(env->ExceptionCheck())) {
540 if (outputMode == OutputMode::Verbose) {
541 if (jthrowable exception = env->ExceptionOccurred()) {
542 env->ExceptionClear();
543 const QString message = exceptionMessage(env, exception);
545 if (!message.isEmpty())
546 qWarning().noquote() << message;
547 env->DeleteLocalRef(exception);
550 env->ExceptionDescribe();
551 env->ExceptionClear();
554 env->ExceptionClear();
564
565
566QStringList QJniEnvironment::stackTrace(jthrowable exception)
568 return exceptionMessage(getJniEnv(), exception).split(u'\n');
~QJniEnvironmentPrivateTLS()
Combined button and popup list for selecting options.