这个模块共有四篇1.实现 Android 字符设备驱动2.Android 15 及以上版本创建系统级 app 并测试驱动3.在 Android 系统中自定义 LedManagerService 服务并提供给 app 使用4.为 LedManagerService 添加区权限申请功能一、开发环境LineageOS 23.2 Android 16Ubuntu 24.04.4 LTS红米9 lancelot已解锁 BL 并刷如 LineageOS 23.2二、实现字符设备驱动这里以模拟LED为例实现一个字符设备驱动用于控制LED的亮灭。首先在 YourSource/kernel/xiaomi/mt6768/drivers/char 目录下创建一个目录 myled用于存放字符设备驱动的源文件。创建驱动文件 YourSource/kernel/xiaomi/mt6768/drivers/char/myled/myled.c#includelinux/module.h#includelinux/kernel.h#includelinux/init.h#includelinux/fs.h#includelinux/cdev.h#includelinux/uaccess.h#includelinux/miscdevice.h#defineLED_ON1#defineLED_OFF0staticintled_fd-1;staticintled_stateLED_OFF;staticssize_tmyled_write(structfile*filp,constchar__user*buf,size_tcount,loff_t*f_pos){printk(KERN_ALERT############# myled_write ########\n);charled_on;if(count!1)return-EINVAL;if(copy_from_user(led_on,buf,1))return-EFAULT;if(led_onLED_ONled_state!LED_ON){// 确保LED硬件处于关闭状态再打开// ... 执行打开LED的操作 ...}elseif(led_onLED_OFFled_state!LED_OFF){// 确保LED硬件处于打开状态再关闭// ... 执行关闭LED的操作 ...}else{// 如果请求的LED状态与当前状态相同则无需操作return0;}led_stateled_on?LED_ON:LED_OFF;return1;}staticssize_tmyled_read(structfile*file,char__user*buf,size_tcount,loff_t*ppos){printk(KERN_ALERT############# myled_read ########\n);// 实现读逻辑return0;}staticconststructfile_operationsmyled_fops{.ownerTHIS_MODULE,.readmyled_read,.writemyled_write,};staticstructmiscdevicemyled_misc{.minorMISC_DYNAMIC_MINOR,.namemyled,.fopsmyled_fops,.mode0666,// 根据安全需求调整这里设置无效需要单独配置 SELinux 和 UAC 权限};staticint__initled_init(void){// 用 misc_register() 而非 register_chrdev()因为前者会自动处理设备号分配并触发热插拔事件简化设备节点的创建// led_fd register_chrdev(0, myleddev, myled_fops);// return 0;returnmisc_register(myled_misc);}staticvoid__exitled_exit(void){// unregister_chrdev(led_fd, myleddev);misc_deregister(myled_misc);}module_init(led_init);module_exit(led_exit);MODULE_LICENSE(GPL);MODULE_AUTHOR(LED);MODULE_DESCRIPTION(A simple LED driver for Android.);创建配置文件 YourSource/kernel/xiaomi/mt6768/drivers/char/myled/Kconfigconfig MY_LED boolMy Led Testdefaulty help This is a led demo to test kernel experiment On Android.创建 Makefile 文件 YourSource/kernel/xiaomi/mt6768/drivers/char/myled/Makefile#obj-m 会编译成 myled.o 文件,这里使用 obj-y 直接编译到 boot.img 中obj-ymyled.o三、将驱动配置到 kernelconfig 中配置好后才能编译到 boot.img 中在 YourSource/kernel/xiaomi/mt6768/drivers/char/Kconfig 中添加以下内容sourcedrivers/char/myled/Kconfig在 YourSource/kernel/xiaomi/mt6768/drivers/char/Makefile 中添加以下内容obj-ymyled/四、配置 SELinux 权限在 YourSource/device/xiaomi/mt6768-common/sepolicy/vendor/file.te 中添加以下内容#myled为led驱动定义一个设备类型以方便SELinux权限管理type myled_device,dev_type;在 YourSource/device/xiaomi/mt6768-common/sepolicy/vendor/file_contexts 中添加以下内容#myled/dev/myled u:object_r:myled_device:s0因为 myled 挂载在 /dev 下面所以在 file_contexts 中添加上面的权限即可如果是在 /sys 下面需要使用 genfscon sysfs 来添加权限请自行搜索 genfscon sysfs、genfscon debugfs 和 genfscon devtmpfs 的使用方法。在 YourSource/device/xiaomi/mt6768-common/sepolicy/vendor/system_app.te 中添加以下内容#myledallow system_app myled_device:chr_file{getattr open read write ioctl};五、配置 UAC 权限在 YourSource/device/xiaomi/mt6768-common/rootdir/etc/ueventd.mtk.rc 中添加以下内容/dev/myled 0660 system system六、编译并刷入镜像驱动在 boot 分区需要编译 boot.img 文件# 编译 boot.img 文件mka bootimage# 进入 fastboot 模式adbrebootbootloader# 刷入 boot.img 文件fastboot flash boot boot.imgSELinux 配置在 vendor 分区需要编译 vendor.img 文件# 编译 vendor.img 文件mka vendorimage# android 10 以上需要进入 fastbootd 模式adbrebootfastboot# 刷入 vendor.img 文件fastboot flash vendor vendor.img七、测试驱动验证驱动是否刷入成功执行下面的命令后显示如下则说明正确配置并刷入了。(base)testtest:~$ adb shellls-l/dev/myled crw-rw----1system system10,612026-09-2810:55 /dev/myled(base)testtest:~$ adb shellls-Z/dev/myled u:object_r:myled_device:s0 /dev/myled因为 LED 驱动在 system 域所以需要创建个系统级 app 来测试驱动。由于 Android 15 及以上版本在 app 中添加 sharedUserId“android.uid.system” 并不能实现系统级权限所以还是在下一篇中介绍怎么处理吧。八、总结驱动在 boot 分区需要编译 boot.img 文件SELinux 配置在 vendor 分区需要编译 vendor.img 文件而 Android 10 以上需要进入 fastbootd 模式