Documentation improvements to JNI API

Amends 4e60681c879a54cf5b34862a30e27c492ed36363.

Fixes: QTBUG-89632
Change-Id: I7856e9b63eea5ba68a5472575016540ae656ec5f
Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
Reviewed-by: Alex Blasche <alexander.blasche@qt.io>
Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
(cherry picked from commit 817f8ac03cd4e85b7813b45f8cabf5b679f28702)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
Assam Boudjelthia 2021-02-01 15:08:21 +02:00 committed by Qt Cherry-pick Bot
parent bbdcc86c52
commit 77b035aa6e
5 changed files with 366 additions and 268 deletions

View File

@ -79,7 +79,7 @@ void functionScope()
}
//! [QJniObject scope]
//! [Registering native methods]
//! [C++ native methods]
static void fromJavaOne(JNIEnv *env, jobject thiz, jint x)
{
Q_UNUSED(env);
@ -94,26 +94,19 @@ static void fromJavaTwo(JNIEnv *env, jobject thiz, jint x)
qDebug() << x << ">= 100";
}
void registerNativeMethods() {
JNINativeMethod methods[] {{"callNativeOne", "(I)V", reinterpret_cast<void *>(fromJavaOne)},
{"callNativeTwo", "(I)V", reinterpret_cast<void *>(fromJavaTwo)}};
QJniObject javaClass("my/java/project/FooJavaClass");
QJniEnvironment env;
jclass objectClass = env->GetObjectClass(javaClass.object<jobject>());
env->RegisterNatives(objectClass,
methods,
sizeof(methods) / sizeof(methods[0]));
env->DeleteLocalRef(objectClass);
}
void foo()
{
// register the native methods first, ideally it better be done with the app start
JNINativeMethod methods[] {{"callNativeOne", "(I)V", reinterpret_cast<void *>(fromJavaOne)},
{"callNativeTwo", "(I)V", reinterpret_cast<void *>(fromJavaTwo)}};
QJniEnvironment env;
env.registerNativeMethods("my/java/project/FooJavaClass", methods, 2);
// Call the java method which will calls back to the C++ functions
QJniObject::callStaticMethod<void>("my/java/project/FooJavaClass", "foo", "(I)V", 10); // Output: 10 < 100
QJniObject::callStaticMethod<void>("my/java/project/FooJavaClass", "foo", "(I)V", 100); // Output: 100 >= 100
}
//! [Registering native methods]
//! [C++ native methods]
//! [Java native methods]
class FooJavaClass

View File

@ -1,6 +1,6 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the documentation of the Qt Toolkit.
@ -65,3 +65,28 @@
\externalpage https://marcmutz.wordpress.com/effective-qt/containers/
\title Understand the Qt Containers
*/
/*!
\externalpage https://developer.android.com/training/articles/perf-jni#javavm-and-jnienv
\title JNI tips: JavaVM and JNIEnv
*/
/*!
\externalpage https://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/jniTOC.html
\title Java Native Interface Specification
*/
/*!
\externalpage https://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/functions.html
\title Oracle: JNI Functions
*/
/*!
\externalpage https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/design.html#global_and_local_references
\title JNI Design Overview: Global and Local References
*/
/*!
\externalpage https://developer.android.com/training/articles/perf-jni#local-and-global-references
\title JNI tips: Local and global references
*/

View File

