官方的文档我觉得是最终的产品形态,一个新品在开发移植过程中不太可能一步到位,尤其是非官方支持版本,所以多少还是要拆分下。

准备整体构建环境

1 准备代码

理论上path不是问题,只要找到就好。这里就把要用的三方内核,比如我的是Linux-5.4就放到Linux目录下。

tj@ubuntu:~/code/oh-3.2.2/kernel/linux$ ls
build config linux-5.10 linux-5.4 patches third_party vendor

2 配置ARM64编译环境

check build/kernel.mk:

31 CLANG_HOST_TOOLCHAIN := $(OHOS_BUILD_HOME)/prebuilts/clang/ohos/linux-x86_64/llvm/bin
32 KERNEL_HOSTCC := $(CLANG_HOST_TOOLCHAIN)/clang
33 KERNEL_PREBUILT_MAKE := make
34 CLANG_CC := $(CLANG_HOST_TOOLCHAIN)/clang
39 else ifeq ($(KERNEL_ARCH), arm64)
40 KERNEL_TARGET_TOOLCHAIN := $(PREBUILTS_GCC_DIR)/linux-x86/aarch64/gcc-linaro-7.5.0-2019.12-x86_64_aarch64-linux-gnu/bin
41 KERNEL_TARGET_TOOLCHAIN_PREFIX := $(KERNEL_TARGET_TOOLCHAIN)/aarch64-linux-gnu-

进入Linux-5.4:

export PATH=./../../prebuilts/clang/ohos/linux-x86_64/llvm/bin:./../../prebuilts/gcc/linux-x86/aarch64/gcc-linaro-7.5.0-2019.12-x86_64_aarch64-linux-gnu/bin/:$PATH
export MAKE_OPTIONS="ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- CC=clang HOSTCC=clang"

3 编译Image和模块

移植前先编译一次三方内核,确保无误。

make $MAKE_OPTIONS O=out/ -j4
make $MAKE_OPTIONS O=out/ -j4 modules

移植内核态基础代码

官方文档提到的hilog/hievent:

drivers/staging/hilog
drivers/staging/hievent

还有这几个特性:

drivers/staging/hisysevent
drivers/staging/hungtask
drivers/staging/zerohung
drivers/staging/blackbox

对应的头文件:

include/dfx/hiview_hisysevent.h               |   67 ++
include/dfx/hung_wp_screen.h | 24 +
include/dfx/hungtask_base.h | 111 ++
include/dfx/zrhung.h | 11 +
include/linux/blackbox.h | 84 ++
include/linux/blackbox_common.h | 44 +
include/linux/blackbox_storage.h | 22 +

drivers下还有个accesstokenid特性,改的地方还不只一处:

tj@ubuntu:~/ohos-3.2.2/kernel/linux/linux-5.10$ grep -R ACCESS_TOKENID --exclude-dir=accesstokenid
include/linux/sched.h:#ifdef CONFIG_ACCESS_TOKENID
drivers/Makefile:obj-$(CONFIG_ACCESS_TOKENID) += accesstokenid/
drivers/android/binder.c:#ifdef CONFIG_ACCESS_TOKENID
drivers/android/binder.c:#define ENABLE_ACCESS_TOKENID 1
drivers/android/binder.c:#define ENABLE_ACCESS_TOKENID 0
drivers/android/binder.c:#endif /* CONFIG_ACCESS_TOKENID */
drivers/android/binder.c:#define ACCESS_TOKENID_FEATURE_VALUE (ENABLE_ACCESS_TOKENID << 0)
drivers/android/binder.c:#define BINDER_CURRENT_FEATURE_SET ACCESS_TOKENID_FEATURE_VALUE
drivers/android/binder.c:#ifdef CONFIG_ACCESS_TOKENID
drivers/android/binder.c:#endif /* CONFIG_ACCESS_TOKENID */
drivers/android/binder.c:#ifdef CONFIG_ACCESS_TOKENID
drivers/android/binder.c:#endif /* CONFIG_ACCESS_TOKENID */
drivers/android/binder.c:#ifdef CONFIG_ACCESS_TOKENID
drivers/android/binder.c:#endif /* CONFIG_ACCESS_TOKENID */
drivers/android/binder.c:#ifdef CONFIG_ACCESS_TOKENID
drivers/android/binder.c:#endif /* CONFIG_ACCESS_TOKENID */
drivers/android/binder.c:#ifdef CONFIG_ACCESS_TOKENID
drivers/android/binder.c:#endif /* CONFIG_ACCESS_TOKENID */
fs/proc/base.c:#ifdef CONFIG_ACCESS_TOKENID
fs/proc/base.c:#endif /* CONFIG_ACCESS_TOKENID */
fs/proc/base.c:#ifdef CONFIG_ACCESS_TOKENID
fs/proc/base.c:#ifdef CONFIG_ACCESS_TOKENID
kernel/fork.c:#ifdef CONFIG_ACCESS_TOKENID

