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)

更多相关文章

  1. 【android】AIDL传递自定义类型参数
  2. android 滑动事件冲突解决 Touch事件处理机制
  3. 【Android(安卓)Developers Training】 79. 连接到网络
  4. Android获取常用辅助方法(获取屏幕高度、宽度、密度、通知栏高度
  5. Android(安卓)Design Library之四:BottomSheetDialog
  6. Android弹出DatePickerDialog并获取值的方法
  7. android Cursor的自动管理方式
  8. (1)LruCache原理分析
  9. android动态获取权限方法

随机推荐

  1. Android中常常使用shape来定义控件的一些
  2. Android Databinding(一)
  3. android之listview内存优化
  4. 闲谈Android中的@和?符号的引用区别
  5. 待续
  6. [原]Android应用程序发送广播(sendBroadca
  7. Android动态设置Margin的方法
  8. [转]Android Recovery模式
  9. Android SDK Manager 更新时的“https://
  10. Android 反汇编Smali语言中插入log打印