您的位置:首页 > 编程语言 > Java开发

安卓驱动、HAL、JNI与java

2015-11-24 22:33 501 查看
最近看了安卓驱动层到应用层的实现,总结一下所学,新手学习,不足之处请指正(以LED为例):

网址:/content/9907059.html

由驱动层到应用层的流程Linux驱动->HAL->JNI->APK

首先是驱动层:

1)创建cdev与实现file_operations 。

2)module_init与module_exit的实现:在module_init中实现cdev_init()、register_chrdev_region()或alloc_chrdev_region()与cdev_add(),同时实现class_create()、device_class()。在module_exit中实现device_destroy()、class_destroy()与unregister_chrdev_region()。

3)open与release函数的实现,open函数中实现gpio_request()、s3c_gpio_cfgpin()、gpio_direction_output()函数。release函数中实现gpio_free()。

4)ioctl函数实现

5)MODULE_LICENSE("GPL")

6)对Makefile与Kconfig函数修改。

其次HAL层实现:

HAL层的入口函数为HAL_MODULE_INFO_SYM,调用过程为HAL_MODULE_INFO_SYM-> hw_module_methods_t->open,在open中对包含hw_device_t的结构体进行一系列初始化,并打开LED驱动设备。具体实现过程如下:

1)定义结构体和宏

hw_module_t,hw_device_t及IO,HAL规定不可直接使用hw_module_t结构体,因此,需要在hw_module_t外再套一层结构体。hw_module_t及hw_device_t自定义结构体内的第一个成员变量数据结构必须为hw_module_t与hw_device_t。在hw_device_t自定义的结构体内可定义函数指针,函数指针的数量与参数可自己定义,但必须与上层调用形式保存一致。

2)编写HAL模块的open函数

(1)初始化hw_device_t子结构体、必要操作、硬件操作函数指针。

(2)打开设备文件。

(3)初始化寄存器

3)定义hw_module_methods_t结构体变量

4)定义HAL_MODULE_INFO_SYM变量,一般为hw_module_t或子结构体,并对其初始化。

5)编写HAL模块close函数

6)编写控制函数

7)编写Android.mk

再次编写JNI函数

1)编写JNI_Onload函数,系统在成功装载JNI共享库后自动调用,一般用于初始化JNI,函数如下:主要实现功能:告诉JavaVm使用虚拟机那一个版本:初值设定获取JavaVm接口

/*没有理解JNI_OnLoad函数与register_android_server_LedService函数,若您理解了之后可以留言教我一下吗*/

jint JNI_OnLoad(JavaVM* vm, void* reserved)

{

JNIEnv* env = NULL;

jint result = -1;

if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {

LOGE("GetEnv failed!");

return result;

}

LOG_ASSERT(env, "Could not retrieve the env !");

register_android_server_LedService( env );//将JNI程序库与Java类绑定

return JNI_VERSION_1_4;

}

int register_android_server_LedService(JNIEnv *env)

{

static const char* const kClassName = " android /server/LedService";/*kclassname‍ 指定了需要调用该Jni库的Java APP类*/

jclass clazz;

/* look up the class */

clazz = env->FindClass(kClassName);

if (clazz == NULL)

{

LOGE("Can't find class %s/n", kClassName);

return -1;

}

/* register all the methods */

if (env->RegisterNatives(clazz, method_table,

sizeof(method_table) / sizeof(method_table[0]))
!= JNI_OK)

{

LOGE("Failed registering methods for %s/n", kClassName);

return -1;

}

/* fill out the rest of the ID cache */

return 0;

}

/*JNI与JAVA对应映射表,格式:要注册到java类中的方法名;方法参数与返回值的类型;要注册到JNI的指针函数*/

