JNI简单示例
来源:互联网 发布:淘宝卖家回复评价语 编辑:程序博客网 时间:2024/06/05 16:55
JNI简单示例
例子简介:
这个简单的例子展示了上层应用程序如果利用JNI接口和底层驱动进行交互:上层应用通过两个按钮控制灯的开关。
步骤:
一、应用程序
包含两个按钮,一个是开,一个是关,另外包含一个RadioButton指示灯的状态。
关键代码:
package com.android.test;
public class LightControl extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
System.loadLibrary("light_control");//加载liblight_control.so动态库
init_native();
}
//声明JNI方法
private static native void light_control(int onoff);
private static native int init_native();
private static native int destroy_native();
}
二、JNI接口
JNI层需要打开设备,并提供上层应用程序的读写接口,并在退出时释放占有的相关资源。由于HAL层是用C/C++语言编写的,而上层应用程序是由java语言编写的,因此中间层与上层程序之间沟通的桥梁,就是众所周知的JNI接口(JNI接口不是唯一的桥梁,采用socket等同样可以做到)。
JNI需要完成如下工作:建立一个C/C++函数与Java函数映射的表,即JNINativeMethod表,对应上层应用中声明的JNI方法。
static JNINativeMethod method_table[] = {
{"light_control","(I)V",(void*)light_control_native},
{ "init_native", "()I", (void*)init_native },
{ "destroy_native", "()I", (void*)destroy_native },
};
为了理解上面表的含义,先来看看JNINativeMethod结构体的定义:
typedef struct {
const char* name;
const char* signature;
void* fnPtr;
} JNINativeMethod;
name为指向java代码中函数的名称,fnPtr为本地函数指针,signature为描述函数参数和返回值类型的字符串,其中函数参数为java代码中的函数参数,本地函数的参数会多两个:JNIEnv *env和jobject clazz。
从上面的method_table[]映射表可以看出,一共有三组函数映射,java代码中的light_control函数映射到本地函数light_control_native上,init_native函数映射到本地函数init_native上,destroy_native函数映射到本地函数destroy_native函数上。每个映射中的第二字符串,是函数参数和返回值类型的描述字符串,比如"(I)V",括号里面的每一个字符(或一组以L开头分号结束的字符串)都对应描述了函数的一个参数,紧跟在括号后面的字符(串)描述了函数的返回值类型。
因此需要在本地代码中完成下面三个函数的定义:
static void light_control_native(JNIEnv *env, jobject clazz, jint onoff)
static jint init_native(JNIEnv *env, jobject clazz)
static jint destroy_native(JNIEnv *env, jobject clazz)
然后定义一个名为JNI_OnLoad的函数,注意该函数名必须为JNI_OnLoad,且需要用extern “C”声明为C语言方式编译和链接的函数(在源文件为c++文件时才需要),同时返回值类型必须为jint。
extern "C" jint JNI_OnLoad(JavaVM* vm, void* reserved)
{
......//此处省略
return JNI_VERSION_1_4;
}
这些代码将被编译为动态库,比如例子中编译成了liblight_control.so动态库。那么上层程序可以通过System.loadLibrary("light_control")来加载该动态库。注意参数字符串是去掉”lib”和”.so”的库文件名称,同时需要确保liblight_control.so放置于/system/lib目录下。如果放置于其它地方,可以通过System.load(path)来加载,其中path为动态库文件的全路径名称。
在动态库被加载后,会立即调用该库里面定义的JNI_OnLoad函数。因此需要在该函数中调用jniRegisterNativeMethods()来完成函数映射表在dalvik上的注册:
jniRegisterNativeMethods(env, "com/android/test/LightControl",method_table, NELEM(method_table))
env为dalvik的运行环境对象,字符串"com/android/test/LightControl"是java层的JNI接口类的包名和类名。method_table即为上面定义的函数映射表数组。
在完成函数映射表数组的注册之后,java层程序就可以通过呼叫其JNI接口方法,来调用本地代码的JNI接口函数了。例如上面的例子中,在java层程序中通过调用light_control(onoff),就可以透过JNI接口调用本地代码的light_control_native(env,clazz, onoff)函数了。其中env和clazz参数是在dalvik环境调用本地代码函数时添加的两个参数,后面会分析其作用。
最后需要写一个Android.mk来将这些代码编译成动态库。主要的编译设定为:
LOCAL_SRC_FILES:= com_android_test_LightControl.cpp
定义这次编译的源代码文件。
LOCAL_SHARED_LIBRARIES := \
libandroid_runtime \
libcutils \
libnativehelper
定义在连接时相关的库,其中libcutils在用到LOGD等log信息打印函数的时候才需要。
LOCAL_MODULE:= liblight_control
定义生成的动态库的文件名为liblight_control.so。
三、底层驱动
在light_init()初始化函数中:
int light_init(void)
{
int ret;
printk("init light control\n");
ret = register_chrdev(LIGHT_CTL_MAJOR_NUM, DEV_NAME, &light_ctl_ops);
light_ctl_class = class_create(THIS_MODULE, DEV_NAME);
device_create(light_ctl_class, NULL, MKDEV(LIGHT_CTL_MAJOR_NUM, LIGHT_CTL_MINOR_NUM), NULL, DEV_NAME);
if(ret < 0){
printk("Fail to register the light control device! ret=%d\n", ret);
return ret;
}
return 0;
}
注册一个字符设备,其中DEV_NAME为"light_ctl",建立light_ctl_class的目的是为了在加载驱动后,会自动由udev在/dev目录下生成对应的设备文件:/dev/light_ctl。
对驱动的控制通过ioctl来完成:
static int light_status = 0;
int light_ctl_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
int value;
switch(cmd)
{
case LIGHT_CTL_SET:
if(copy_from_user(&value,(void *)arg,sizeof(int)))
return - EFAULT;
else
light_status = value;
break;
case LIGHT_CTL_GET:
value = light_status;
if(copy_to_user((void *)arg, &value, sizeof(int)))
break;
default :
printk("Unsupported command!\n");
break;
}
return 0;
}
从ioctl函数中可以看出,在应用程序中,可以设置变量light_status的值,也可以读取其值。这些都是属于linux驱动设计的范畴,详细可以参考《Linux设备驱动程序》这本书。
- JNI简单示例
- JNI简单示例
- JNI简单示例
- java JNI简单示例
- JNI简单示例
- android JNI 的简单示例
- 一个简单的JNI示例
- JNI技术介绍与简单示例
- Windows平台下JNI简单示例
- JNI的初步了解与简单示例
- JNI示例
- JNI示例
- JNI示例
- openGL/ESv2 通过JNI的简单示例代码
- JNI初步 -- Hello JNI示例
- JNI使用小示例
- android JNI 示例详解
- JNI示例及讲解
- 第16周报告2:求奇因子
- 继承映射
- java虚拟机端口JVM_Bind异常
- 重定向和请求分派的比较
- 平面设计常见的配色方案及色标
- JNI简单示例
- Three20软件引擎之构建开发环境与第一个项目HelloWorld(一)
- Android之路-TextView组件
- 并行计算之计算模型
- Hibernate常见的集合映射主要有Set,List,Array,Map,Bag等
- proc buddyinfo
- SDK编程笔记 - DLL篇
- 3836. 计算组合数
- C语言也面向对象