The Invocation API

翻译自https://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/invocation.html

Chapter   5

The Invocation API allows software vendors to load the Java VM into an arbitrary native application. Vendors can deliver Java-enabled applications without having to link with the Java VM source code.

Invocation API允许软件供应商将Java VM加载到任意本地应用程序中。 供应商可以交付支持Java的应用程序,而无需链接Java VM源代码。

本章从Invocation API的概述开始。 随后是所有Invocation API函数的参考页。

Overview

The following code example illustrates how to use functions in the Invocation API. In this example, the C++ code creates a Java VM and invokes a static method, called Main.test. For clarity, we omit error checking.

以下代码示例说明了如何使用Invocation API中的函数。 在此示例中,C ++代码创建一个Java VM,并调用一个名为Main.test的静态方法。 为了清楚起见,我们省略了错误检查。

#include        /* where everything is defined */
    ...
    JavaVM *jvm;       /* denotes a Java VM */
    JNIEnv *env;       /* pointer to native method interface */
    JavaVMInitArgs vm_args; /* JDK/JRE 6 VM initialization arguments */
    JavaVMOption* options = new JavaVMOption[1];
    options[0].optionString = "-Djava.class.path=/usr/lib/java";
    vm_args.version = JNI_VERSION_1_6;
    vm_args.nOptions = 1;
    vm_args.options = options;
    vm_args.ignoreUnrecognized = false;
    /* load and initialize a Java VM, return a JNI interface
     * pointer in env */
    JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args);
    delete options;
    /* invoke the Main.test method using the JNI */
    jclass cls = env->FindClass("Main");
    jmethodID mid = env->GetStaticMethodID(cls, "test", "(I)V");
    env->CallStaticVoidMethod(cls, mid, 100);
    /* We are done. */
    jvm->DestroyJavaVM();
    

This example uses three functions in the API. The Invocation API allows a native application to use the JNI interface pointer to access VM features. The design is similar to Netscape’s JRI Embedding Interface.

本示例在API中使用三个函数。 Invocation API允许本地应用程序使用JNI接口指针来访问VM功能。 该设计类似于Netscape的JRI嵌入接口。

Creating the VM

The JNI_CreateJavaVM() function loads and initializes a Java VM and returns a pointer to the JNI interface pointer. The thread that called JNI_CreateJavaVM() is considered to be the main thread.

JNI_CreateJavaVM()函数加载并初始化Java VM,并返回指向JNI接口指针的指针。 调用JNI_CreateJavaVM()的线程被视为主线程。

Attaching to the VM

The JNI interface pointer (JNIEnv) is valid only in the current thread. Should another thread need to access the Java VM, it must first call AttachCurrentThread() to attach itself to the VM and obtain a JNI interface pointer. Once attached to the VM, a native thread works just like an ordinary Java thread running inside a native method. The native thread remains attached to the VM until it calls DetachCurrentThread() to detach itself.

JNI接口指针(JNIEnv)仅在当前线程中有效。 如果另一个线程需要访问Java VM,则必须首先调用AttachCurrentThread()将其自身依附到VM并获取JNI接口指针。 一旦依附到VM,本地线程就可以像在本地方法中运行的普通Java线程一样工作。 本地线程将保持与VM的连接,直到它调用DetachCurrentThread()使其脱离。

The attached thread should have enough stack space to perform a reasonable amount of work. The allocation of stack space per thread is operating system-specific. For example, using pthreads, the stack size can be specified in the pthread_attr_t argument to pthread_create.
附着线程应具有足够的堆栈空间以执行合理的工作量。 每个线程的堆栈空间分配是特定于操作系统的。 例如,使用pthreads,可以在pthread_create的pthread_attr_t参数中指定堆栈大小。

Detaching from the VM

A native thread attached to the VM must call DetachCurrentThread() to detach itself before exiting. A thread cannot detach itself if there are Java methods on the call stack.

附着到VM的本地线程必须在退出之前调用DetachCurrentThread()使其自身分离。 如果调用堆栈上有Java方法,则线程无法自行分离。

Unloading the VM

