OpenHarmony内核开发实战手册:编译构建、HCK框架与性能优化
目录
- 标准系统内核概述
- 编译构建指导
- HCK内核解耦框架
- 内存增强特性
- NewIP内核协议栈
- 任务调度优化
- 开发板Patch使用
- CPU资源管理
1. 标准系统内核概述
1.1 基本概念
OpenHarmony标准系统采用Linux内核作为其核心基础。Linux内核是一个开源的类Unix操作系统内核,最初由Linus Torvalds于1991年开始开发,目前已成为全球最广泛使用的操作系统内核之一。
1.2 内核版本类型
Linux内核主要有以下版本类型:
- 稳定版(Stable):经过充分测试的稳定版本,推荐生产环境使用
- LTS版(Long Term Support):长期支持版本,提供长期的更新和维护
1.3 OpenHarmony内核版本支持
OpenHarmony标准系统支持多个Linux内核版本,包括:
- 4.19版本:广泛应用的LTS版本,稳定性好
- 5.10版本:较新的LTS版本,性能和功能增强
- 6.6版本:最新的长期支持版本,提供最新特性
OpenHarmony在标准系统场景下,通过适配不同版本的Linux内核,为不同硬件平台和应用场景提供统一的操作系统基础。
2. 编译构建指导
2.1 编译环境准备
在开始编译OpenHarmony标准系统内核之前,需要确保开发环境已正确配置,包括必要的编译工具链和依赖库。
2.2 rk3568开发板编译示例
以rk3568开发板为例,介绍OpenHarmony标准系统内核的编译流程:
2.2.1 指定内核版本编译
# 编译rk3568开发板的内核
./build.sh --product-name rk3568 --kernel-version 5.10
2.2.2 编译命令说明
--product-name rk3568:指定目标产品为rk3568开发板--kernel-version 5.10:指定使用的Linux内核版本为5.10
2.2.3 编译输出
编译完成后,内核镜像和相关的设备树文件将在输出目录中生成,可用于在rk3568开发板上部署和运行OpenHarmony系统。
3. HCK内核解耦框架
3.1 基本概念
HCK(Hook Common Kernel)是一个内核解耦框架,OpenHarmony标准系统内核通过HCK框架实现对不同厂商内核功能的插桩式适配,避免对原生内核代码的直接侵入式修改。
3.2 背景介绍
在传统内核开发中,针对不同厂商的内核功能适配通常需要直接修改内核源码,这会带来以下问题:
- 维护复杂:每次内核升级都需要重新适配,工作量大
- 代码污染:厂商代码与原生内核代码混杂,难以维护
- 扩展困难:新增功能需要重新适配所有厂商版本
HCK框架通过插桩方式解决了这些问题,实现了内核功能的解耦和标准化。
3.3 使用范围
HCK框架主要应用于以下场景:
- 厂商驱动适配:为不同厂商的硬件驱动提供统一的适配接口
- 内核功能扩展:在不修改原生内核代码的情况下扩展内核功能
- 性能优化:为特定平台提供性能调优的插桩点
- 调试和监控:提供内核行为监控和调试的接口
3.4 接口说明
3.4.1 核心宏定义
// 定义HCK轻量级钩子
#define DECLARE_HCK_LITE_HOOK(name) \static typeof(name) *hck_lite_##name// 注册HCK轻量级钩子
#define REGISTER_HCK_LITE_HOOK(name, func) \do { \hck_lite_##name = func; \} while (0)// 调用HCK轻量级钩子
#define CALL_HCK_LITE_HOOK(name, ...) \(hck_lite_##name ? hck_lite_##name(__VA_ARGS__) : 0)
3.4.2 接口使用说明
- DECLARE_HCK_LITE_HOOK(name):声明HCK钩子变量
- REGISTER_HCK_LITE_HOOK(name, func):注册钩子函数
- CALL_HCK_LITE_HOOK(name, …):调用钩子函数
3.5 使用指导
3.5.1 配置阶段
在目标平台的内核配置文件中启用HCK框架:
HCK_VENDOR_HOOKS=y
3.5.2 定义阶段
在供应商提供的内核扩展模块中定义钩子函数:
// 供应商钩子函数实现
void vendor_specific_function(void)
{// 供应商特定的功能实现printk("Vendor specific hook called\n");
}
3.5.3 注册阶段
在模块初始化时注册钩子函数:
static int __init vendor_module_init(void)
{// 注册钩子函数REGISTER_HCK_LITE_HOOK(vendor_hook_name, vendor_specific_function);return 0;
}
3.5.4 调用阶段
在原生内核代码中的插桩点调用钩子:
// 原生内核代码中的插桩点
void kernel_common_function(void)
{// 原生内核逻辑// 调用钩子函数(如果已注册)CALL_HCK_LITE_HOOK(vendor_hook_name);
}
3.6 使用规范
3.6.1 命名规范
- 钩子名称:使用描述性名称,明确表达钩子的功能
- 模块名称:遵循内核模块命名规范,以"hck_"开头
- 函数名称:使用小写字母和下划线,遵循内核编码规范
3.6.2 目录规范
- HCK框架代码:位于内核源码的
kernel/hck/目录下 - 供应商扩展:位于
drivers/hck/目录下 - 配置文件:位于内核配置目录的相关文件中
4. 内存增强特性
4.1 Enhanced SWAP特性
4.1.1 基本概念
ESwap(Enhanced Swap)是OpenHarmony标准系统内核提供的高级内存交换特性,它提供了自定义新增存储分区作为内存交换分区的能力。
4.1.2 工作原理
ESwap通过以下机制实现内存优化:
- ZRAM压缩:首先将匿名页压缩到ZRAM设备
- ESwap换出:将ZRAM压缩后的匿名页加密换出到ESwap存储分区
- zswapd守护进程:常驻进程zswapd负责后台回收和管理
- 内存回收:完全释放可用内存,维持Memavailable水线
4.1.3 配置指导
启用ESwap配置:
CONFIG_HYPERHOLD=y // 启用HyperHold
CONFIG_HYPERHOLD_DEBUG=y // 启用调试
CONFIG_HYPERHOLD_ZSWAPD=y // 启用zswapd线程
CONFIG_HYPERHOLD_FILE_LRU=y // 启用文件LRU
CONFIG_HYPERHOLD_MEMCG=y // 启用内存控制组
CONFIG_ZRAM_GROUP=y // 启用ZRAM对象管理
CONFIG_ZRAM_GROUP_DEBUG=y // 启用ZRAM组调试
CONFIG_ZLIST_DEBUG=y // 启用ZRAM列表调试
CONFIG_ZRAM_GROUP_WRITEBACK=y // 启用写回功能
依赖配置:
CONFIG_MEMCG=y // 启用内存控制器
CONFIG_SWAP=y // 启用匿名内存交换
CONFIG_ZSMALLOC=y // 启用压缩页内存分配器
CONFIG_ZRAM=y // 启用压缩RAM块设备
4.1.4 设备创建与配置
创建ESwap设备:
# 创建交换文件(512MB)
dd if=/dev/random of=/data/hpdisk bs=4096 count=131072# 绑定为loop设备
losetup /dev/block/loop6 hpdisk# 配置ESwap设备
echo /dev/block/loop6 > /proc/sys/kernel/hyperhold/device# 配置软件加密(可选)
echo 0 > /proc/sys/kernel/hyperhold/soft_crypt# 使能ESwap
echo enable > /proc/sys/kernel/hyperhold/enable
4.1.5 ZRAM配置
初始化ZRAM:
# 配置ZRAM交互方式
echo readwrite > /sys/block/zram0/group# 设置ZRAM大小
echo 512M > /sys/block/zram0/disksize# 启用ZRAM交换分区
mkswap /dev/block/zram0
swapon /dev/block/zram0
4.1.6 相关接口
控制接口:
| 接口名称 | 功能描述 | 示例 |
|---|---|---|
| avail_buffers | 设置buffer区间 | echo 300 250 350 200 > /dev/memcg/memory.avail_buffers |
| zswapd_single_memcg_param | 设置memcg配置 | echo 300 40 0 0 > /dev/memcg/memory.zswapd_single_memcg_param |
| zram_wm_ratio | 设置ZRAM换出水线 | echo 30 > /dev/memcg/memory.zram_wm_ratio |
状态接口:
| 接口名称 | 功能描述 |
|---|---|
| zswapd_pressure_show | 显示当前压力状态 |
| stat | 检测ESwap实时情况 |
| zswapd_vmstat_show | 记录zswapd运行事件 |
5. NewIP内核协议栈
5.1 基本概念
New IP是OpenHarmony标准系统内核提供的创新网络协议栈,它在现有IP能力的基础上,以灵活轻量级报头和可变长多语义地址为基础,通过二三层协议融合,对协议去冗和压缩,减少冗余字节,实现高能效比、高净吞吐,提升通信效率。
5.2 技术优势
5.2.1 报头优化
传统IPv4/IPv6协议存在以下开销问题:
- IPv4地址:固定4字节长度
- IPv6地址:固定16字节长度
- IPv4报头:20-60字节长度
- IPv6报头:40字节长度
New IP技术优势:
- 可变长多语义地址:最短1字节
- 可变长定制化报头:最短5字节
- 报头开销降低:相比IPv4节省25.9%,相比IPv6节省44.9%
- 传输效率提升:相比IPv4提高最少1%,相比IPv6提高最少2.33%
5.2.2 效率对比
| 场景 | 报头开销 | 载荷传输效率(WiFi MTU=1500B) |
|---|---|---|
| IPv4 for WiFi | 30+8+20=58 B | 96.13% |
| IPv6 for WiFi | 30+8+40=78 B | 94.8% |
| New IP for WiFi | 30+8+5=43 B | 97.13% |
5.3 可变长报头格式
5.3.1 报文结构
New IP WiFi灵活极简报文头结构如下:
+------------------+------------------+------------------+
| Dispatch (1bit) | Bitmap (变长) | Value (变长) |
+------------------+------------------+------------------+
5.3.2 字段说明
Dispatch字段:
- 长度:1比特
- 0b0:表示极简封装子类
- 标识报头的封装类型
Bitmap字段:
- 长度:变长,默认为7比特
- 可持续扩展,最后一位置0表示结束
- 每比特表示报头中是否携带特定字段
Value字段:
- 长度:1字节的整数倍
- 类型及长度由报头字段语义表确定
5.3.3 Bitmap字段定义
第一字节定义:
| 比特位 | 字段 | 长度 | 描述 |
|---|---|---|---|
| 0 | Dispatch | 1bit | 0=极简封装,1=非极简封装 |
| 1 | TTL | 1 Byte | 剩余跳数 |
| 2 | Total Length | 2 Byte | UDP置0,TCP置1,报文总长度 |
| 3 | Next Header | 1 Byte | 协议类型 |
| 4 | Reserve | - | 保留字段,置0 |
| 5 | Dest Address | 变长(1-8 Byte) | 目的地址 |
| 6 | Source Address | 变长(1-8 Byte) | 源地址 |
| 7 | Bitmap扩展标志 | - | 0=结束,1=扩展 |
5.4 可变长地址格式
New IP支持1-48位可变长地址,编码格式如下:
| 地址前缀 | 地址长度 | 有效范围 |
|---|---|---|
| 0x00-0xDC | 1字节 | 0-220 |
| 0xDD-0xF0 | 2字节 | 221-5119 |
| 0xF1 | 3字节 | 5120-65535 |
| 0xF2 | 5字节 | 65536-4,294,967,295 |
| 0xF3 | 7字节 | 4,294,967,296-281,474,976,710,655 |
| 0xFE | 8字节 | 0-72,057,594,037,927,935 |
5.5 配置指导
5.5.1 使能New IP
在rk3568开发板Linux 5.10内核上配置New IP:
CONFIG_NEWIP=y // 使能New IP内核协议栈
CONFIG_NEWIP_HOOKS=y // 使能插桩函数注册
HCK_VENDOR_HOOKS=y // 使能内核插桩基础框架
5.5.2 编译验证
# 编译完成后验证New IP代码
find out/ -name *nip*.o# 输出示例:
out/kernel/OBJ/linux-5.10/net/newip/nip_addrconf_core.o
out/kernel/OBJ/linux-5.10/net/newip/nip_hdr_decap.o
out/kernel/OBJ/linux-5.10/net/newip/nip_addr.o
5.5.3 插桩机制
OpenHarmony内核要求所有原生内核代码侵入式修改都采用插桩方式:
// 注册New IP功能函数到内核
void nip_ninet_ehashfn_lhck_register(void)
{REGISTER_HCK_LITE_HOOK(nip_ninet_ehashfn_lhck, nip_ninet_ehashfn);
}// 在公共流程中通过函数指针调用
static u32 sk_ehashfn(const struct sock *sk)
{if (sk->sk_family == AF_NINET) {u32 ret = 0;CALL_HCK_LITE_HOOK(nip_ninet_ehashfn_lhck, sk, &ret);return ret;}// IPv4/IPv6处理...
}
5.6 Socket API接口
5.6.1 核心接口列表
| 函数 | 输入参数 | 返回值 | 描述 |
|---|---|---|---|
| socket | domain, type, protocol | sockfd | 创建New IP socket |
| bind | sockfd, sockaddr_nin, addrlen | 错误码 | 绑定地址和端口 |
| listen | sockfd, backlog | 错误码 | 监听连接 |
| connect | sockfd, sockaddr_nin, addrlen | 错误码 | 创建连接 |
| accept | sockfd, sockaddr_nin, addrlen | 新sockfd | 接受连接 |
| send | sockfd, msg, len, flags, dst_addr, addrlen | 错误码 | 发送数据 |
| recv | sockfd, buf, len, flags, src_addr, addrlen | 错误码 | 接收数据 |
| close | sockfd | 错误码 | 关闭socket |
5.6.2 地址结构
// New IP短地址索引枚举
enum nip_8bit_addr_index {NIP_8BIT_ADDR_INDEX_0 = 0,NIP_8BIT_ADDR_INDEX_1 = 1,NIP_8BIT_ADDR_INDEX_2 = 2,NIP_8BIT_ADDR_INDEX_3 = 3,NIP_8BIT_ADDR_INDEX_4 = 4,NIP_8BIT_ADDR_INDEX_5 = 5,NIP_8BIT_ADDR_INDEX_6 = 6,NIP_8BIT_ADDR_INDEX_7 = 7,NIP_8BIT_ADDR_INDEX_MAX,
};
6. 任务调度优化
6.1 关联线程组调度
6.1.1 基本概念
关联线程组(Related Thread Group,RTG)调度特性提供了对一组关键线程调度优化的能力,支持对关键线程组单独进行负载统计和预测,并且设置优选CPU cluster功能,从而为组内线程选择最优CPU运行,并根据分组负载选择合适的CPU调频点运行。
6.1.2 核心特性
负载管理:
- 对关键线程组进行独立的负载统计
- 提供负载预测功能
- 避免关键线程受到其他任务影响
CPU选择优化:
- 为组内线程选择最优CPU
- 根据分组负载选择合适的CPU调频点
- 支持CPU cluster级别的优选设置
6.1.3 配置指导
启用关联线程组:
CONFIG_SCHED_RTG=y // 使能关联线程组调度
CONFIG_SCHED_RTG_DEBUG=y // 使能调试功能
CONFIG_SCHED_RTG_FRAME=y // 使能框架支持
CONFIG_SCHED_RTG_RT_THREAD_LIMIT=y // 限制实时线程
依赖配置:
CONFIG_SCHED_WALT=y // 依赖WALT调度器
6.1.4 使用方法
添加进程到关联线程组:
# 将进程添加到group id为2的关联线程组
echo 2 > /proc/<pid>/sched_group_id# 将进程移出关联线程组(group id=0表示非关联线程组)
echo 0 > /proc/<pid>/sched_group_id
6.1.5 信息查看
查看关联线程组信息:
cat /proc/sched_rtg_debug
输出示例:
RTG_ID : 2 // 分组ID
RTG_INTERVAL : UPDATE:8ms#INVALID:4294ms // CPU调频间隔和负载有效时长
RTG_CLUSTER : -1 // 优选CPU cluster ID
RTG_THREADS : 0/1 // 分组包含的线程总数
STATE COMM PID PRIO CPU // 线程信息
---------------------------------------------------------S bash 436 120 1(0-3)
字段说明:
- RTG_ID:分组ID(group id=1为预留分组,不支持添加进程)
- RTG_INTERVAL:CPU调频间隔和负载有效时长
- RTG_CLUSTER:分组优选CPU cluster ID(-1表示未设置)
- RTG_THREADS:分组包含的线程总数
7. 开发板Patch使用
7.1 基本概念
OpenHarmony开发板Patch使用指导描述了如何在不同内核版本上合入HDF(Harmony Driver Foundation)补丁和芯片平台驱动补丁,以确保OpenHarmony系统能够在特定硬件平台上正常运行。
7.2 HDF补丁合入
7.2.1 合入方法
按照kernel.mk中的HDF补丁合入方法,合入不同内核版本对应的HDF内核补丁:
$(OHOS_BUILD_HOME)/drivers/hdf_core/adapter/khdf/linux/patch_hdf.sh \$(OHOS_BUILD_HOME) $(KERNEL_SRC_TMP_PATH) $(KERNEL_PATCH_PATH) $(DEVICE_NAME)
7.2.2 补丁路径规则
不同芯片平台的驱动补丁按照kernel.mk中的路径规则放置:
DEVICE_PATCH_DIR := $(OHOS_BUILD_HOME)/kernel/linux/patches/${KERNEL_VERSION}/$(DEVICE_NAME)_patch
DEVICE_PATCH_FILE := $(DEVICE_PATCH_DIR)/$(DEVICE_NAME).patch
7.3 芯片平台驱动补丁
7.3.1 补丁命名规则
补丁文件按照命名规则放置在对应路径下:
- 路径:
kernel/linux/patches/${KERNEL_VERSION}/${DEVICE_NAME}_patch/ - 文件名:
${DEVICE_NAME}.patch
7.3.2 编译配置
修改编译所需的内核配置文件:
KERNEL_CONFIG_PATH := $(OHOS_BUILD_HOME)/kernel/linux/config/${KERNEL_VERSION}
DEFCONFIG_FILE := $(DEVICE_NAME)_$(BUILD_TYPE)_defconfig
7.4 编译配置修改
7.4.1 配置放置路径
将芯片平台配置文件放置在指定路径下:
- 路径:
kernel/linux/config/${KERNEL_VERSION}/ - 文件名:
${DEVICE_NAME}_${BUILD_TYPE}_defconfig
7.4.2 注意事项
须知:
由于OpenHarmony工程的编译构建流程中会拷贝kernel/linux/linux-*.*的代码环境后进行打补丁动作,在使用OpenHarmony的版本级编译命令前,需要kernel/linux/linux-*.*原代码环境。
7.4.3 配置生效流程
- 基于最后生成的内核进行对应平台的config修改
- 将生成的
.config文件复制到config仓对应平台的路径文件里 - 确保配置生效并用于后续编译
8. CPU资源管理
8.1 CPU轻量级隔离
8.1.1 基本概念
CPU轻量级隔离特性提供了根据系统负载和用户配置来选择合适的CPU进行动态隔离的能力。内核会将被隔离CPU上的任务和中断迁移到其他合适的CPU上执行,被隔离的CPU会进入idle状态,以此来达到功耗优化的目标。
8.1.2 核心特性
动态CPU隔离:
- 根据系统负载自动选择合适的CPU进行隔离
- 支持用户配置的CPU隔离策略
- 实时调整CPU在线状态
任务和中断迁移:
- 自动将被隔离CPU上的任务迁移到其他CPU
- 将中断重新分配到活跃CPU
- 保证系统正常运行
功耗优化:
- 被隔离CPU进入idle状态
- 减少CPU功耗
- 提升整体能效比
8.1.3 配置指导
启用CPU轻量级隔离:
CONFIG_CPU_ISOLATION_OPT=y // 使能CPU隔离优化
CONFIG_SCHED_CORE_CTRL=y // 使能CPU核心控制
依赖配置:
CONFIG_SMP=y // 对称多处理器支持
CONFIG_SCHED_WALT=y // WALT调度器支持
8.2 相关接口
8.2.1 接口位置
CPU轻量级隔离接口位于每个CPU cluster的首个CPU设备信息目录中:
- 目录:
/sys/devices/system/cpu/cpu0/core_ctl
8.2.2 控制接口
| 接口名称 | 描述 |
|---|---|
| enable | 功能开关:1=开启,0=关闭 |
| min_cpus | 设置活跃(未隔离)CPU最小值个数 |
| max_cpus | 设置活跃(未隔离)CPU最大值个数 |
8.2.3 状态接口
| 接口名称 | 描述 |
|---|---|
| active_cpus | 显示当前活跃(未隔离)的CPU个数 |
| need_cpus | 显示当前需要解隔离的CPU个数 |
| global_state | 记录系统所有CPU cluster的状态信息 |
8.3 使用方法
8.3.1 功能开关
# 开启CPU轻量级隔离
echo 1 > /sys/devices/system/cpu/cpu0/core_ctl/enable# 关闭CPU轻量级隔离
echo 0 > /sys/devices/system/cpu/cpu0/core_ctl/enable
8.3.2 CPU数量设置
# 设置最小活跃CPU数为2
echo 2 > /sys/devices/system/cpu/cpu0/core_ctl/min_cpus# 设置最大活跃CPU数为4
echo 4 > /sys/devices/system/cpu/cpu0/core_ctl/max_cpus
8.3.3 状态查询
# 查看当前活跃CPU数
cat /sys/devices/system/cpu/cpu0/core_ctl/active_cpus# 查看需要解隔离的CPU数
cat /sys/devices/system/cpu/cpu0/core_ctl/need_cpus# 查看全局状态
cat /sys/devices/system/cpu/cpu0/core_ctl/global_state
