OPhone平台的JNI机制探索
2010-10-14 16:15
169 查看
OPhone平台的JNI机制探索
JNI是Java Native Interface的缩写,中文可译为Java本地调用。Java Native Interface (JNI)标准成为java平台的一部分,它允许Java代码和其他语言写的代码进行交互.OPhone下的JNI使得Dalvik虚拟机内部运行的Java代码能够与其他语言编写的应用程序或者库(例如C++编译完成之后的
so文件)进行交互.虽然JNI并不是Android的技术发展方向,但是作为一种重要的技术手段可以解决Linux内核和Dalvik虚拟机之间的交互
问题.
JNI提供的交互通道是双向的,即Java代码可以调用C/C++库中的功能, 另外,C/C++库也可以调用到Dalvik虚拟机之上的Java库功能.下面就针对这两种应用方式做详细说明。
1:通过JNI实现Java调用C/C++库功能
在Android的代码中,这样的例子不胜枚举.比如Media中的视频音频播放控制,Web页面的解析渲染显示,Graphics中
Paint功能等等,这些Java类在C++部分都有负责实现功能的C++类库相对应.较之Java,C++有更强的平台操控性和执行效率,所以比如像
WebKit这样需要复杂运算和平台依赖的核心类库来说,大部分的代码都是由C++来实现的.Brower这种强烈依赖WebKit的应用程序在
OPhone下都是用Java来实现的,这样JNI就负责了Java层与webcore.so(WebKit编译之后的类库)之间的通信.
打开Eclipse,我们做一个HelloJNI的例子.
创建一个Android工程,命名为HelloJNI
编写Java端文件: HelloJNI.java
view plain
copy to clipboard
?
public
class
HelloJNI
extends
Activity {
static
{
String libPath="cpluslib.so"
;
//向Dalvik加载指定相对路径的C++库。
System.loadLibrary(libPath);
}
//需要JNI的函数必须声明为 public native static
public
native
static
int
get();
public
native
static
void
set(
int
i);
@Override
public
void
onCreate(Bundle savedInstanceState) {
super
.onCreate(savedInstanceState);
setContentView(R.layout.main);
set(100
);
Log.v("HelloJNI"
,
"value="
+get());
}
}
public class HelloJNI extends Activity { static { String libPath="cpluslib.so"; //向Dalvik加载指定相对路径的C++库。 System.loadLibrary(libPath); } //需要JNI的函数必须声明为 public native static public native static int get(); public native static void set(int i); @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); set(100); Log.v("HelloJNI","value="+get()); } }
用javac HelloJNI.java编译它,会生成HelloJNI.class。
再用javah HelloJNI ,则会在当前目录下生成HelloJNI.h文件,这个文件需要被C/C++程序调用来生成所需的库文件。 如下(此文件不能被修改)
view plain
copy to clipboard
?
/* DO NOT EDIT THIS FILE - it is machine generated */
#include
/* Header for class HelloJNI*/
#ifndef _Included_HelloJNI
#define _Included_HelloJNI
#ifdef __cplusplus
extern "C"
{
#endif
/*
* Class: HelloJNI
* Method: get
* Signature: ()I
*/
JNIEXPORT jint JNICALL Java_HelloJNI_get (JNIEnv *, jclass);
/*
* Class: HelloJNI
* Method: set
* Signature: (I)V
*/
JNIEXPORT void
JNICALL Java_HelloJNI_set (JNIEnv *, jclass, jint);
#ifdef __cplusplus
}
#endif
#endif
/* DO NOT EDIT THIS FILE - it is machine generated */ #include /* Header for class HelloJNI*/ #ifndef _Included_HelloJNI #define _Included_HelloJNI #ifdef __cplusplus extern "C" { #endif /* * Class: HelloJNI * Method: get * Signature: ()I */ JNIEXPORT jint JNICALL Java_HelloJNI_get (JNIEnv *, jclass); /* * Class: HelloJNI * Method: set * Signature: (I)V */ JNIEXPORT void JNICALL Java_HelloJNI_set (JNIEnv *, jclass, jint); #ifdef __cplusplus } #endif #endif
打开Vim,编写C++端代码
在具体实现的时候,我们只关心两个函数原型
JNIEXPORT jint JNICALL Java_HelloJNI_get (JNIEnv *, jclass); 和
JNIEXPORT void JNICALL Java_HelloJNI_set (JNIEnv *, jclass, jint);
这里JNIEXPORT和JNICALL都是JNI的关键字,表示此函数是要被JNI调用的。函数的名称是JAVA_再加上java程序的package路径再加函数名组成的。参数中,我们也只需要关心在JAVA程序中存在的参数。
view plain
copy to clipboard
?
#include
"HelloJNI.h"
int
i =
0
;
JNIEXPORT jint JNICALL Java_HelloJNI_get (JNIEnv *, jclass)
{
return
i;
}
JNIEXPORT void
JNICALL Java_HelloJNI_set (JNIEnv *, jclass, jint j)
{
i = j;
}
#include "HelloJNI.h" int i = 0; JNIEXPORT jint JNICALL Java_HelloJNI_get (JNIEnv *, jclass) { return i; } JNIEXPORT void JNICALL Java_HelloJNI_set (JNIEnv *, jclass, jint j) { i = j; }
编译链接生成cpluslib.so,将HelloJIN.apk和cpluslib.so Push到手机的/System/app下,运行.就可以在Log中看到.
2:通过JNI C/C++调用Java
在OPhone的系统框架中,在Applications和Linux
kernal中间有三部分. Application Framework, Libraries, Android
Runtimes.而Application
Frameworks提供了Java层的框架API和核心对象,如Activity,View,ContentProvider,Service等等.他
们都是基于Dalvik虚拟机的Java类库. 与之相对的,Libraries都是C++类库,他们为上面的App
Frameworks提供了核心对象的基础API,而后者对Libraries进行了包装来提供给Apps进行调用. C++
Libraries与App Frameworks的交互基本上都是通过JNI来实现的.
举一个JNI C/C++调用Java的例子. WebKit加载网页的过程中,
需要调用到Java层的HttpClient做网页的下载,C/C++要调用OPhone中Java程序的功能,必须先加载Dalvik虚拟机,由
Dailvk虚拟机解释执行apk/odex/dex文件。为了初始化Dalvik虚拟机,JNI提供了一系列的接口函数,通过这些函数方便地加载虚拟机
到内存.
1.加载虚拟机:
下面是WebKit加载Dalvik虚拟机的代码.
view plain
copy to clipboard
?
static
jint KJS_GetCreatedJavaVMs(JavaVM** vmBuf, jsize bufLen, jsize* nVMs)
{
static
void
* javaVMFramework =
0
;
//通过Dlopen来动态加载Java虚拟机
if
(!javaVMFramework)
javaVMFramework = dlopen("/System/Library/Frameworks/JavaVM.framework/JavaVM"
, RTLD_LAZY);
if
(!javaVMFramework)
return
JNI_ERR;
static
jint(*functionPointer)(JavaVM**, jsize, jsize *) =
0
;
if
(!functionPointer)
//调用创建虚拟机的函数,从已经加载的动态连接库中.
functionPointer = (jint(*)(JavaVM**, jsize, jsize *))dlsym(javaVMFramework, "JNI_GetCreatedJavaVMs"
);
if
(!functionPointer)
return
JNI_ERR;
return
functionPointer(vmBuf, bufLen, nVMs);
}
static jint KJS_GetCreatedJavaVMs(JavaVM** vmBuf, jsize bufLen, jsize* nVMs) { static void* javaVMFramework = 0; //通过Dlopen来动态加载Java虚拟机 if (!javaVMFramework) javaVMFramework = dlopen("/System/Library/Frameworks/JavaVM.framework/JavaVM", RTLD_LAZY); if (!javaVMFramework) return JNI_ERR; static jint(*functionPointer)(JavaVM**, jsize, jsize *) = 0; if (!functionPointer) //调用创建虚拟机的函数,从已经加载的动态连接库中. functionPointer = (jint(*)(JavaVM**, jsize, jsize *))dlsym(javaVMFramework, "JNI_GetCreatedJavaVMs"); if (!functionPointer) return JNI_ERR; return functionPointer(vmBuf, bufLen, nVMs); }
2.获取指定对象的类定义:
已知类名的情况使用FindClass来获取,如获得Java中的HashMap
jclass mapClass = env->FindClass("java/util/HashMap");
通过对象直接得到类定义GetObjectClass
jCalss clazz=env->GetObjectClass(obj);
3.获取要调用的方法:
比如Java端有个函数 void setTitle(String title);
C++部分要通过JNI获得这个方法:
jMethodID mSetTitle=env->GetMethodID(clazz,"setTitle","Ljava/lang/String;)V");
第三个参数是这个方法的Signature.如果不知道,那么运行javap -s -p 类名 就可以得到了.
4.调用JAVA层的方法
如上面已经得到SetTitle的Method ID,只需要运行env->CallVoidMethod(env, clazz , mSetTitle).
另外还有CallObjectMethod()方法,用来调用有返回值的java层方法。如:
view plain
copy to clipboard
?
jobject obj = env->CallObjectMethod(env,calzz, dialog, userGesture);
jobject obj = env->CallObjectMethod(env,calzz, dialog, userGesture);
更加详尽的JNI资料请参见JNI白皮书,另外在WebKit Android版本的WebCoreFrameBridge.cpp和WebCoreJni.cpp能找到更多相关的应用实例。
http://www.ophonesdn.com/article/show/116
相关文章推荐
- Android平台Native开发与JNI机制详解
- Android平台Native开发与JNI机制详解
- Android平台Native开发与JNI机制详解
- Android平台Native开发与JNI机制详解
- AndroidO 平台JNI机制的学习
- 深入浅出 - Android系统移植与平台开发(十二)- Android JNI机制
- Android平台Native开发与JNI机制详解
- Android平台Native开发与JNI机制详解
- Android平台Native开发与JNI机制
- MTK平台屏幕切换机制探索--group机制(11A版本)
- 深入探索Java-垮平台机制
- 深入浅出 - Android系统移植与平台开发(十二)- Android JNI机制
- Android平台Native开发与JNI机制详解
- Android平台Native开发与JNI机制详解
- Android平台Native开发与JNI机制详解
- Android平台Native开发与JNI机制详解
- Android平台Native开发与JNI机制详解
- 【Linux高级驱动】linux设备驱动模型之平台设备驱动机制【转】
- Android平台从Froyo 2.2开始支持jni单步调试了!
- 入了解android平台的jni(一)