The JNI_DestroyJavaVM() function unloads a Java VM. As of JDK/JRE 1.1, only the main thread could unload the VM, by calling DestroyJavaVM. As of JDK/JRE 1.2, the restriction was removed, and any thread may call DestroyJavaVM to unload the VM.

JNI_DestroyJavaVM()函数卸载Java VM。 在JDK / JRE 1.1中,只有主线程可以通过调用DestroyJavaVM卸载VM。 从JDK / JRE 1.2开始,该限制已删除,任何线程都可以调用DestroyJavaVM来卸载VM。

The VM waits until the current thread is the only non-daemon user thread before it actually unloads. User threads include both Java threads and attached native threads. This restriction exists because a Java thread or attached native thread may be holding system resources, such as locks, windows, and so on. The VM cannot automatically free these resources. By restricting the current thread to be the only running thread when the VM is unloaded, the burden of releasing system resources held by arbitrary threads is on the programmer.


VM将等待直到当前线程是唯一的非守护程序用户线程,然后才实际卸载。 用户线程包括Java线程和附着的本地线程。 之所以存在此限制,是因为Java线程或附着的本地线程可能正在持有系统资源,例如锁,窗口等。 VM无法自动释放这些资源。 通过在卸载VM时将当前线程限制为唯一正在运行的线程,释放由任意线程持有的系统资源的后果由程序员承担。

Library and Version Management

As of JDK/JRE 1.1, once a native library is loaded, it is visible from all class loaders. Therefore two classes in different class loaders may link with the same native method. This leads to two problems:

从JDK / JRE 1.1开始,一旦加载了本地库,就可以在所有类加载器中看到它。因此,两个不同的类加载器可能使用相同的本地方法链接。这导致两个问题:

  • A class may mistakenly link with native libraries loaded by a class with the same name in a different class loader.
  •  一个类可能会错误地链接到被一个不同的类加载器中的同名类加载的本地库。
  • Native methods can easily mix classes from different class loaders. This breaks the name space separation offered by class loaders, and leads to type safety problems.
  •  本地方法可以轻松地混合使用来自不同类加载器的类。这打破了类加载器提供的命名空间分隔,并导致类型安全问题。

As of JDK/JRE 1.2, each class loader manages its own set of native libraries. The same JNI native library cannot be loaded into more than one class loader. Doing so causes UnsatisfiedLinkError to be thrown. For example, System.loadLibrary throws an UnsatisfiedLinkError when used to load a native library into two class loaders. The benefits of the new approach are:

从JDK / JRE 1.2开始,每个类加载器都管理自己的本地库组。同一JNI本地库不能被加载到多个类加载器中。这样做会引发UnsatisfiedLinkError。例如,当System.loadLibrary被用于将本地库加载到两个类加载器中时,抛出UnsatisfiedLinkError。新方法的好处是:

  • Name space separation based on class loaders is preserved in native libraries. A native library cannot easily mix classes from different class loaders.
  • In addition, native libraries can be unloaded when their corresponding class loaders are garbage collected.
  • 基于类加载器的命名空间隔离保留在本地库中。本地库无法轻松地混合使用来自不同类加载器的类。
  • 另外,当本地库的相应类加载器被垃圾回收时,它们可以被卸载。

To facilitate version control and resource management, JNI libraries as of JDK/JRE 1.2 optionally export the following two functions:
为了促进版本控制和资源管理,从JDK / JRE 1.2开始的JNI库可以选择导出以下两个函数:

JNI_OnLoad

jint JNI_OnLoad(JavaVM *vm, void *reserved);

The VM calls JNI_OnLoad when the native library is loaded (for example, through System.loadLibrary). JNI_OnLoad must return the JNI version needed by the native library.

加载本地库时(例如,通过System.loadLibrary),VM调用JNI_OnLoad。 JNI_OnLoad必须返回本地库所需的JNI版本。

In order to use any of the new JNI functions, a native library must export a JNI_OnLoad function that returns JNI_VERSION_1_2. If the native library does not export a JNI_OnLoad function, the VM assumes that the library only requires JNI version JNI_VERSION_1_1. If the VM does not recognize the version number returned by JNI_OnLoad, the native library cannot be loaded.

