• 6.4 Android硬件访问服务编写HAL代码


    JNI向上提供本地函数,向下加载HAL文件,并调用HAL的函数;

    HAL负责访问驱动程序执行硬件操作

    JNI和HAL都是用c语言或者C++语言编写的,JNI加载HAL的实质就是使用dlopen加载动态库文件

    安多人源代码中第dlopen做了一层封装,在JNI中是通过hw_get_module来加载动态库

    externalchromium_org hird_partyhwcplussrchardware.c
    hw_get_module("led")//分析hw_get_module

      1. 模块名==>文件名
        hw_get_module_by_class("led", NULL)
          name = "led"
            property_get(prop_name,prop,NULL)     prop_name是某个属性,根据属性来获得prop值
            hw_module_exists 判断是否存在led.prop.so
    (在运行的Android系统中执行 getprop ro.hardware可以查看这个ro.hardware属性存在么,并打印其值)

      2. 加载
        load
          dlopen(filename)
          dlsym("HMI") 从SO文件中获得名为HMI的hw_module_t结构体
          strcmp(id, hmi->id) 判断名字是否一致(hmi->id, "led")

          如果一致,把找到的hmi结构体传出去

    hw_module_exists(char *path, size_t path_len, const char *name,const char *subname)

    led.tiny4412.so(不存在)
    led.exynos4.so(不存在)
    led.default.so(存在)

    它用来判断"name"."subname".so文件是否存在
    查找的目录:
    a. HAL_LIBRARY_PATH 环境变量
    b. /vendor/lib/hw
    c. /system/lib/hw    //4412开发板只会去这个目录下去查找,其他几个目录都没设置

     
    property_get : 属性系统
    属性<键,值> <name, value>

    JNI 怎么使用 HAL
    a. hw_get_module 获得一个hw_module_t结构体
    b. 调用 module->methods->open(module, device_name, &device) //module里面有多个device
      获得一个hw_device_t结构体
      并且把hw_device_t结构体转换为设备自定义的结构体

    HAL 怎么写
    a. 实现一个名为HMI的hw_module_t结构体
    b. 实现一个open函数, 它会根据name返回一个设备自定义的结构体
      这个设备自定义的结构体的第1个成员是 hw_device_t结构体
      还可以定义设备相关的成员

    打印信息简介:
    a. 有三类打印信息: app, system, radio
    程序里使用 ALOGx, SLOGx, RLOGx来打印(分别对应应用打印信息、系统打印信息,Radio打印信息)
    b. x表示6种打印级别,有:
    V Verbose
    D Debug
    I Info
    W Warn
    E Error
    F Fatal

    比如:
    #define LOG_TAG "LedHal"
    ALOGI("led_open : %d", fd);

    c. 打印出来的格式为:
    I        / LedHal     ( 1987)   : led_open : 65
    (级别) LOG_TAG 进程号 打印信息

    d. 在开发板上使用 logcat 命令查看 或者logcat LEDHAL:I *:S(过滤规则) 或者logcat | grep “LedHal”
    logcat LedHal:I *:S//*.S表示其他信息不打印

    过滤规则:<tag>[:priority]

    实现led_hal.c

     /*a. 实现一个名为HMI的hw_module_t结构体*/
    /*b. 实现一个open函数, 它会根据name返回一个设备自定义的结构体led_device_t*/

    /*c.实现led_device_t结构体*/

    /*参看文件hardwarelibhardwaremodulesvibratorvibrator.c*/

    #define LOG_TAG "LedHal"//ALOGI会用到这个宏定义来打印,然后在打印信息中我们可以通过筛选Ledhal来区分不同的打印信息

    #include <hardware/led_hal.h>

    #include <hardware/hardware.h>

    ......还有很多头文件.........

    static int fd;

    static int led_open(struct led_device_t *dev)

    {

        fd = open("/dev/leds",O_RDWR);

        ALOGI(“ ledOpen:%d”,fd);//打印

        if(fd >=0)

          return 0;

        else

          return -1;

    }

    static int led_close(struct led_device_t *dev){

      close(fd);

      return 0;

    }

    static int led_ctrl(struct led_device_t *dev,int which,int status)

    {

        int ret = ioctl(fd,status,which);

        return ret;

    }

    static struct led_device_t led_dev = {

      .common = {

      .close = led_close , 

      },

      .led_open = led_open ,

      .led_ctrl = led_ctrl ,

    };

    static int led_device_open(const struct hw_module_t *module,const char *id,struct hw_device_t **device)

    {

      //正常的做法是通过id找到led_device_t ,这里有位只有一个led_device_t,就没有查找了

      *device = &led_dev //led_dev 的第一个成员就是hw_device_t ,他们地址一样

    }

    static struct hw_module_methods_t led_module_methods {

      .open = led_device_open;

    };

    struct hw_module_t HAL_MODULE_INFO_SYM = {

      //.tag = HARDWARE_MODULE_TAG,

      //.module_api_version = ........,

      //.hal_api_version = HARDWARE_HAL_API_VERSION,

      .id = "led ",//JNI中通过hw_get_module('led')来获得hw_module_t 

      //.name =,

      //.auth,

      .methods = led_module_methods;

    }

    实现led_hal.h 

    #ifndef ANDROID_LED_INTERFACE_H

    #define ANDROID_LED_INTERFACE_H

    #include <stdint.h>

    #include <sys/cdefs.h>

    #include <sys/types.h>

    #include <hardware/hardware.h>

    __BEGIN_DECLS

    struct led_device_t {

      struct hw_device_t common;

      int (*led_open)(struct led_device_t *dev);

      int (*led_ctrl)(struct led_device_t *dev,int which,int status);

    }

    __END_DECLS

    #endif

    修改之前写的JNI文件com_android_server_LedService.cpp

      #define LOG_TAG "LedService"

      #include "jni.h"

      #include "JNIHelp.h"

      #include "android_runtime/AndroidRuntime.h"

      #include <utils/misc.h>

      #include <utils/Log.h>

      #include <hardware_legacy/vibrator.h>

      #include <stdio.h>

      //还有一些头问题

      #include <hardware/led_hal.h>

      namespace android

      {

      static led_device_t* led_device;

      jint ledOpen(JNIEnv *env,jobject cls)

      {

        jint err;

        hw_module_t* module;

        hw_device_t* device;

        /*1、调用hw_get_module*/

        err = hw_get_module("led",(hw_module_t const **)&module);

        if(err == 0){

          /*2、调用module->methods->open来get device*/

          err = module->methods->open(module,NULL,&device)

          if(err == 0){

            led_device = (light_device_t *)device;

            /*3、call led_open*/

            return led_device ->led_open(led_device );

          }else{

            return -1;

          }

        }  

        return -1;

      } 

      void ledClose(JNIEnv *env,jobject cls) 

      {

        

      }  

      jint ledCtrl(JNIEnv *env,jobject cls,jint which,jint status)

      {

        return led_device->led_ctrl(led_device,which,status);

      }

      static const JNINativeMethod methods[] = {

        {"native_ledOpen","()I",(void *)ledOpen},

        {"native_ledClose","()V",(void *)ledClose},

        {"native_ledCtrl","(II)I",(void *)ledCtrl},

      };

      int register_android_server_LedService(JNIEnv *env)

      {

        return jniRegisterNativeMethods(env,"com/android/server/LedService",methods,NELEM(methods));

      }

      }

    上传编译:

    (1)、JNI重新上传到

      frameworks/base/services/core/jni/com_android_server_LedService.cpp

    (2)、HAL:led_hal.h和led_hal.c

     hardware/libhardware/include/hardware/led_hal.h

     hardware/libhardware/modules/led/led_hal.c

     hardware/libhardware/modules/led/Android.mk

    Android.mk内容如下:

    LOCAL_PATH := $(call my-dir)

    include $(CLEAR_VARS)

    LOCAL_MODULE := led.default  //指定了最后编译出来的模块是led.default.so,这就和前面分析的通过hw_get_module找so对应上了

    LOCAL_MODULE_RELATIVE_PATH :=hw  //指定了so存在的目录在/system/lib/hw下

    LOCAL_C_INCLUDES := hardware/libhardware  //头文件

    LOCAL__SRC_FILES := led_hal.c  //源文件

    LOCAL_SHARED_LIBRARIES := liblog

    LOCAL_MODULE_TAGS := eng

    include $(BUILD_SHARED_LIBRARY)

    编译:

    mmm frameworks/base/services  //编译JNI

    mmm hardware/libhardware/modules/led   //编译C库 led.default.so

    make snod

    ./gen-img.sh

  • 相关阅读:
    C# 应用
    C# 基础
    C# 基础
    C# 基础
    vs
    C# 基础
    C# 基础
    C# 基础
    C# 基础
    C# 基础
  • 原文地址:https://www.cnblogs.com/liusiluandzhangkun/p/9125810.html
Copyright © 2020-2023  润新知