Android底层开发之JNI编程
Android中JNI编程—-android应用是如何与驱动进行交互
a, java代码调用jni的接口
b, jni代码的实现
jni: java native interface,java本地接口
或者是: java调用c/c++代码的接口
图1 JNI的实现原理
——————————————————————————————————————
app中: 与jni交互的接口;
1, 加载动态库
static{//优先执行
System.loadLibrary(“led_jni”); // /system/lib/libled_jni.so
}
2, 声明本地方法,名字和参数都是自定义
public native int openDev();
public native int devOn();
public native int devOff();
public native int closeDev();
3, 调用本地方法
LedNative myled;
myled = new LedNative();
myled.openDev();
接下来在eclipse中写相关代码:(功能:实现点灯)
创建new project
在UI中添加2个button
包名:com.example.ledcontrol
类:/LedControl/src/com/example/ledcontrol/LedActivity.java
package com.example.ledcontrol;//这个程序不能直接在安卓模拟器运行import com.example.lowlevel.LedNative;import android.app.Activity;import android.os.Bundle;import android.view.View;import android.util.Log;import android.view.View.OnClickListener;import android.widget.Button;import android.widget.Toast;//外加设置监听事件public class LedActivity extends Activity implements OnClickListener{ final String TAG = "LedActivity";//写log Button btn_led_on; Button btn_led_off; LedNative myled; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_led); initUI(); // 3.调用本地方法 myled = new LedNative(); myled.openDev(); //这里有4个方法,这是其中之一 } //实现 private void initUI() { // TODO Auto-generated method stub btn_led_on = (Button) findViewById(R.id.btn_led_on);//初始化 btn_led_on.setOnClickListener(this);//设置监听自己 btn_led_off = (Button) findViewById(R.id.btn_led_off); btn_led_off.setOnClickListener(this); } @Override //处理UI public void onClick(View v) { // TODO Auto-generated method stub switch (v.getId()) { case R.id.btn_led_on: Toast.makeText(LedActivity.this, "亮灯啦-----", 1000).show();//显示效果 Log.d(TAG, "好亮啊-----"); myled.devOn(); break; case R.id.btn_led_off: Toast.makeText(LedActivity.this, "灭灯啦-----", 1000).show(); Log.d(TAG, "天黑请闭眼"); myled.devOff(); break; default: break; } } @Override protected void onDestroy() { // TODO Auto-generated method stub super.onDestroy(); myled.closeDev(); }}
包名:com.example.lowlevel
类:/LedControl/src/com/example/lowlevel/LedNative.java
package com.example.lowlevel;//这个程序不能直接在安卓模拟器运行public class LedNative { //1.加载动态库 static{ //优先执行 System.loadLibrary("led_jni");// /system/lib/libled_jni.so } //2, 声明本地方法,名字和参数都是自定义 public native int openDev();//在底层中先打开 public native int devOn();//控制过程 public native int devOff(); public native int closeDev();//最后关闭 }
——————————————————————————————————————————————————
在Ubuntu中去编写jni: 用sourceinsight
准备步骤:先把si_android404-android.tgz拷贝到目录下,并解压tar -xvf si_android404-android.tgz
接下来编写led_jni.cpp
编写方法:参考模板—development/samples/SimpleJNI/jni
实现JNI_onLoad() jint JNI_OnLoad(JavaVM* vm, void* reserved) { //获取到环境变量对象---提供各种操作方法---注册方法 JNIEnv *env = NULL; jint vm->GetEnv(void * * env,jint version) //构建映射表,注册给dvm typedef struct { const char* name; //java的方法名 const char* signature; //方法的描述 void* fnPtr;//c/c++的函数名 } JNINativeMethod; // 参数1-- java方法所在的包路径信息--通过env->FindClass得到 //参数2---映射表 //参数3--映射表中的项目个数 //返回值--错误为负数 jint env->RegisterNatives(jclass clazz,const JNINativeMethod * methods,jint nMethods) }
代码led_jni.cpp
#include #include #include #include #include #include #define LOG_TAG "led_jni_log"#include #include "jni.h"static jint fd;jint open_led(JNIEnv *env, jobject thiz)//记住参数{ LOGD("-----------%s--------------\n", __FUNCTION__); fd = open("/dev/led1", O_RDWR); if(fd < 0) { LOGE("open error : %s\n", strerror(errno)); return -1; } return 0;}jint led_on(JNIEnv *env, jobject thiz){ LOGD("-----------%s--------------\n", __FUNCTION__); jint on = 1; jint ret; ret = write(fd, &on, 4);//第3个参数表示4字节 if(ret < 0) { LOGE("write on error : %s\n", strerror(errno)); return -1; } return 0;}jint led_off(JNIEnv *env, jobject thiz){ LOGD("-----------%s--------------\n", __FUNCTION__); jint on = 0; jint ret; ret = write(fd, &on, 4); if(ret < 0) { LOGE("write off error : %s\n", strerror(errno)); return -1; } return 0;}jint close_led(JNIEnv *env, jobject thiz){ LOGD("-----------%s--------------\n", __FUNCTION__); close(fd); return 0;}//映射表数组const JNINativeMethod led_jni_methods[] = { {"openDev", "()I", (void*)open_led}, {"devOn", "()I", (void*)led_on}, {"devOff", "()I", (void*)led_off}, {"closeDev", "()I", (void*)close_led},};//实现JNI_onLoad()//JNI_OnLoad返回值--正确为JNI_VERSION_1_4,错误为负数jint JNI_OnLoad(JavaVM * vm,void * reserved){ LOGD("-----------%s--------------\n", __FUNCTION__); JNIEnv *env = NULL; jint ret; //1.获取到环境变量对象---提供各种操作方法---注册方法 // 参数1--被初始化的env //参数2--jni的版本 //返回值--正确为0,错误为负数 ret = vm->GetEnv((void * * )&env, JNI_VERSION_1_4); if(ret != JNI_OK) { LOGE("vm->GetEnv error\n"); return -1; } //2.构建映射表,注册给dvm jclass clz = env->FindClass("com/example/lowlevel/LedNative"); if(clz == NULL) { LOGE("env->FindClass error\n"); return -1; } // 参数1-- java方法所在的包路径信息--通过env->FindClass得到 //参数2---映射表 //参数3--映射表中的项目个数 //返回值--错误为负数 ret = env->RegisterNatives(clz, led_jni_methods, sizeof(led_jni_methods)/sizeof(led_jni_methods[0])); if(ret < 0) { LOGE("env->RegisterNatives error\n"); return -1; } return JNI_VERSION_1_4;}
代码Android.mk
1 LOCAL_PATH:= $(call my-dir) 2 include $(CLEAR_VARS) 3 4 LOCAL_MODULE_TAGS := optional 5 6 #编译后的目标文件,一定要和System.loadLibrary()名字保持一致 7 LOCAL_MODULE := libled_jni 8 9 #指定的原文件 10 LOCAL_SRC_FILES := led_jni.cpp 11 12 #因为使用了LOGD 13 LOCAL_SHARED_LIBRARIES := libutils 14 15 #因为使用了jni.h, LOCAL_C_INCLUDES用于jni.h的所在路径 16 LOCAL_C_INCLUDES += $(JNI_H_INCLUDE) 17 18 #把目标文件编译成动态库 19 include $(BUILD_SHARED_LIBRARY)
6 #编译后的目标文件,一定要和System.loadLibrary()名字保持一致
如图:
还要注意:JNI_H_INCLUDE
接下来执行程序
每次打开一个终端,先执行以下命令:
接着编译:
可以看到目标文件libled_jni.so安装到/system/lib…里面(这是安卓默认的路径,apk一般编译到system/app里面)
接着编写驱动程序 ko
需要用Makefile编译
在src_210目录下创建mydrv/led_drv/Makefile
ifeq ($(KERNELRELEASE),) KERNELDIR = /home/george/src_210/linux-3.0.8-FS210 PWD =$(shell pwd)modules: $(MAKE) -C $(KERNELDIR) M=$(PWD) modules #arm-none-linux-gnueabi-gcc hello_test.c -o hello_test #cp hello_test hello.ko /opt/filesystem/s5pv210modules_install: $(MAKE) -C $(KERNELDIR) M=$(PWD) modules_installclean: rm -rf *_test *.so *.o *.ko .tmp_versions *.mod.c *.order *.symvers else obj-m :=s5pv210_led.oendif
最后是运行:
apk—>安装到开发板
1,自动安装—/system/lib
2,手动安装—/mnt/sdcard/(需要重启)
vim init.fs210.rc
7 mkdir /mnt/sdcard 0777 system system
8 mkdir /mnt/ext_sd 0777 system system
9 mkdir /mnt/usb 0777 system system
jni.so ---> /system/lib cp -raf out/target/product/fs210/system/lib/libled_jni.so /opt/rootfs_dir/system/libdrv.ko --> /system/lib/modules/ cp -raf s5pv210_led.ko /opt/rootfs_dir/system/lib/modules/
接着把制作好的apk放到/opt/rootfs_dir/mnt/sdcard中
在开发板中:
logcat -c
logcat
I/ActivityManager( 2213): START {act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 pkg=com.hq.ledcontrol cmp=com.hq.ledcontrol/.LedActivity} from pid 2884
D/dalvikvm( 3010): Not late-enabling CheckJNI (already on)
E/AudioHardware( 2139): AudioStreamOutALSA::write END WITH ERROR !!!!!!!!!(0x4667d0, 4096)
D/dalvikvm( 2213): GC_CONCURRENT freed 424K, 8% free 9263K/9991K, paused 14ms+45ms
I/ActivityManager( 2213): Start proc com.hq.ledcontrol for activity com.hq.ledcontrol/.LedActivity: pid=3010 uid=10053 gids={}
D/OpenGLRenderer( 2884): Flushing caches (mode 0)
D/led_jni_log( 3010): ———–JNI_OnLoad————–
D/led_jni_log( 3010): ———–open_led————–
E/led_jni_log( 3010): open error : No such file or directory // 驱动没有安装
解决:
/ # insmod /system/lib/modules/s5pv210_led.ko
再次启动:
/ # logcat
——— beginning of /dev/log/system
I/ActivityManager( 2213): START {act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.hq.ledcontrol/.LedActivity} from pid 2487
——— beginning of /dev/log/main
D/dalvikvm( 2213): GC_FOR_ALLOC freed 317K, 10% free 9181K/10119K, paused 31ms
D/led_jni_log( 3010): ———–open_led————–
E/led_jni_log( 3010): open error : Permission denied //权限有问题
I/ActivityManager( 2213): Displayed com.hq.ledcontrol/.LedActivity: +240ms
W/IInputConnectionWrapper( 3010): showStatusIcon on inactive InputConnection
D/OpenGLRenderer( 2487): Flushing caches (mode 1)
D/OpenGLRenderer( 2487): Flushing caches (mode 0)
W/InputManagerService( 2213): Starting input on non-focused client com.android.internal.view.IInputMethodClientProxy@4139d230 (uid=10028 pid=2487)
D/LedActivity( 3010): 亮瞎了狗眼
D/led_jni_log( 3010): ———–led_on————–
E/led_jni_log( 3010): write on error : Bad file number
解决:
/ # chmod 777 /dev/led1
再次重启应用程序:
总结,每次打开应用程序都要装载驱动,修改权限,不方便,这时,我们可以
自动装载ko和修改权限: init.rc(/opt/rootfs_dir/)
283 insmod /system/lib/modules/s5pv210_led.ko
284 chmod 777 /dev/led1
285
286
287 on boot
288 # basic network init
程序链接地址:LED_CODE.zip(链接:https://pan.baidu.com/s/1dAGY2y 密码:os15)
更多相关文章
- 【android】AIDL传递自定义类型参数
- android 滑动事件冲突解决 Touch事件处理机制
- 【Android(安卓)Developers Training】 79. 连接到网络
- Android获取常用辅助方法(获取屏幕高度、宽度、密度、通知栏高度
- Android(安卓)Design Library之四:BottomSheetDialog
- Android弹出DatePickerDialog并获取值的方法
- android Cursor的自动管理方式
- (1)LruCache原理分析
- android动态获取权限方法