编辑
2025-01-22
记录知识
0

OH有两种类型的开发者,一个是应用开发者,一个是设备开发者,对于我们来说,我们既是应用开发者又是设备开发者

一、应用开发者

对于OH的应用开发者,目前逐渐推荐使用Stage模型开发程序。Stage的模型如下

image.png 根据文中意思:一个应用程序提供两种类型组件,1是UIAbility,2是ExtensionAbility。UI用作交互,Ex用作能力扩展。

这里ExAbility可以是OH默认提供的基本功能,也可以是自己封装的第三方库。

当然,OH的应用开发者默认要使用ArkTS来开发ArkUI,所以学习ArkTS应该是当前第一步骤

二、设备开发者

对于不同的设备,我们应该默认按照标准系统移植方式开发,一方面我们本身是Linux系统厂商,不会也没必要基于轻量(MCU)系统开发,和小型(嵌入式设备)系统开发。包括当前OH提供的api10,都是基于标准系统进行扩展的。这里可以大胆笃定OH默认的发展方向和市场前景在于Linux标准系统侧,与传统Linux桌面系统厂商竞争。

开发标准系统需要自行定义板级配置和为其编写HDF抽象层驱动,主要如文中介绍

标准驱动架构图如下

image.png 这里可以知道,标准系统长期应该仍基于Linux的LTS进行开发,OH做的是OSAL层抽象。相关具体的代码位置如下

image.png 所以我们的职责目前应该是在LTS的Linux版本,例如4.19和5.10上,搞定OH的OSAL层,这也就搞定了OH的底层

当然,OH的设备开发者默认需要在具体的硬件设备上支持,所以按照OH的SDK的编译构建流程来适配指定的开发板应该是第一步骤

三、其他开发者

根据OH的整体设计,可以发现不仅包括了应用层和内核层,还有框架层和系统服务层,这两层应该怎么办呢

image.png 首先,根据OH当前社区发展现状可以知道,OH目前大部分的代码仍是鸿蒙团队和鸿蒙扶持的相关团队在开发

其次,根据和鸿蒙沟通的情况,可以知道OH商务路线策略是扶持多个发行版厂商,而不是建立大一统的开源开放策略,目前鸿蒙内部团队的代码优于开发社区版本1个版本

并且,OH官网的适配样例绝大部分仍处于应用设计层次,并没有涉及系统的层次,参考《OpenHarmony样例展示视频合集》

根据上面两方面信息,可以知道,作为其他公司开发鸿蒙的框架层和系统服务层,有如下缺点

  • 非鸿蒙原生团队故接触此两层技术难度较大,且我们非鸿蒙扶持的相关公司
  • 代码不是最新的(开源落后鸿蒙团队1个版本)
  • 这两个层的代码会经常修改(鸿蒙团队会完善框架)
编辑
2025-01-22
记录知识
0

Openharmony的boot_linux.img 是标准的ext2格式,他需要通过syslinux来标准启动,但是鉴于有些uboot并没有默认打开syslinux,而使用默认的fit格式启动,所以本文介绍将原来的ext2的boot.img转换成fit格式的boot,从而使得系统加载更兼容

一、什么是fit镜像

关于fit镜像的说明,可以参考如下文档FIT镜像说明

二、its设置

为了打包fit格式的boot镜像,我们需要编写its文件,本文给一个示例文件如下:

/dts-v1/; / { description = "U-Boot FIT source file for arm"; images { fdt { data = /incbin/("rk3568-evb1-ddr4-v10-linux.dtb"); type = "flat_dt"; arch = "arm64"; compression = "none"; load = <0xffffff00>; hash { algo = "sha256"; }; }; kernel { data = /incbin/("Image"); type = "kernel"; arch = "arm64"; os = "linux"; compression = "none"; entry = <0xffffff01>; load = <0xffffff01>; hash { algo = "sha256"; }; }; ramdisk { data = /incbin/("ramdisk.img"); type = "ramdisk"; arch = "arm64"; os = "linux"; compression = "none"; entry = <0x00000000>; load = <0x00000000>; hash { algo = "sha256"; }; }; resource { data = /incbin/("resource.img"); type = "multi"; arch = "arm64"; compression = "none"; hash { algo = "sha256"; }; }; }; configurations { default = "conf"; conf { rollback-index = <0x00>; fdt = "fdt"; kernel = "kernel"; multi = "resource"; ramdisk = "ramdisk"; signature { algo = "sha256,rsa2048"; padding = "pss"; key-name-hint = "dev"; sign-images = "fdt", "kernel", "multi", "ramdisk"; }; }; }; };

