上海古都建筑设计集团,上海办公室装修设计公司,上海装修公司高质量的内容分享社区,上海装修公司我们不是内容生产者,我们只是上海办公室装修设计公司内容的搬运工平台

rk3566-Android11 从驱动到 app 第二章添加 hall 层

guduadmin241月前

文章目录

    • 1. 数据结构
      • 1) hw_module_t
      • 2) hw_module_methods_t
      • 3) hw_device_t
      • 2. 程序编写
      • 3. 编译程序
      • 4. 验证程序
      • 5. 添加权限
        • 1) 设备节点添加权限
        • 2) 添加 shell linux 权限

          作者: baron

              对 linux 驱动程序进行封装,其主要设计意图是向下屏蔽设备以及其驱动的实现细节,向上为系统服务以及 Framework 提供提供统一的设备访问接口。就是 linux 驱动只提供硬件读写接口, 业务逻辑通过 hall 封装成 so 库. 这样就不用遵循 kernel 的 gpl 开源协议, 从而保护厂商的利益. 不过也因为这个原因安卓被 linux 踢出了内核主线程.

          1. 数据结构

          1) hw_module_t

          用来表示硬件的抽象

          • 每一个模块都必须自定义一个硬件抽象层模块结构体,而且他的第一个成员变量的类型必须为 hw_module_t.
          • 硬件抽象层每一个模块都必须声明为HAL_MODULE_INFO_SYM
          • 结构体 hw_module_t的成员变量 tag的值必须设置为HARDWARE_MODULE_TAG
          • dso 用来保存加载硬件抽象层模块后得到的句柄值.
            // libhardware/include/hardware/hardware.h
            typedef struct hw_module_t {
                uint32_t tag;  // 值必须声明为 HARDWARE_MODULE_TAG
                uint16_t module_api_version;     // 模块 API 版本
            #define version_major module_api_version
                uint16_t hal_api_version;        // HAL API 版本
            #define version_minor hal_api_version
                const char *id;       // 模块的唯一标识符, 通过该标识符查找该 module
                const char *name;     // 模块的名称
                const char *author;   // 模块的作者
                struct hw_module_methods_t* methods;  // 模块的方法集合
                void* dso;  // 模块的共享对象(动态共享库)
            #ifdef __LP64__
                uint64_t reserved[32-7];  // 保留字段,64 位系统上使用 64 位整数数组
            #else
                uint32_t reserved[32-7];  // 保留字段,32 位系统上使用 32 位整数数组
            #endif
            } hw_module_t;
            

            2) hw_module_methods_t

            封装 open 函数, 通过 open 函数获取 hw_device_t

            // libhardware/include/hardware/hardware.h
            typedef struct hw_module_methods_t {
                int (*open)(const struct hw_module_t* module, const char* id,
                        struct hw_device_t** device);
            } hw_module_methods_t;
            

            3) hw_device_t

            open 函数返回的结构, 硬件设备结构的第一个结构.

            • tag的值必须设置为HARDWARE_DEVICE_TAG
            • close 回调接口用来关闭设备
              // libhardware/include/hardware/hardware.h
              typedef struct hw_device_t {
                  uint32_t tag;               // 赋值为 HARDWARE_DEVICE_TAG
                  uint32_t version;           // 版本号
                  struct hw_module_t* module; // 属于哪个 hw_module_t 
              #ifdef __LP64__
                  uint64_t reserved[12];
              #else
                  uint32_t reserved[12];
              #endif
                  int (*close)(struct hw_device_t* device); // close 方法
              } hw_device_t;
              

              有了这几个接口就可以用来封装我们驱动接口了.

              2. 程序编写

              创建头文件: hardware/libhardware/include/hardware/hello.h内容如下.

              // include/hardware/hello.h
              #ifndef ANDROID_INCLUDE_HARDWARE_HELLO_H
              #define ANDROID_INCLUDE_HARDWARE_HELLO_H
              #include 
              #include 
              #include 
              #include 
              #include 
              #include 
              #define HELLO_HARDWARE_MODULE_ID "hello"
              // 创建一个 hello_module_t 类用来描述硬件的抽象
              // 它的第一个结构必须是 hw_module_t
              // 它必须被实例化为 HAL_MODULE_INFO_SYM
              typedef struct hello_module {
                  struct hw_module_t common;
              }hello_module_t;
              // 硬件设备结构 hello_device
              // 它的第一个结构必须为 hw_device_t, 因为这样就可以通过 hw_device_t 拿到 hello_device
              typedef struct hello_device {
                  struct hw_device_t common;
                  int fd;
                  int (*write_string)(struct hello_device* dev, const char *str);
                  int (*read_string)(struct hello_device* dev, char* str);
              }hello_device_t;
              #endif /* ANDROID_INCLUDE_HARDWARE_HELLO_H  */
              

              创建 hardware/libhardware/modules/hello/hello.c文件

              // hardware/libhardware/modules/hello/hello.c`
              #define LOG_TAG "Legacy HelloHAL"
              #include 
              #include 
              #include 
              #include 
              #include 
              #include 
              #include 
              #include 
              #include 
              #include 
              #include 
              #include 
              #include 
              #define DEVICE_NAME "/dev/hello"
              #define MODULE_NAME "Default Hello HAL"
              #define MODULE_AUTHOR "The Android Open Source Project"
              // 接口声明
              static int hello_device_open(const struct hw_module_t* module, const char* name, struct hw_device_t** device);
              static int hello_device_close(struct hw_device_t* device);
              static int hello_write_string(struct hello_device* dev, const char * str);
              static int hello_read_string(struct hello_device* dev, char* str);
              // 创建 hw_module_methods_t 用来提供 open 方法
              static struct hw_module_methods_t hello_module_methods = {
                  .open = hello_device_open,
              };
              // 实例化 hello_module_t 硬件抽象模块为 HAL_MODULE_INFO_SYM
              // ******** 必须实例化为 HAL_MODULE_INFO_SYM 这个名字不能变
              hello_module_t HAL_MODULE_INFO_SYM = {
                  .common = {
                      .tag = HARDWARE_MODULE_TAG, // 必须设置为这个 tag
                      .module_api_version = 1,
                      .hal_api_version = 1,
                      .id = HELLO_HARDWARE_MODULE_ID, // 通过这个查找对应的 moduel
                      .name = MODULE_NAME,
                      .author = MODULE_AUTHOR,
                      .methods = &hello_module_methods, // 设置 open 方法
                  },
              };
              // open 方法的具体实现
              static int hello_device_open(const struct hw_module_t* module, const char* name, struct hw_device_t** device)
              {
                  // 创建一个 hello_device_t 结构
                  hello_device_t *dev = malloc(sizeof(hello_device_t));
                  memset(dev, 0, sizeof(hello_device_t));
                  ALOGE("Hello: hello_device_open name = %s",name);
                  dev->common.tag = HARDWARE_DEVICE_TAG; // 必须设置为 HARDWARE_DEVICE_TAG
                  dev->common.version = 0;
                  dev->common.module = (hw_module_t*)module; // 设置 module
                  dev->common.close = hello_device_close;    // 设置关闭设备接口
                  dev->write_string = hello_write_string;    // 设置 write 方法
                  dev->read_string = hello_read_string;      // 设置 read 方法
                  // 打开设备
                  if((dev->fd = open(DEVICE_NAME, O_RDWR)) == -1) {
                      ALOGE("Hello: open /dev/hello fail-- %s.", strerror(errno));free(dev);
                      return -EFAULT;
                  }
                  // 返回 hw_device_t 结构
                  *device = &(dev->common);
                  ALOGE("Hello: open /dev/hello successfully.");
                  return 0;
              }
              // 关闭设备释放资源
              static int hello_device_close(struct hw_device_t* device) 
              {
                  // 通过 device 可以拿到 hello_device
                  struct hello_device* hello_device = (struct hello_device*)device;
                  if(hello_device) {
                      close(hello_device->fd);
                      free(hello_device);
                  }
                  return 0;
              }
              // 写方法实现
              static int hello_write_string(struct hello_device* dev,const char * str)
              {
                  ALOGE("Hello:write string: %s", str);
                  write(dev->fd, str, sizeof(str));
                  return 0;
              }
              // 读方法实现
              static int hello_read_string(struct hello_device* dev, char* str)
              {
                  ALOGE("Hello:read hello_read_string");
                  read(dev->fd,str, sizeof(str));
                  return 0;
              }
              

              3. 编译程序

              创建 hardware/libhardware/modules/hello/Android.bp添加内容如下.

              cc_library_shared {
                  name: "hello.default",
                  relative_install_path: "hw",
                  proprietary: true,
                  srcs: ["hello.c"],
                  cflags: ["-Wall", "-Werror"],
                  header_libs: ["libhardware_headers"],
                  shared_libs: [
                      "liblog",
                      "libcutils",
                      "libutils",
                  ],
              }
              

              在 build/make/target/product/full_base.mk中添加如下内容, 将我们的添加的 hall 库编译进系统.对应的位置为 /vendor/lib/hw/hello.default.so.

              diff --git a/target/product/full_base.mk b/target/product/full_base.mk
              index ffd3cde11a..9f7270bd2f 100644
              -- a/target/product/full_base.mk
              ++ b/target/product/full_base.mk
              @@ -32,7 +32,8 @@ PRODUCT_PACKAGES += \
               #   audio.a2dp.default is a system module. Generic system image includes
               #   audio.a2dp.default to support A2DP if board has the capability.
               PRODUCT_PACKAGES += \
              -    audio.a2dp.default
              +    audio.a2dp.default \
              +       hello.default
              

              运行 ./build.sh -UKAup编译代码. 编译完成之后可以在 out 目录下发现 hello.default

              $ find out/ -name "hello\.default"
              out/soong/.intermediates/hardware/libhardware/modules/hello/hello.default
              

              4. 验证程序

              添加验证代码 frameworks/base/services/core/jni/com_android_server_AlarmManagerService.cpp修改如下

              rk3566-Android11 从驱动到 app 第二章添加 hall 层,第1张

              对应代码

              #include 
              #include 
              struct hello_device* hello_device = NULL;
               static inline int hello_device_open(const hw_module_t* module, struct hello_device** device)
              {
                   return module->methods->open(module, HELLO_HARDWARE_MODULE_ID, (struct hw_device_t**)device);
               }
              static jint HelloServiceInit()
              {
                  ALOGE("HelloServiceInit HelloServiceInit");
                  const hw_module_t *hw_module = NULL;
                  ALOGE("Hello JNI: initializing......");
                  // 通过 HELLO_HARDWARE_MODULE_ID 找到对应的 hw_module
                  if(hw_get_module(HELLO_HARDWARE_MODULE_ID, &hw_module) == 0) {
                      ALOGE("Hello JNI: hello Stub found.");
                      // 调用 open 接口获取到 hello_device
                      if(hello_device_open(hw_module, &hello_device) == 0) {
                        ALOGE("Hello JNI: hello device is open.");
                        return 0;
                      }
                      ALOGE("Hello JNI: failed to open hello device.");
                      return -1;
                  }
                  ALOGE("Hello JNI: failed to get hello stub hw_module.");
                  return -1;
              }
              

              修改 system/sepolicy/vendor/file_contexts添加库的位置让系统能够找到, 该正则表达式指定了库的位置为 /vendor/lib64/hw/hello.default.so

              diff --git a/vendor/file_contexts b/vendor/file_contexts
              index 1b2bc2357..92c166b6c 100644
              -- a/vendor/file_contexts
              ++ b/vendor/file_contexts
              @@ -86,6 +86,7 @@
               /(vendor|system/vendor)/lib(64)?/hw/android\.hardware\.graphics\.mapper@4\.0-impl\.so u:object_r:same_process_hal_file:s0
               /(vendor|system/vendor)/lib(64)?/hw/android\.hardware\.renderscript@1\.0-impl\.so     u:object_r:same_process_hal_file:s0
               /(vendor|system/vendor)/lib(64)?/hw/gralloc\.default\.so                              u:object_r:same_process_hal_file:s0
              +/(vendor|system/vendor)/lib(64)?/hw/hello\.default\.so                                u:object_r:same_process_hal_file:s0
              

              刷机开机打印 log 如下

              01-18 07:32:55.775   419   419 E AlarmManagerService: HelloServiceInit HelloServiceInit
              01-18 07:32:55.776   419   419 E AlarmManagerService: Hello JNI: initializing......
              01-18 07:32:55.778   419   419 E AlarmManagerService: Hello JNI: hello Stub found.
              01-18 07:32:55.778   419   419 E Legacy HelloHAL: Hello: hello_device_open name = hello
              01-18 07:32:55.778   419   419 E Legacy HelloHAL: Hello: open /dev/hello fail-- Permission denied.
              01-18 07:32:55.778   419   419 E AlarmManagerService: Hello JNI: failed to open hello device.
              

              提示没没有权限

              5. 添加权限

              1) 设备节点添加权限

              给我们的设备节点添加权限修改路径 system/core/rootdir/如下

              diff --git a/rootdir/ueventd.rc b/rootdir/ueventd.rc
              index 1550894ce..428cc1ec2 100644
              -- a/rootdir/ueventd.rc
              ++ b/rootdir/ueventd.rc
              @@ -39,6 +39,7 @@ subsystem sound
               /dev/vndbinder            0666   root       root
               /dev/pmsg0                0222   root       log
              +/dev/hello                0666   root       root
               # kms driver for drm based gpu
               /dev/dri/*                0666   root       graphics
              

              添加权限之后报错如下

              01-17 09:52:50.271   265   265 E MtpDeviceJNI: HelloServiceInit HelloServiceInit
              01-17 09:52:50.272   265   265 E MtpDeviceJNI: Hello JNI: initializing......
              // 多了这个信息需要增加 selinux 权限
              01-17 09:52:50.276   265   265 W main    : type=1400 audit(0.0:17): avc: denied { read write } for name="hello" dev="tmpfs" ino=11079 scontext=u:r:zygote:s0 tcontext=u:object_r:device:s0 tclass=chr_file permissiv
              e=0
              01-17 09:52:50.280   265   265 E MtpDeviceJNI: Hello JNI: hello Stub found.
              01-17 09:52:50.280   265   265 E Legacy HelloHAL: Hello: hello_device_open name = hello
              01-17 09:52:50.281   265   265 E Legacy HelloHAL: Hello: open /dev/hello fail-- Permission denied.
              01-17 09:52:50.281   265   265 E MtpDeviceJNI: Hello JNI: failed to open hello device.
              

              2) 添加 shell linux 权限

              1. 在 system/sepolicy/public/device.te中添加类别为 hello_device 的对象, 并且设置 attribute 为 dev_type. 修改如下
              diff --git a/public/device.te b/public/device.te
              index 32563d67c..cc6fc2881 100644
              -- a/public/device.te
              ++ b/public/device.te
              @@ -39,6 +39,7 @@ type serial_device, dev_type;
               type socket_device, dev_type;
               type owntty_device, dev_type, mlstrustedobject;
               type tty_device, dev_type;
              +type hello_device, dev_type;
               type video_device, dev_type;
               type zero_device, dev_type, mlstrustedobject;
               type fuse_device, dev_type, mlstrustedobject;
              

              修改的文件如下,修改的内容和上面是一样的.:

              rk3566-Android11 从驱动到 app 第二章添加 hall 层,第2张

              1. 将 /dev/hello 设备节点和 SELinux 类别为 hello_device 的对象进行关联, 即我们前面创建的. 如下所示
              zhaosheng@YF-zhaosheng:~/work2/ad500/system/sepolicy$ gf private/file_contexts
              diff --git a/private/file_contexts b/private/file_contexts
              index a5763bdf4..4475b1598 100755
              -- a/private/file_contexts
              ++ b/private/file_contexts
              @@ -102,6 +102,7 @@
               /dev/input(/.*)?       u:object_r:input_device:s0
               /dev/iio:device[0-9]+   u:object_r:iio_device:s0
               /dev/ion               u:object_r:ion_device:s0
              +/dev/hello             u:object_r:hello_device:s0
               /dev/keychord   u:object_r:keychord_device:s0
               /dev/loop-control      u:object_r:loop_control_device:s0
               /dev/modem.*           u:object_r:radio_device:s0
              
              •  /dev/hello:表示规则适用于 /dev/hello这个设备节点
              •  u:object_r:hello_device:s0:指定 SELinux 上下文,hello_device是 SELinux 类别,s0表示 SELinux 安全等级为 0

                需要修改的文件如下, 修改的内容和上面是一模一样的.

                rk3566-Android11 从驱动到 app 第二章添加 hall 层,第3张

                编译完成后报错如下

                01-18 07:07:17.681   421   421 E AlarmManagerService: HelloServiceInit HelloServiceInit
                01-18 07:07:17.681   421   421 E AlarmManagerService: Hello JNI: initializing......
                01-18 07:07:17.683   421   421 W system_server: type=1400 audit(0.0:17): avc: denied { read write } for name="hello" dev="tmpfs" ino=3901 scontext=u:r:system_server:s0 tcontext=u:object_r:hello_device:s0 tclass=c
                hr_file permissive=0
                01-18 07:07:17.683   421   421 E AlarmManagerService: Hello JNI: hello Stub found.
                01-18 07:07:17.683   421   421 E Legacy HelloHAL: Hello: hello_device_open name = hello
                01-18 07:07:17.683   421   421 E Legacy HelloHAL: Hello: open /dev/hello fail-- Permission denied.
                01-18 07:07:17.683   421   421 E AlarmManagerService: Hello JNI: failed to open hello device.
                01-18 07:07:17.685   421   421 E UsbAlsaJackDetectorJNI: Can't register UsbAlsaJackDetector na
                
                1. 增加 avc 权限

                关键信息是这句话缺少 avc 权限, 请注意前面的报错是 tcontext=u:object_r:device这里是 tcontext=u:object_r:hello_device说前面的 hello_device 修改已经生效.

                01-18 07:07:17.683   421   421 W system_server: type=1400 audit(0.0:17): avc: denied { read write } for name="hello" dev="tmpfs" ino=3901 scontext=u:r:system_server:s0 tcontext=u:object_r:hello_device:s0 tclass=c
                hr_file permissive=0
                
                • 缺少什么权限: denied { read write }==> 缺少 rw_file_perms权限
                • 那个文件缺少权限: scontext=u:r:system_server:s0==> system_server.te这个文件
                • 谁缺少权限: tcontext=u:object_r:hello_device:s0==> hello_device这个对象
                • 文件类型: tclass=chr_file ==> chr_file字符设备

                  这里的知识详细请参考: 浅谈SEAndroid安全机制及应用方法

                  于是在 system/sepolicy/private/system_server.te增加

                  diff --git a/private/system_server.te b/private/system_server.te
                  index 3c1d192d7..d742471b1 100644
                  -- a/private/system_server.te
                  ++ b/private/system_server.te
                  @@ -372,6 +372,7 @@ allow system_server video_device:chr_file rw_file_perms;
                   allow system_server adbd_socket:sock_file rw_file_perms;
                   allow system_server rtc_device:chr_file rw_file_perms;
                   allow system_server audio_device:dir r_dir_perms;
                  +allow system_server hello_device:chr_file rw_file_perms;
                   # write access to ALSA interfaces (/dev/snd/*) needed for MIDI
                   allow system_server audio_device:chr_file rw_file_perms;
                  

                  修改的文件如下, 修改的内容和上面是一样的.

                  rk3566-Android11 从驱动到 app 第二章添加 hall 层,第4张

                  修改完成之后再次烧录验证查看 log, 正常发现设备正常打开 hall 层添加成功. 真不容易啊 =-=.

                  01-18 07:44:49.688   415   415 E AlarmManagerService: HelloServiceInit HelloServiceInit
                  01-18 07:44:49.688   415   415 E AlarmManagerService: Hello JNI: initializing......
                  01-18 07:44:49.690   415   415 E AlarmManagerService: Hello JNI: hello Stub found.
                  01-18 07:44:49.691   415   415 E Legacy HelloHAL: Hello: hello_device_open name = hello
                  01-18 07:44:49.691   415   415 E Legacy HelloHAL: Hello: open /dev/hello successfully.
                  01-18 07:44:49.691   415   415 E AlarmManagerService: Hello JNI: hello device is open.
                  

                  验证 hall 需要修改的 selinux 相关文件如下. 全部都要改到不要偷懒.

                  rk3566-Android11 从驱动到 app 第二章添加 hall 层,第5张

                  参考文章:

                  https://blog.csdn.net/Luoshengyang/article/details/6567257

                  https://developer.aliyun.com/article/651348

网友评论

搜索
最新文章
热门文章
热门标签
 
 梦见别人杀鱼的预兆  周公解梦官网大全查询梦2345原版  女人梦到乌云密布黑云遮天