看了下 caller path:

base/security/access_token

所以说,要拿一个非官方支持的内核版本落地产品,不是说不能做,还是要考虑清楚。

移植内核态必选特性HDF

官方的打hdf patch方法, 看kernel.mk:

83         $(hide) $(OHOS_BUILD_HOME)/drivers/hdf_core/adapter/khdf/linux/patch_hdf.sh $(OHOS_BUILD_HOME) $(KERNEL_SRC_TMP_PATH) $(KERNEL_PATCH_PATH) $(DEVICE_NAME)

patch_hdf.sh:

65 function main()
66 {
67 cd $KERNEL_BUILD_ROOT
68 put_hdf_patch
69 ln_hdf_repos
70 copy_external_compents
71 cd -
72 }

put_hdf_patch:

55 function put_hdf_patch()
56 {
57 HDF_PATCH_FILE=${KERNEL_PATCH_PATH}/${DEVICE_NAME}_patch/hdf.patch
58 if [ ! -e "${HDF_PATCH_FILE}" ]
59 then
60 HDF_PATCH_FILE=${KERNEL_PATCH_PATH}/${HDF_COMMON_PATCH}_patch/hdf.patch
61 fi
62 patch -p1 < $HDF_PATCH_FILE
63 }

我们这里用的是60行通用的hdf.patch:

kernel/linux/patches/linux-5.10/common_patch/hdf.patch

这个patch是给5.10用,我们是5.4,直接打多少应该是有问题的,还好只有300多行,手动改改即可。

然后,注掉这个put_hdf_patch, 跑下patch_hdf.sh即可, 多了个PRODUCT_PATH:

export PRODUCT_PATH=vendor/$your_product

使能几个,最大的问题就是有很多下面这类错误:

../drivers/hdf/khdf/manager/../../../..//framework/core/host/src/hdf_device_node.c:156:27: error: ISO C90 forbids mixing declarations and code [-Werror,-Wdeclaration-after-statement]
struct HdfServiceInfo servInfo;

code是这样写的:

149 int HdfDeviceNodePublishPublicService(struct HdfDeviceNode *devNode)
150 {
151 int ret;
152 if (devNode == NULL || devNode->deviceObject.service == NULL) {
153 HDF_LOGE("failed to publish public service, devNode is NULL");
154 return HDF_FAILURE;
155 }
156 struct HdfServiceInfo servInfo;
157 HdfServiceInfoInit(&servInfo, devNode);
158 ret = DevSvcManagerClntAddService(&devNode->deviceObject, &servInfo);
159 if (ret == HDF_SUCCESS) {
160 devNode->servStatus = true;
161 }
162

C90不允许declaration-after-statement,看了下5.4/5.10还是gnu89, 上游已经更新到gnu11了,照样改过来fix即可。

整个移植下来的感觉就是你可以把它当成个黑盒,不需要有太多的Linux Kernel背景。

参考