为了使用任何新的JNI函数,本地库必须导出返回JNI_VERSION_1_2的JNI_OnLoad函数。 如果本地库未导出JNI_OnLoad函数,则VM假定该库仅需要JNI版本JNI_VERSION_1_1。 如果VM无法识别JNI_OnLoad返回的版本号,则无法加载本地库。

LINKAGE:

Exported from native libraries that contain native method implementation.

从包含本地方法实现的本地库中导出。

SINCE:

JDK/JRE 1.4

In order to use the JNI functions introduced in J2SE release 1.2, in addition to those that were available in JDK/JRE 1.1, a native library must export a JNI_OnLoad function that returns JNI_VERSION_1_2.

为了使用J2SE 1.2版中引入的JNI函数,除了JDK / JRE 1.1中可用的那些函数外,本地库还必须导出返回JNI_VERSION_1_2的JNI_OnLoad函数。

In order to use the JNI functions introduced in J2SE release 1.4, in addition to those that were available in release 1.2, a native library must export a JNI_OnLoad function that returns JNI_VERSION_1_4.
为了使用J2SE 1.4版中引入的JNI函数,除了1.2版中可用的那些函数外,本地库还必须导出返回JNI_VERSION_1_4的JNI_OnLoad函数。

If the native library does not export a JNI_OnLoad function, the VM assumes that the library only requires JNI version JNI_VERSION_1_1. If the VM does not recognize the version number returned by JNI_OnLoad, the native library cannot be loaded.
如果本地库未导出JNI_OnLoad函数,则VM假定该库仅需要JNI版本JNI_VERSION_1_1。 如果VM无法识别JNI_OnLoad返回的版本号,则无法加载本地库。

JNI_OnUnload

void JNI_OnUnload(JavaVM *vm, void *reserved);

The VM calls JNI_OnUnload when the class loader containing the native library is garbage collected. This function can be used to perform cleanup operations. Because this function is called in an unknown context (such as from a finalizer), the programmer should be conservative on using Java VM services, and refrain from arbitrary Java call-backs.

当包含本地库的类加载器被垃圾回收时,VM会调用JNI_OnUnload。 此功能可用于执行清理操作。 由于此函数是在未知上下文中(例如,从终结器中)调用的,因此程序员在使用Java VM服务时应保持保守,并避免进行任意Java回调。

Note that JNI_OnLoad and JNI_OnUnload are two functions optionally supplied by JNI libraries, not exported from the VM.
请注意,JNI_OnLoad和JNI_OnUnload是JNI库可选提供的两个函数,而不是从VM导出的。

LINKAGE:

Exported from native libraries that contain native method implementation.

从包含本地方法实现的本地库中导出。

Invocation API Functions

The JavaVM type is a pointer to the Invocation API function table. The following code example shows this function table.

JavaVM是指向Invocation API函数表的指针。下列代码展示了这个函数表。

typedef const struct JNIInvokeInterface *JavaVM;


const struct JNIInvokeInterface ... = {
    NULL,
    NULL,
    NULL,

    DestroyJavaVM,
    AttachCurrentThread,
    DetachCurrentThread,

    GetEnv,

    AttachCurrentThreadAsDaemon
};
 

Note that three Invocation API functions, JNI_GetDefaultJavaVMInitArgs(), JNI_GetCreatedJavaVMs(), and JNI_CreateJavaVM(), are not part of the JavaVM function table. These functions can be used without a preexisting JavaVM structure.

请注意,三个Invocation API函数JNI_GetDefaultJavaVMInitArgs(),JNI_GetCreatedJavaVMs()和JNI_CreateJavaVM()不在JavaVM函数表中。 可以在没有预先存在的JavaVM结构的情况下使用这些函数。

JNI_GetDefaultJavaVMInitArgs

jint JNI_GetDefaultJavaVMInitArgs(void *vm_args);

Returns a default configuration for the Java VM. Before calling this function, native code must set the vm_args->version field to the JNI version it expects the VM to support. After this function returns, vm_args->version will be set to the actual JNI version the VM supports.

返回Java VM的默认配置。 在调用此函数之前,本地代码必须将vm_args-> version字段设置为期望VM支持的JNI版本。 该函数返回后,vm_args-> version将被设置为VM支持的实际JNI版本。

LINKAGE:

