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

本文涉及的产品
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
简介:   [置顶] Android通过JNI调用驱动程序(完全解析实例)            要达到的目的:android系统中,用JAVA写界面程序,调用jni中间库提供的接口,去操作某个驱动节点,实现read,writer ioctl等操作!这对底层驱动开发人...
 

[置顶] 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]
clip_image004

新键工程后,

如果出现如下错误:

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/>
</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 文件

clip_image002[18]
修改如下

<?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 运行程序。

clip_image004[11]

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

clip_image002[20]

填参数:

clip_image002[22]

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模拟器,看到如下效果

clip_image002[24]

安装到开发板:

在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亮灭了!



要学好嵌入式,还是建议买一个开发板,因为在枯燥学习中,要实践才会记忆深刻,而且,在看到自已学的知道能做出一些功能,会很有成就感,更能积累信心往深处学。例如学驱动开发,能在开发板上做出一个应用,调用自已写的驱动程序,控制LED灯的亮灭,这就很能鼓励自已,让自已更有兴趣往下学,这样学习来会更快!

推荐下面4款,你可以根据你的经济能力来选一个


1、高级嵌入式开发板 ARM-A8内核,价格在2200~2700
X-210开发板(代码开放度高,XBOOT很牛)   
Mini210开发板 (友善的板子,有沉淀)

2、入门级嵌入式开发板 ARM11内核  ,价格在500~650之间
Tiny6410    (友善之臂经典之作)     
OK6410    (特点是支持WINCE7.0)

可以去风火轮团队的店里看一下,在他们那里买板有个好处,他们提从更周到的技术支持

风火轮技术开发团队  www.arm-cn.com

官方淘宝店:smartfire.taobao.com


相关文章
|
2月前
|
Java 开发工具 Android开发
Android与iOS开发环境搭建全解析####
本文深入探讨了Android与iOS两大移动操作系统的开发环境搭建流程,旨在为初学者及有一定基础的开发者提供详尽指南。我们将从开发工具的选择、环境配置到第一个简单应用的创建,一步步引导读者步入移动应用开发的殿堂。无论你是Android Studio的新手还是Xcode的探索者,本文都将为你扫清开发道路上的障碍,助你快速上手并享受跨平台移动开发的乐趣。 ####
|
2月前
|
存储 负载均衡 监控
数据库多实例的深入解析
【10月更文挑战第24天】数据库多实例是一种重要的数据库架构方式,它为数据库的高效运行和灵活管理提供了多种优势。在实际应用中,需要根据具体的业务需求和技术环境,合理选择和配置多实例,以充分发挥其优势,提高数据库系统的性能和可靠性。随着技术的不断发展和进步,数据库多实例技术也将不断完善和创新,为数据库管理带来更多的可能性和便利。
124 57
|
21天前
|
数据挖掘 vr&ar C++
让UE自动运行Python脚本:实现与实例解析
本文介绍如何配置Unreal Engine(UE)以自动运行Python脚本,提高开发效率。通过安装Python、配置UE环境及使用第三方插件,实现Python与UE的集成。结合蓝图和C++示例,展示自动化任务处理、关卡生成及数据分析等应用场景。
88 5
|
1月前
|
存储 Linux API
深入探索Android系统架构:从内核到应用层的全面解析
本文旨在为读者提供一份详尽的Android系统架构分析,从底层的Linux内核到顶层的应用程序框架。我们将探讨Android系统的模块化设计、各层之间的交互机制以及它们如何共同协作以支持丰富多样的应用生态。通过本篇文章,开发者和爱好者可以更深入理解Android平台的工作原理,从而优化开发流程和提升应用性能。
|
1月前
|
存储 网络协议 算法
【C语言】进制转换无难事:二进制、十进制、八进制与十六进制的全解析与实例
进制转换是计算机编程中常见的操作。在C语言中,了解如何在不同进制之间转换数据对于处理和显示数据非常重要。本文将详细介绍如何在二进制、十进制、八进制和十六进制之间进行转换。
43 5
|
1月前
|
Java 调度 Android开发
安卓与iOS开发中的线程管理差异解析
在移动应用开发的广阔天地中,安卓和iOS两大平台各自拥有独特的魅力。如同东西方文化的差异,它们在处理多线程任务时也展现出不同的哲学。本文将带你穿梭于这两个平台之间,比较它们在线程管理上的核心理念、实现方式及性能考量,助你成为跨平台的编程高手。
|
2月前
|
存储 机器学习/深度学习 编解码
阿里云服务器计算型c8i实例解析:实例规格性能及使用场景和最新价格参考
计算型c8i实例作为阿里云服务器家族中的重要成员,以其卓越的计算性能、稳定的算力输出、强劲的I/O引擎以及芯片级的安全加固,广泛适用于机器学习推理、数据分析、批量计算、视频编码、游戏服务器前端、高性能科学和工程应用以及Web前端服务器等多种场景。本文将全面介绍阿里云服务器计算型c8i实例,从规格族特性、适用场景、详细规格指标、性能优势、实际应用案例,到最新的活动价格,以供大家参考。
|
2月前
|
开发框架 Dart Android开发
安卓与iOS的跨平台开发:Flutter框架深度解析
在移动应用开发的海洋中,Flutter作为一艘灵活的帆船,正引领着开发者们驶向跨平台开发的新纪元。本文将揭开Flutter神秘的面纱,从其架构到核心特性,再到实际应用案例,我们将一同探索这个由谷歌打造的开源UI工具包如何让安卓与iOS应用开发变得更加高效而统一。你将看到,借助Flutter,打造精美、高性能的应用不再是难题,而是变成了一场创造性的旅程。
|
2月前
|
安全 Java Linux
深入解析Android系统架构及其对开发者的意义####
【10月更文挑战第21天】 本文旨在为读者揭开Android操作系统架构的神秘面纱,探讨其如何塑造现代移动应用开发格局。通过剖析Linux内核、硬件抽象层、运行时环境及应用程序框架等关键组件,揭示Android平台的强大功能与灵活性。文章强调了理解Android架构对于开发者优化应用性能、提升用户体验的重要性,并展望了未来技术趋势下Android的发展方向。 ####
58 0
|
3月前
|
XML 数据格式
HTML 实例解析
本文介绍了HTML中常见元素的使用方法,包括`&lt;p&gt;`、`&lt;body&gt;`和`&lt;html&gt;`等。详细解析了这些元素的结构和作用,并强调了正确使用结束标签的重要性。此外,还提到了空元素的使用及大小写标签的规范。

推荐镜像

更多