安卓驱动、HAL、JNI与java

来源:互联网 发布:ai软件 服装设计 编辑:程序博客网 时间:2024/04/27 02:27

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

网址:http://blog.csdn.net/liruicom/article/details/8517948

由驱动层到应用层的流程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);
}
}
}