Exported from the native library that implements the Java virtual machine.

PARAMETERS:

vm_args: a pointer to a JavaVMInitArgs structure in to which the default arguments are filled.

RETURNS:

Returns JNI_OK if the requested version is supported; returns a JNI error code (a negative number) if the requested version is not supported.

JNI_GetCreatedJavaVMs

jint JNI_GetCreatedJavaVMs(JavaVM **vmBuf, jsize bufLen, jsize *nVMs);

Returns all Java VMs that have been created. Pointers to VMs are written in the buffer vmBuf in the order they are created. At most bufLen number of entries will be written. The total number of created VMs is returned in *nVMs.

返回所有已创建的Java VM。 指向VM的指针按照创建顺序写入缓冲区vmBuf中。 最多将写入bufLen个条目。 在* nVMs中返回创建的VM总数。

As of JDK/JRE 1.2, creation of multiple VMs in a single process is not supported.

从JDK/JRE 1.2开始,不支持在一个进程中创建多个VM。

LINKAGE:

Exported from the native library that implements the Java virtual machine.

PARAMETERS:

vmBuf: pointer to the buffer where the VM structures will be placed.

bufLen: the length of the buffer.

nVMs: a pointer to an integer.

RETURNS:

Returns JNI_OK on success; returns a suitable JNI error code (a negative number) on failure.

JNI_CreateJavaVM

jint JNI_CreateJavaVM(JavaVM **p_vm, void **p_env, void *vm_args);

Loads and initializes a Java VM. The current thread becomes the main thread. Sets the env argument to the JNI interface pointer of the main thread.

加载并初始化Java VM。 当前线程成为主线程。 将env参数设置为主线程的JNI接口指针。

As of JDK/JRE 1.2 , creation of multiple VMs in a single process is not supported.

从JDK / JRE 1.2开始,不支持在单个进程中创建多个VM。

The second argument to JNI_CreateJavaVM is always a pointer to JNIEnv *, while the third argument is a pointer to a JavaVMInitArgs structure which uses option strings to encode arbitrary VM start up options:
JNI_CreateJavaVM的第二个参数始终是指向JNIEnv *的指针,而第三个参数是指向JavaVMInitArgs结构的指针,该结构使用可选的字符串编码任意VM启动选项:

typedef struct JavaVMInitArgs {
    jint version;

    jint nOptions;
    JavaVMOption *options;
    jboolean ignoreUnrecognized;
} JavaVMInitArgs;

The version field must be set to at least JNI_VERSION_1_2. The options field is an array of the following type:

typedef struct JavaVMOption {
    char *optionString;  /* the option as a string in the default platform encoding */
    void *extraInfo;
} JavaVMOption;

The size of the array is denoted by the nOptions field in JavaVMInitArgs. If ignoreUnrecognized is JNI_TRUE, JNI_CreateJavaVM ignore all unrecognized option strings that begin with "-X" or "_". If ignoreUnrecognized is JNI_FALSE, JNI_CreateJavaVM returns JNI_ERR as soon as it encounters any unrecognized option strings. All Java VMs must recognize the following set of standard options:

数组的大小由JavaVMInitArgs中的nOptions字段表示。 如果ignoreUnrecognized为JNI_TRUE,则JNI_CreateJavaVM会忽略所有以“ -X”或“ _”开头的无法识别的选项字符串。 如果ignoreUnrecognized为JNI_FALSE,则JNI_CreateJavaVM在遇到任何无法识别的选项字符串时将立即返回JNI_ERR。 所有Java VM必须识别以下标准选项集:

optionString meaning
-D= Set a system property
-verbose[:class|gc|jni] Enable verbose output. The options can be followed by a comma-separated list of names indicating what kind of messages will be printed by the VM. For example, "-verbose:gc,class" instructs the VM to print GC and class loading related messages. Standard names include: gc, class, and jni. All nonstandard (VM-specific) names must begin with "X".
vfprintf extraInfo is a pointer to the vfprintf hook.
exit extraInfo is a pointer to the exit hook.
abort extraInfo is a pointer to the abort hook.

 

