OpenHarmony富设备移植指南(4)第三方内核适配与定制 原创 精华
1,OpenHarmony移植为什么这么难?
为什么OpenHarmony的移植这么久才出来,安卓手机厂商开源了内核代码之后LineageOS可以很快跟进,这应该是广大网友都疑惑的事情,我这里可以简单解释一下,这个跟内核与驱动有着直接关系。
下面是我总结的一个简单解释:
Linux设备:标准Linux内核 + 硬件驱动
安卓设备:安卓内核(标准内核+安卓定制)+ 硬件驱动(调用部分定制接口)
OH设备:OH内核(标准内核+OH定制)+ 硬件驱动(调用部分定制接口)
如果安卓设备的驱动调用了安卓内核特有的接口,安卓的驱动就不能用到标准内核上,也不能用在OH内核上,如果安卓的驱动调用的是标准Linux内核的接口,这就可以用到OH设备上,但是这个很少,这也是为什么你们会在pmOS看到有些设备的支持状况是这样的。
很多网友都期待OpenHarmony移植到自己的手机能打电话,以为只要开发者坚持就能成功,这里我可以泼一盆冷水,因为基带芯片的驱动厂商是不开源的,没有驱动源码就不可能有适配OH内核的驱动,厂商也不可能花力气去基于OH内核帮你适配驱动,所以移植适配评估的时候我参考的是pmOS,因为pmOS是用标准Linux内核,Ubuntu Touch的内核为什么不能用?了解过的同学应该知道,Ubuntu Touch用的是安卓内核,它能用安卓驱动,所以小米6得Ubuntu Touch支持打电话,但是pmOS不行。
另外Linux内核版本每次变更都会频繁改动代码,这导致了同样的代码很可能无法编译通过,这也是为什么SOC厂商和驱动厂商都对升级内核版本不积极,可用内核和可用驱动的缺少导致了这么长时间,移植OpenHarmony都是吃力不讨好的事情,并且只能开机点亮,没有驱动,上限被卡死,所以移植这件事不是有人努力移植就行的,希望大家能多多理解。
2,OH内核特性移植
在OH官方的doc仓中,标准内核介绍里有OH内核特性的部分讲解(如下图),可惜这个只是部分,一些更基础的驱动没有列出来,接下来我们先移植基础的部分,保证能开机亮屏,更高级一点的特性先不移植。
zh-cn/device-dev/kernel · OpenHarmony/docs - 码云 - 开源中国 (gitee.com)
2.1 添加设备内核编译配置文件
上篇文章【OH编译框架适配与定制】中我们已经把源码下载到kernel/linux/linux-sagit目录下,接下来我们找到【从postmarketOS获取移植资源】文章中解包出的config配置,把config放到device/board/xiaomi/sagit/kernel/configs下并重命名为sagit_oh_defconfig,因为我是定制过Linux编译流程的,我的编译脚本把会把sagit_oh_defconfig复制到linux-sagit/arch/arm64/configs下。
熟悉Linux内核编译的同学也可以按照自己的思路做,这一部只是简单的添加移植设备的编译配置。
2.2 移植staging下OH添加的hilog,hievent,hisysevent,zerohung,hungtask,blackbox驱动
2.2.1 更新最新内核代码
移植驱动前,我们先更新官方内核到最新版,尽量保证驱动没有bug
cd ~/ohos_beta3/kernel/linux/linux-5.10/
git fetch origin
git checkout origin/master
2.2.2 复制代码,修正Kconfig,Makefile
复制linux-5.10/driver/staging/下的hilog,hievent,hisysevent,zerohung,hungtask,blackbox源码到linux-sagit/driver/staging/目录下。
修改linux-sagit/driver/staging/下的Kconfig文件,在末尾添加如下信息
修改linux-sagit/driver/staging/下的Makefile文件,在末尾添加如下信息
只是复制staging下的文件还不行,编译的时候会报错,还有些头文件缺失,
复制linux-5.10/include下的dfx文件夹到linux-sagit/include下,
同时linux-5.10/include/linux/下的三个头文件
blackbox.h,blackbox_storage.h,blackbox_common.h
也需要复制到对应的linux-sagit/include/linux/下,补全头文件。
2.2.3 修复get_fs(),set_fs()函数缺失问题
头文件补全之后编译仍会报错,我调查发现这是因为mm_segment_t,get_fs(),set_fs()等结构体跟函数已经在新版内核中移除了,而且是在5.10内核中标记移除的,不懂为什么OH的内核维护者不移除掉,这个操作因为会导致安全问题,现代cpu已经不支持了,所以我们可以大胆的去掉这部分代码,我实际验证也是不影响内核运行,所以搜索我们移植的文件,把这些都删掉吧。
这是我的改动,注释掉的部分就是已经无用的代码。
2.2.3 修复inode_permission(),vfs_mkdir(),vfs_unlink()函数参数问题
因为api改动,上记三个函数参数增加了,我参考了内核其他代码的调用,确认添加【&init_user_ns】参数可以解决问题。
修改如下图所示
把下面的配置加到内核编译sagit_oh_defconfig的末尾,编译一次内核看看能否成功。
2.3 移植accesstokenid驱动
2.3.1 复制驱动代码,修正Kconfig,Makefile
复制linux-5.10/drivers下的accesstokenid文件夹到linux-sagit/drivers文件夹下,
同样的做法,把Kconfig,Makefile修正添加进accesstokenid驱动
2.3.2修改accesstokenid驱动关联文件
通过【CONFIG_ACCESS_TOKENID】进行搜索,发现红框中的文件有accesstokenid相关联的改动,需要手动处理。
官方linux-5.10内核的改动是在【FORBIDDEN_MMAP_FLAGS】后面添加代码。
我们同样把【CONFIG_ACCESS_TOKENID】包含的代码复制到linux-sagit的内核中,同时【ACCESS_TOKENID_FEATURE_VALUE】跟【BINDER_CURRENT_FEATURE_SET】是依赖【ENABLE_ACCESS_TOKENID】的,也一并复制。
接下来就是捉迷藏游戏,把这些改动找出来,然后再根据插入位置的上一行代码或者下一行代码进行搜索,把他们都转移到对应的位置,手动合并改动。
有些找不到对应位置的,有可能是把声明移到.h头文件了,比如binder_thread这个结构体5.10版本的时候是放在binder.c文件,6.0抽到binder_internal.h里面了。
还有一些改动是加到switch里面的,直接放到default前面就行。
linux-5.10:
linux-sagit:
这里需要注意【BINDER_FEATURE_SET】也要一起复制过来,因为都是OH添加的,我一开始没复制,导致开机时log里面一直报binder错误,后面通过gitee的按行查看功能,查看了binder.c的代码才确定这段代码也是OH团队添加的,属于ACCESS_TOKENID的相关功能。。。。。。。
还有一些是上游代码优化了写法的,这个要读懂代码才能改,比如binder_init下面这段
kernel-5.10的binder_init中,OH在【debugfs_create_file("failed_transaction_log"】后面添加了一段代码
在我们的linux-sagit中是linux6.0的代码,已经优化掉了,不能像之前那样直接找到插入的位置
新版直接用for循环简化掉了大段的代码
为了保证移植的正确,这时我们要分析代码运行了
旧版:
1.debugfs_create_dir("binder", NULL);
2.debugfs_create_dir("proc",binder_debugfs_dir_entry_root);
3.debugfs_create_file("state"/"transactions"...
4.(OH)proc_create_data("transaction_proc"...
新版:
1.debugfs_create_dir("binder", NULL);
2.debugfs_create_file("state"/"transactions"..
3.debugfs_create_dir("proc",binder_debugfs_dir_entry_root);
根据函数名可以得知OH新加的时进程相关的(proc),而且是在2.debugfs_create_dir("proc",binder_debugfs_dir_entry_root);的后面,所以我们参照这个逻辑,新版的改动可以对应为
新版:
1.debugfs_create_dir("binder", NULL);
2.debugfs_create_file("state"/"transactions"..
3.debugfs_create_dir("proc",binder_debugfs_dir_entry_root);
4.(OH)proc_create_data("transaction_proc"...
至此我移植时遇到的问题以及解决的办法已经讲完了,各位按照上面的这些办法把需要移植代码找到,添加到对应的位置即可。
2.4逆移植ashmem驱动
后续我在点亮后发现桌面图标无法显示,hilog疯狂提示db方面的错误,定位发现需要ashmem驱动,但是这个驱动在Linux5.18的时候被移除了,我们需要把它重新移植回来,我参考网上SoulInfernoDE发布的方法进行了ashmem驱动的还原
wget -O remove_ashmem.patch https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/patch/?id=721412ed3d819e767cac2b06646bf03aa158aaec
interdiff -q remove_ashmem.patch /dev/null > enable_ashmem.patch
patch -p1 -i enable_ashmem.patch
同时【CONFIG_ANDROID】这个标志已经移除了,我们还需要一些修改以便ashmem驱动能正常编译。
在staging下的Makefile中
obj-$(CONFIG_ANDROID) 改成obj-y
在staging/android下的Kconfig中
去掉if ANDROID的判断
至此内核代码方面的改动讲解完成。
3,内核编译配置修改
3.1 添加设备必要内核驱动
在之前我们解包的文件中,有个deviceinfo的文件,里面可以看到,启动的时候,内核需要加载以下这些模块:
panel-jdi-fhd-r63452 msm i2c-qup rmi_i2c qcom_spmi_fg qcom_spmi_haptics
我们直接把他们编译进内核,这样后续不需要修改gn处理ko模组文件,也不需要写init配置文件添加启动时模组加载的语句。
运行命令进入内核配置菜单
make -C /home/diemit/OpenHarmony/out/KERNEL_OBJ/kernel/src_tmp/linux-sagit ARCH=arm64 CC="/home/diemit/OpenHarmony/prebuilts/clang/ohos/linux-x86_64/llvm/bin/clang" HOSTCC="/home/diemit/OpenHarmony/prebuilts/clang/ohos/linux-x86_64/llvm/bin/clang" PERL=/usr/bin/perl CROSS_COMPILE="/home/diemit/OpenHarmony/prebuilts/gcc/linux-x86/aarch64/gcc-linaro-7.5.0-2019.12-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-"menuconfig
按键盘的【/】键进行搜索,输入【r63452】
得到驱动的状态和菜单位置,我之前已经该过,所以现在时y(编译进内核),默认是m(编译成模组)
3.2 添加相关联相关驱动
把上面列出的这些必要的驱动全部编译进内核,同时关联的驱动也一并编译进内核,比如
触摸屏会跟Input device support里面的这个event interface有关联,不一起编译进内核的话触摸屏驱动无法正常工作。
添加ashmem驱动
3.3 添加OH定制驱动
添加accestoken驱动,hdf可以不选
添加关联的binder ipc驱动
添加hilog,hievent等驱动
3.4 添加调试所需驱动
根据pmOS的指导,添加usb串口驱动
Serial debugging/Serial Gadget - postmarketOS
CONFIG_USB_G_SERIAL=y
CONFIG_U_SERIAL_CONSOLE=y
CONFIG_USB_U_SERIAL=y
按照pmOS给出的配置,在menuconfig界面搜索对应驱动进行选择,或者直接编辑defconfig文件加入。
至此内核相关定制适配讲解完成,下篇讲解打包刷机调试,敬请期待。
看来OH的移植还是只能指望手机厂商开源代码了
查缺补漏:小米6的这个pmOS内核没有配置看门狗,OH的服务里面有需要看门狗驱动,解决方案是启用内核的软件看门狗驱动
生态能发展还是要厂商和开发者双向奔赴
通读文章感受到了移植的不易
这还只是能开机点亮,触摸使能而已,系统开发是真的难
开发中找不到厂商文档的时候是挺无奈的
学习学习,平时只会调用,完全没关注过底层