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目录,它里面有一些例子,可以参考这些例子来写我们自已的模块。
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"
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/>
</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 android.widget.TextView;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.util.Log;
import android.app.Activity;
import android.os.Bundle;
public 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亮灭了!
Android通过JNI调用驱动程序(完全解析实例)的更多相关文章
- 【转】Android通过JNI调用驱动程序(完全解析实例)
原文网址:http://blog.csdn.net/ok138ok/article/details/6560875 要达到的目的:android系统中,用JAVA写界面程序,调用jni中间库提供的接口 ...
- [置顶] android利用jni调用第三方库——第三篇——编写库android程序整合第三方库libhello.so到自己的库libhelloword.so
0:前言: 在第二篇中,我们主要介绍了丙方android公司利用乙方C++公司给的动态库,直接调用库中的方法,但是这样方式受限于: 乙方C++公司开发的动态库是否符合jni的规范,如果不规范,则不能直 ...
- [置顶] android利用jni调用第三方库——第二篇——编写库android程序直接调用第三方库libhello.so
0:前言 1:本文主要作为丙方android公司的身份来写 2:作者有不对的地方,请指出,谢谢 [第一篇:android利用jni调用第三方库——编写库libhello.so] [第二篇:androi ...
- Android的JNI调用(一)
Android提供NDK开发包来提供Android平台的C++开发,用来扩展Android SDK的功能.主要包括Android NDK构建系统和JNI实现与原生代码通信两部分. 一.Android ...
- Android的JNI调用(二)
Android Studio 2.3在native下已经有了代码提示功能,按照提示下载相应组件就可以debug native代码. 一.Java调用JNI与JNI调用Java 1.1 C调用Java ...
- android camera jni调用
http://www.mamicode.com/info-detail-1002139.html how to compile library of native camera for androi ...
- (AIDE)Android Eclipse JNI 调用 .so文件加载问题
背景:对于Android工程 Eclipse里编译好的.so文件放到 libs\armeabi下以后, 这样.so文件就可以打包到apk文件里,在apk装到手机上以后 在libs\armeabi下的. ...
- Android于JNI调用列出的程序
1.安装和下载cygwin,下载Android NDK: 2.于ndk工程JNI接口设计: 3.采用C/C++实现本地方法. 4.JNI生成动态链接库.so档: 5.动态链接库副本javaprojec ...
- android studio jni调用入门
一.开发环境配置: 1.Android Studio 2.3.3 2.android-ndk-r14b-windows-x86_64 二.创建项目 1.新建android项目 2.新建文件 3.编译生 ...
随机推荐
- Window.Open参数、返回值
一.window.open()支持环境: JavaScript1.0+/JScript1.0+/Nav2+/IE3+/Opera3+ 二.基本语法: window.open(pageURL,name, ...
- 高德开发 android 出现 key 鉴权失败
环境windows + android studio 原因: 曾经更改过key.store 解决办法: 首先运行cmd移动到keystore的目录下keytool -list -keystore 文件 ...
- Start my cnBlogs
Compared to CSDN blog, althought it's my first time to use CNBlog,i felt it makes me more comfortabl ...
- 【笔记】UML核心元素
1.参与者 定义:在系统之外与系统交互的某人或某物. 特点:1.可以非人:2.与系统直接交互:3.主动发出动作并获得反馈:4.涉众(stakerholder)的代表 具有两个版型: 1.业务主角(bu ...
- C# - (0x80040154): Retrieving the COM class factory for component with CLSID {877AA945-1CB2-411C-ACD7-C70B1F9E2E32} failed
1. Exeption Error: System.Runtime.InteropServices.COMException (0x80040154): Retrieving the COM clas ...
- Linux/Ubuntu常用快捷键
问题描述: Linux/Ubuntu常用快捷键 问题解决: +++++++++++++++++++ 全局系统 +++++++++++++++++++++ Alt + F1:相当于w ...
- 查看系统网络连接打开端口、系统进程、DOS打开文件
问题描述: DOS查看系统网络连接打开端口.打开的服务 问题解决: (1)DOS查看系统网络连接打开端口 注: 使用 netstat 命令,可以查看系统打开的端口 (2)查看和关闭系统打开进程 ...
- Html特殊字符转义处理
#region 将Html特殊字符转义处理 /// <summary> /// 将Html特殊字符转义处理 /// </summary> ...
- SQL Server 之 锁
锁,是由锁管理器负责维护,其目的是保证事务的ACID,是平衡并发和数据安全的机制. 锁定粒度与并发性是成反比的,默认情况下,SQL Server Compact 4.0 对数据页使用行级锁定,对索引页 ...
- effect state dx11
一个blendstate { BlendEnable[0]=TRUE; SrcBlend[0]=ONE; DestBlend[]=ONE; BlendOp[0]=ADD; } [0]-----一次混合 ...