In addition, each VM implementation may support its own set of non-standard option strings. Non-standard option names must begin with "-X" or an underscore ("_"). For example, the JDK/JRE supports -Xms and -Xmx options to allow programmers specify the initial and maximum heap size. Options that begin with "-X" are accessible from the "java" command line.

另外,每个VM实现都可以支持其自己的一组非标准选项字符串。 非标准选项名称必须以“ -X”或下划线(“ _”)开头。 例如,JDK / JRE支持-Xms和-Xmx选项,以允许程序员指定初始堆大小和最大堆大小。 可从“ java”命令行访问以“ -X”开头的选项。

Here is the example code that creates a Java VM in the JDK/JRE:
以下是在JDK / JRE中创建Java VM的示例代码:

JavaVMInitArgs vm_args;
JavaVMOption options[4];

options[0].optionString = "-Djava.compiler=NONE";           /* disable JIT */
options[1].optionString = "-Djava.class.path=c:\myclasses"; /* user classes */
options[2].optionString = "-Djava.library.path=c:\mylibs";  /* set native library path */
options[3].optionString = "-verbose:jni";                   /* print JNI-related messages */

vm_args.version = JNI_VERSION_1_2;
vm_args.options = options;
vm_args.nOptions = 4;
vm_args.ignoreUnrecognized = TRUE;

/* Note that in the JDK/JRE, there is no longer any need to call
 * JNI_GetDefaultJavaVMInitArgs.
 */
res = JNI_CreateJavaVM(&vm, (void **)&env, &vm_args);
if (res < 0) ...

LINKAGE:

Exported from the native library that implements the Java virtual machine.

PARAMETERS:

p_vm: pointer to the location where the resulting VM structure will be placed.

p_env: pointer to the location where the JNI interface pointer for the main thread will be placed.

vm_args: Java VM initialization arguments.

RETURNS:

Returns JNI_OK on success; returns a suitable JNI error code (a negative number) on failure.

DestroyJavaVM

jint DestroyJavaVM(JavaVM *vm);

Unloads a Java VM and reclaims its resources.

卸载Java VM并回收其资源。

The support for DestroyJavaVM was not complete in JDK/JRE 1.1. As of JDK/JRE 1.1 Only the main thread may call DestroyJavaVM. Since JDK/JRE 1.2, any thread, whether attached or not, can call this function. If the current thread is attached, the VM waits until the current thread is the only non-daemon user-level Java thread. If the current thread is not attached, the VM attaches the current thread and then waits until the current thread is the only non-daemon user-level thread. The JDK/JRE still does not support VM unloading, however.

在JDK / JRE 1.1中,对DestroyJavaVM的支持不完整。 从JDK / JRE 1.1开始,只有主线程可以调用DestroyJavaVM。 从JDK / JRE 1.2开始,任何线程(无论是否连接)都可以调用此函数。 如果当前线程处于连接状态,则VM会等待直到当前线程是唯一的非守护程序用户级Java线程。 如果未附加当前线程,则VM会连接当前线程,然后等待直到当前线程是唯一的非守护程序用户级线程。 但是,JDK / JRE仍然不支持VM卸载。

LINKAGE:

Index 3 in the JavaVM interface function table.

PARAMETERS:

vm: the Java VM that will be destroyed.

RETURNS:

Returns JNI_OK on success; returns a suitable JNI error code (a negative number) on failure.

As of JDK/JRE 1.1.2 unloading of the VM is not supported.

AttachCurrentThread

jint AttachCurrentThread(JavaVM *vm, void **p_env, void *thr_args);

Attaches the current thread to a Java VM. Returns a JNI interface pointer in the JNIEnv argument.

Trying to attach a thread that is already attached is a no-op.

A native thread cannot be attached simultaneously to two Java VMs.

When a thread is attached to the VM, the context class loader is the bootstrap loader.

将当前线程附着到Java VM。 在JNIEnv参数中返回JNI接口指针。

尝试附着已连接的线程是一项禁忌措施。

本地线程不能同时附着到两个Java VM。

将线程附加到VM时,上下文类加载器就是引导加载器 bootstrap loader。

LINKAGE:

Index 4 in the JavaVM interface function table.

PARAMETERS:

vm: the VM to which the current thread will be attached.

