Android驱动之JNI编写
要想用java去调用C函数接口那么就需要使用JNI(Java Native Interface,Java 本地调用)去访问本地的动态链接库。
关于NDK的安装,现在有linux环境下的版本,也有windows环境下的版本,这个可自行百度,这里不多说
在eclipse中配置NDK:打开我们的eclipse->window->preference->android->ndk设置ndk路径->ok。
1、使用cygwin编译生成.so文件:右键单击项目->Android Tools->Add Native Support...->.so文件命名例如test->ok。
完成之后eclipse会生成一个jni文件夹,里面会生成一个test.cpp的文件。
但是我一般不用这个文件,直接delete,新建三个文件(.h .c .mk)。
.h和.c文件是用来编写kernel访问接口,可以直接调用驱动程序里的函数,这里需要注意命名规则:Java_包名_类名_接口名,此类表示调用.h中的方法的类
.mk文件是用来编译生成.so文件的,这里需要注意LOCAL_MODULE := HelloJni,表示生成HelloJni.so库,
在java中调用该库的入口是System.loadLibrary("HelloJni");
2、使用脚本编译的配置方法
在NDKr7开始,google的windos版NDK提供了一个ndk-build.cmd的脚本,这样就可以直接利用这个脚本编译,而不需要cygwin了。 1、选择你的android工程,右击->Properties->Builders->new,新添加一个编译器,点击之后出现添加界面,选择Program,点击ok。
2、出现了添加界面,我们先给编译器设置名称,如XXX_builder。设置Location为<NDK安装目录>\ndk-build.cmd
设置Working Directory为${workspace_loc:/项目名称}
3、切换到Refersh选项卡,给Refersh resources upon completion打上勾,选择“the entire resource”选项
4、切换到Build Options选项卡,勾选上最后三项。再点击Specify Resource按钮,选择你的android工程
5、在编译工具列表,我们最好将我们新建的编译器置顶。选中点击Up按钮置顶ok.
样例如下:
1、com_pngcui_HelloJni.h //命名规则:Java_包名_类名_接口名
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_neojet_scanner_key */ #ifndef _Include_com_pngcui_helloJni
#define _Inlcude_com_pngcui_helloJni #ifdef _cplusplus
extern "C"{
#endif /*Java_packagename_classname_methodname*/
/*open()*/
JNIEXPORT jint JNICALL Java_com_pngcui_helloJni_HelloJni_Open
(JNIEnv *,jobject); /*close()*/
JNIEXPORT jint JNICALL Java_com_pngcui_helloJni_HelloJni_Close
(JNIEnv *,jobject); /*ioctl()*/
JNIEXPORT jint JNICALL Java_com_pngcui_helloJni_HelloJni_Ioctl
(JNIEnv *,jobject,jint num,jint en); #ifdef _cplusplus
}
#endif
#endif
2、com_pngcui_HelloJni.c //实现.h方法
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <stdint.h>
#include <termios.h>
#include <android/log.h>
#include <sys/ioctl.h> #include "com_pngcui_helloJni.h" #undef TCSAFLUSH
#define TCSAFLUSH TCSETSF
#ifndef _TERMIOS_H_
#define _TERMIOS_H_
#endif int fd = ; /*open()*/
JNIEXPORT jint JNICALL Java_com_pngcui_helloJni_HelloJni_open
(JNIEnv *env , jobject obj){
/*只允许打开一次设备!*/
if(fd<=)
fd = open("/dev/jni",O_RDWR|O_NDELAY|O_NOCTTY);
if(fd<=)
__android_log_print(ANDROID_LOG_INFO,"serial","open /dev/jni Error..");
else
__android_log_print(ANDROID_LOG_INFO,"serial","open /dev/jni Sucess fd = %d",fd);
} JNIEXPORT jint JNICALL Java_com_pngcui_helloJni_HelloJni_close
(JNIEnv *env,jobject obj){ if(fd > )
close(fd);
} JNIEXPORT jint JNICALL Java_com_pngcui_helloJni_HelloJni_ioctl
(JNIEnv *env,jobject obj,jint num , jint en){ ioctl(fd,en,num);
}
3、Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := HelloJni
LOCAL_SRC_FILES := com_pngcui_helloJni.c
LOCAL_LDLIBS += -llog
LOCAL_LDLIBS +=-lm
include $(BUILD_SHARED_LIBRARY)
在android.mk文件中我们可以知道最后会生成一个libHelloJni.so本地库文件。
LOCAL_PATH - 编译时的目录
$(call
目录,目录….)
目录引入操作符
如该目录下有个文件夹名称
src,则可以这样写
$(call
src),那么就会得到
src
目录的完整路径
include
$(CLEAR_VARS) -清除之前的一些系统变量
LOCAL_MODULE
-
编译生成的目标对象
LOCAL_SRC_FILES
-
编译的源文件
LOCAL_C_INCLUDES
-
需要包含的头文件目录
LOCAL_SHARED_LIBRARIES
-
链接时需要的外部库
LOCAL_PRELINK_MODULE
-
是否需要prelink处理
include$(BUILD_SHARED_LIBRARY)
-
指明要编译成动态库
把以上三个文件放入jni文件夹中,最后编写一个java类,也就是命名规则的那个java类名
Jni.java
package com.pngcui.helloJni; public class Jni { public native int Open();
public native int Close();
public native int Ioctl(int num, int en);
}
最后在调用Jni.java的类中需要声明本地库的路径
static {
System.loadLibrary("HelloJni");
}
附上完整的MainActivity.java代码
package com.pngcui.helloJni; import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button; public class MainActivity extends Activity { Jni jni = new Jni(); private Button y1;
private Button y2;
private Button n1;
private Button n2;
private Button start; int i; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); y1 = (Button)findViewById(R.id.y1);
y2 = (Button)findViewById(R.id.y2);
n1 = (Button)findViewById(R.id.n1);
n2 = (Button)findViewById(R.id.n2);
start = (Button)findViewById(R.id.start); jni.Open(); y1.setOnClickListener(new manager());
n1.setOnClickListener(new manager());
y2.setOnClickListener(new manager());
n2.setOnClickListener(new manager());
start.setOnClickListener(new manager()); } class manager implements OnClickListener{ @Override
public void onClick(View v) { //gpio_set_value(led_gpio[i],cmd),且二极管为低电平有效 switch(v.getId()){ case R.id.y1:
jni.Ioctl(0, 0);
break;
case R.id.n1:
jni.Ioctl(0, 1);
break; case R.id.y2:
jni.Ioctl(1, 0);
break;
case R.id.n2:
jni.Ioctl(1, 1);
break; case R.id.start:
try {
start();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
break; } } private void start() throws InterruptedException {
// TODO Auto-generated method stub i = 10;
while(i>0){
i--;
jni.Ioctl(1, 0);
jni.Ioctl(0, 1); Thread.sleep(200); jni.Ioctl(1, 1);
jni.Ioctl(0,0); Thread.sleep(200);
}
jni.Ioctl(1, 0);
} } static {
System.loadLibrary("HelloJni");
}
}
最后还有一个问题,那就是权限问题!也就是说到现在我们还没有给我们的驱动程序生成的设备节点设置权限,也就是可读可写权限,如果不设置这个权限,那么我们的android应用时无法打开设备节点的!!!在调用open函数时会直接返回-1!!而在exynos4412平台上的android设置权限的文件在device/samsung/smdk4x12/conf/init.smdk4x12.rc中,而不是网上说的init.rc和ueventd.rc文件中,但是!!本人在里面设置了chmod 777 /dev/jni 依旧不能正常open,百思不得其解,有哪位大神知道怎么去自动设置权限,还麻烦教导我一下,不甚感激!
附上蠢蠢的解决办法:在串口终端使用命令chmod 777 /dev/jni然后运行app,可暂时性解决此问题,但是开发板重启以后就需要重修设置权限!!
---------------------------------2016.4.12 update------------------------------------------------------
权限问题的解决方案:为什么在脚本中写了chmod命令还是不能open设备文件,因为没有烧写ramdisk.img文件啊啊啊啊!!!只烧写了system.img,因为rc脚本会编译到ramdisk镜像中。
参考链接:http://blog.csdn.net/loongembedded/article/details/39778409
最后附上查看设备权限命令:ls -al /dev/xxx
r: 对应数值4
w: 对应数值2
x:对应数值1
-:对应数值0
eg。-rwxrwxrwx 对应0777 即所有用户都可读可写可执行
---------------------2016.4.20补充驱动函数返回数据到java中----------------------
如果需要读取底层硬件状态等信息,并返回到app上,则需要使用jni里的方法去调用驱动函数的ioctl,而不能直接在java中写data = jni.Ioctl(a,b);
JNIEXPORT jint JNICALL Java_com_pngcui_fm_Jni_GetData
(JNIEnv *env,jobject obj,jint cmd ){ jint data = ; data = ioctl(fd,cmd,); return data;
}
使用如上方法才能正常返回!
Android驱动之JNI编写的更多相关文章
- 自己动手写最简单的Android驱动---LED驱动的编写【转】
本文转载自:http://blog.csdn.net/k_linux_man/article/details/7023824 转载注明出处,作者:K_Linux_Man, 薛凯 山东中医药大学,给文章 ...
- 【转】 Android 开发 之 JNI入门 - NDK从入门到精通
原文网址:http://blog.csdn.net/shulianghan/article/details/18964835 NDK项目源码地址 : -- 第一个JNI示例程序下载 : GitHub ...
- android驱动[置顶] 我的DIY Android之旅--驱动并控制你的Android开发板蜂鸣器
改章节个人在深圳游玩的时候突然想到的...这几周就有想写几篇关于android驱动的博客,所以回家到之后就奋笔疾书的写出来发布了 这些天一直在想Android驱动框架层的实现,本文借助老罗教师的博客和 ...
- 【Android 应用开发】Android 开发 之 JNI入门 - NDK从入门到精通
NDK项目源码地址 : -- 第一个JNI示例程序下载 : GitHub - https://github.com/han1202012/NDKHelloworld.git -- Java传递参数给C ...
- Android 开发 之 JNI入门 - NDK从入门到精通
NDK项目源码地址 : -- 第一个JNI示例程序下载 : GitHub - https://github.com/han1202012/NDKHelloworld.git -- Java传递参数给C ...
- Android系统篇之—-编写系统服务并且将其编译到系统源码中【转】
本文转载自:http://www.wjdiankong.cn/android%E7%B3%BB%E7%BB%9F%E7%AF%87%E4%B9%8B-%E7%BC%96%E5%86%99%E7%B3% ...
- Android驱动开发5-8章读书笔记
Android驱动开发读书笔记 第五章 S5PV210是一款32位处理器,具有 ...
- Android内核驱动程序的编写和编译过程
注意:涉及的代码为android内核代码而不是android源码. 在智能手机时代,每个品牌的手机都有自己的个性特点.正是依靠这种与众不同的个性来吸引用户,营造品牌凝聚力和用户忠城度,典型的代表非ip ...
- 如何做更好的Android驱动project师
随着智能手机的飞跃发展,特别是Android智能机的爆炸性发展,Android驱动project师是越来越受欢迎的一个职位,并且是一个非常值得人期待的职位,由于可能你參与研发的一款手机就能改变 ...
随机推荐
- 如何查看JDK以及JAVA框架的源码
如何查看JDK以及JAVA框架的源码 设置步骤如下: 1.点 “window”-> "Preferences" -> "Java" -> &q ...
- Diablo2 1.13版&PlugY10.00 男巫存档
下载地址: http://files.cnblogs.com/files/xiandedanteng/20160805D2113NanwuL83Backup.rar 解压后文件放到Diablo2游戏的 ...
- 简单理解php的socket编程
php的socket编程算是比较难以理解的东西吧,不过,我们只要理解socket几个函数之间的关系,以及它们所扮演的角色,那么理解起来应该不是很难了,在笔者看来,socket编程,其实就是建立一个网络 ...
- iOS:集成支付宝支付
一.介绍 支付宝的集成还是比较简单的,按照文档来一步步操作,基本上很顺利.不过,仍然有两个地方会是坑.这里我集成成功了,在此整理一下.说先说一下我遇到的坑如下: 第一个坑:下载的SDK文件AliPay ...
- Nginx+Lua(OpenResty)开发高性能Web应用
使用Nginx+Lua(OpenResty)开发高性能Web应用 博客分类: 跟我学Nginx+Lua开发 架构 ngx_luaopenresty 在互联网公司,Nginx可以说是标配组件,但是主要场 ...
- 利用tween,使用原生js实现模块回弹动画效果
最近有一个需求,就是当屏幕往下一定像素时,下方会有一个隐藏的模块马上显现出来,向上运动后带有回弹效果.然后屏幕滚回去时这个模块能够原路返回 其实这个效果css3就可以很轻松实现,但是公司要求最低兼容i ...
- js插入拼接链接 --包含可变字段
// newsId: 传参过来的Id, pathIdlet newsDetailId = parseInt(this.props.newsId); goTo() { window.location.h ...
- 【转】PowerShell入门(九):访问.Net程序集、COM和WMI
转至:http://www.cnblogs.com/ceachy/archive/2013/02/28/PowerShell_DotNet_COM_WMI.html PowerShell可以设计的大而 ...
- Android APK反编译easy 详解
在学习Android开发的过程你,你往往会去借鉴别人的应用是怎么开发的,那些漂亮的动画和精致的布局可能会让你爱不释手,作为一个开发者,你可能会很想知道这些效果界面是怎么去实现的,这时,你便可以对改应用 ...
- 如何修改VPN连接的MTU,解决频繁断线和页面打不开的问题
如何修改VPN连接的MTU,解决频繁断线和页面打不开的问题 MTU 介绍:MTU 即最大传输单元,它是指一种通信协议的某一层上面所能通过的最大数据包大小.为什么需要修改 MTU大多数设备原本支持通过 ...