OpenHarmony设备开发 移植子系统
移植子系统概述
OpenHarmony系统功能按照“系统 > 子系统 > 部件”逐级展开,支持根据实际需求裁剪某些非必要的部件,本文以部分子系统、部件为例进行介绍。若想使用OpenHarmony系统的能力,需要对相应子系统进行适配。
OpenHarmony芯片适配常见子系统列表如下(详见表1),需结合具体芯片再做增删减操作。
表1 OpenHarmony子系统
子系统 | 作用 |
applications | 应用程序demo。可将应用相关源码存放在此目录下。 |
kernel | 内核子系统。负责任务调度、内存管理等常见的内核功能。 |
hiviewdfx | 可维可测子系统。提供日志相关功能。 |
communication | 通信子系统。包含Wi-Fi,蓝牙功能。 |
iothardware | IOT外设子系统。提供常见的外设接口,例如GPIO,I2C,SPI等。 |
startup | 启动子系统。内核启动后运行的第一个子系统,负责在内核启动之后到应用启动之前的系统关键进程和服务的启动过程的功能。 |
update | 升级子系统。用来支持OpenHarmony设备的OTA升级。 |
utils | 公共基础库子系统。提供了一些常用的C、C++开发增强API。 |
distributed_schedule | 分布式调度子系统。负责跨设备部件管理,提供访问和控制远程组件的能力,支持分布式场景下的应用协同。 |
security | 安全子系统。包括系统安全、数据安全、应用安全等功能,为OpenHarmony提供有效保护应用和用户数据的能力。当前开源的功能,包括应用完整性保护、应用权限管理、设备认证、密钥管理服务、数据传输管控。 |
test | 测试子系统。OpenHarmony为开发者提供了一套全面的自测试框架,开发者可根据测试需求开发相关测试用例,开发阶段提前发现缺陷,大幅提高代码质量。 |
移植启动恢复子系统
启动恢复子系统负责在内核启动之后到应用启动之前的系统关键进程和服务的启动过程的功能。
移植指导
针对轻量系统主要提供了各服务和功能的启动入口标识。在SAMGR启动时,会调用bootstrap标识的入口函数,并启动系统服务。
适配完成后,调用OHOS_SystemInit()接口,即可启动系统。
路径:“base/startup/bootstrap_lite/services/source/system_init.c”
void OHOS_SystemInit(void)
{
MODULE_INIT(bsp); //执行.zinitcall.bspX.init段中的函数
MODULE_INIT(device); //执行.zinitcall.deviceX.init段中的函数
MODULE_INIT(core); //执行.zinitcall.coreX.init段中的函数
SYS_INIT(service); //执行.zinitcall.sys.serviceX.init段中的函数
SYS_INIT(feature); //执行.zinitcall.sys.featureX.init段中的函数
MODULE_INIT(run); //执行.zinitcall.runX.init段中的函数
SAMGR_Bootstrap(); //SAMGR服务初始化
}
移植实例
- 在“config.json”中添加启动子系统。 路径:“vendor/MyVendorCompany/MyProduct/config.json”
修改如下:
{
subsystem": "startup",
components": [
{ "component": "bootstrap_lite", "features":[] },
{ "component": "syspara_lite", "features":[] }
]
},
在startup子系统中有部分部件(如:syspara_lite等),会依赖“$ohos_product_adapter_dir/utils”中的模块。其中“ohos_product_adapter_dir”就是在config.json文件中配置的“product_adapter_dir”,我们通常配置其为“vendor/MyVendorCompany/MyProduct/hals”。
2.添加zinitcall以及run定义。 在厂商ld链接脚本中.text段中,添加如下代码:
__zinitcall_bsp_start = .;
KEEP (*(.zinitcall.bsp0.init))
KEEP (*(.zinitcall.bsp1.init))
KEEP (*(.zinitcall.bsp2.init))
KEEP (*(.zinitcall.bsp3.init))
KEEP (*(.zinitcall.bsp4.init))
__zinitcall_bsp_end = .;
__zinitcall_device_start = .;
KEEP (*(.zinitcall.device0.init))
KEEP (*(.zinitcall.device1.init))
KEEP (*(.zinitcall.device2.init))
KEEP (*(.zinitcall.device3.init))
KEEP (*(.zinitcall.device4.init))
__zinitcall_device_end = .;
__zinitcall_core_start = .;
KEEP (*(.zinitcall.core0.init))
KEEP (*(.zinitcall.core1.init))
KEEP (*(.zinitcall.core2.init))
KEEP (*(.zinitcall.core3.init))
KEEP (*(.zinitcall.core4.init))
__zinitcall_core_end = .;
__zinitcall_sys_service_start = .;
KEEP (*(.zinitcall.sys.service0.init))
KEEP (*(.zinitcall.sys.service1.init))
KEEP (*(.zinitcall.sys.service2.init))
KEEP (*(.zinitcall.sys.service3.init))
KEEP (*(.zinitcall.sys.service4.init))
__zinitcall_sys_service_end = .;
__zinitcall_sys_feature_start = .;
KEEP (*(.zinitcall.sys.feature0.init))
KEEP (*(.zinitcall.sys.feature1.init))
KEEP (*(.zinitcall.sys.feature2.init))
KEEP (*(.zinitcall.sys.feature3.init))
KEEP (*(.zinitcall.sys.feature4.init))
__zinitcall_sys_feature_end = .;
__zinitcall_run_start = .;
KEEP (*(.zinitcall.run0.init))
KEEP (*(.zinitcall.run1.init))
KEEP (*(.zinitcall.run2.init))
KEEP (*(.zinitcall.run3.init))
KEEP (*(.zinitcall.run4.init))
__zinitcall_run_end = .;
__zinitcall_app_service_start = .; //SAMGR执行.zinitcall.app.serviceX.init段中的函数
KEEP (*(.zinitcall.app.service0.init))
KEEP (*(.zinitcall.app.service1.init))
KEEP (*(.zinitcall.app.service2.init))
KEEP (*(.zinitcall.app.service3.init))
KEEP (*(.zinitcall.app.service4.init))
__zinitcall_app_service_end = .;
__zinitcall_app_feature_start = .; //SAMGR执行.zinitcall.app.featureX.init段中的函数
KEEP (*(.zinitcall.app.feature0.init))
KEEP (*(.zinitcall.app.feature1.init))
KEEP (*(.zinitcall.app.feature2.init))
KEEP (*(.zinitcall.app.feature3.init))
KEEP (*(.zinitcall.app.feature4.init))
__zinitcall_app_feature_end = .;
__zinitcall_test_start = .;
KEEP (*(.zinitcall.test0.init))
KEEP (*(.zinitcall.test1.init))
KEEP (*(.zinitcall.test2.init))
KEEP (*(.zinitcall.test3.init))
KEEP (*(.zinitcall.test4.init))
__zinitcall_test_end = .;
__zinitcall_exit_start = .;
KEEP (*(.zinitcall.exit0.init))
KEEP (*(.zinitcall.exit1.init))
KEEP (*(.zinitcall.exit2.init))
KEEP (*(.zinitcall.exit3.init))
KEEP (*(.zinitcall.exit4.init))
__zinitcall_exit_end = .;
3.芯片SDK创建任务。 配置任务参数,系统启动后,启动任务,示例如下:
void mainTask(void) {
//厂商自定义功能
OHOS_SystemInit(); //启动子系统初始化
printf("MainTask running...\n");
}
void main(VOID) {
//硬件初始化,printf输出重定向到debug串口等
if (LOS_KernelInit() == 0) { //ohos内核初始化
task_init_param.usTaskPrio = 10; //任务优先级
task_init_param.pcName = "mainTask"; //任务进程名
task_init_param.pfnTaskEntry = (TSK_ENTRY_FUNC)mainTask; //任务入口函数
task_init_param.uwStackSize = 8192; //任务栈大小
LOS_TaskCreate(&tid, &task_init_param); //创建任务
LOS_Start(); //启动任务
}
else {
printf("[BUG] LOS_KernelInit fail\n");
}
printf("[BUG] reach to unexpected code\n");
while (1);
}
移植文件子系统
utils部件可被各业务子系统及上层应用使用,依赖芯片文件系统实现,需要芯片平台提供文件打开、关闭、读写、获取大小等功能。
移植指导
OpenHarmony文件系统需要适配如下HAL层接口:
表1 文件打开或关闭
接口名 | 描述 |
HalFileOpen | 文件打开或创建新文件。 |
HalFileClose | 文件关闭。 |
表2 文件操作
接口名 | 描述 |
HalFileRead | 读文件。 |
HalFileWrite | 写文件。 |
HalFileDelete | 删除文件。 |
HalFileStat | 获取文件属性。 |
HalFileSeek | 文件查找。 |
厂商适配相关接口的实现,请参考OpenHarmony中file的接口和hal层适配接口的定义:
//utils/native/lite/file
├── BUILD.gn
└── src
└── file_impl_hal
└── file.c #file接口
//utils/native/lite/hals
└── file
└── hal_file.h #hal层接口头文件
其中BUILD.gn的内容如下:
import("//build/lite/config/component/lite_component.gni")
static_library("native_file") {
sources = [
"src/file_impl_hal/file.c",
]
include_dirs = [
"//utils/native/lite/include",
"//utils/native/lite/hals/file",
]
deps = ["$ohos_vendor_adapter_dir/hals/utils/file:hal_file_static"] #依赖厂商的适配
}
lite_component("file") {
features = [
":native_file",
]
}
从中可以看到厂商适配相关接口的存放目录应为“$ohos_vendor_adapter_dir/hals/utils/file”,且该目录下BUILD.gn文件中的目标应为hal_file_static。
通常厂商可以采用下面三种方式适配hal层接口:
- 直接flash读写,模拟文件的操作。
- 使用littlefs或者fatfs文件系统进行适配,littlefs或者fatfs都是轻量级文件系统适配简单,其中OpenHarmony的“//thirdparty”目录下已有fatfs可供参考。
- 使用厂商已有的文件系统进行适配。
移植实例
- “config.json”添加文件系统。 路径:“vendor/MyVendorCompany/MyProduct/config.json”
修改如下:
{
"subsystem": "utils",
"components": [
{ "component": "file", "features":[] }
]
},
2.添加适配文件。 在“vendor/MyVendorCompany/MyProduct/config.json”文件中,vendor_adapter_dir配置项通常进行如下配置:
“vendor_adapter_dir”: “//device/MyDeviceCompany/MyBoard/adapter”。
在该目录下进行UtilsFile接口适配:
hals/utils/file
├── BUILD.gn
└── src
└── hal_file.c
其中BUILD.gn内容如下:
import("//build/lite/config/component/lite_component.gni")
static_library("hal_file_static") { #目标名
sources = [ "src/hal_file.c" ] #厂商适配的源文件
include_dirs = [
"//utils/native/lite/hals/file",
]
}
移植安全子系统
安全子系统提供网络设备连接、认证鉴权等功能,依赖mbedtls实现硬件随机数以及联网功能。
由于每个厂商芯片硬件与实现硬件随机数的方式不同,需要适配硬件随机数接口。
移植指导
OpenHarmony提供了mbedtls的开源三方库,路径为“//third_party/mbedtls”。此库中提供了“mbedtls_platform_entropy_poll”、“mbedtls_hardclock_poll”、“mbedtls_havege_poll”、“mbedtls_hardware_poll”等几种产生随机数的方式。厂商需要根据芯片适配“mbedtls_hardware_poll”方式。
移植实例
- “config.json”添加文件系统。 路径:“vendor/MyVendorCompany/MyProduct/config.json”
修改如下:
{
"subsystem": "security",
"components": [
{ "component": "hichainsdk", "features":[] },
{ "component": "huks", "features":[]}
]
},
2.配置宏,打开硬件随机数接口相关代码。 根据mbedtls的编译文件可以看出,配置宏的位置在"MBEDTLS_CONFIG_FILE=<…/port/config/config_liteos_m.h>"文件中。
路径:“third_party/mbedtls/BUILD.gn”
if (ohos_kernel_type == "liteos_m") {
defines += [
"__unix__",
"MBEDTLS_CONFIG_FILE=<../port/config/config_liteos_m.h>",
]
}
根据代码我们可以看出需要配置“MBEDTLS_NO_PLATFORM_ENTROPY”、“MBEDTLS_ENTROPY_HARDWARE_ALT”两个宏,才能编译硬件随机数的相关代码。
路径:“third_party/mbedtls/library/entropy.c”
#if !defined(MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES)
#if !defined(MBEDTLS_NO_PLATFORM_ENTROPY)
mbedtls_entropy_add_source( ctx, mbedtls_platform_entropy_poll, NULL,
MBEDTLS_ENTROPY_MIN_PLATFORM,
MBEDTLS_ENTROPY_SOURCE_STRONG );
#endif
......
#if defined(MBEDTLS_ENTROPY_HARDWARE_ALT)
mbedtls_entropy_add_source( ctx, mbedtls_hardware_poll, NULL,
MBEDTLS_ENTROPY_MIN_HARDWARE,
MBEDTLS_ENTROPY_SOURCE_STRONG );
#endif
......
#endif /* MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES */
}
3.适配硬件随机数接口 接口定义如下:
路径:“third_party/mbedtls/include/mbedtls/entropy_poll.h”
int mbedtls_hardware_poll( void *data,unsigned char *output, size_t len, size_t *olen );
表1 安全子系统配置项
配置项 | 意义 |
disable_huks_binary | 是否编译HUKS源码。 (1) 默认值: false,不编译HUKS源码。 (2) 其他值: true,编译HUKS源码。 |
disable_authenticate | 是否需要裁剪hichain认证功能。 (1) 默认值: true,不裁剪。 (2) 其他值: false,裁剪hichain认证功能。 |
huks_use_lite_storage | 是否采用轻量化存储方案。无文件系统、仅有flash存储的设备,可采用轻量化存储方案。 (1) 默认值: true,使用轻量化存储。 (2) 其他值: false,不使用轻量化存储。 |
huks_use_hardware_root_key | 是否使用硬件根密钥。设备存在硬件根密钥能力时,需要根据自身能力适配硬件根密钥方案;HUKS提供的RKC方案仅为模拟实现。 (1) 默认值:false,默认值,默认无硬件根密钥。 (2) 其他值:true,设备具有硬件根密钥相关能力时,应自行适配。 |
huks_config_file | 是否使用HUKS默认配置文件。 (1) 默认值:“”:使用HUKS默认配置文件hks_config.h。 (2) 其他文件:产品可在HUKS支持能力集合中自行选择所要支持的特性。 |
说明:
在添加安全子系统时,可直接通过配置feature来选择安全子系统特性。
{ "subsystem": "security",
"components": [
{ "component": "hichainsdk", "features":[] },
{ "component": "huks", "features":
[
"disable_huks_binary = false",
"disable_authenticate = false"
]
}
]
},
移植通信子系统
通信子系统目前涉及Wi-Fi和蓝牙适配,厂商应当根据芯片自身情况进行适配。
移植指导
Wi-Fi编译文件内容如下:
路径:“foundation/communication/wifi_lite/BUILD.gn”
group("wifi") {
deps = [ "$ohos_board_adapter_dir/hals/communication/wifi_lite/wifiservice:wifiservice" ]
}
从中可以看到厂商适配相关接口的.c文件存放目录应为“$ohos_board_adapter_dir/hals/communication/wifi_lite/wifiservice”,且该目录下BUILD.gn文件中的目标应为“wifiservice”。需要厂商适配的Wi-Fi接口见表1 、表2 和表3,蓝牙接口见表4和表5。
表1 wifi_device.h
接口 | 作用 |
EnableWifi | 启用Wi-Fista模式。 |
DisableWifi | 禁用Wi-Fi sta模式。 |
IsWifiActive | 检查Wi-Fi sta模式是否启用。 |
Scan | 扫描热点信息。 |
GetScanInfoList | 获取所有扫描到的热点列表。 |
AddDeviceConfig | 配置连接到的热点信息。 |
GetDeviceConfigs | 获取配置连接到的热点信息。 |
RemoveDevice | 删除指定的热点配置信息。 |
ConnectTo | 接到指定的热点。 |
Disconnect | 断开Wi-Fi连接。 |
GetLinkedInfo | 获取热点连接信息。 |
RegisterWifiEvent | 为指定的Wi-Fi事件注册回调。 |
UnRegisterWifiEvent | 取消注册以前为指定Wi-Fi事件注册的回调。 |
GetDeviceMacAddress | 获取设备的MAC地址。 |
AdvanceScan | 根据指定参数启动Wi-Fi扫描。 |
表2 wifi_hotspot_config.h
接口 | 作用 |
SetBand | 设置该热点的频段。 |
GetBand | 获取该热点的频段。 |
表3 wifi_hotspot.h
接口 | 作用 |
EnableHotspot | 启用Ap热点模式。 |
DisableHotspot | 禁用Ap热点模式。 |
SetHotspotConfig | 设置指定的热点配置。 |
GetHotspotConfig | 获取指定的热点配置。 |
IsHotspotActive | 检查Ap热点模式是否启用。 |
GetStationList | 获取连接到此热点的一系列STA。 |
GetSignalLevel | 获取指定接收信号强度指示器(RSSI)和频带指示的信号电平。 |
DisassociateSta | 使用指定的MAC地址断开与STA的连接。 |
AddTxPowerInfo | 将hotspot功率发送到beacon。 |
表4 ohos_bt_gatt.h
接口 | 作用 |
InitBtStack | 初始化蓝牙协议栈。 |
EnableBtStack | 使能蓝牙协议栈。 |
DisableBtStack | 禁用蓝牙协议栈。 |
SetDeviceName | 设置蓝牙设备名称。 |
BleSetAdvData | 设置广播数据。 |
BleStartAdv | 开始广播。 |
BleStartAdvEx | 传入构建好的广播数据,参数,开启蓝牙广播。 |
BleStopAdv | 停止发送广播。 |
BleUpdateAdv | 更新advertising参数。 |
BleSetSecurityIoCap | 设置蓝牙的IO能力为NONE,配对方式为justworks。 |
BleSetSecurityAuthReq | 设置蓝牙是否需要配对绑定。 |
BleGattSecurityRsp | 响应安全连接请求。 |
ReadBtMacAddr | 获取设备MAC地址。 |
BleSetScanParameters | 设置扫描参数。 |
BleStartScan | 开始扫描。 |
BleStopScan | 停止扫描。 |
BleGattRegisterCallbacks | 注册gap,GATT事件回调函数。 |
表5 ohos_bt_gatt_server.h
接口 | 作用 |
BleGattsRegister | 使用指定的应用程序UUID注册GATT服务器。 |
BleGattsUnRegister | 断开GATT服务器与客户端的连接。 |
BleGattsDisconnect | 断开GATT服务器与客户端的连接。 |
BleGattsAddService | 添加了一个服务。 |
BleGattsAddIncludedService | 将包含的服务添加到指定的服务。 |
BleGattsAddCharacteristic | 向指定的服务添加特征。 |
BleGattsAddDescriptor | 将描述符添加到指定的特征。 |
BleGattsStartService | 启动一个服务。 |
BleGattsStopService | 停止服务。 |
BleGattsDeleteService | 删除一个服务。 |
BleGattsClearServices | 清除所有服务。 |
BleGattsSendResponse | 向接收到读取或写入请求的客户端发送响应。 |
BleGattsSendIndication | 设备侧向APP发送蓝牙数据。 |
BleGattsSetEncryption | 设置GATT连接的加密类型。 |
BleGattsRegisterCallbacks | 注册GATT服务器回调。 |
BleGattsStartServiceEx | 根据传入的服务列表,创建gatt服务。 |
BleGattsStopServiceEx | 传入gatt服务句柄,停止gatt服务。 |
说明:
不同版本接口可能存在差异,需要根据当前版本的具体文件进行适配。
适配实例
- 在“config.json”中添加communication子系统。 路径:“vendor/MyVendorCompany/MyProduct/config.json”
修改如下:
{
"subsystem": "communication",
"components": [
{ "component": "wifi_lite", "features":[] }
]
},
2.添加适配文件。
在“vendor/MyVendorCompany/MyProduct/config.json”文件中,通常将配置“ohos_board_adapter_dir”配置为 “//vendor/MyVendorCompany/MyProduct/adapter”。
在“ohos_board_adapter_dir”目录下根据上述适配指导中提到的头文件,适配Wi-Fi、蓝牙接口。
移植外设驱动子系统
外设驱动子系统提供OpenHarmony专有的外部设备操作接口。本模块提供设备操作接口有:FLASH, GPIO, I2C, PWM, UART, WATCHDOG等。
OpenHarmony提供了两种驱动适配方式:使用外设驱动子系统、使用HDF驱动框架。由于轻量级系统的资源有限,这里建议使用IOT子系统方式。
移植指导
厂商需要根据OpenHarmony提供的接口定义实现其功能,IOT子系统接口定义的头文件如下:
base/iot_hardware/peripheral/
├── BUILD.gn
└── interfaces
└── kits
├── iot_errno.h
├── iot_flash.h
├── iot_gpio.h
├── iot_i2c.h
├── iot_pwm.h
├── iot_uart.h
├── iot_watchdog.h
├── lowpower.h
└── reset.h
其中“base/iot_hardware/peripheral/BUILD.gn”文件如下:
import("//build/lite/config/subsystem/lite_subsystem.gni")
import("//build/lite/ndk/ndk.gni")
lite_subsystem("iothardware") {
subsystem_components = [
"$ohos_vendor_adapter_dir/hals/iot_hardware/wifiiot_lite:hal_iothardware",
]
}
if (ohos_kernel_type == "liteos_m") {
ndk_lib("iothardware_ndk") {
deps = [
"$ohos_vendor_adapter_dir/hals/iot_hardware/wifiiot_lite:hal_iothardware", #依赖厂商的适配
]
head_files = [ "//base/iot_hardware/peripheral/interfaces/kits" ]
}
}
从中可以看到厂商适配相关接口的存放目录应为“$ohos_vendor_adapter_dir/hals/iot_hardware/wifiiot_lite”,且该目录下BUILD.gn文件中的目标应为hal_iothardware。
移植实例
- 在“config.json”中添加iot_hardware子系统。 路径:“vendor/MyVendorCompany/MyProduct/config.json”
修改如下:
{
subsystem": "iot_hardware",
components": [
{ "component": "iot_controller", "features":[] }
]
},
2.添加适配文件。
在“vendor/MyVendorCompany/MyProduct/config.json”文件中,通常将配置“vendor_adapter_dir”配置为 “//device/MyDeviceCompany/MyBoard/adapter”。
在“vendor_adapter_dir”目录下进行适配:
hals/iot_hardware/wifiiot_lite
├── BUILD.gn
├── iot_flash.c
├── iot_gpio.c
├── iot_i2c.c
├── iot_lowpower.c
├── iot_pwm.c
├── iot_reset.c
├── iot_uart.c
└── iot_watchdog.c
其中BUILD.gn内容如下:
static_library("hal_iothardware") { #目标名
sources = [ #厂商适配的源文件
"iot_watchdog.c",
"iot_reset.c",
"iot_flash.c",
"iot_i2c.c",
"iot_gpio.c",
"iot_pwm.c",
"iot_uart.c"
]
include_dirs = [ ]
}
其中,“include_dirs”需要根据工程实际情况包含两个路径:
- iot子系统的头文件路径
- 适配iot子系统所使用到的SDK的头文件路径
配置其他子系统
除上述子系统之外,还有一些必要但是无需进行移植的子系统。如:分布式任务调度子系统、DFX子系统。
这些子系统添加方式比较简单,在“vendor/MyVendorCompany/MyProduct/config.json”文件中进行如下配置即可:
{
"subsystem": "distributed_schedule",
"components": [
{ "component": "system_ability_manager", "features":[] } # 此处部件名不同版本可能有变化,请根据实际代码填写
]
},
{
"subsystem": "hiviewdfx",
"components": [
{ "component": "hilog_lite", "features":[] },
{ "component": "hievent_lite", "features":[] }
]
},