三、准备镜像

根据上述的its的描述,我们需要如下文件

# "rk3568-evb1-ddr4-v10-linux.dtb" # "Image" # "ramdisk.img" # "resource.img"

3.1 dtb

对于openharmony,我们需要找到的dtb的位置在如下

out/kernel/OBJ/linux-5.10/arch/arm64/boot/dts/rockchip/xxxx.dtb

此时我们复制文件即可

cp out/kernel/OBJ/linux-5.10/arch/arm64/boot/dts/rockchip/xxxx.dtb fit/

3.2 Image

对于openharmony,我们需要找到的image的位置如下

out/kernel/OBJ/linux-5.10/arch/arm64/boot/Image

此时我们复制文件即可

cp out/kernel/OBJ/linux-5.10/arch/arm64/boot/Image fit/

3.3 ramdisk

对于openharmony,我们需要找到ramdisk的位置如下

out/rk3568/packages/phone/images/ramdisk.img

此时我们复制文件即可

cp out/rk3568/packages/phone/images/ramdisk.img fit/

3.4 resource

对于openharmony,我们需要找到resource的位置如下

out/kernel/OBJ/linux-5.10/resource.img

此时我们复制文件即可

cp out/kernel/OBJ/linux-5.10/resource.img fit/

四、制作boot

根据上述操作,我们可以开始通过mkimage制作镜像,先安装mkimage命令

apt install u-boot-tools

此时系统具备mkimage二进制,开始制作命令如下

mkimage -f boot.its -E -p 0x800 boot.img

制作时的日志信息如下:

FIT description: U-Boot FIT source file for arm Created: Fri May 24 03:34:16 2024 Image 0 (fdt) Description: unavailable Created: Fri May 24 03:34:16 2024 Type: Flat Device Tree Compression: uncompressed Data Size: 143744 Bytes = 140.38 KiB = 0.14 MiB Architecture: AArch64 Load Address: 0xffffff00 Hash algo: sha256 Hash value: 9df414ede45c3a2417bbcc4b8de9510aba9e2600f5a160a6a3b721c761400e31 Image 1 (kernel) Description: unavailable Created: Fri May 24 03:34:16 2024 Type: Kernel Image Compression: uncompressed Data Size: 24385552 Bytes = 23814.02 KiB = 23.26 MiB Architecture: AArch64 OS: Linux Load Address: 0xffffff01 Entry Point: 0xffffff01 Hash algo: sha256 Hash value: 4f3ad02eb1c101976b8b3dea5bce379efb0fd00a61a646b336c725d388dd4bea Image 2 (ramdisk) Description: unavailable Created: Fri May 24 03:34:16 2024 Type: RAMDisk Image Compression: uncompressed Data Size: 2509910 Bytes = 2451.08 KiB = 2.39 MiB Architecture: AArch64 OS: Linux Load Address: 0x00000000 Entry Point: 0x00000000 Hash algo: sha256 Hash value: 027f5c7aa5ca3a2dde9d0bb744d3a508321308c1f47cb34b4053317e39fe6ecc Image 3 (resource) Description: unavailable Created: Fri May 24 03:34:16 2024 Type: Multi-File Image Compression: uncompressed Data Size: 12588544 Bytes = 12293.50 KiB = 12.01 MiB Hash algo: sha256 Hash value: bcd3ccc6ac2747de83f27d320bd3c3aed18762bb5f3045fa84ff926345e2a125 Default Configuration: 'conf' Configuration 0 (conf) Description: unavailable Kernel: kernel Init Ramdisk: ramdisk FDT: fdt

至此,我们可以获得boot.img用于fit启动

编辑
2025-01-22
记录知识
0

