问题现象
在龙芯 LS2K300 平台(OpenHarmony 6.1,LiteOS-M 内核)上运行 HCTest 测试框架时,系统输出的产品参数信息全部为空值或占位符 "****":
******To Obtain Product Params Start******
Device Type = NULL
Security Patch = NULL
OsFullName =
DisplayVersion = NULL
VersionID =
DevUdid = NULL
manuFacture = NULL
productModel = NULL
serial = ****
brand = NULL
productSeries = NULL
softwareModel = NULL
HardwareModel = NULL
BuildRootHash = NULL
marketName = NULL
SdkApiVersion = 0
firstApiVersion = 0
bootloaderVersion = NULL
incrementalVersion = NULL
buildType = NULL
buildUser = NULL
buildHost = NULL
buildTime = NULL
AbiList = NULL
******To Obtain Product Params End ******
唯一看起来有值的 serial = **** 其实也是默认占位符,并非真正的设备序列号。这些参数的缺失会导致依赖产品信息的系统服务或应用无法正常运行。
表层原因:缺少平台 HAL 适配
初步排查发现,vendor/loongson/ls2k300_mini_dp 目录下缺少 hals/utils/sys_param/ 平台适配实现。构建系统找不到板级 HAL 库时,会回退到 base/startup/init/interfaces/hals/utils/sys_param/hal_sys_param.c 中的通用默认实现,该实现所有字段均返回 "****"。
为此,我们在板级目录下创建了以下三个文件:
vendor/loongson/ls2k300_mini_dp/hals/utils/sys_param/
├── hal_sys_param.c # 实现所有 HalGet*() 函数,填入真实设备信息
├── BUILD.gn # 声明 hal_sysparam 静态库
└── vendor.para # 运行时参数服务读取的 key=value 配置文件
hal_sys_param.c 中实现了如下函数(示例):
c
const char *HalGetManufacture(void) { return "Loongson"; }
const char *HalGetDeviceType(void) { return "mini"; }
const char *HalGetHardwareModel(void) { return "LS2K300V1.0"; }
// ... 其他字段类似
同时,vendor.para 文件以 key=value 格式提供运行时参数:
const.ohos.serial=0123456789abcdef
const.ohos.hardwaremodel=LS2K300V1.0
const.ohos.version.security_patch=2024-01-01
const.ohos.apiversion=12
const.product.manufacturer=Loongson
...
然而,重新编译后,问题依旧存在------HCTest 输出的产品参数仍然全部为空。
深层根因:参数服务初始化顺序竞争
进一步分析 LiteOS-M 内核上产品参数的获取流程:
GetDeviceType() / GetManufacture() / ...
↓
GetProperty("const.product.*")
↓
SystemReadParam() // 从参数服务读取
关键发现 :在 LiteOS-M(mini 系统)上,上述接口并不直接调用 HalGetXxx(),而是通过 GetProperty() 从参数服务(LiteParamService)的内存工作区读取值。
参数服务的初始化函数 LiteParamService 和 HCTest 框架的初始化函数 InitTestSuiteMgr 均使用 CORE_INIT() 宏注册 ,该宏默认优先级为 2。同一优先级内的函数执行顺序由链接器决定,不可控。
当 InitTestSuiteMgr 恰好在 LiteParamService 之前执行时,参数服务的工作区尚未初始化,此时任何 GetProperty() 调用都会因工作区为空而返回 NULL。这就是即使 HAL 层已正确实现、配置文件也已提供,产品参数依然全为空的根本原因。
时序示意图
系统启动 → CORE_INIT 阶段(优先级 2)
│
├─ InitTestSuiteMgr() ← 若先执行,参数服务未就绪,读取失败
│
└─ LiteParamService() ← 初始化参数工作区,加载 vendor.para
修复方案:提升参数服务初始化优先级
为解决该竞争问题,我们将 LiteParamService 的初始化优先级从默认的 2 提升至 0,确保它在所有默认优先级的初始化函数之前运行。
文件 :base/startup/init/services/param/liteos/param_service.c 第 148 行
c
// 修改前
CORE_INIT(LiteParamService);
// 修改后
CORE_INIT_PRI(LiteParamService, 0);
CORE_INIT_PRI 宏会将函数指针放入 .zinitcall.core0.init 段,该段中的函数会在系统启动最早阶段执行(优先级 0),远早于默认优先级 2 的其他 CORE_INIT 函数。
安全性说明
LiteParamService函数内部已有static int init标志防止重复初始化,即使system_init.c中还存在显式调用也不会重复执行。- 提升优先级仅影响 LiteOS-M 内核的参数服务,不改变其他模块的初始化顺序。
- 其他所有依赖参数服务的组件(包括 HCTest)都能在运行时获得已就绪的参数工作区。
验证结果
应用上述两项修改(添加平台 HAL 适配 + 提升参数服务优先级)后,重新构建并烧录镜像,HCTest 框架输出如下:
******To Obtain Product Params Start******
Device Type = default
Security Patch = 2026/02/01
OsFullName = OpenHarmony-6.1.0.31
DisplayVersion = OpenHarmony 6.1.0.31
VersionID = default/Loongson/Loongson/LS2K0300/OpenHarmony-6.1.0.31/LS2K0300/LiteOS-M/23/OpenHarmony 6.1 rel/debug
DevUdid = EDD27AEB735CF09FE6AF91F25782BECB1A55DA4CA9A3F9E38DA86DFDDAB45FC0
manuFacture = Loongson
productModel = LS2K0300
serial = 0123456789abcdef
brand = Loongson
productSeries = LS2K0300
softwareModel = LiteOS-M
HardwareModel = LS2K0300V1.0
BuildRootHash = default
marketName = LS2K0300 Mini
SdkApiVersion = 23
firstApiVersion = 1
bootloaderVersion = bootloader
incrementalVersion = OpenHarmony 6.1 rel
buildType = debug
buildUser = jenkins
buildHost = linux
buildTime = 1776392302060
AbiList = loongarch64-liteos
******To Obtain Product Params End ******
所有产品参数均正常显示,问题彻底解决。
总结与启示
本次调试过程揭示了两层隐蔽的技术陷阱:
- 平台 HAL 适配缺失导致回退默认值:构建系统在找不到板级实现时会自动回退到通用实现,该实现往往仅返回占位符,不会产生编译错误,极易被忽略。
- 初始化顺序竞争:在 LiteOS-M 这类资源受限、启动流程紧凑的内核上,依赖同一优先级初始化的组件之间存在竞态风险。当某个服务消费者在服务提供者之前初始化时,读取操作会静默失败(返回 NULL),而不会触发明显错误。
通用排查建议
- 若发现系统参数输出为
"****"或NULL,首先检查板级目录下是否提供了hals/utils/sys_param/实现。 - 若 HAL 已正确实现但运行时仍为空,请检查参数服务初始化是否在所有消费者之前完成。
- 对于 LiteOS-M 平台,可借助链接 Map 文件查看
.zinitcall.coreX.init段中函数的实际排布顺序,以诊断初始化顺序问题。