4.6.3 安全机制
2026/7/16大约 5 分钟内核组件内核错误处理安全机制钩子函数
4.6.3 安全机制
📚 本节导读
学习时长: 约 20 分钟
难度级别: ⭐⭐⭐☆☆
前置知识: 断言机制、异常处理基础、钩子函数概念
🎯 学习目标
- 理解 OneOS 安全机制的设计目的和处理流程
- 掌握用户自定义钩子函数的注册方法
- 理解安全机制启用和禁用时的不同行为
- 了解安全机制与断言、异常处理的关系
一、安全机制概念
安全机制(Safety Mechanism)是 OneOS 错误处理体系的第三层,也是最后一层防护。当系统发生关键故障时(堆栈溢出、断言失败、硬件异常),安全机制提供最终的保护处理,防止系统进入不可控状态。
安全机制 API 定义在 kernel/include/os_safety.h 中,行为由 OS_USING_SAFETY_MECHANISM 宏控制。
二、安全机制 API
2.1 钩子注册函数
安全机制提供了三个钩子注册函数,允许应用程序注册自定义的故障处理函数:
#ifdef OS_USING_SAFETY_MECHANISM
/* 注册堆栈溢出处理钩子 */
void os_safety_task_stack_overflow_set_hook(void (*hook)(void));
/* 注册断言失败处理钩子 */
void os_safety_assert_set_hook(void (*hook)(void));
/* 注册异常处理钩子 */
void os_safety_exception_set_hook(void (*hook)(void));钩子函数签名:
void my_hook(void); /* 无参数,无返回值 */2.2 处理函数
当故障发生时,系统调用相应的处理函数:
/* 处理堆栈溢出 */
void os_safety_task_stack_overflow_process(void);
/* 处理断言失败 */
void os_safety_assert_process(void);
/* 处理异常 */
void os_safety_exception_process(void);三、安全机制的处理流程
3.1 启用安全机制时(OS_USING_SAFETY_MECHANISM 已定义)
故障发生
│
├─ os_safety_*_process()
│ │
│ ├─ 检查是否注册了用户钩子
│ │ │
│ │ ├─ 已注册 → 调用用户钩子函数
│ │ │ │
│ │ │ ├─ 钩子返回 → 继续默认处理
│ │ │ └─ 钩子不返回(如重启系统)
│ │ │
│ │ └─ 未注册 → 直接进入默认处理
│ │
│ └─ 默认处理(具体行为取决于实现)
│
└─ 系统处理完毕3.2 未启用安全机制时(OS_USING_SAFETY_MECHANISM 未定义)
当安全机制未启用时,处理函数被替换为简单的宏(定义在 os_safety.h):
#define os_safety_task_stack_overflow_process() \
do \
{ \
os_irq_disable(); \
while (1) \
; \
} while (0)
#define os_safety_assert_process() \
do \
{ \
os_irq_disable(); \
while (1) \
{ \
; \
} \
} while (0)
#define os_safety_exception_process() \
do \
{ \
os_irq_disable(); \
while (1) \
{ \
; \
} \
} while (0)默认行为:关闭全局中断,进入无限循环,停止系统运行。这是一种"安全停止"策略——当系统发生无法恢复的故障时,停止一切活动以防止进一步的破坏。
四、代码示例
4.1 注册自定义钩子
#include <os_safety.h>
#include <os_util.h>
/* 自定义断言失败处理钩子 */
static void my_assert_hook(void)
{
/* 记录故障信息到非易失存储 */
save_fault_info_to_flash("ASSERT_FAILED");
/* 尝试通知外部监控系统 */
send_heartbeat_failure();
/* 执行系统复位 */
os_hw_reboot();
}
/* 自定义堆栈溢出处理钩子 */
static void my_stack_overflow_hook(void)
{
os_kprintf("!!! STACK OVERFLOW DETECTED !!!\r\n");
/* 记录当前任务信息 */
os_kprintf("Task: %s\r\n", os_task_get_name(os_task_self()));
os_kprintf("Stack top: 0x%08X\r\n", os_task_get_stack_top(os_task_self()));
os_kprintf("Stack begin: 0x%08X\r\n", os_task_get_stack_begin(os_task_self()));
/* 保存关键信息后复位 */
save_fault_info_to_flash("STACK_OVERFLOW");
os_hw_reboot();
}
void safety_hooks_init(void)
{
/* 注册自定义钩子函数 */
os_safety_assert_set_hook(my_assert_hook);
os_safety_task_stack_overflow_set_hook(my_stack_overflow_hook);
os_safety_exception_set_hook(my_assert_hook); /* 异常也使用相同的处理 */
}4.2 自定义异常钩子
/* 自定义异常处理钩子 */
static void my_exception_hook(void)
{
/* 收集异常信息 */
dump_cpu_registers();
/* 记录故障任务 */
extern os_task_t *g_os_current_task;
if (g_os_current_task != OS_NULL)
{
os_kprintf("Fault task: %s\r\n", g_os_current_task->name);
}
/* 记录系统 tick */
os_kprintf("System tick: %d\r\n", os_tick_get_value());
/* 执行系统复位 */
os_hw_reboot();
}4.3 记录故障后安全停止
static void safe_stop_hook(void)
{
/* 设置所有 GPIO 为安全状态 */
set_all_outputs_to_safe_state();
/* 关闭可能危险的输出 */
disable_motor();
disable_heater();
/* 记录故障码 */
write_fault_code(FAULT_CODE_ASSERT);
/* 钩子返回后,系统会继续默认处理(停止运行) */
os_kprintf("System halted due to safety fault\r\n");
}
void safety_init(void)
{
os_safety_assert_set_hook(safe_stop_hook);
os_safety_task_stack_overflow_set_hook(safe_stop_hook);
os_safety_exception_set_hook(safe_stop_hook);
}五、与断言和异常的关系
┌──────────────────────────────────────────────────────────────┐
│ 故障来源 触发入口 处理函数 │
├──────────────────────────────────────────────────────────────┤
│ OS_ASSERT 失败 → os_safety_assert_process() │
│ OS_ASSERT_EX 失败 → os_safety_assert_process() │
│ 堆栈溢出检测 → os_safety_task_stack_overflow_process() │
│ HardFault 异常 → os_safety_exception_process() │
│ MemManage 异常 → os_safety_exception_process() │
│ BusFault 异常 → os_safety_exception_process() │
│ UsageFault 异常 → os_safety_exception_process() │
└──────────────────────────────────────────────────────────────┘六、配置与使用建议
6.1 配置选项
/* 在 oneos_config.h 中 */
#define OS_USING_SAFETY_MECHANISM /* 启用安全机制 */6.2 使用建议
| 场景 | 建议 |
|---|---|
| 开发调试 | 启用安全机制,注册钩子打印详细故障信息 |
| 生产环境 | 启用安全机制,注册钩子记录故障并执行安全复位 |
| 关键安全系统 | 启用安全机制,注册钩子将系统置于安全状态后停止 |
| 资源极度受限 | 可考虑禁用安全机制,使用默认的死循环保护 |
重要:在安全关键的应用中,钩子函数应尽可能简单可靠,避免在其中执行可能再次触发故障的操作(如动态内存分配、复杂的日志输出)。
📝 本节小结
安全机制是 OneOS 错误处理体系的第三层防护,为堆栈溢出、断言失败和异常三种关键故障提供最终处理。通过 os_safety_*_set_hook 函数,应用程序可以注册自定义的故障处理钩子,实现故障记录、系统复位或安全停止等操作。未启用安全机制时,系统采取最简单的保护策略:关闭中断并进入无限循环。安全机制与断言、异常处理紧密配合,构成了完整的故障处理链路。