我们在调试openharmony内核的时候,通常来看编译速度比正常内核都慢,主要是btf配置的影响,这里记录此问题,在我们调试的时候,如果不需要btf,可以关掉CONFIG_DEBUG_INFO_BTF配置,这样内核编译速度快点

一、BTF是什么

BTF可能不熟悉的比较陌生,但是说起BPF就不陌生了,其实BTF是BPF的type format而已,而BPF一个工具,用于网络数据包过滤、性能监控、安全性应用等。BTF 格式的调试信息使得 BPF 程序可以轻松地获取内核数据结构的布局和类型信息,从而使 BPF 程序能够更深入地访问和操作内核数据

二、CONFIG_DEBUG_INFO_BTF

这个配置就是为内核添加btf信息,从而使得应用可以调用bpf程序来观测内核

三、pahole

pahole是一个工具,在内核编译的时候会使用pahole来打包btf。真正使得内核编译很慢的原因是pahole工具

四、禁用CONFIG_DEBUG_INFO_BTF

禁用CONFIG_DEBUG_INFO_BTF可以加快内核编译速度

编辑
2025-01-22
记录知识
0

开发Openharmony的设备开发第一步就是移植内核,本文基于openharmony的sdk角度介绍openharmony的内核编译方式和单独编译内核的命令

一、原始内核位置

这里内核有两个位置,一个是内核原始源码位置,这是oh标准内核,位置为/kernel/linux/linux-5.10/

在这个内核上,会添加如下几个依赖仓库的改动如下

"kernel/linux/build" # 编译相关脚本 "kernel/linux/linux-5.10" # 内核仓库 "kernel/linux/patches" # 内核相关补丁 "kernel/linux/config" # 内核的defconfig "kernel/linux/common_modules" # oh特性的内核驱动 "third_party/bounds_checking_function" # libboundscheck库,安全函数,带边界检查的标准函数 "device/soc/hisilicon/common/platform/wifi" # 海思wifi "third_party/FreeBSD/sys/dev/evdev" # evdev 头文件 "drivers/hdf_core" # hdf 核心驱动 "prebuilts/clang/ohos/linux-x86_64/llvm/bin" # llvm

这里值得注意的是,patch目录,它需要对内核合入hdf补丁,并且需要合入rk3568芯片的基础改动的patch,主要如下

└── rk3568_patch ├── kernel.patch # linux-5.10 rk3568 SOC patches └── hdf.patch # linux-5.10 rk3568 定制 HDF patches

我们通常做移植的后续工作是设配oh的硬件抽象层,主要如下

├── adapter ├── bundle.json ├── figures ├── framework ├── interfaces ├── LICENSE ├── OAT.xml ├── README.md └── README_zh.md

二、编译后内核位置

编译后的内核位置为/out/kernel/src_tmp/linux-5.10/, 编译后内核的中间文件位置为/out/kernel/OBJ/linux-5.10/

此时代码是已经合入补丁和相关oh特性功能的代码。

三、编译内核

编译内核可以分为最外层sdk模块编译,内核源码build_kernel.sh脚本编译(合并前),内核源码make-ohos.sh脚本编译(合并后),和内核分步骤编译,可以按需自行编译

3.1、sdk模块编译

对于内核而言,sdk模块编译目前默认不支持,但sdk外层编译有必要解释一下,所以编译内核的最外层sdk编译命令如下

./build.sh --product-name rk3568 --ccache

上述命令可以整体环境编译,故内核也编译了,但是缺点是编译一次时间太长。为了指定模块的单独编译,可以设置--build-target,如下是代码示例

group("make_images") group("eng_system_image") group("eng_chipset_image") group("chip_prod_image") group("sys_prod_image") group("system_image") group("userdata_image") group("vendor_image") group("ramdisk_image") group("updater_ramdisk_image") group("updater_image")

可以知道,通过如下参数指定编译

./build.sh --product-name rk3568 --ccache --build-target make_images ./build.sh --product-name rk3568 --ccache --build-target system_image ./build.sh --product-name rk3568 --ccache --build-target userdata_image

build-target还能通过指定gn路径+目标名指定模块编译,如下

