Android通过JNI调用驱动程序(完全解析实例)

发布于:2021-07-20 04:24:21

分类: android 2011-06-22 13:48 251 人阅读 评论(2) 收藏 举报

--作者:赖玉*(Peter Lai)aulyp@163.com 要达到的目的:android 系统中,用 JAVA 写界面程序,调用 jni 中间库提 供的接口,去操作某个驱动节点,实现 read,writer ioctl 等操作!这对底层驱动 开发人员是很重要的一个调试通道, 也是 android 系统下提供一些特殊功能接口 的方法! 本文前提:我们假设已经写了一个驱动程序,它是控制 LED 的亮灭的,并且创 建了一个节点:/dev/vib,也就是通过 open 这个 vib 节点,可以 read/write/ioctl 操作驱动程序实现 LED 灯的亮灭控制,具体可以看我另一篇博文《android 驱 动例子(LED 灯控制)》 开发环境 1、ubuntu 下的 NDK 编译环境,2、Esclips 开发环境 一、编写 JNI 模块 当安装好 NDK 编译环境后,会在它的目录下找到 sample 目录,它里面有一些 例子,可以参考这些例子来写我们自已的模块。

1、 source 文件夹下,新建“LEDSJNI”文件夹。 2、 Source/LEDSJNI/jni/目录下,新建“vib-jni.c” vib-jni.c 文件 #include <string.h> #include <jni.h> #include <fcntl.h> /*包括文件操作,如 open() read() close()

write()等*/ //----for output the debug log message #include <android/log.h> #define LOG_TAG "vib-jni" #define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__) #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__) #define DEVICE_NAME "/dev/vib" //device point #define VIB_ON 0x11 #define VIB_OFF 0x22 int fd; jstring Java_com_auly_control_vibClass_stringFromJNI( JNIEnv* env, jobject thiz ) { return (*env)->NewStringUTF(env, "Hello from JNI--Peter for vib!");//打印字符串 } jint Java_com_auly_control_vibClass_Init( JNIEnv* env ) { LOGE("vibClass_Init() /n"); fd = open(DEVICE_NAME,O_RDWR);//打开设备 LOGE("vibClass_Init()-> fd = %d /n",fd); if(fd == -1) { LOGE("open device %s error /n ",DEVICE_NAME);//打印调试信息 return 0; } else { return 1; } } jint Java_com_auly_control_vibClass_IOCTLVIB( JNIEnv* env, jobject thiz, jint controlcode )

