文档内容拷贝自:
codebase_host/yunhal/opendoc/zh/porting_guide/kdbus.md
联系人:李诚
版本:commit-id(9c70d1039181574402b7af4efa36e3090f0f8d10
)
变更记录
版本编号 | 修订内容 | 日期 | 修订人 |
---|---|---|---|
0.1 | 初稿 | 2016.06.12 | 李诚 |
0.2 | 针对codebase_host_ocean分支修订 | 2017.03.15 | 李诚 |
KDBus是D-Bus协议在内核层的实现,作为YunOS的IPC机制为上层应用服务。同时也是YunOS权限系统不可或缺的组成部分。(权限相关内容请参考“权限系统移植文档”)
KDBus代码来自于上游社区,参考https://github.com/gregkh/kdbus 。最初的KDBus代码是基于Kernel-3.18版本实现,后来跟随Linux Kernel的演进而不断更新,最新的kdbus代码是基于kernel-4.4版本的。
YunOS6.0中,KDBus代码位于host/security/extern/gpl/kernel/ipc目录,编译时通过软连接的方式参与kernel的编译。
代码目录结构如下:
security/extern/gpl/kernel/ ├── include │ └── uapi │ └── linux │ └── kdbus.h └── ipc └── kdbus ├── *.c ├── *.h
KDBus代码中采用KERNEL_VERSION宏来包围特定内核版本的API接口,可以同时支持不同版本的内核。
由于KDBus代码最终并未进入Linux主线,所以没有经过大规模验证。随着YunOS在TV,手机和车机等多个平台的长期使用,暴露出一些bug,比如不能给自身connection发消息,给不存在的service发异步消息时不能立即返回错误等等。这些bug在YunOS6.0上都已修复。
此外,YunOS6.0中,KDBus也添加了对debugfs的支持,方便调试。
为使KDBus在低版本的kernel上可以工作,修改了一些不存在或工作不正常的api接口,如task_cgroup_path(), truncate_inode_pages_final()等,以及struct timespec等结构体。
memfd机制是在Kernel-3.18版本合入linux主线的,若平台所用kernel版本较低,仍需手动移植memfd相关代码。特别注意的是,不同版本的kernel其支持的系统调用总数是不同的,需要为memfd_create()设定合适的系统调用号,并且此系统调用号必须与host/third_party/libkdbus/shared/memfd.h保持一致。
YunOS6.0适配过多个平台,kernel版本有3.10, 3.14, 3.18和4.4等。适配kernel-4.4版本最简单,只需修改init/Kconfig和ipc/Makefile,并参考2.1.3节使能KDBus即可。
而适配kernel-3.10则需要的改动最多,也比较分散。可参考:
http://gerrit2.alibaba-inc.com:8080/#/c/170140 http://gerrit2.alibaba-inc.com:8080/#/c/170141
涉及代码有:
kernel/ ├── arch/arm/ 或 arch/x86 或arch/arm64 : 添加memfd_create()系统调用号 │ ├── fs/*.c : 主要是反向移植iterate_dir()以及支持memfd的SEAL机制 │ ├── include/linux/*.h : 主要是添加新版本linux的数据结构及API接口 │ └── linux │ └──*.h │ └── uapi │ └── linux │ └── *.h ├── init/Kconfig : 添加config KDBUS │ ├── ipc/Makefile : 编译 KDBus代码 │ ├── kernel/*.c : 反向移植必要的API接口 │ ├── lib/*.c : 反向移植div64和idr相关代码 │ ├── mm/*.c : 反向移植memfd相关代码 │
打开CONFIG_KDBUS即可使能KDBus。另外需要在编译host时指定- -with-kdbus=yes。若不写- -with-kdbus,缺省值是yes。
打开CONFIG_KDBUS后,KDBus相应代码会编译进内核中。
KDBus本身工作并没有其他依赖,但上层应用不能直接与kernel 中的KDBus交互,所以KDBus在平台上正常工作,需要上层的libkdbus, libbase,ubus.js等文件都存在,且包含完整的patch。
? Memfd_create()的系统调用号
由于memfd及相关的系统调用是在3.18及以上的内核版本才存在,在低版本的内核上需要为SYSCALL_memfd选定一个号码,且与third_party/libkdbus/shared/memfd.h中的系统调用号保持一致。
注意:在SC9860等ARM64平台,在上述patch之外,需额外修改
arch/arm64/include/asm/unistd.h
和 arch/arm64/include/asm/unistd32.h
以确保memfd的系统调用号 以及系统总的系统调用数目作了相应修改。
? 系统启动后kdbusfs不能正常挂载
只在L5pro手机平台移植时出现此问题,原因是在L5pro平台打开CONFIG_KDBUS需要同时修改l5pro_debug_defconfig 和 l5pro_defconfig 两个文件,否则CONFIG_KDBUS不生效。
? 系统启动后kdbusfs虽正常挂载,但无法看到/sys/fs/kdbus目录下的文件节点
两个可能原因:一是平台上有host和container两个文件系统,要注意adb/acb连接的是哪个系统,如果连接的是container,要去/root/sys/fs/kdbus目录下去看是否有文件节点。
另一个原因和CONFIG_COMPAT选项有关。为使KDBus在低版本内核上能工作正常,我们修改了fs/readdir.c中的系统调用及相关数据结构体,但在Intel CPU的PAD 平台上,使能了CONFIG_COMPAT选项,所以其真正调用的是fs/compat.c里的系统调用函数。
? 系统启动后桌面黑屏,logcat报“can’t send kdbus method call,… error: invalid argument”
这是由于上层权限相关的代码在平台bringup的过程中已经合入,但KDBus初始移植时权限相关的patch尚未合入,导致上层应用所发的消息中所附带的KDBUS_ITEM_SESSION_PERM部分不被kernel KDBus所识别,所以出错。
BaseTest --gtest_filter=DBusSignalTest.* BaseTest --gtest_filter=DBusDeathTest.* BaseTest --gtest_filter=DBusTest.* 这三个命令需运行正常,以便确保kdbus可以正常工作。
移植完成后,KDBus能否正常工作,可由多个层面的单元测试来验证。因为KDBus提供给上层应用使用,由下而上经过了libsystemd, libbase, libubus多层封装,每层封装都有自己的单元测试,所有单元测试都通过,才能确保应用基于KDBus的IPC能正常工作。
一是third_party/kdbus_test目录下的单元测试,这是社区提供的单元测试用例,直接测试KDBus kernel代码的。
二是third_party/libkdbus/sd-bus/test-bus*.c编译出的测试用例,确保libkdbus需要KDBus提供的功能都工作正常。
三是framework/libs/base/test/DBus*.cpp编译出的测试用例。
四是framework/npm/extras/node-ubus/test/目录下的JS测试脚本。