linux驱动|基于老罗的freg案例,使用NDK工具调用驱动流程详细分析

鉴于老罗的《Android内核源代码情景分析》第二章介绍的实例freg,全是在源代码中完成(添加HAL层、JNI层以及开启系统服务),这是一个相对复杂的过程。虽然这种调用过程是比较标准的,但对于项目的开发进度会造成很大的拖延(应用程序每变动一次,你不可能就对内核编译一次吧,虽然使用mmm命令每次花费时间几分钟,但一个项目积累下来这个时间量是相当惊人的)。所以本人通过使用NDK工具直接编写JNI层,生成so库文件,然后在Android应用程序中添加类,加载so库文件即可完成对设备驱动的调用。
说实话,没人指导,一人在那摸索真是痛苦,不过痛苦之后方见彩虹,一切都是值得的。允许我唠叨了些,(*^__^*) 好了,废话不多说,直接进入正题,我仍以freg为例进行讲解编写jni库文件用以调用设备的驱动程序,开发板是飞思卡尔的IMX53开发板,cortex-A8内核。
first,编写Android驱动程序,在myAndroid/kernel_imx/drivers文件夹下新建freg文件夹,文件夹下包含freg.c、freg.h、Kconfig、Makefile,内容就不多说了,照着老罗的驱动copy过来即可,当然你要是有耐心自己一点点敲更好了,加深印象嘛。
接着就到了修改drivers目录下kconfig和Makefile的环节,kconfig中添加 source "drivers/freg/Kconfig",Makefile中添加 obj-$(CONFIG_FREG) += freg/。
剩下的工作就是编译生成系统文件了。
second,到了本文的重点——编写JNI文件。首先新建Java类,

package com.lcl.whut_open;


import android.util.Log;


public class Jni_open {


public static native int open();
// public static native int get_number();
public static native int write(int i);
public static native int close();


static {


try {
Log.i("JNI", "trying to load freg.default.so");
System.loadLibrary("freg.default");
}catch (UnsatisfiedLinkError e) {
Log.e("JNI", "WARNING: Could not load freg.default.so");
}
}


}
生成头文件,找到你的项目文件保存目录(我的项目文件保存在C:\cygwin\usr\local\android\android-ndk-r6b\samples),在cmd中依次输入
cd C:\cygwin\usr\local\android\android-ndk-r6b\samples\whut_open和javah -classpath bin\classes -d jni com.lcl.whut_open.Jni_open。就可生成相应的头文件。
根据头文件编写freg.c,
#include
#include
#include
#include
#include
#include




#define LOG_TAG "System.out"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG , LOG_TAG , __VA_ARGS__)


#define LOGI(...) __android_log_print(ANDROID_LOG_INFO , LOG_TAG , __VA_ARGS__)


#define DEV_NAME "/dev/freg"
int fd;


JNIEXPORT jint JNICALL Java_com_lcl_whut_1open_Jni_1open_open
(JNIEnv* env, jclass thiz)
【linux驱动|基于老罗的freg案例,使用NDK工具调用驱动流程详细分析】{
fd = open(DEV_NAME, O_RDWR);
if(fd<0)
{
LOGD ("open failed!");
return fd;
}


LOGD ("freg open success!");
return fd;
}


JNIEXPORT jint JNICALL Java_com_lcl_whut_1open_Jni_1open_write
(JNIEnv* env, jclass thiz, jint i)
{
write(fd,&i,sizeof(i));
return 0;
}


JNIEXPORT jint JNICALL Java_com_lcl_whut_1open_Jni_1open_close
(JNIEnv* env, jclass thiz)
{
close(fd);
return 0;
}
编写Android.mk,
LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE := freg.default
LOCAL_SRC_FILES := freg.c

LOCAL_LDLIBS += -llog

include $(BUILD_SHARED_LIBRARY)
最后使用NDK来编译生成so库文件,1)、运行cygwin,输入命令cd C:/cygwin/usr/local/android/android-ndk-r6b/samples/JNItest,进入到JNItest目录。
2)、输入"$NDK/ndk-build",执行成功后,它会自动生成一个libs目录,把编译生成的.so文件放在里面。($NDK是调用我们之前配置好的环境变量,ndk-build是调用ndk的编译程序)。
finally,在Android应用层代码通过类访问驱动,代码如下:
package com.lcl.whut_open;

import android.os.Bundle;
import android.app.Activity;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;

public class MainActivity extends Activity {

private final static String LOG_TAG = "com.lcl.whut_open.MainActivity";

public int fd=0;
public int val;

private EditText valueText = null;
private EditText EditText01 = null;
private Button openButton = null;
private Button readButton = null;
private Button writeButton = null;
private Button closeButton = null;


private Button.OnClickListener writebutton_listener=new Button.OnClickListener()
{
public void onClick(View v)
{
int i=-1;
val=4;
i=Jni_open.write(val);
Log.d(LOG_TAG, "write success");
String text = String.valueOf(i);
valueText.setText(text);
}
};
private Button.OnClickListener openbutton_listener=new Button.OnClickListener()
{
public void onClick(View v)
{

fd=Jni_open.open();
if(-1==fd){
Log.d(LOG_TAG, "open device error!");
}

String text = String.valueOf(fd);
EditText01.setText(text);
}
};

private Button.OnClickListener closebutton_listener=new Button.OnClickListener()
{
public void onClick(View v)
{
fd=Jni_open.close();
if(-1==fd)
Log.d(LOG_TAG, "close device error!");
String text = String.valueOf(fd);
EditText01.setText(text);
valueText.setText(text);

}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);

valueText = (EditText)findViewById(R.id.edit_value);
EditText01 = (EditText)findViewById(R.id.EditText01);
openButton= (Button)findViewById(R.id.button_open);
readButton= (Button)findViewById(R.id.button_read);
writeButton= (Button)findViewById(R.id.button_write);
closeButton= (Button)findViewById(R.id.button_close);

String text = String.valueOf(fd);
EditText01.setText(text);

openButton.setOnClickListener(openbutton_listener);
// readButton.setOnClickListener(readbutton_listener);
writeButton.setOnClickListener(writebutton_listener);
closeButton.setOnClickListener(closebutton_listener);


}
至此整个编写过程已经完成,接下来就是将应用软件安装到imx536开发板上(需要注意的是,安装apk之前必须在电脑上运行360手机助手之类的软件,要不然无法直接运行程序,++,诡异的开发板,花了哥大把时间在这上面。),就可发现apk软件来控制freg驱动程序了。(应用程序的界面图就不提供了,和老罗的应用程序界面基本一样,太麻烦,懒人一枚望见谅。)
望此文对新手们有用,当然我也是新手一枚。




    推荐阅读