p_env: pointer to the location where the JNI interface pointer of the current thread will be placed.

thr_args: can be NULL or a pointer to a JavaVMAttachArgs structure to specify additional information:

As of JDK/JRE 1.1, the second argument to AttachCurrentThread is always a pointer to JNIEnv. The third argument to AttachCurrentThread was reserved, and should be set to NULL.

从JDK / JRE 1.1开始,AttachCurrentThread的第二个参数始终是指向JNIEnv的指针。 AttachCurrentThread的第三个参数已保留,应设置为NULL。

As of JDK/JRE 1.2, you pass NULL as the third argument for 1.1 behavior, or pass a pointer to the following structure to specify additional information:

从JDK / JRE 1.2开始,第三个参数 传递NULL作为1.1的行为,或传递以下结构体的指针来指定额外信息:

typedef struct JavaVMAttachArgs {
    jint version;  /* must be at least JNI_VERSION_1_2 */
    char *name;    /* the name of the thread as a modified UTF-8 string, or NULL */
    jobject group; /* global ref of a ThreadGroup object, or NULL */
} JavaVMAttachArgs

RETURNS:

Returns JNI_OK on success; returns a suitable JNI error code (a negative number) on failure.

AttachCurrentThreadAsDaemon

jint AttachCurrentThreadAsDaemon(JavaVM* vm, void** penv, void* args);

Same semantics as AttachCurrentThread, but the newly-created java.lang.Thread instance is a daemon.

语义与AttachCurrentThread相同,但是新创建的java.lang.Thread实例是一个守护程序。

If the thread has already been attached via either AttachCurrentThread or AttachCurrentThreadAsDaemon, this routine simply sets the value pointed to by penv to the JNIEnv of the current thread. In this case neither AttachCurrentThread nor this routine have any effect on the daemon status of the thread.
如果线程已经通过AttachCurrentThread或AttachCurrentThreadAsDaemon附着,则该例程将penv指向的值简单地设置为当前线程的JNIEnv。 在这种情况下,AttachCurrentThread和此例程都不会对线程的守护程序状态产生任何影响。

LINKAGE:

Index 7 in the JavaVM interface function table.

PARAMETERS:

vm: the virtual machine instance to which the current thread will be attached.

penv: a pointer to the location in which the JNIEnv interface pointer for the current thread will be placed.

args: a pointer to a JavaVMAttachArgs structure.

RETURNS

Returns JNI_OK on success; returns a suitable JNI error code (a negative number) on failure.

EXCEPTIONS

None.

SINCE:

JDK/JRE 1.4

DetachCurrentThread

jint DetachCurrentThread(JavaVM *vm);

Detaches the current thread from a Java VM. All Java monitors held by this thread are released. All Java threads waiting for this thread to die are notified.

从Java VM中分离当前线程。 释放该线程拥有的所有Java监视器。 所有等待该线程死亡的Java线程都会被通知。

As of JDK/JRE 1.2 , the main thread can be detached from the VM.
从JDK / JRE 1.2开始,可以从VM分离主线程。

LINKAGE:

Index 5 in the JavaVM interface function table.

PARAMETERS:

vm: the VM from which the current thread will be detached.

RETURNS:

Returns JNI_OK on success; returns a suitable JNI error code (a negative number) on failure.

GetEnv

jint GetEnv(JavaVM *vm, void **env, jint version);

LINKAGE:

Index 6 in the JavaVM interface function table.

PARAMETERS:

vm: The virtual machine instance from which the interface will be retrieved.
env: pointer to the location where the JNI interface pointer for the current thread will be placed.
version: The requested JNI version.

RETURNS:

If the current thread is not attached to the VM, sets *env to NULL, and returns JNI_EDETACHED. If the specified version is not supported, sets *env to NULL, and returns JNI_EVERSION. Otherwise, sets *env to the appropriate interface, and returns JNI_OK.

如果当前线程未连接到VM,则将* env设置为NULL,并返回JNI_EDETACHED。 如果不支持指定的版本,请将* env设置为NULL,并返回JNI_EVERSION。 否则,将* env设置为适当的接口,并返回JNI_OK。

SINCE:

JDK/JRE 1.2

你可能感兴趣的:(Android)