static JNINativeMethod method_table[] = {

{ "led_init", "()Z", (void*)Java_com_embedsky_led_LedActivity_ledInit },

{ "led_setOn", "(I)Z", (void*)Java_com_embedsky_led_LedActivity_ledSetOn },

{ "led_setOff", "(I)Z", (void*)Java_com_embedsky_led_LedActivity_ledSetOff },

{ "led_close", "()Z", (void*)Java_com_embedsky_led_LedActivity_ledClose },

2)实现method_table[] 中JNI的指针函数,在init中调用hw_get_module函数,实现通过调用hw_get_module函数找到HAL中定义头文件的ID来查找HAL模块,并获得hw_module_t的子结构,来调用hw_module_methods_t中的open函数来初始化hw_device_t的子结构体。

最后实现JAVA函数

1)package xxx/*声明源文件中的类属于哪个具体包,包的名字是有层次的,各层之间以点分割,必须与文件系统结构相同*/

2)import xxx /*将其他包中的类引入当前名字空间中*/

3)public class LedActivity extends Activity {

static {

System.loadLibrary("led");??作用是什么,不太理解?

}

/*在C++中实现native函数,需要特定格式,可以用javah来帮助声明用javac编译我们的java类,获得class文件,然后javah xxx.class 生成.h文件JNI格式按.h文件书写*/

public static native boolean ledInit();/*要将JNI调用的方法做本地声明,关键词native*/

public static native boolean ledClose();

private static native boolean ledSetOn(int number);

private static native boolean ledSetOff(int number);

CheckBox[] cb = new CheckBox[8];

CheckBox cbAll;// 全选

Button btnQuit;// 退出按钮

@Override/*重写父类,加 @Override系统可以帮你检查方法的正确性*/

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.main);

// 获取 xml 中对应的控件

cb[0] = (CheckBox) findViewById(R.id.cbLed1);

cb[1] = (CheckBox) findViewById(R.id.cbLed2);

cb[2] = (CheckBox) findViewById(R.id.cbLed3);

cb[3] = (CheckBox) findViewById(R.id.cbLed4);

cb[4] = (CheckBox) findViewById(R.id.cbLed5);

cb[5] = (CheckBox) findViewById(R.id.cbLed6);

cb[6] = (CheckBox) findViewById(R.id.cbLed7);

cb[7] = (CheckBox) findViewById(R.id.cbLed8);

cbAll = (CheckBox) findViewById(R.id.cbLedAll);

btnQuit = (Button) findViewById(R.id.btnQuit);

// 初始化点击事件对象

// 初始化点击事件对象

MyClickListener myClickListern = new MyClickListener();

// LED1-LED8 选中 / 取消事件

for (int i = 0; i < 8; i++) {

cb[i].setOnClickListener(myClickListern);

}

// 全选选中 / 取消事件

cbAll.setOnClickListener(myClickListern);

// 退出按钮点击事件处理

btnQuit.setOnClickListener(new OnClickListener() {

@Override

public void onClick(View v) {

finish();

}

}

// led 初始化

if (!ledInit()) {

new AlertDialog.Builder(this).setTitle("init led fail").show();

//led 初始化失败,则使控件不可点击

for (int i = 0; i < 8; i++)

cb[i].setEnabled(false);

cbAll.setEnabled(false);

}

}

// 自定义的事件监听器类,用来处理 CheckBox 选中和取消事件

public class MyClickListener implements OnClickListener {

@Override

public void onClick(View v) {

// 遍历数组,判断是哪个 led 控件被选中

for (int i = 0; i < 8; i++) {

if (v == cb[i]) {

// 根据选中 / 取消状态来控制 led 灯的亮 / 灭

controlLed(i + 1, cb[i].isChecked());

return;

}

}

// 全选按钮,遍历数组,对所有 led 灯做控制

if (v == cbAll) {

for (int i = 0; i < 8; i++) {

controlLed(i + 1, cbAll.isChecked());

cb[i].setChecked(cbAll.isChecked());

}

}

}

/*******************************************/

// 功能: LED 亮 / 灭处理

// 参数:

// number : 灯编号

// on :true ,亮 ;fase, 灭

/*******************************************/

private void controlLed(int number, boolean on) {

if (on) {

ledSetOn(number);

} else {

ledSetOff(number);

}

}

}

/content/9907059.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: