当前位置:操作系统 > 安卓/Android >>

Android通过JNI调用驱动程序

要达到的目的: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目录,它里面有一些例子,可以参考这些例子来写我们自已的模块。
clip_image002

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
clip_image002[8]

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


新键工程后,
如果出现如下错误:
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
clip_image002[12]
 

把里面的android 2.1勾上,Build project,就OK了
clip_image002[14]

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

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"
    androidrientation="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/>补充:移动开发 , Android ,

CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,