@ -49,11 +49,19 @@ QT_BEGIN_NAMESPACE
/*!
\class QJniEnvironment
\inmodule QtCore
\brief The QJniEnvironment provides access to the JNI Environment.
\since 6.1
\brief The QJniEnvironment class provides access to the JNI Environment (JNIEnv).
\note This API has been tested and meant to be mainly used for Android and it hasn't been tested
for other platforms.
When using JNI, the \l {JNI tips: JavaVM and JNIEnv}{JNIEnv} class is a pointer to a function
table and a member function for each JNI function that indirects through the table. \c JNIEnv
provides most of the JNI functions. Every C++ native function receives a \c JNIEnv as the first
argument. The JNI environment cannot be shared between threads.
Since \c JNIEnv doesn't do much error checking, such as exception checking and clearing,
QJniEnvironment allows you to do that easily.
\note This API has been designed and tested for use with Android.
It has not been tested for other platforms.
*/
static const char qJniThreadName[] = "QtThread";
@ -96,7 +104,7 @@ Q_GLOBAL_STATIC(QThreadStorage<QJniEnvironmentPrivateTLS *>, jniEnvTLS)
/*!
\fn QJniEnvironment::QJniEnvironment()
Constructs a new QJniEnvironment object and attaches the current thread to the Java VM.
Constructs a new JNI Environment object and attaches the current thread to the Java VM.
*/
QJniEnvironment::QJniEnvironment()
: d(new QJniEnvironmentPrivate{})
@ -120,6 +128,7 @@ QJniEnvironment::QJniEnvironment()
\fn QJniEnvironment::~QJniEnvironment()
Detaches the current thread from the Java VM and destroys the QJniEnvironment object.
This will clear any pending exception by calling exceptionCheckAndClear().
*/
QJniEnvironment::~QJniEnvironment()
{
@ -152,13 +161,13 @@ QJniEnvironment::operator JNIEnv* () const
Searches for \a className using all available class loaders. Qt on Android
uses a custom class loader to load all the .jar files and it must be used
to find any classes that are created by that class loader because these
classes are not visible in the default class loader.
classes are not visible when using the default class loader.
Returns the class pointer or null if is not found.
A use case for this function is searching for a custom class then calling
its memeber method. The following code snippet create an instance of the
class \c CustomClass and then calls \c printFromJava() method:
its member method. The following code snippet creates an instance of the
class \c CustomClass and then calls the \c printFromJava() method:
\code
QJniEnvironment env;
@ -170,8 +179,6 @@ QJniEnvironment::operator JNIEnv* () const
"(Ljava/lang/String;)V",
javaMessage.object<jstring>());
\endcode
\since Qt 6.1
*/
jclass QJniEnvironment::findClass(const char *className)
{
@ -181,9 +188,9 @@ jclass QJniEnvironment::findClass(const char *className)
/*!
\fn JavaVM *QJniEnvironment::javaVM()
Returns the Java VM interface.
Returns the Java VM interface for the current process. Although it might
be possible to have multiple Java VMs per process, Android allows only one.
\since Qt 6.1
*/
JavaVM *QJniEnvironment::javaVM()
{
@ -191,10 +198,11 @@ JavaVM *QJniEnvironment::javaVM()
}
/*!
\fn bool QJniEnvironment::registerNativeMethods(const char *className, JNINativeMethod methods[])
\fn bool QJniEnvironment::registerNativeMethods(const char *className, JNINativeMethod methods[], int size)
Registers the Java methods \a methods that can call native C++ functions from class \a
className. These methods must be registered before any attempt to call them.
Registers the Java methods in the array \a methods of size \a size, each of
which can call native C++ functions from class \a className. These methods
must be registered before any attempt to call them.
Returns True if the registration is successful, otherwise False.
@ -209,10 +217,8 @@ JavaVM *QJniEnvironment::javaVM()
JNINativeMethod methods[] {{"callNativeOne", "(I)V", reinterpret_cast<void *>(fromJavaOne)},
{"callNativeTwo", "(I)V", reinterpret_cast<void *>(fromJavaTwo)}};
QJniEnvironment env;
env.registerNativeMethods("org/qtproject/android/TestJavaClass", methods);
env.registerNativeMethods("org/qtproject/android/TestJavaClass", methods, 2);
\endcode
\since Qt 6.1
*/
bool QJniEnvironment::registerNativeMethods(const char *className, JNINativeMethod methods[], int size)
{
@ -233,18 +239,23 @@ bool QJniEnvironment::registerNativeMethods(const char *className, JNINativeMeth
}
/*!
\enum QJniExceptionCleaner::OutputMode
\enum QJniEnvironment::OutputMode
\value Silent the exceptions are cleaned silently
\value Verbose describes the exceptions before cleaning them
\value Silent The exceptions are cleaned silently
\value Verbose Prints the exceptions and their stack backtrace as an error
to \c stderr stream.
*/
/*!
\fn QJniEnvironment::exceptionCheckAndClear(OutputMode outputMode = OutputMode::Silent)
\fn QJniEnvironment::exceptionCheckAndClear(OutputMode outputMode = OutputMode::Verbose)
Cleans any pending exceptions either silently or with descriptions, depending on the \a outputMode.
Cleans any pending exceptions either silently or reporting stack backtrace,
depending on the \a outputMode.
\since 6.1
In contrast to \l QJniObject, which handles exceptions internally, if you
make JNI calls directly via \c JNIEnv, you need to clear any potential
exceptions after the call using this function. For more information about
\c JNIEnv calls that can throw an exception, see \l {Oracle: JNI Functions}{JNI Functions}.
*/
bool QJniEnvironment::exceptionCheckAndClear(QJniEnvironment::OutputMode outputMode)
{
@ -260,11 +271,16 @@ bool QJniEnvironment::exceptionCheckAndClear(QJniEnvironment::OutputMode outputM
}
/*!
\fn QJniEnvironment::exceptionCheckAndClear(JNIEnv *env, OutputMode outputMode = OutputMode::Silent)
\fn QJniEnvironment::exceptionCheckAndClear(JNIEnv *env, OutputMode outputMode = OutputMode::Verbose)
Cleans any pending exceptions for \a env, either silently or with descriptions, depending on the \a outputMode.
Cleans any pending exceptions for \a env, either silently or reporting
stack backtrace, depending on the \a outputMode. This is useful when you
already have a \c JNIEnv pointer such as in a native function implementation.
\since 6.1
In contrast to \l QJniObject, which handles exceptions internally, if you
make JNI calls directly via \c JNIEnv, you need to clear any potential
exceptions after the call using this function. For more information about
\c JNIEnv calls that can throw an exception, see \l {Oracle: JNI Functions}{JNI Functions}.
*/
bool QJniEnvironment::exceptionCheckAndClear(JNIEnv *env, QJniEnvironment::OutputMode outputMode)
{

File diff suppressed because it is too large Load Diff

View File

@ -58,9 +58,9 @@ class Q_CORE_EXPORT QJniObject
public:
QJniObject();
explicit QJniObject(const char *className);
explicit QJniObject(const char *className, const char *sig, ...);
explicit QJniObject(const char *className, const char *signature, ...);
explicit QJniObject(jclass clazz);
explicit QJniObject(jclass clazz, const char *sig, ...);
explicit QJniObject(jclass clazz, const char *signature, ...);
QJniObject(jobject globalRef);
~QJniObject();
@ -69,19 +69,20 @@ public:
jobject object() const;
template <typename T>
T callMethod(const char *methodName, const char *sig, ...) const;
T callMethod(const char *methodName, const char *signature, ...) const;
template <typename T>
T callMethod(const char *methodName) const;
template <typename T>
QJniObject callObjectMethod(const char *methodName) const;
QJniObject callObjectMethod(const char *methodName, const char *sig, ...) const;
QJniObject callObjectMethod(const char *methodName, const char *signature, ...) const;
template <typename T>
static T callStaticMethod(const char *className, const char *methodName, const char *sig, ...);
static T callStaticMethod(const char *className, const char *methodName,
const char *signature, ...);
template <typename T>
static T callStaticMethod(const char *className, const char *methodName);
template <typename T>
static T callStaticMethod(jclass clazz, const char *methodName, const char *sig, ...);
static T callStaticMethod(jclass clazz, const char *methodName, const char *signature, ...);
template <typename T>
static T callStaticMethod(jclass clazz, const char *methodName);
@ -89,13 +90,13 @@ public:
static QJniObject callStaticObjectMethod(const char *className, const char *methodName);
static QJniObject callStaticObjectMethod(const char *className,
const char *methodName,
const char *sig, ...);
const char *signature, ...);
template <typename T>
static QJniObject callStaticObjectMethod(jclass clazz, const char *methodName);
static QJniObject callStaticObjectMethod(jclass clazz,
const char *methodName,
const char *sig, ...);
const char *signature, ...);
template <typename T>
T getField(const char *fieldName) const;
@ -107,35 +108,38 @@ public:
template <typename T>
QJniObject getObjectField(const char *fieldName) const;
QJniObject getObjectField(const char *fieldName, const char *sig) const;
QJniObject getObjectField(const char *fieldName, const char *signature) const;
template <typename T>
static QJniObject getStaticObjectField(const char *className, const char *fieldName);
static QJniObject getStaticObjectField(const char *className,
const char *fieldName,
const char *sig);
const char *signature);
template <typename T>
static QJniObject getStaticObjectField(const char *className,
const char *fieldName,
const char *sig);
const char *signature);
template <typename T>
static QJniObject getStaticObjectField(jclass clazz, const char *fieldName);
static QJniObject getStaticObjectField(jclass clazz, const char *fieldName, const char *sig);
static QJniObject getStaticObjectField(jclass clazz, const char *fieldName,
const char *signature);
template <typename T>
static QJniObject getStaticObjectField(jclass clazz, const char *fieldName, const char *sig);
static QJniObject getStaticObjectField(jclass clazz, const char *fieldName,
const char *signature);
template <typename T>
void setField(const char *fieldName, T value);
template <typename T>
void setField(const char *fieldName, const char *sig, T value);
void setField(const char *fieldName, const char *signature, T value);
template <typename T>
static void setStaticField(const char *className, const char *fieldName, T value);
template <typename T>
static void setStaticField(const char *className, const char *fieldName,
const char *sig, T value);
const char *signature, T value);
template <typename T>
static void setStaticField(jclass clazz, const char *fieldName, const char *sig, T value);
static void setStaticField(jclass clazz, const char *fieldName,
const char *signature, T value);
template <typename T>
static void setStaticField(jclass clazz, const char *fieldName, T value);
@ -154,31 +158,33 @@ public:
private:
struct QVaListPrivate { operator va_list &() const { return m_args; } va_list &m_args; };
QJniObject(const char *className, const char *sig, const QVaListPrivate &args);
QJniObject(jclass clazz, const char *sig, const QVaListPrivate &args);
QJniObject(const char *className, const char *signature, const QVaListPrivate &args);
QJniObject(jclass clazz, const char *signature, const QVaListPrivate &args);
template <typename T>
T callMethodV(const char *methodName, const char *sig, va_list args) const;
QJniObject callObjectMethodV(const char *methodName, const char *sig, va_list args) const;
T callMethodV(const char *methodName, const char *signature, va_list args) const;
QJniObject callObjectMethodV(const char *methodName,
const char *signature,
va_list args) const;
template <typename T>
static T callStaticMethodV(const char *className,
const char *methodName,
const char *sig,
const char *signature,
va_list args);
template <typename T>
static T callStaticMethodV(jclass clazz,
const char *methodName,
const char *sig,
const char *signature,
va_list args);
static QJniObject callStaticObjectMethodV(const char *className,
const char *methodName,
const char *sig,
const char *signature,
va_list args);
static QJniObject callStaticObjectMethodV(jclass clazz,
const char *methodName,
const char *sig,
const char *signature,
va_list args);
bool isSameObject(jobject obj) const;