./build.sh --product-name rk3568 --ccache --build-target commonlibrary/c_utils/base:util

这里commonlibrary/c_utils/base是BUILD.gn文件目录,util是BUILD.gn声明的模块名称。

虽然内核不能单独编译,但是执行全量编译只需要等待即可获得boot_linux.img文件

查看build-target支持的选项,如下命令

prebuilts/build-tools/linux-x86/bin/ninja -w dupbuild=warn -C out/rk3568/ -t targets

对于查出来的选项,可以直接用ninja编译模块,以内核举例

prebuilts/build-tools/linux-x86/bin/ninja -w dupbuild=warn -C out/rk3568/ kernel

如果使用hb命令,可以如下编译内核

hb build -T kernel

3.2、build_kernel.sh脚本编译

build_kernel.sh作为内核单模块BUILD.gn拉起的脚本,我们可以主动调用它来单独编译内核,但是前提是代码是全编过一次的,也就是out/rk3568目录存在。编译命令如下

`pwd`/../../device/board/hihope/rk3568/kernel/build_kernel.sh `pwd`/../../kernel/linux/linux-5.10 `pwd`/../../out/rk3568/packages/phone/images `pwd`/../../device/board/hihope/rk3568 vendor/hihope/rk3568 `pwd`/../../ rockchip rk3568 hihope root default disable_lto_O0 enable_ramdisk

这里解释如下

此命令需要绝对路径

build_kernel.sh需要11个形参分别如下 $1=../../kernel/linux/linux-5.10 # pushd 参数,切换目录到linux-5.10上 $2=out/rk3568/packages/phone/images # 镜像输出目录 $3=device/board/hihope/rk3568 # BUILD_SCRIPT_PATH变量 $4=vendor/hihope/rk3568 # PRODUCT_PATH变量 $5=`pwd` # ROOT_DIR变量 $6=rockchip # DEVICE_COMPANY变量 $7=rk3568 # DEVICE_NAME变量 $8=hihope # PRODUCT_COMPANY变量 $9=root # KERNEL_FORM变量 $10=default # KERNEL_PROD变量 $11=disable_lto_O0 # ENABLE_LTO_O0变量 $12=enable_ramdisk # 判断是否生成ramdisk

此命令如果是第一次运行,会自动打patch和复制oh特性驱动代码。如果不是第一次运行,则跳过不应用补丁,直接开始编译。此命令会主动拷贝文件到out/rk3568/packages/phone/images目录。

3.3、 make-ohos.sh脚本编译

根据对build_kernel.sh的解析,为了在代码目录out/kernel/src_tmp/linux-5.10直接编译,可以直接如下命令编译

KBUILD_OUTPUT=../../OBJ/linux-5.10 PRODUCT_PATH=vendor/hihope/rk3568 DEVICE_COMPANY=rockchip DEVICE_NAME=rk3568 PRODUCT_COMPANY=hihope GPUDRIVER=mali ./make-ohos.sh TB-RK3568X0 enable_ramdisk

对于参数解析如下:

KBUILD_OUTPUT:指定内核编译中间文件位置 PRODUCT_PATH:指定产品路径,khdf需要使用 GPUDRIVER: 指定显卡驱动,瑞芯微支持mali和panfrost两种驱动 TB-RK3568X0:指定开发板类型,当前oh的sdk只支持TB-RK3568X0和TB-RK3568X10两款开发板,两个开发板对应的设备树不一样而已,其他没区别 enable_ramdisk:指定生成ramdisk镜像

通过上述命令可以在源码目录生成boot_linux目录和boot_linux.img,注意,此时的boot_linux.img不会主动复制到out/rk3568/packages/phone/images目录。

3.4、内核分步骤编译

内核编译分三个步骤

编译defconfig 编译ko模块 编译image内核二进制

内核打包通过mke2fs打包ext2格式的镜像,通过make-boot.sh打包

涉及命令主要如下:

