JNI(5)The Invocation API
调用API允许软件提供商加载Java VM 到任意的本地应用中。供应商可以提供支持Java的应用程序而无需链接Java VM的代码。
概述
下面代码展示了通过调用API如何使用函数。这个例子中C++代码创建了一个Java VM 和调用一个静态方法,方法为Main.test.为了代码简洁,省略了错误检查。
#include <jni.h> /* 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();
这个例子使用接口中的三个方法,调用API允许本地应用使用JNI接口指针去访问VM的特性。设计类似于网景的JRI嵌入接口。
创建 VM
JNI_CreateJavaVM()方法加载和初始化java VM和返回一个指向JNI接口指针的指针。JNI_CreateJavaVM()在主线程里面调用。
添加到 VM
JNI接口指针(JNIEnv)在当前线程中有效。如果另外一个线程要访问它,那么它必须先调用AttachCurrentThread()添加自己到VM中,并且得到JNI接口指针。一旦添加到VM,本地线程运行和java线程运行在本地方法一样。本地线程保持着VM的引用,知道调用DetachCurrentThread()方法,才会取消之间的关联关系。
附加的线程堆栈应该有足够的空间来执行一个合理数量的任务。操作系统给每个线程分配指定的空间。例如,使用线程,栈大小可以通过pthread_attr_t参数指定。
从VM中分离
卸载VM
JNI_DestroyJavaVM()
卸载 Java VM. As of JDK/JRE 1.1, 只有主线程能够调用DestroyJavaVM卸载java VM
. As of 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.
库和版本管理
As of JDK/JRE 1.1, 一旦本地库加载, 所有的类加载器都能够看到它。因此不同的两个类在不同的类加载器中有可能链接的是同一个本地方法。这样会导致两个问题:
- 一个类在不同的类加载器中可能会错误的链接本地库。
- 本地方法可以很容混淆不同类加载器加载的类。这样打破了类加载器提供的命名空间分离,并且导致类型安全问题。
As of JDK/JRE 1.2, 每一个类加载器管理自己的本地库。同一个JNI本地库在一个类加载器中不能重复加载。如果那样做,会导致UnsatisfiedLinkError 抛出,例如,通常加载本地库到两个类装入器,System.loadLibrary
会抛出UnsatisfiedLinkError。这样做的好处是:
- 基于类加载器的命名空间分离是保存在本地库里面。一个原生的库无法从不同的类加载器里面混淆类。
- 此外,当他们对应的类加载器被垃圾回收之后也会卸载。
为了提高版本控制和资源管理,JNI库在JDK/JRE 1.2 里面提供了以下两个方法:
JNI_OnLoad
jint JNI_OnLoad(JavaVM *vm, void *reserved);
当原生库加载的时候,VM才调用JNI_OnLoad(例如,通过System.loadLibrary).JNI_OnLoad必须返回原生库需要的JNI版本。
要是新的JNI函数,原生库JNI_OnLoad函数必须返回JNI_VERSION_1_2。如果原生库没有JNI_OnLoad函数,那么VM会假定库需要的是JNI_VERSION_1_1. 如果VM不能识别JNI_OnLoad方法返回的值,那么原生库将不能被加载。
LINKAGE:
Exported from native libraries that contain native method implementation.
SINCE:
JDK/JRE 1.4
使用在J2SE1.2中介绍的JNI方法,除了JDK/JRE 1.1中的功能,原生包的JNI_OnLoad方法必须返回JNI_VERSION_1_2.
使用在J2SE1.4中介绍的JNI方法,除了JDK/JRE 1.2中的功能,原生包的JNI_OnLoad方法必须返回JNI_VERSION_1_4.
如果原生包没有JNI_OnLoad
函数, VM会认为包需要JNI的版本为JNI_VERSION_1_1.如果VM 不能识别JNI_OnLoad函数放回的版本号,那么原生包将不能被加载。
JNI_OnUnload
void JNI_OnUnload(JavaVM *vm, void *reserved);
VM在原生包被垃圾回收的时候调用JNI_OnUnload函数。这个函数可以用来执行清理操作。因为这个函数被一个不知道的上下文调用(比如从一个终结器),程序员应该保守使用Java VM服务,和避免任意Java回调。
注意:JNI onload和JNI onunload是两个函数出自JNI库,而不是VM。
LINKAGE:
Exported from native libraries that contain native method implementation.
Invocation API Functions
指针JavaVM类型调用API函数表。下面的代码示例显示了该函数表。
typedef const struct JNIInvokeInterface *JavaVM; const struct JNIInvokeInterface ... = {
NULL,
NULL,
NULL, DestroyJavaVM,
AttachCurrentThread,
DetachCurrentThread, GetEnv, AttachCurrentThreadAsDaemon
};
注意这三个调用API的函数:JNI_GetDefaultJavaVMInitArgs()
, JNI_GetCreatedJavaVMs()
, 和 JNI_CreateJavaVM()
, 不是 JavaVM 函数表的一部分. 这些函数在javaVM之前就已经可以使用。
JNI_GetDefaultJavaVMInitArgs
jint JNI_GetDefaultJavaVMInitArgs(void *vm_args);
返回Java VM的默认配置。在使用这个函数之前,需要制定JNI版本的版本号( 设置这个属性vm_args->version),它表明VM需要的JNI版本号。这个方法返回之后,vm_args->version的值是VM支持的版本值。
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);
返回所有已经创建的Java vm。Returns all Java VMs that have been created. 所有的VM指针按照它们创建的顺序保存在vmBuf缓冲区中。VM 的总数是存放在*nVms 中。
在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);
加载和初始化java VM. 当前线程成为主线程。设置主线程的JNI接口指针env参数。
在JDK/JRE 1.2 ,在一个进程中创建多个VM是支持的。
第二个参数JNI_CreateJavaVM
总是指向 JNIEnv *
,而第三个参数是一个指针JavaVMInitArgs结构,使用选项字符串编码任意VM启动选项:
typedef struct JavaVMInitArgs {
jint version; jint nOptions;
JavaVMOption *options;
jboolean ignoreUnrecognized;
} JavaVMInitArgs;
version至少设置
JNI_VERSION_1_2
. options
的类型是:
typedef struct JavaVMOption {
char *optionString; /* the option as a string in the default platform encoding */
void *extraInfo;
} JavaVMOption;
数组的大小是nOptions字段表示的。如果ignoreUnrecognized
为 JNI_TRUE
, JNI_CreateJavaVM
忽略所有以 "-X
" 或者 "_
"开头的不能识别的选项字符串。 如果ignoreUnrecognized
为JNI_FALSE
, JNI_CreateJavaVM 遇到不能识别的字符串会立刻返回
JNI_ERR
。所有的java VMs必须都识别下面的标准的参数:
optionString | meaning |
---|---|
-D<name>=<value> |
设置一个系统属性 |
-verbose[:class|gc|jni] |
启用详细的输出。 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. |
此外,每个VM实现可能会支持自己的一套标准选项字符串。非标准的选项名称必须开始以“- x”或下划线(“_”)。例如,JDK/JRE 支持-Xms
和-Xmx
允许指定初始的和最大的堆内存大小。以"-X"的选项都可以在java命令行中运行。
下面是示例代码,创建一个Java VM在JDK / JRE:
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
: VM 结构的地址.
p_env
: JNI接口的地址(主线程中).
vm_args
: VM初始化参数.
RETURNS:
Returns JNI_OK
on success; returns a suitable JNI error code (a negative number) on failure.
DestroyJavaVM
jint DestroyJavaVM(JavaVM *vm);
卸载一个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.
JDK / JRE 1.1不完全支持DestroyJavaVM. 在JDK/JRE 1.1 只有主线程可以叫DestroyJavaVM。 从JDK/JRE 1.2, 任何线程都可以调用这个函数, 不管是否从依附的线程中. 如果与当前线程连接, VM等到当前线程是唯一非守护进程。如果没有与当前线程相连接,那么VM会与当前线程相连,并且等待当前线程是非守护线程. The JDK/JRE still does not support VM unloading, however.
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.
在JDK / JRE 1.1.2卸载虚拟机不支持。
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(本机线程不能同时与两个Java虚拟机连接。).
When a thread is attached to the VM, the context class loader is the 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
.
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:
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.
If the thread has already been attached via either AttachCurrentThread or AttachCurrentThreadAsDaemon, this routine simply sets the value pointed to bypenv 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.
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.
As of JDK/JRE 1.2 , the main thread can be detached from the 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
.
SINCE:
JDK/JRE 1.2
JNI(5)The Invocation API的更多相关文章
- Android JNI 学习(十一):Invocation Api
1. 简介 Invocation API允许软件提供商在原生程序中内嵌Java虚拟机.因此可以不需要链接任何Java虚拟机代码来提供Java-enabled的应用程序. 以下代码演示如何使用: #in ...
- Android 开创java世界(JNI Invocation API)
在Android的世界中,由名称为app_process的C++本地应用程序(路径为:framework/base/cmds/app_process/app_main.cpp)调用JNI Invoca ...
- Java Native Interface 基于JNI的嵌入式手机软件开发实例
1.通过JNI和c/c++的库组件.其他代码交互 2.java和c不能互通的原因时数据类型问题 Introduction https://docs.oracle.com/javase/8/docs/t ...
- Android JNI学习(四)——JNI的常用方法的中文API
本系列文章如下: Android JNI(一)——NDK与JNI基础 Android JNI学习(二)——实战JNI之“hello world” Android JNI学习(三)——Java与Nati ...
- 一、Android NDK编程预备之Java jni简介
转自: http://www.eoeandroid.com/thread-264384-1-1.html 游戏开发 视频教程 博客 淘帖 论坛›eoe·Android应用开发区›Androi ...
- NDK(12)Jni常用函数
参考官方文档 http://docs.oracle.com/javase/7/docs/technotes/guides/jni/ http://docs.oracle.com/javase/7/do ...
- Android学习笔记--JNI的使用方法
1.JNI是什么 JNI是Java Native Interface的缩写,它提供若干的API实现Java与其他语言之间的通信.而Android Framework由基于Java语言的的Java层与基 ...
- Java jvm级别native关键词、JNI详解
1.native关键词的引入 再完美的编程语言也有自己的不足之处,当然Java也不例外,Java的不足之处除了体现在运行速度(这点往往被一些其他编程语言使用者所诟病)上要比传统的C++慢许多之外,Ja ...
- JNI详解---从不懂到理解
转载:https://blog.csdn.net/hui12581/article/details/44832651 Chap1:JNI完全手册... 3 Chap2:JNI-百度百科... 11 C ...
随机推荐
- Ecstore中Mootools和Jquery如何同时存在,解决冲突?
- swift 重载 泛式 inout的使用
swift 重载 泛式 inout的使用 函数 func 关键字 -> 表示返回值信息等等 那我们接下来利用函数做几件事情 -a 比较两个数字的大小 -b 比较两个字符串 -c 既能比较字符串, ...
- iOS9中请求出现App Transport Security has blocked a cleartext HTTP (http://)
错误描述: App Transport Security has blocked a cleartext HTTP (http://) resource load since it is insecu ...
- 关于.net 对excel操作的方法
asp.net打印文件用的最多的一般2种,word和excel,今天在这里整洁一下关于打印excel的几种方式及优缺点 第一种:直接打印html代码,然后将输出类型伪装成excel文件(excel是可 ...
- 带左右箭头切换的自动滚动图片JS特效
效果图 按钮 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www. ...
- sprintf mfc
sprintf(d,"char is %d",wparam);wparam以%d形式存入d中 并不是输出到屏幕上!
- smarty 自定义函数
自定义函数:<{方法名称}> 在lib/plugins中新建文件,命名方式是固定的:function.方法名称.php 或者 block.方法名称.php 1.<{literal}& ...
- JQuery 获取验证码倒计时
HTML代码: <button id="btn">点击获取验证码</button> Jquery:代码: $(document).ready(functio ...
- javascript回调函数
function $$(f) { if (typeof f == 'function') {//f是一个函数 f(); } else { alert('not a function'); } } $$ ...
- Python自动化运维之7、生成器、迭代器、列表解析、迭代器表达式
迭代器和生成器 1.迭代器 迭代器是访问集合元素的一种方式.迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束.迭代器只能往前不会后退,不过这也没什么,因为人们很少在迭代途中往后退.另外 ...