{ int CTLCODE = controlcode; LOGE("IOCTLVIB() = %x --vibClass_IOCTLVIB /n",CTLCODE); switch(CTLCODE) { case VIB_ON: { ioctl(fd,VIB_ON);//调用驱动程序中的 ioctrl 接口,把命令 VIB_ON 传 下去,实现硬件操作 break; } case VIB_OFF: { ioctl(fd,VIB_OFF);//调用驱动程序中的 ioctrl 接口,把命令 VIB_OFF 传下去,实现硬件操作 break; } default:break; } return 1; } 3、相同目录下的新建 Android.mk 如下 Android.mk 文件 LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := vib-jni LOCAL_SRC_FILES := vib-jni.c LOCAL_CFLAGS := -Werror LOCAL_LDLIBS := -llog -lGLESv2 //__android_log_print 函数 include $(BUILD_SHARED_LIBRARY) 可以看到,主要是修改 LOCAL_SRC_FILES 指向源文件的名称! 还有一点很重要,如果要使用调试 LOG 打印,也就是__android_log_print 函 数。要在 LOCAL_LDLIBS 中添加-llog,如上面的 Android.mk 所示。 4、编译 JNI 模块

#cd /home/workspace/android-ndk-r4b/sources/LEDSJNI 进到刚才写的 JNI 目录

#ndk-build 编译 JNI,编译成功后,会在 LEDSJNI 文件夹下生成 libs 和 obj 两个文件夹,并 在 LEDSJNI/libs/armeabi 下得到目标文件 libvib-jni.so

(目前 LEDSJNI 文件夹只有 3 个目录 jni,libs,obj) 二、JAVA 程序 1、Eclipse 新建工程 拷贝 LEDSJNI 目录到 Windows 下, 例如 C 盘下。 然后在它里面新建 Eclipse 工 程。

新键工程后, 如果出现如下错误:

ERROR: Unable to open class file C:/LEDSJNI/gen/com/auly/control/R.java: No such file or directory 解决方法如下:

对着该工程鼠标右键 》bulid path 》configure build path》 java build path》order and Export

把里面的 android 2.1 勾上,Build project,就 OK 了

然后 Run as > Android application,就会出现 android 的模拟器了,里面跑个 helloworld 出来。

2、加入 button 和文本输出 程序到上面为止代码是 ADT 自动生成的,似乎与我们一点关系也没有。那我们 来改一下代码, 因为我们调用 JNI 接口是为了访问驱动程序操作硬件的, 例如写, 读,打开 LED,关闭 LED 等等,由按钮触发的动作。 第一步是,增加两个 Button,,在 main.xml 里描述一下:打开 Res > layout> main.xml 文件 <?xml version="1.0" encoding="utf-8"?> <LinearLayout

xmlns:android="http://schemas.android.com/apk/res/android " android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/hello" /> <Button android:id="@+id/led_on"/*这表示需要一个唯一的 UID 来作 为 Button 的 ID,它的引用名是 led_on。*/ android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/LEDon">/*表示这个按钮的文本是来源于另一个 资源描述文件 strings.xml 里的文:字资源 LEDon */ <requestFocus/> </Button> <Button android:id="@+id/led_off" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/LEDoff"> <requestFocus/> </Button> </LinearLayout> 实际代码中,把注释去掉,否则编译不过的。 3、加入输出字符串资源 工程 > values > strings.xml 文件

修改如下 <?xml version="1.0" encoding="utf-8"?> <resources> <string name="hello">Led 控制程序</string> <string name="app_name">LEDAPP</string> <string name="LEDon">打开 LED</string> <string name="LEDoff">关闭 LED</string> </resources> 上面的”打开 LED”等资源,就是用在按钮上显示出来的字符串 经过上面的修改,现在程序界面上,已经有如下效果了 鼠标右键工程名>Run as > Android application 运行程序。

4、加入按钮对应的动作 “打开 LED”按扭:调用 JNI 的 IOCTLVIB(VIB_ON); “关闭 LED”按钮:调用 JNI 的 IOCTLVIB(VIB_OFF); 操作: 在 LEDAPP > src > com.auly.control > vibrator.java 文件 package com.auly.control; /**定义头文件*/ import import import import import import import import import import public android.widget.TextView; android.app.Activity; android.os.Bundle; android.view.View; android.widget.Button; android.widget.EditText; android.widget.TextView; android.util.Log; android.app.Activity; android.os.Bundle; class vibrator extends Activity {

/** 定义变量 */ public static final int VIB_ON = 0x11; public static final int VIB_OFF = 0x22; vibClass mvibClass;/**定义类*/ @Override

public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); /**----------------初始化------------- */ mvibClass = new vibClass();/*声明类*/ mvibClass.Init(); //调用 JNI 库里的初始化函数 /**----------------按钮:打开 LED------------- */ Button btn1 = (Button)findViewById(R.id.led_on);/*这里用到的 ID,就是在 main.xml 里定义的 led_on*/ btn1.setOnClickListener(new View.OnClickListener() { public void onClick(View v) /**当按钮按下*/ { mvibClass.IOCTLVIB(VIB_ON); } }); /**----------------按钮:关闭 LED------------- */ Button btn2 = (Button)findViewById(R.id.led_off);/*声明按 钮,id main.xml 里有定义*/ btn2.setOnClickListener(new View.OnClickListener() { public void onClick(View v) /**当按钮按下*/ { mvibClass.IOCTLVIB(VIB_OFF); } }); } } 如果在保存时遇到说 save problems,无法保存,请先复制上面的代码,然后, 关闭 vibrator.java,提示保存时选不保存,然后在左边资源窗中再次双击打开该

文件,把几日才复制下来的内容,粘贴上去,一般就能正常保存,不知道是不是 Eclipse 的不稳定造成的。 5、添加类 vibClass 鼠标右键 com.auly.control > new > Class

填参数:

Finish 后,在/src/com/auly/control/得到如下的类文件 vibClass.java 修改如下 package com.auly.control; /*Class for Vibrator --peter*/ public class vibClass { static { System.loadLibrary("vib-jni");/*加载 JNI 库*/ }

/*声明 函数*/ public static native String stringFromJNI();/*输出字符串 对应于 JNI 里面的 jstring Java_com_auly_control_vibClass_stringFromJNI( JNIEnv* env,jobject thiz ) */ public static native int Init();/*初始化函数,对应于 JNI 里面的 jint Java_com_auly_control_vibClass_Init( JNIEnv* env ) */ public static native int IOCTLVIB(int controlcode); /*IO CTRL 接口 * 对应于 JNI 里的 jint Java_com_auly_control_vibClass_IOCTLVIB( JNIEnv* env, jobject thiz, jint controlcode ) */ } 三、 编译运行 鼠标右键工程名,弹出菜单,选择 Run as > Android Application 就可以看到编 译过程,编译完成后,会自动调用 android 模拟器,看到如下效果

安装到开发板:

在 C:/LEDSJNI 目录下, 会看到 bin 文件夹, 里面的 LEDAPP.apk 就是这个程序 的安装文件,可以把它安装的开发板上,运行本程序,看控制开发板上的 LED 灯的效果。 步骤: 1、开发板上跑的 kenel 就已经把了 LED 驱动编译在里面了, 可以参考《android 驱动例子(LED 灯控制)》 2、开发板 android 跑起来后,PC 机打开串口工具例如 DNW,打开与开发板连 接的 COM 口,然后敲打回车,就会在终端里看到“#”并有光标,表面进入了开发 板的命令行终端, 输入命令: #chmod 777 /dev/vib 这是为了使得 vib 这个节点可以被我们写的 JNI 操作, 不然会 open 失败的, 因为 APK 安装的 JNI 模块,权限不够,这个节点是我们的 LED 驱动生成的控制 节点。 也可以在 android 文件系统 yaffs 编译时,通过 init.rc 文件来实现这个操作,就 是在该文件里随便一行,写上面的命令行,启动时会自动执行!这样就不用手动 的改变该节点的属性了。 3、拷贝 LEDAPP.apk 到开发板上,通过安装工具把它安装到开发板上,如果不 会安,可以 GOOGLE 一下, 4、运行程序,就能按程序上的*钮来控制开发板上的 LED 亮灭了!


相关推荐

最新更新

猜你喜欢