make KBUILD_OUTPUT=../../OBJ/linux-5.10 PRODUCT_PATH=vendor/hihope/rk3568 LLVM=1 LLVM_IAS=1 CROSS_COMPILE=aarch64-linux-gnu- ARCH=arm64 rockchip_linux_defconfig make KBUILD_OUTPUT=../../OBJ/linux-5.10 PRODUCT_PATH=vendor/hihope/rk3568 LLVM=1 LLVM_IAS=1 CROSS_COMPILE=aarch64-linux-gnu- ARCH=arm64 modules_prepare rm -rf ../../../kernel/vendor/hihope/rk3568/hdf_config/khdf/hdf_test/ make KBUILD_OUTPUT=../../OBJ/linux-5.10 PRODUCT_PATH=vendor/hihope/rk3568 LLVM=1 LLVM_IAS=1 CROSS_COMPILE=aarch64-linux-gnu- ARCH=arm64 rk3568-toybrick-x0-linux.img -j96

这时候内核已经编译成Image文件,需要手动cp一下

cp ../../OBJ/linux-5.10/arch/arm64/boot/Image boot_linux/extlinux/Image

然后运行make-boot.sh脚本打包boot_linux.img

./make-boot.sh ../../../

此时boot_linux.img文件存放在/rk3568/packages/phone/images/内

3.4.1 hdf_hcs_hex.o重编译

默认的hdf_test在单编译的时候会报错如下:

ld.lld: error: drivers/built-in.a(../../../vendor/hihope/rk3568/hdf_config/khdf/hdf_test/hdf_hcs_hex.o): Invalid value (Producer: 'LLVM15.0.4' Reader: 'LLVM 12.0.1')

上述日志说明hdf_hcs_hex.o和当前单编的llvm版本不一样,所以删除.o即可,如下操作

rm -rf ../../../kernel/vendor/hihope/rk3568/hdf_config/khdf/hdf_test/

3.4.2 缺少包pahole工具

缺少工具是因为缺少包导致,错误信息如下

BTF: .tmp_vmlinux.btf: pahole (pahole) is not available

安装dwarves包即可

apt install dwarves

3.4.5 编译有不匹配的残留文件

如果编译环境出问题,如下命令清理一下

KBUILD_OUTPUT=../../OBJ/linux-5.10 make LLVM=1 LLVM_IAS=1 CROSS_COMPILE=aarch64-linux-gnu- ARCH=arm64 PRODUCT_PATH=vendor/hihope/rk3568 DEVICE_COMPANY=rockchip mrproper

如果是误操作在out/kernel/src_tmp/linux-5.10编译了中间文件,则需要在本目录操作mrproper,如下

make LLVM=1 LLVM_IAS=1 CROSS_COMPILE=aarch64-linux-gnu- ARCH=arm64 PRODUCT_PATH=vendor/hihope/rk3568 DEVICE_COMPANY=rockchip mrproper
编辑
2025-01-22
记录知识
0

我们在开发openharmony的时候经常修改内核代码,而在openharmony内内核的编译目录在out临时目录下,所以我们应该遵循openharmony的规范提交内核,如下是具体情况

一、定制仓库

根据openharmony的仓库目录,我们可以知道,如果我们修改一个设备的配置,通常其目录在device/board/xxx下,例如hihope的设备,那么配置仓库为device_board_hihope

仓库下面的build_kernel.sh是编译内核的脚本,我们需要重点关注

二、openharmony的内核编译配置

根据分析build_kernel.sh脚本,我们可以知道如下:

2.1 kernel source

对于openharmony内核而言,原始代码地址在

KERNEL_SOURCE=${ROOT_DIR}/kernel/linux/linux-5.10

2.2 kernel patch

对于厂商的补丁而言,其patch位置在

KERNEL_PATCH=${ROOT_DIR}/kernel/linux/patches/linux-5.10/rk3568_patch/kernel.patch

这是openharmony团队适配rk3568平台的补丁

2.3 defconfig

对于内核,配置是多个config组合的,如下:

KERNEL_CONFIG_FILE=${ROOT_DIR}/device/board/hihope/rk3568/kernel/kernel_config/linux-5.10/rk3568_standard_defconfig

这里可以知道,openharmony的内核配置是rockchip的配置defconfig

三、如何添加配置

根据二中的分析,我们可以知道,2.1不建议修改,因为是华为的内核源码,2.2也不建议修改,因为是openharmony适配rk3568的通用修改,2.3 是默认配置,不建议修改。我们如果需要修改,需要另加patch,如下方式

# rk628 驱动 KERNEL_RK628_PATCH=${ROOT_DIR}/device/board/hihope/rk3568/kernel/kernel_patch/linux-5.10/allgo_patch/rk628.patch # allgo 设备树 KERNEL_DTS_MBRC3568A=${ROOT_DIR}/device/board/hihope/rk3568/kernel/kernel_patch/linux-5.10/allgo_patch/allgo-mbrc3568a-dts.patch # make-ohos patch BUILD_MBRC3568_PATCH=${ROOT_DIR}/device/board/hihope/rk3568/kernel/kernel_patch/linux-5.10/allgo_patch/build-mbrc3568a.patch # bugfix patch KERNEL_BUGFIX_ON_MBRC3568_PATH=${ROOT_DIR}/device/board/hihope/rk3568/kernel/kernel_patch/linux-5.10/allgo_patch/mbrc3568a-bugfix.patch

根据这些定义,在后面需要合入补丁

# patching rk628 patch -p1 < ${KERNEL_RK628_PATCH} # patching dts patch -p1 < ${KERNEL_DTS_MBRC3568A} # patching build script patch -p1 < ${BUILD_MBRC3568_PATCH} # patching bugfix patch patch -p1 < ${KERNEL_BUGFIX_ON_MBRC3568_PATH}

这里KERNEL_RK628_PATCH是适配rk628驱动的单独补丁,KERNEL_DTS_MBRC3568A是适配众达机器的设备树,BUILD_MBRC3568_PATCH是合入openharmony编译的改动,KERNEL_BUGFIX_ON_MBRC3568_PATH是根据上述改动后,针对bugfix的改动补丁。

所以后续如果我们针对众达3568机器的补丁修复,可以持续更新补丁文件mbrc3568a-bugfix.patch即可。

四、更新方法

根据上面提到的,我们需要更新补丁,这里提供补丁的更新方法如下:

4.1 未修改前的初始仓库

假设我们基于声卡做了定制修改,我们需要进入声卡的驱动目录做如下工作:

cd sound/soc/codecs git init . git add . git commit -m 'initail code'

此时我们初始化了一个空的仓库

4.2 修改代码

如果我们修改代码,直接vim修改即可,如下

vim es8323.c

修改后我们可以看到改动情况如下:

git status . 位于分支 master 尚未暂存以备提交的变更: (使用 "git add <文件>..." 更新要提交的内容) (使用 "git restore <文件>..." 丢弃工作区的改动) 修改: es8323.c

4.3 生成补丁

根据上面的修改代码,可以直接用git diff生成,如下:

git diff > support-sound-card.patch

此时我们将产生一个基于es8323改造的补丁,但是需要留意的是如下:

patch -p1 < ${KERNEL_BUGFIX_ON_MBRC3568_PATH}

这里合入补丁的方式是p1,所以我们需要整改一下这个patch,如下

%s/a\//a\/sound\/soc\/codecs\//g %s/b\//b\/sound\/soc\/codecs\//g

此时pathc的变化如下,先显示未修改之前的

diff --git a/es8323.c b/es8323.c index 6365108..5241703 100755 --- a/es8323.c +++ b/es8323.c

再通过替换符合p1路径的,也就是修改之后的,如下:

diff --git a/sound/soc/codecs/es8323.c b/sound/soc/codecs/es8323.c index 6365108..5241703 100755 --- a/sound/soc/codecs/es8323.c +++ b/sound/soc/codecs/es8323.c

此时这个补丁基本可用了。我们需要将其合入mbrc3568a-bugfix.patch。

4.4 合入mbrc3568a-bugfix.patch

合入补丁的方式也很简单,通过追加的方式即可,如下:

cat support-sound-card.patch >> device/board/hihope/rk3568/kernel/kernel_patch/linux-5.10/allgo_patch/mbrc3568a-bugfix.patch

此时我们在仓库device_board_hihope上做提交即可。

git add rk3568/kernel/kernel_patch/linux-5.10/allgo_patch/mbrc3568a-bugfix.patch git commit git push