项内容
文档版本v1.0
日期2026-09-19
研究范围ESP32-S3 平台上的动态扩展/多语言运行时机制
结论来源源码逐文件阅读 + 构建产物实测(.so 段表/符号表解析、固件 map 归因)

依据说明(重要)

  • 文中所有事实性结论均标注出处 文件路径:行号。
  • 无法从现有源码/产物直接确认的,标注 【推断】。
  • 尚未核对、需要后续确认的,标注 【待核实】。
  • 路径基准:除特别说明外,路径相对于 bs_hmi_base_s3/,即 [project_root]/。
  • Brookesia 源码全部位于 so_build/ref/。
  • 本文档不含推测性评价;涉及"建议"的部分集中在第 4 章,且均给出依据。

目录


0. 结论速览

结论依据
elf_loader 基座架构是层级式:elf_loader 是唯一执行基座,Lua 是运行在其中一个 .so 内的内容so_build/lua_engine/CMakeLists.txt、components/elf_loader/src/esp_elf.c
Brookesia 是对等式:ELF/Lua/JS/WASM 四个平级后端,共享一套宿主契约brookesia_runtime_manager/include/brookesia/runtime_manager/backend.hpp:19-64
elf_loader 基座的加载链路强于官方 ELF 后端(加密、符号白名单、host call)对比见 3.3;官方证据 brookesia_runtime_elf/src/backend.cpp:101-104, 266-281
lua_engine(跑在基座上的 Lua 层)定位更接近官方 system_core(应用服务器),而非 runtime_lua(脚本容器)对比见 3.4
Brookesia v0.8 全栈无法在 IDF 5.5.4 落地,硬门槛是 idf: >=6.0,<=6.2brookesia_lib_utils/idf_component.yml:8
WASM 方向的关键未知项(AOT 代码落点)已确认:S3 开 PSRAM 时 AOT 进 PSRAMwasm-micro-runtime/core/shared/platform/esp-idf/shared_platform.cmake:18-22、espidf_memmap.c:20-51
lua_engine.so 已完成 -Os + 元数据段裁剪,体积 553,048 → 257,972 B(-53.4%)本文 1.8 节实测数据

1. elf_loader 基座架构

命名说明:本文档用 “elf_loader 基座架构” 指代我们当前的实现(基座固件 + elf_loader + .so + Lua), 而不使用"我方架构"这类表述。原因有二:

  1. 它描述的是架构形态(单一 ELF 执行基座)而非归属,便于与 Brookesia 的"多后端对等"形态直接对照;
  2. Brookesia 的 runtime_elf 后端同样复用官方 espressif/elf_loader(ref/brookesia_runtime_elf/idf_component.yml:5-7), 若用"我方"会掩盖"同一个 loader、两种用法"这一关键对照点。

后文对比表格中该列简称为 “elf_loader 基座”。

1.1 全貌

elf_loader 基座架构总览基座固件 bs_hmi_base_s3(ESP32-S3 / ESP-IDF 5.5.4)LVGL / lcd_ui / arduino-esp32 / esp-fs-webserver ...shared_memory 组件(区域表 + 字段布局)elf_loader 组件(ELF 加载 + 重定位 + 解密回调)elf_ext 组件(符号导出 + .so 调度 + 动态加载器)LFS 分区(lfs_storage 7MB):.so / 脚本 / 资源esp_elf_init / relocate / requestlua_engine.so内含 Lua VMui_mirror.soWebSocket 镜像bs_link_hmi.so总线 / OTA其他 .soHMI 等执行 .lua 脚本(作业模型)脚本经 shm 与基座 / 其他 .so 交换数据
图 1.1 elf_loader 基座架构全貌:.so 是唯一的扩展单元,Lua 解释器运行在 .so 内部,脚本经共享内存与基座交换数据。

核心特征:.so 是唯一的扩展单元;脚本(Lua)不直接由基座执行,而是由运行在 .so 内的解释器执行。

依据:

  • so_build/lua_engine/CMakeLists.txt:154-155 的自定义链接命令(-shared -fPIC -nostdlib -nostartfiles -Wl,--allow-shlib-undefined)
  • components/elf_loader/src/esp_elf.c:127(读文件到 PSRAM)、:432-442(pdata 分配)
  • components/elf_ext/src/elf_so_loader.c:247-283(dlsym("app_main") → 起任务)

1.2 基座固件(bs_hmi_base_s3)

1.2.1 平台与关键配置

配置值出处
目标芯片esp32s3sdkconfig.defaults:1
IDF 版本5.5.4_run_build.bat:4(IDF_PATH=[idf_path]/)
ELF 加载到 PSRAMCONFIG_ELF_LOADER_LOAD_PSRAM=ysdkconfig:2394
总线地址镜像CONFIG_ELF_LOADER_BUS_ADDRESS_MIRROR=ysdkconfig:2389
Cache 偏移CONFIG_ELF_LOADER_CACHE_OFFSET=ysdkconfig:2393
libc 符号表CONFIG_ELF_LOADER_LIBC_SYMBOLS=ysdkconfig:2399
IDF 符号表CONFIG_ELF_LOADER_ESPIDF_SYMBOLS=ysdkconfig:2400
符号表预分配数CONFIG_ELF_LOADER_NUMBER_SYMBOLS=32sdkconfig:2402
PSRAM mallocCONFIG_SPIRAM_USE_MALLOC=ysdkconfig:1279
PSRAM BSS 段CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY=ysdkconfig:1284
编译优化CONFIG_COMPILER_OPTIMIZATION_SIZE=ysdkconfig:654
断言CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_ENABLE=y,LEVEL=2sdkconfig:657,662
日志等级CONFIG_LOG_DEFAULT_LEVEL=3(INFO),MAXIMUM=3sdkconfig:1683,1687

1.2.2 分区

分区类型偏移大小
nvsdata/nvs0x90000x4000
otadatadata/ota0xd0000x2000
phy_initdata/phy0xf0000x1000
lfs_storagedata/littlefs0x100000x700000(7 MB)
ota_0app/ota_00x7100000x400000(4 MB)
ota_1app/ota_10xB100000x400000(4 MB)

出处:partitions.csv:1-7

1.2.3 构建产物规模(实测)

指标值说明
app bin2,106,112 B(2056.75 KB)build/bs_hmi_base_s3.bin
.flash.text1,359,624 B代码(IROM)
.flash.rodata653,092 B只读数据(DROM)
.iram0.text69,423 B内部 RAM 代码
.iram0.vectors1,028 B中断向量
.dram0.data22,544 B内部 RAM 数据
.dram0.bss30,816 B内部 RAM 零初始化
.ext_ram.bss122,436 BPSRAM 零初始化段

出处:build/bs_hmi_base_s3.map 输出段统计(解析脚本 build/analyze_map.py)

1.2.4 组件级 flash 占用 Top(实测归因)

组件flash.textflash.rodata合计
lvgl230,740136,141366,881
esp_wifi227,57043,950272,685
esp_app_format479227,504227,983(见下方说明)
esp-fs-webserver42,028166,617208,645
lwip109,69217,483127,175
arduino-esp3269,77723,18992,966
elf_ext5,58887,23292,820
lcd_ui21,07043,49064,560
mbedtls50,02412,24062,344
wpa_supplicant54,0851,98056,065
mdns39,9075,44945,356
esp_hw_support22,9189,07042,375

关于 esp_app_format 的 227,983 B:该数字挂在 esp_app_desc.c.obj 名下,但该源文件仅 5,394 B([idf_path]//components/esp_app_format/esp_app_desc.c)。实际读取固件 rodata 后确认,这是全工程 .rodata.str1.1 合并字符串池(SHF_MERGE 段的 map 归属特性)。池内容实测:227,496 B / 7,746 条字符串,其中日志格式串合计 62,477 B(E (%lu) 978 条、W (%lu) 74 条、I (%lu) 138 条、[%6u][E] 170 条、I (%d) 101 条)、ESP_ERR_* 223 条、LVGL 断言串(lv_obj_* 137 条、lv_style_* 111 条)、断言文件路径(//IDF/components/*)78 条共 6,648 B。 出处:build/bs_hmi_base_s3.map:115809-115810(.rodata.__esp_system_init_fn_init_show_app_info.str1.1 = 0x378a8)、ELF .flash.rodata 起始内容解析。

1.3 ELF 动态加载层(elf_loader)

1.3.1 内存分配策略(决定性)

// components/elf_loader/src/esp_elf_adapter.c:29-51
void *esp_elf_malloc(uint32_t n, bool exec)
{
#ifdef CONFIG_ELF_LOADER_LOAD_PSRAM
    caps = MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT;
#else
    caps = MALLOC_CAP_EXEC / MALLOC_CAP_8BIT;
#endif
    caps |= MALLOC_CAP_CACHE_ALIGNED;   // IDF >= 5.3
    return heap_caps_malloc(n, caps);
}

因为基座开了 CONFIG_ELF_LOADER_LOAD_PSRAM=y,.so 的 text 与 data(含 bss)全部从 PSRAM 分配。

1.3.2 加载流程

步骤行为出处
打开读整个 .so 文件到 PSRAM(size 字节一块)esp_elf.c:127-131
解密若注册了 esp_elf_decrypt_cb,原地解密 ELFC 格式(AES-256-CTR)esp_elf.c:53, 148-153
保留 payloadfile->payload = pbuf; file->size = size;esp_elf.c:155-156
分配代码elf->ptext = esp_elf_malloc(text_size, true)esp_elf.c:425
分配数据elf->pdata = esp_elf_malloc(DATA+RODATA+BSS+DRLRO, false)(一整块)esp_elf.c:432-442
段拷贝各节按 sec[].size 拷入 ptext/pdataesp_elf.c:445-512
释放文件缓冲relocate 成功后立即 esp_elf_close(&file)dlmod.c:251
执行入口dlsym(handle, "app_main") → elf_task_create() 起任务elf_so_loader.c:247-283

要点:.so 文件缓冲只是加载期峰值,不常驻(dlmod.c:251)。lua_engine.so 当前 257,972 B,即单次加载峰值约 252 KB PSRAM。

1.3.3 任务与栈

// components/elf_ext/src/elf_task_api.c:111,115
core_id, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT   // .so 入口任务栈默认放 PSRAM

出处:elf_ext/include/elf_task_api.h:58(文档:“默认用 PSRAM (MALLOC_CAP_SPIRAM) 分配任务栈”)

1.3.4 崩溃保护

elf_so_loader.c:166-170:s_dynamic_loading_enabled 为假时拒绝加载(crash loop protection)。

1.4 符号与宿主能力导出(elf_ext)

1.4.1 机制

基座在编译期从指定静态库用 nm 抽取符号,生成 generated/<name>_syms.c,由 elf_sym_register.c 在启动时注册进 ELF 符号表。

// components/elf_ext/src/elf_tab_syms.c:188-192(部分)
ESP_ELFSYM_EXPORT(heap_caps_malloc),
ESP_ELFSYM_EXPORT(heap_caps_calloc),
ESP_ELFSYM_EXPORT(heap_caps_get_free_size),
// components/elf_ext/src/elf_sym_register.c:55
(esp_elf_symbol_table_t *)s_tables[i]

符号表宏与容器:so_build/lua_engine/elf_api/include/private/elf_symbol.h:24-34(ESP_ELFSYM_EXPORT / esp_elfsym / ESP_ELFSYM_END)

1.4.2 符号表清单(21 张)

出处:components/elf_ext/CMakeLists.txt:74-95

gpio, uart, lfs, log, freertos, wifi, netif, event, nvs, lvgl, lcd,
libgcc, libm, newlib, ping, mdns, i2c, mcpwm, syshal, vfs

生成方式:components/elf_ext/CMakeLists.txt:97-160(symbols.py -t l -i <lib.a> -of gen_<name>_syms.c) 过滤机制:components/elf_ext/tools/filter_syms.py(支持 --drop-pattern,如对 netif 过滤 esp_netif_action_、_unsafe$、_api$ 等)

1.4.3 关键特性

特性说明出处
白名单裁剪只有清单里的库 + 过滤规则通过的符号才导出CMakeLists.txt:74-95、filter_syms.py
编译期确定新增宿主 API 需重跑 CMake 生成 + 重编基座同上
符号可插拔解析elf_set_symbol_resolver 支持自定义 resolverelf_api/include/private/elf_symbol.h:66-124
运行时注册esp_elf_register_symbol / esp_elf_unregister_symbol / esp_elf_find_symbolelf_api/include/esp_elf.h:155-177

1.5 Lua 运行时层(lua_engine.so)

1.5.1 组成

构建源集合(so_build/lua_engine/CMakeLists.txt:160-188):

分组来源
入口main/*.c
Lua 解释器components/georgik__lua/lua/*.c(排除 lua.c / onelua.c)
引擎components/lua_engine/src/*.c
引擎核心components/lua_engine_core/src/*.c
I2C 驱动components/espressif__i2c_bus/i2c_bus_v2.c
内置模块lua_mods/lua_module_{storage,json,i2c,gpio,mcpwm,esp_heap,system,crc16,shared_memory}/src/*.c

Lua 版本:5.5(so_build/lua_engine/components/georgik__lua/lua/lua.h:20-22:LUA_VERSION_MAJOR_N 5 / MINOR 5 / RELEASE 0)

1.5.2 引擎能力(源码事实)

能力位置说明
PSRAM 分配器components/lua_engine/src/lua_runtime.c:183-223lua_psram_allocator,MALLOC_CAP_SPIRAM
Lua 状态创建lua_runtime.c:699lua_newstate(lua_psram_allocator, ...)
输出缓冲lua_runtime.c:684(LUA_OUTPUT_BUFFER_SIZE)、lua_async.c:286(LUA_OUTPUT_BUF_SIZE)PSRAM
异步作业components/lua_engine/src/lua_async.c作业槽位、互斥组、状态机、停止请求
启动日志components/lua_engine/src/lua_bootlog.c4 KB 缓冲 + vprintf hook 捕获 E 级日志 + 文件轮转
自启动components/lua_engine/src/lua_autorun.c解析 autorun.ini(delay / loadui / 脚本指令)
脚本管理lua_script.c:186,216列表读写在 PSRAM
字节码lua_bytecode.c:65校验缓冲显式用内部 RAM
模块注册表lua_engine_core.c:20-29s_modules[32]
共享内存绑定lua_mods/lua_module_shared_memory/src/lua_module_shared_memory_lua.c:820-831导出 get/create/read/write/list/wait_for/read_typed/write_typed/layout/read_struct/write_struct
模块清单components/lua_engine/src/lua_modules.c:468shared_memory 模块描述:“读写与基座共享的内存区域(bat_ch_data 等电池模拟器数据结构)”

1.5.3 静态数据落点

.so 的 .data/.rodata/.bss/.data.rel.ro 被 esp_elf_malloc(..., false) 整块分配到 PSRAM(见 1.3.1),因此:

  • s_jobs[LUA_ASYNC_MAX_JOBS] 4,480 B → PSRAM
  • g_log_buffer 4,112 B → PSRAM
  • instructions[20] 1,680 B → PSRAM
  • 全部 .bss 11,612 B / .data 2,696 B → PSRAM

注意:源码中这些变量标注了 EXT_RAM_BSS_ATTR(lua_async.c:95-98、lua_bootlog.c:87,613),但该宏在本 .so 编译环境中展开为空(so_build/lua_engine/build/config/sdkconfig.h 中不存在 CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY),所以落的是普通 .bss。当前不影响结果(loader 统一放 PSRAM),但语义上名不副实。

刻意保留在内部 RAM 的少数(有源码注释依据):

位置内容依据
lua_async.c:1256-1257s_job_lock_buf(StaticSemaphore_t + 128 B)注释:“必须在 init 时用 heap_caps_malloc(MALLOC_CAP_INTERNAL) 显式分配”
lua_async.c:1273-1274s_slot_sem_buf同上
lua_bootlog.c:54-55fs 互斥量缓冲MALLOC_CAP_INTERNAL
lua_bytecode.c:65字节码校验缓冲MALLOC_CAP_INTERNAL
lua_autorun.c:447auto_start 任务栈注释:“必须从内部RAM分配栈”

1.5.4 编译与裁剪现状

# so_build/lua_engine/CMakeLists.txt:150-152
# -Os:手工调用编译器绕过了 IDF 默认编译选项,不加优化会按 -O0 编译,
#      导致 .text/.rela.dyn/.got 显著膨胀(见 release 目录 .so 体积分析)。
set(so_compile_flags -c -fPIC -Os -ffunction-sections -fdata-sections)
# so_build/lua_engine/CMakeLists.txt:222-226
# .xt.prop / .xt.lit 是 Xtensa relaxation 元数据(非 ALLOC),链接完成后
# 无任何作用,占成品 .so 约 1/3 体积,直接移除(PT_LOAD 内容不受影响)。
COMMAND ${CMAKE_STRIP_SO} --strip-unneeded -R .comment -R .note
    -R .xt.prop -R .xt.lit
    ${so_output}

其它 .so 工程(bs_link_hmi、ui_mirror、terminal、bs_link_scpi、bs_hmi_320x240)在同一次优化中做了相同改动(各自 CMakeLists.txt 的 so_compile_flags 与 strip 命令)。

1.6 共享内存数据通道

1.6.1 组件实现(基座侧)

能力API出处
创建区域(幂等)shared_mem_createcomponents/shared_memory/src/shared_memory.c:105-165
查询区域shared_mem_getshared_memory.c:167-177
等待区域shared_mem_wait_forshared_memory.h:150-158
登记字段布局shared_mem_set_layoutshared_memory.c:348-372(深拷贝到 PSRAM)
查询字段布局shared_mem_get_layoutshared_memory.c:375-382
销毁shared_mem_destroyshared_memory.c:207(全工程无调用点,见下)

1.6.2 布局登记链路

布局登记链路bs_hmi_1ch_{480x272,320x240}/main/main.ccreate_shared_regions() → shared_mem_create × 7bat_state_layout_register() (state_layout.c:103-132)shared_mem_set_layout(region, fields, count) × 7 个区域
图 1.2 布局登记链路:main.c 入口 → 创建 7 个共享内存区域 → 逐个注册布局 → 字段落表。
出处:`so_build/bs_hmi_1ch_480x272/main/main.c:58-70`、`so_build/bs_hmi_1ch_480x272/main/state_layout.c:103-132`

已登记的 7 个区域与字段数:bat_ch_data(9)、bat_ch_cfg(10)、bat_dev_state(7)、bat_ota_state(12)、bat_pending_fw(4)、bat_fps(1)、bat_mode_slots(6) 出处:state_layout.c:27-117

1.6.3 Lua 侧读取路径

// lua_module_shared_memory_lua.c:573-592
shared_mem_region_t* region = shared_mem_get(name);
int count = shared_mem_get_layout(region, out_fields);
if (count <= 0) { lua_pushnil(L); lua_pushfstring(L, "No layout registered for '%s'", name); return NULL; }

关键约束:layout / read_struct / write_struct 依赖已有登记;Lua 侧没有 set_layout API(lua_module_shared_memory_lua.c:820-831 的导出清单中无登记接口)。因此若设备上未运行带 state_layout.c 的 HMI .so,这三个接口必然返回 nil。

shared_mem_destroy 在整个 bs_hmi_base_s3/ 内只有定义、没有调用(检索结果),shared_mem_create 同名幂等(shared_memory.c:127-136),所以区域一旦创建,其 layout 不会被销毁路径清掉。

1.7 包分发与加密

项实现出处
加密格式[4B "ELFC"] [16B IV] [AES-256-CTR 数据]so_build/lua_engine/CMakeLists.txt:242-246
加密工具so_build/lua_engine/tools/encrypt_so.py同上
解密时机esp_elf_open() 中原地解密so_build/lua_engine/CMakeLists.txt:245、components/elf_loader/src/esp_elf.c:53,148-153
解密密钥注册elf_so_crypt.c 启动时注册components/elf_ext/src/elf_so_crypt.c:109
发布产物调试期 .so 明文;正式 .epm 加密so_build/lua_engine/CMakeLists.txt:232-254
加密后仍未启用该段 CMake 代码当前被注释so_build/lua_engine/CMakeLists.txt:248-254

LFS 分发:lfs_storage 分区 7 MB(partitions.csv:5),.so/脚本/资源经该分区下发(multi-partition-lfs 组件)。

1.8 关键指标实测

1.8.1 lua_engine.so 优化前后

阶段文件大小PT_LOAD memsz 合计
原始(默认 -O0,含 Xtensa 元数据)553,048 B(540.1 KB)392,208 B(383.0 KB)
+ -Os385,060 B(376.0 KB)268,784 B(262.5 KB)
+ 移除 .xt.prop / .xt.lit257,972 B(251.9 KB)268,784 B(262.5 KB)
累计变化-295,076 B(-53.4%)-123,424 B(-31.5%)

1.8.2 当前 .so 段构成(257,972 B)

段字节占比属性
.text162,06262.8%ALLOC(代码)
.rela.dyn31,94412.4%ALLOC(动态重定位 2,662 项)
.rodata26,83510.4%ALLOC
.dynstr8,8203.4%ALLOC
.dynsym8,7203.4%ALLOC(545 个动态符号)
.got.loc6,1042.4%ALLOC
.rela.plt5,3642.1%ALLOC
.hash4,2721.7%ALLOC
.data.rel.ro2,6321.0%ALLOC
.bss11,6320(不占文件)ALLOC
其余(.dynamic/.data/.got/.xtensa.info/.shstrtab)5870.2%—

PT_LOAD 两段:off=0 filesz=254,272 memsz=254,272 (R+X)、off=254,272 filesz=2,876 memsz=14,512 (RW)

1.8.3 -Os 后各模块体积(code + rodata + data = 198,001 B)

模块新值旧值(-O0)降幅
Lua 解释器(georgik__lua/lua)124,034202,588-38.8%
lua_engine 引擎39,98156,216-28.9%
i2c_bus 驱动6,29510,281-38.8%
9 个内置模块合计25,82835,378-27.0%
engine_core + main1,8632,562-27.3%

1.8.4 静态对象清单(从 .o 符号表统计,.so 已 strip)

符号大小来源
s_jobs4,480lua_async.c:96
g_log_buffer4,112lua_bootlog.c:87
instructions[20]1,680lua_autorun.c:63
script_list[256]256lua_bootlog.c:613
s_modules[32]256lua_engine_core.c:27
s_base_dir256lua_engine_main.c
s_i2c_bus184i2c_bus_v2.c
.bss 合计 / .data 合计11,612 / 2,696—

1.9 elf_loader 基座架构特征总结

特征描述依据
单一执行基座所有扩展必须编译成 ELF .so,由 elf_loader 加载1.1 节
层级组合Lua 运行在 lua_engine.so 内(Lua VM 是 .so 的内容)1.5.1
符号层抽象宿主能力以编译期生成的 C 符号白名单表达1.4
编译期耦合新增宿主 API 需重新生成符号表并重编基座1.4.3
单向调用.so → 基座(app_main 入口 + 符号调用);无基座 → .so 内部函数的反向调用通道elf_so_loader.c:247-283、1.4
PSRAM 优先.so 的 text/data/bss 全部 PSRAM 分配;任务栈默认 PSRAM1.3.1、1.3.3
端到端加密.epm = AES-256-CTR,加载时原地解密1.7
有状态隔离缺失lua_engine 单实例 + 作业槽位模型,无"多 app"概念lua_async.c 作业模型(1.5.2)
跨实例数据通道共享内存 + 字段布局(登记制)1.6

2. ESP-Brookesia 架构

以下内容全部来自 so_build/ref/ 下的源码。

2.1 组件全景

2.1.1 组件与版本(16 个目录)

组件版本CHANGELOG 最新职责
brookesia_lib_utils0.8.22026-07-22基础工具:TaskScheduler(Boost.Asio)、Log、StateMachine、PluginRegistry、signal/slot、describe_helpers
brookesia_service_manager0.8.22026-07-22服务框架:ServiceBase + Function/Event Registry + 绑定 + 拓扑排序
brookesia_service_helper0.8.52026-09-10纯头文件契约层(CRTP 类型安全包装)
brookesia_service_wifi0.8.22026-07-27WiFi 服务实现(服务模板范例)
brookesia_agent_manager0.8.22026-07-27Agent 生命周期/状态机/多后端选择
brookesia_runtime_manager0.8.22026-07-27运行时门面 + IRuntimeBackend 抽象
brookesia_runtime_elf0.8.22026-07-27ELF 后端(复用 IDF elf_loader)
brookesia_runtime_lua0.8.22026-07-27Lua 后端(PUC-Lua 5.5)
brookesia_runtime_js0.8.32026-08-05JS 后端(QuickJS-NG 0.14)
brookesia_runtime_wasm0.8.22026-07-27WASM 后端(WAMR)
brookesia_system_core0.8.42026-08-31App/GUI/Runtime/Storage 系统框架、.bpk 包、验签、安装
brookesia_hal_interface0.8.22026-07-20HAL 抽象(Device/Interface)
brookesia_hal_adaptor0.8.42026-08-25HAL 板级实现(按 Kconfig 条件编译)
brookesia_hal_boards0.8.02026-06-28板级 YAML 配置集
esp-brookesia0.5.02025-05-30旧线:LVGL 9.2 + Phone 系统 UI
wasm-micro-runtime2.4.0~1—WAMR(Espressif fork)

批次判断:14 个 brookesia_* 均含共同的 v0.8.0 - 2026-06-28 基线条目,互引 0.8.*,属同一 v0.8 训练线;patch 号差异(0.8.0~0.8.5)是各自独立迭代。

2.1.2 依赖关系图(源码确认)

Brookesia 组件依赖关系(源码确认)外部依赖(组件管理器拉取)esp-boost 0.6.* / cmake_utilities / elf_loader 1.*quickjs-ng 0.14 / georgik/lua 5.5.* / zlib 1.3.*esp_board_manager 0.5.*lib_utils(idf 6.0~6.2)service_managerhal_interfaceruntime_managerservice_helperruntime_elfruntime_luaruntime_jsruntime_wasmsystem_core(应用包 / 生命周期)(gui_interface / service_storage / service_usb 缺失)agent_manager(service_sntp 缺失)
图 2.1 Brookesia 组件依赖关系(源码确认):lib_utils / service_manager / hal_interface 支撑 runtime_manager 与四个对等后端。

缺失的第一方组件(被引用但 ref/ 中不存在,必须联网拉取):

组件引用方出处
brookesia_service_sntpagent_manager (private)brookesia_agent_manager/idf_component.yml:5-7
brookesia_gui_interfacesystem_core (public)brookesia_system_core/idf_component.yml:2-4
brookesia_service_storagesystem_core / service_wifi (public)brookesia_system_core/idf_component.yml:11-13、brookesia_service_wifi/idf_component.yml:2-4
brookesia_service_usbsystem_core (private)brookesia_system_core/idf_component.yml:14-16

2.2 运行时层(runtime_manager)

2.2.1 核心接口

// brookesia_runtime_manager/include/brookesia/runtime_manager/backend.hpp:19-62
class IRuntimeBackend {
public:
    struct Attributes { std::string name; };
    virtual void set_native_modules(std::vector<NativeModule> modules) = 0;
    virtual std::expected<void, std::string> init() = 0;
    virtual void deinit() = 0;
    virtual std::expected<void, std::string> load_app(AppId id, const AppConfig &config) = 0;
    virtual std::expected<void, std::string> unload_app(AppId id) = 0;
    virtual std::expected<void, std::string> start_app(AppId id) = 0;
    virtual std::expected<void, std::string> stop_app(AppId id) = 0;
    virtual std::expected<NativeValue, std::string> call_function(
        AppId id, std::string_view module_name, std::string_view function_name, const NativeArgs &args) = 0;
    virtual AppState get_app_state(AppId id) const = 0;
protected:
    IRuntimeBackend(BackendType type, Attributes attributes);
private:
    Attributes attributes_;
    BackendType type_ = BackendType::Unknown;
};

2.2.2 数据模型

// types.hpp:22-29
enum class BackendType { Unknown, Lua, JavaScript, Wasm, Elf };
// types.hpp:31-38
enum class AppState { Unloaded, Loaded, Running, Stopped, Error };
// types.hpp:60-67
struct AppConfig {
    BackendType type = BackendType::Unknown;
    std::string app_path;
    std::string entry;
    std::string resource_dir;
    std::vector<std::string> arguments;
};

2.2.3 注册与选择

机制实现出处
后端注册表lib_utils::PluginRegistry<IRuntimeBackend>backend.hpp:64
自动发现Runtime::init() 遍历注册表src/runtime.cpp:60-85
后端选择按 BackendType 查表;Unknown + 单后端时用唯一后端src/runtime.cpp:26-43
后端自注册各后端用 -u <symbol> + 插件注册宏runtime_elf/cmake/esp_platform.cmake:18-24、runtime_lua/...:13-19、runtime_js/...:18-24、runtime_wasm/...:18-24

2.2.4 宿主桥接

机制实现出处
宿主模块容器NativeModule / NativeValue / NativeArgstypes.hpp:40-67
默认 Host Bridge内建 brookesia 模块,5 个函数:current_app_context / finish_app / attach_app_context / detach_app_context / printsrc/host_bridge.cpp:196-225
模块来源遍历 RuntimeFunctionProviderRegistry 自动收集(插件注册)src/function_bridge.cpp:94-125
注册宏BROOKESIA_RUNTIME_FUNCTION_PROVIDER_REGISTER_WITH_SYMBOLfunction_bridge.hpp:73-76
App 上下文隔离thread_local std::optional<AppId> current_app_id + RAII AppContextGuardfunction_bridge.cpp:24, 212-258

2.2.5 职责边界(关键)

brookesia_runtime_manager/docs/main.md:3-24 明确:

brookesia_runtime_manager 只负责 runtime backend 的 app 生命周期和 native host bridge。 .bpk 解包、发布验签与 app package manifest 解析均在 system/brookesia_system_core。

即:运行时管理器不认识包格式、不做验签、不解 manifest。

2.3 四个后端

2.3.1 后端能力对照(源码确认)

后端底层引擎宿主模块注入call_function异步宿主函数中断加密
ELFIDF elf_loader(esp_elf_*)空操作(只记日志)不支持—不支持(同步执行)无
LuaPUC-Lua 5.5(georgik/lua)全局 table + lua_pushcclosure支持不支持不支持无
JSQuickJS-NG 0.14JS_NewCFunctionMagic支持支持(Promise)不支持无
WASMWAMR 2.4.0单桩 (ii)i + JSON + attachment支持—不支持无

出处:

  • ELF:runtime_elf/src/backend.cpp:101-104(set_native_modules 无操作)、:266-281(call_function 不支持)、:258-261(不可中断)、:160-183(esp_elf_init+esp_elf_relocate)、:233-235(esp_elf_request)
  • Lua:runtime_lua/src/backend.cpp:93-104(闭包注入)、:74-76(异步不支持)、:229-237(luaL_dofile)、:185-190(luaL_newstate+luaL_openlibs)
  • JS:runtime_js/src/backend.cpp:481-503(CFunc magic)、:412-479(Promise 异步)、:681-701(JS_NewRuntime/JS_SetMemoryLimit)、:188-224(app 生命周期 hook)
  • WASM:runtime_wasm/src/backend.cpp:627-651(单桩注册)、:601-610(结果句柄)、:656-735(加载流程)、:494-518(PSRAM 分配器)、:682-683(64 KB 栈 / 256 KB 堆)

2.3.2 各后端细节

ELF 后端

  • 委托给 IDF 官方 elf_loader(idf_component.yml:5-7:espressif/elf_loader: 1.*)
  • relocate 前用 BROOKESIA_THREAD_CONFIG_GUARD({ .stack_in_ext = false; }) 强制内部栈,注释说明"因为 relocate 会操作 flash"(backend.cpp:169-176)
  • 文件读取走 Storage 服务(backend.cpp:38-59),非直接 fopen
  • PC 平台直接 FATAL_ERROR(cmake/pc_platform.cmake:4)

Lua 后端

  • 每个 app 一个 lua_State + luaL_openlibs(backend.cpp:185-190)
  • 宿主模块注入:把每个函数用 lua_pushlightuserdata + lua_pushcclosure 包成闭包挂到全局表(backend.cpp:93-104)
  • PC 侧找 Lua 5.4(pkg_check_modules(LUA54 REQUIRED lua5.4),cmake/pc_platform.cmake:24),与 IDF 侧 5.5 不一致

JS 后端

  • QuickJS-NG 0.14,支持 ES module 与全局脚本(backend.cpp:764-769)
  • 内存上限硬编码 16 * 1024 * 1024(backend.cpp:42-47),不可通过 Kconfig 调整
  • 唯一提供 app 级生命周期 hook 的后端:on_install / on_start / on_stop / on_pause / on_resume / on_uninstall / on_action / on_event / on_timer(backend.cpp:188-224)
  • 异步宿主函数用 JS_NewPromiseCapability + TaskScheduler(组 RuntimeJsAsync)resolve(backend.cpp:412-479)
  • 无 QuickJS 时有 fallback 后端(backend.cpp:878-1014)

WASM 后端

  • 加载流程(backend.cpp:656-735):read_wasm_file → register_wamr_brookesia_imports → wasm_runtime_load → wasm_runtime_set_wasi_args → wasm_runtime_instantiate(64KB, 256KB) → wasm_application_execute_main
  • 宿主桥接:模块名固定 "env",所有函数共用桩 wamr_dynamic_import,签名统一 (ii)i,通过 wasm_runtime_get_function_attachment 区分(backend.cpp:520-523, 620, 627-651)
  • 符号名约定:<sanitized_module>_<sanitized_function>(private/import_descriptor.hpp:69-77)
  • 结果回传:brookesia_result_len / brookesia_result_copy / brookesia_result_free,结果池最多 64 条(backend.cpp:601-610、private/host_utils.hpp:21-54)
  • 运行时内存与线性内存都指向 PSRAM(backend.cpp:494-518, 781-793)

2.4 服务层(service_manager + helper + agent)

2.4.1 ServiceBase

// brookesia_service_manager/include/brookesia/service_manager/service/base.hpp:136-175
struct Attributes {
    std::string name;                 // RPC 稳定标识
    std::string description;
    std::string version;              // v0.8.1 起强制非空
    std::vector<std::string> dependencies = {};
    std::optional<lib_utils::TaskSchedulerStartConfig> task_scheduler_config;
    SchedulerType scheduler_type = SchedulerType::Main;
    bool bindable = true;
};

子类覆写:get_function_schemas() / get_event_schemas() / get_function_handlers()(base.hpp:228, 252, 536);生命周期钩子 on_init/on_deinit/on_start/on_stop(base.hpp:446-477)

2.4.2 关键机制

机制实现出处
服务注册ServiceRegistry = lib_utils::PluginRegistry<ServiceBase> + 静态注册宏manager.hpp:36、lib_utils/plugin.hpp:37-47, 415
自动装配add_all_registered_services() + 拓扑排序(Kahn)manager.cpp:818-845、manager.cpp:750-816
函数调用FunctionValue variant(bool/double/string/object/array/RawBuffer)function/definition.hpp:49
SchemaFunctionSchema{name, description, parameters, require_scheduler, default_timeout_ms, return_value}function/definition.hpp:147-154
同步调用call_function_sync(boost::promise + wait_for)service/base.cpp:416, 491-518
事件lib_utils::signal + EventSchema + EventMonitorevent/definition.hpp:70,75,121-126、helper/base.hpp:982-1244
无订阅者跳过publish_event 前检查 has_subscribersservice/base.cpp:781, 804-807
线程模型每服务 3 个串行任务组(<svc>_call/_event/_request)service/base.cpp:1077-1133
绑定模型RAII ServiceBinding + 引用计数,ref_count 归零时 stop()manager.hpp:44、manager.cpp:435, 569
跨进程v0.8.0 已移除 TCP RPCservice_manager/CHANGELOG.md v0.8.0 条目

2.4.3 service_helper(契约层)

  • 纯头文件,0 个 .cpp,约 8.5k 行
  • 核心 CRTP 基类 template <typename Derived> class Base(helper/base.hpp:77),要求 Derived 提供 FunctionId/EventId 枚举、get_name()、schema(helper/base.hpp:32-40)
  • 类型安全调用:call_function_sync<ReturnType>(FunctionId, Args...)(helper/base.hpp:679)
  • get_name() 是稳定 RPC 标识,改名属于破坏性变更(service_helper/README.md:11-13)

2.4.4 service_wifi(服务模板)

可复用要点(service_wifi/src/service_wifi.cpp、service_wifi.hpp):

  1. 属性在构造函数注入(service_wifi.hpp:66-96)
  2. get_function_schemas() 直接返回 helper 的 schema(:122-132)
  3. handler 用 BROOKESIA_SERVICE_HELPER_FUNC_HANDLER_N 逐条绑定(:133-205)
  4. 业务函数返回 std::expected<T, std::string>
  5. 底部静态注册 + CMake -u(service_wifi.cpp:1880-1885、CMakeLists.txt:32-38)

2.4.5 agent_manager

项内容出处
Agent 抽象class Base : public service::ServiceBase,构造时 bindable=falseagent_manager/base.hpp:88, 132-138
生命周期钩子on_activate/on_startup/on_shutdown/on_sleep/on_wakeup + 可选钩子base.hpp:159-181, 188-263
Manager20 个函数(SetAgentInfo/SetTargetAgent/TriggerGeneralAction/Suspend/Resume/…)manager.hpp:131-215
状态机GeneralState:TimeSyncing/Ready/Activating/Activated/Starting/Started/Sleeping/Slept/WakingUp/Stoppingservice_helper/agent/manager.hpp:141-153
后端Coze / OpenAI / XiaoZhi —— ref 中只有 helper 契约,无实现体service_helper/agent/{coze,openai,xiaozhi}.hpp
MCP 接入XiaoZhi helper:AddMCP_ToolsWithServiceFunction / AddMCP_ToolsWithCustomFunction / RemoveMCP_Toolsservice_helper/agent/xiaozhi.hpp:31-37, 66-104
测试无 test_apps 目录目录列举

2.5 系统层(system_core)

2.5.1 定位

brookesia_system_core/README.md:7:

the app, GUI, runtime, storage, timer, and service bridge framework for products.

依赖(system_core/idf_component.yml:1-28):brookesia_gui_interface(缺)、brookesia_runtime_manager、brookesia_service_helper、brookesia_service_storage(缺)、brookesia_service_usb(缺)、zlib ^1.3.0

2.5.2 .bpk 包格式

项内容出处
容器ZIP,根含 manifest.json,签名材料在 META-INF/src/app/package.cpp:39-46
解包目标<install_dir>/<manifest.package.id>/(确定性路径)package.cpp:887-890
安全校验跳过 META-INF/;逐条检查 is_safe_relative_path(防 ../)package.cpp:897-906
命名约定<package.id>.<debug|release>.<version>.bpkpackage.cpp:887-889

2.5.3 manifest 字段(完整)

// include/brookesia/system_core/app/types.hpp:200-245
struct AppManifest {
    std::string id;
    std::string name;
    std::map<std::string, std::string> localized_names;
    std::string version = "0.1.0";
    AppKind kind = AppKind::Native;        // Native / Runtime
    bool visible = true;
    bool preload_dom = false;
    std::string icon_id;
    std::vector<std::string> supported_systems;
    std::string icon_path;
    runtime::BackendType runtime_type = runtime::BackendType::Unknown;
    std::string app_path;
    std::string entry;
    std::string resource_dir;
    std::vector<std::string> arguments;
    std::vector<AppManifestService> services = {};
};

JSON 层级:顶层 package / runtime / services(package.cpp:672-700)

  • package:id(必填)、name(对象形式 {"en":"..."}, 必填)、version(必填)、visible、systems
  • runtime:type(必填)、entry(必填)、resource_dir、arguments
  • services[]:name(必填)、version(必填)、component

2.5.4 验签

项内容出处
算法RSA-PSS / SHA-256,覆盖 META-INF/hash.json + 逐成员 SHA-256include/brookesia/system_core/package.hpp:56-69
签名材料META-INF/hash.json、META-INF/signature.sigsrc/package_release_verify.cpp:42-45
公钥来源文件系统 PEM(mbedtls_pk_parse_public_key)package_release_verify.cpp:551-558
开关CONFIG_BROOKESIA_SYSTEM_CORE_ENABLE_PACKAGE_RELEASE_VERIFY 默认 yKconfig:90-107
载荷加密CONFIG_BROOKESIA_SYSTEM_CORE_ENABLE_PACKAGE_PAYLOAD_ENCRYPTION 默认 n,帮助文本写明 “Not implemented”Kconfig:90-107
工具tools/app_pack.py(pack|sign --private-key)——不在 ref 中【待核实】package_release_verify.cpp:455-457 引用

2.5.5 安装/卸载

// include/brookesia/system_core/system/system.hpp:158-175
std::expected<AppId, std::string> install_app(std::shared_ptr<IApp> app);
std::expected<AppId, std::string> install_runtime_app(const AppManifest &manifest);
std::expected<AppId, std::string> install_runtime_app_package(
    std::string_view package_path, bool replace_existing = true);
std::expected<void, std::string> install_registered_apps();
std::expected<void, std::string> uninstall_app(AppId app_id);
  • 无独立 update API:更新 = install_runtime_app_package(..., replace_existing=true)
  • 安装含回滚(src/app/manager.cpp:393-482)
  • 启动时扫描已解包目录并安装(src/app/package_scan.cpp:30-119)
  • 不存在 “App Store” 组件(ref/ 全境检索仅命中 esp-brookesia/README.md 规划文字)

2.6 HAL 层

层形态出处
hal_interface抽象:Device / Interface / InterfaceHandle<T>device.hpp:48-131、interface.hpp:51-80
接口类型audio / bluetooth / display / network / power / storage / system / video / wifiinterfaces.hpp:13-36
hal_adaptor板级实现,按 Kconfig 条件编译(36 个 .cpp)CMakeLists.txt:117-265
hal_boards纯 YAML 配置(board_info.yaml / board_devices.yaml / board_peripherals.yaml / sdkconfig.defaults.board)boards/**/

与 LVGL 解耦(源码确认):hal_interface/idf_component.yml:1-14 仅依赖 brookesia_lib_utils;hal_adaptor 依赖列表无 LVGL;display 仅提供 panel/touch/backlight 原生接口。

ESP32-S3 板子(boards/**/board_info.yaml):esp_box_3、esp32_s3_korvo2_v3、waveshare/esp32_s3_touch_amoled_{1_75c,1_8,2_16}、rymcu/rymcu_bigsmart

2.7 旧线 esp-brookesia 0.5.0

项内容出处
版本/日期0.5.0 / 2025-05-30esp-brookesia/CHANGELOG.md:3
依赖esp-lib-utils 0.2.*、lvgl/lvgl 9.2.*、idf >=5.3esp-brookesia/idf_component.yml:2-17
内容LVGL 封装 + Phone 系统 UI(app_launcher / gesture / navigation_bar / recents_screen / status_bar + 多分辨率 stylesheet)src/systems/phone/widgets/**
资源规模壁纸:720×720 8.9 MB、480×480 3.96 MB、240×240 1.0 MB;字体 24 个文件合计约 2.5 MBsrc/systems/phone/assets/**
示例镜像>2.3 MB(boot 日志 size=1c5f04h + 76e50h)examples/phone_s3_box_3/README.md:65-69
与 0.8 关系无依赖关系,属不同代依赖图核对

2.8 WAMR 在 ESP-IDF / ESP32-S3 上的集成事实

项结论出处
支持芯片esp32, esp32s3, esp32c3, esp32c6, esp32p4, esp32c5wasm-micro-runtime/idf_component.yml:28-34
IDF 约束>=5.1同文件 :2
AOT 默认WAMR_ENABLE_AOT=ybuild-scripts/esp-idf/wamr/Kconfig:13-15
解释器默认WAMR_ENABLE_INTERP=y + WAMR_INTERP_MODE=FastKconfig:17-19, 23-32
libc 默认libc-builtin=y、libc-wasi=yKconfig:50-56
JITESP-IDF 不提供(Kconfig 无 JIT 项;Fast JIT codegen 仅 x86-64)build-scripts/esp-idf/wamr/Kconfig、core/iwasm/fast-jit/iwasm_fast_jit.cmake:97-101
架构分支xtensa → WAMR_BUILD_TARGET=XTENSA;riscv → RISCV32_ILP32Fbuild-scripts/esp-idf/wamr/CMakeLists.txt:7-17
AOT 代码落点S3 开 PSRAM → WASM_MEM_DUAL_BUS_MIRROR=1 → MALLOC_CAP_SPIRAM(PSRAM)+ ibus 镜像;否则 MALLOC_CAP_EXEC(内部 RAM)core/shared/platform/esp-idf/shared_platform.cmake:18-22、core/shared/platform/esp-idf/espidf_memmap.c:20-51
XIP 模式AOT ELF 支持 E_TYPE_XIP,is_indirect_mode 时不 mmap/copy text,就地执行core/iwasm/aot/aot_loader.c:260-263, 4283-4291, 4349-4350
xtensa 重定位限制仅 R_XTENSA_32 / R_XTENSA_SLOT0_OP;l32r 越界需 wamrc --size-level=0core/iwasm/aot/arch/aot_reloc_xtensa.c:8-9, 272-280
内存模型分配器三选一:Pool / Allocator / System;brookesia 用 Alloc_With_Allocator → PSRAMcore/iwasm/include/wasm_export.h:169-200、runtime_wasm/src/backend.cpp:781-793
全局堆池默认关闭;ESP-IDF 上不支持(示例 #error)core/config.h:376-379、external_examples/968944e8/esp-idf/main/main.c:45-52
体积参考(官方 README)fast-interp 58.9 KB / classic 56.3 KB / AOT 29.4 KB / libc-wasi 21.4 KB / libc-builtin 3.7 KBwasm-micro-runtime/README.md:25-29

2.9 落地门槛

2.9.1 IDF 版本(决定性)

文件:行约束影响
brookesia_lib_utils/idf_component.yml:8idf: '>=6.0,<=6.2'几乎所有第一方组件的传递依赖,5.5.4 直接求解失败
esp-brookesia/idf_component.yml:5idf: '>=5.3'仅旧线可用
wasm-micro-runtime/idf_component.yml:2idf: '>=5.1'可单独用于 5.5.4

其余 0.8 组件(service_manager / service_helper / service_wifi / agent_manager / runtime_* / system_core / hal_*)的 idf_component.yml 均未声明 IDF 约束,其下限由 lib_utils 决定。

2.9.2 其它门槛

门槛内容出处
Boostesp-boost 0.6.*(Boost thread/system/chrono/json)lib_utils/idf_component.yml:5-7、service_manager/Kconfig:2-6
C++ 标准runtime_*/system_core 强制 cxx_std_23;使用 std::expected(runtime_elf/src/backend.cpp:38 等)、std::span各 cmake/esp_platform.cmake
pthread wrap-Wl,--wrap=pthread_mutex_init / --wrap=pthread_mutex_destroy,INTERFACE 传播lib_utils/cmake/esp_platform.cmake:12-18
插件符号保留-u <symbol>(后端、服务、HAL 设备共十余处)各 CMakeLists.txt / cmake/esp_platform.cmake
强制 mbedtlssystem_core 在 ESP 恒追加 mbedtls(验签用)system_core/cmake/esp_platform.cmake:4-6
运行期打补丁hal_adaptor 用 git apply 给 media_lib_sal 打 IDF 6 TLS 补丁,需要 githal_adaptor/CMakeLists.txt:26-99, 284-295
运行时 RAM默认主调度器 3 worker × 64 KB 栈(≈192 KB 内部 RAM)+ 每服务 3 个串行任务组system_core/include/brookesia/system_core/macro_configs.h:108-140、service/base.cpp:1077-1133

2.9.3 缺失组件(需联网拉取)

brookesia_service_sntp、brookesia_gui_interface、brookesia_service_storage、brookesia_service_usb(出处见 2.1.2)

2.10 Brookesia 特征总结

特征描述依据
对等后端ELF/Lua/JS/WASM 四个平级运行时,各自实现同一接口2.2、2.3
后端层抽象语言差异由后端吸收;宿主能力用与语言无关的 NativeModule 元数据描述2.2.4
反向调用宿主可通过 call_function(app_id, module, fn, args) 进入 app 内部(ELF 后端除外)2.3.1
App 隔离AppId + thread_local 上下文 + RAII guard2.2.4
编译期装配插件注册表 + -u 符号,Runtime::init() 自动发现;基座不硬编码后端2.2.3
包/运行时解耦.bpk + manifest 由 system_core 解析,运行时只收 AppConfig2.2.5
验签不加密RSA-PSS 完整性/来源验证默认开;载荷加密未实现2.5.4
进程内服务框架schema 校验 + 依赖拓扑 + 引用计数绑定 + 事件 await;v0.8.0 移除跨进程 RPC2.4.2
MCP 桥服务函数可直接暴露为 MCP 工具(经 XiaoZhi helper)2.4.5
快速演进0.8.x 内多次 Breaking Change(删 RPC、强制 version、隐藏 Impl)各 CHANGELOG
HAL 与 GUI 解耦HAL 三层不依赖 LVGL2.6

3. 对比分析

3.1 根本差异:抽象放在哪一层

elf_loader 基座Brookesia
抽象单元符号(esp_elfsym 数组 + 白名单)后端(IRuntimeBackend 实现)
语言差异处理方.so 内部自己消化(lua_module_* 绑定)后端实现吸收(Lua 闭包 / JS CFunc / WASM 单桩)
宿主能力描述编译期 C 符号名 → 地址运行期 NativeModule 元数据
新增语言必须编成新的 .so加一个后端组件 + 链接项
新增宿主 API重生成符号表 + 重编基座加一个 Provider + -u 符号

3.2 分层图对照

elf_loader 基座(层级式)

elf_loader 基座:分层结构基座固件elf_loader(唯一执行基座)+ elf_ext 符号白名单lua_engine.so内含 Lua VM执行 .lua(作业模型)ui_mirror.soWebSocket 镜像bs_link_hmi.so总线 / OTA
图 3.1 elf_loader 基座分层:单一 ELF 执行基座 + 符号白名单,脚本由 .so 内的解释器执行。

Brookesia(对等式)

Brookesia:分层结构system_core.bpk / manifest / 验签 / 安装RuntimeAppId / 生命周期 / app 上下文 / host bridgeRuntimeELFesp_elf loaderRuntimeLua每 app 一个 lua_StateRuntimeJSQuickJSRuntimeWasmWAMRNative 模块由插件注册,统一以 NativeModule 元数据注入各后端
图 3.2 Brookesia 分层:system_core 管理应用包(.bpk / manifest / 验签),Runtime 之上是四个对等后端,共享同一套宿主契约。

3.3 逐维度对比

维度elf_loader 基座Brookesia证据
执行基座单一(ELF)四个对等1.1 / 2.1
语言扩展方式新编 .so加后端组件1.4 / 2.2.3
宿主能力导出编译期符号白名单 + nm 生成运行期 NativeModule 元数据 + 后端翻译1.4 / 2.2.4
宿主→app 反向调用无有(call_function,ELF 后端不支持)1.4 / 2.3.1
app 生命周期管理.so 入口任务;Lua 走作业模型AppState 状态机 + 可选 hook(JS 最全)1.3.2 / 2.2.2、2.3.2
多实例隔离无(单引擎 + 作业槽)AppId + thread-local 上下文1.5.2 / 2.2.4
包格式.so/.epm(加密)+ 明文 .lua(两套).bpk(ZIP + manifest,统一容器)1.7 / 2.5.2-2.5.3
完整性/来源验证无(仅加密)RSA-PSS/SHA-256 验签(默认开)1.7 / 2.5.4
载荷加密AES-256-CTR(已实现)官方未实现1.7 / 2.5.4
跨实例/跨进程通道共享内存 + 字段布局(已实现)v0.8.0 已移除 TCP RPC,仅进程内1.6 / 2.4.2
服务框架claw agent(Lua + skill,运行期加载)ServiceBase + schema + 拓扑 + 事件 await(编译期注册)【待核实】 / 2.4
事件机制需自建lib_utils::signal + EventMonitor(schema 校验,可 await)— / 2.4.2
依赖拓扑/引用计数无有(Kahn 排序 + ref_count 绑定)— / 2.4.2
LLM 工具接入skill 即工具MCP 工具 = 服务函数封装【待核实】 / 2.4.5
沙箱能力无(native 同地址空间)JS / WASM 强隔离1.1 / 2.3
代码体积控制已做(-Os + 段裁剪,-53.4%)每后端一套运行时,体积叠加1.8 / 2.3.1
运行内存策略全 PSRAM(loader 决定)全 PSRAM(WAMR 分配器决定)1.3.1 / 2.3.2
IDF 要求5.5.4(现状)6.0~6.2_run_build.bat:4 / 2.9.1
语言标准C(.so 全 C)C++23 + Boost1.5.1 / 2.9.2

3.4 Lua 层的定位差异(重点)

elf_loader 基座上的 lua_engineBrookesia runtime_lua
形态常驻引擎(单实例)每 app 一个 lua_State
脚本角色作业(job):异步、互斥组、状态查询、输出捕获、停止请求app 本体:luaL_dofile 执行一次
内置能力i2c/mcpwm/storage/json/gpio/crc16/system/esp_heap/shared_memory 9 个模块无内置模块,全靠宿主注入
异步有(lua_async)不支持异步 native 函数
生命周期作业状态机(lua_job_record_t.status)AppState(Unloaded→Loaded→Running→Stopped/Error)
Lua 版本5.55.5(同一个 georgik/lua 组件)
定位类比更接近 system_core(应用服务器/运行时容器)脚本容器(与 JS/WASM 平级的第四种后端)

Lua 版本相同这一点值得注意:两个方案底层用的是同一份 Lua 源码(georgik__lua/lua/lua.h:20-22 与 runtime_lua/idf_component.yml:5-7 的 georgik/lua 5.5.*)。差异全在宿主层设计,不在语言实现。

3.5 双方强项/弱项清单

elf_loader 基座架构强项(有依据)

强项依据
ELF 加载链路内聚(加载+重定位+解密+白名单+执行)components/elf_loader/src/esp_elf.c、components/elf_ext/**
端到端加密(AES-256-CTR + ELFC 容器)so_build/lua_engine/CMakeLists.txt:242-254、esp_elf.c:148-153
宿主符号裁剪(白名单 + drop-pattern 过滤)elf_ext/CMakeLists.txt:74-95、tools/filter_syms.py
Lua 作业模型(异步/互斥/状态/停止/输出捕获)components/lua_engine/src/lua_async.c
共享内存 + 字段布局(跨 .so 数据通道)components/shared_memory/**、lua_module_shared_memory_lua.c
内置硬件模块(9 个)so_build/lua_engine/CMakeLists.txt:170-178
.so 体积优化已落地(-53.4%)1.8.1

elf_loader 基座架构弱项(有依据)

弱项依据
无反向调用(基座无法调 app 内函数)1.4
无沙箱(native 同地址空间,崩溃即整机)1.3
无统一包格式/验签(两套分发路径)1.7
无多 app 隔离1.5.2
新增宿主 API 需重编基座(编译期耦合)1.4.3

Brookesia 强项(有依据)

强项依据
统一后端抽象 + 插件化2.2
反向调用 + app 上下文隔离2.2.4、2.3.1
.bpk 统一包 + RSA-PSS 验签2.5.2-2.5.4
服务框架工程化(schema/拓扑/引用计数/事件 await)2.4.2
JS/WASM 沙箱后端2.3.2
MCP 工具接入2.4.5
HAL 三层与 GUI 解耦、S3 板级配置齐全2.6

Brookesia 弱项(有依据)

弱项依据
IDF 6.0~6.2 硬门槛2.9.1
缺 4 个第一方组件(离线不可构建)2.1.2
载荷加密未实现2.5.4
跨进程 RPC 已移除2.4.2
ELF 后端能力弱于 elf_loader 基座(无 host call/无加密/不可中断)2.3.1
0.8.x 频繁 Breaking Change各 CHANGELOG
Boost + C++23 + 192 KB 内部 RAM 开销2.9.2
无 App Store 实体(仅安装原语)2.5.5

4. 可借鉴项与验证计划

4.1 零成本借鉴(只读源码,不改架构)

借鉴项参考出处用途
IRuntimeBackend 接口形态runtime_manager/include/brookesia/runtime_manager/backend.hpp:19-62给现有 .so 与 Lua 加统一抽象层
AppState 状态机types.hpp:31-38统一 app/作业状态表达
NativeModule/NativeValue 元数据types.hpp:40-67替代/包装现有编译期符号白名单
.bpk manifest 字段表system_core/include/brookesia/system_core/app/types.hpp:200-245设计自有包格式
RSA-PSS 验签方案(hash.json + 逐成员 SHA-256)system_core/src/package_release_verify.cpp:24-45, 551-558与现有 AES 加密叠加,补"来源可信"
服务依赖拓扑排序(Kahn)service_manager/src/service/manager.cpp:750-816服务/模块依赖管理
schema 校验 + FunctionValue 变体service_manager/include/brookesia/service_manager/function/definition.hpp:49, 147-154服务接口契约化
JS 后端 Promise 异步桥接runtime_js/src/backend.cpp:412-479优化 lua_async 的宿主回调设计
Lua 后端闭包注入runtime_lua/src/backend.cpp:93-104优化 Lua 模块绑定写法
WASM 单桩 + attachment 桥接runtime_wasm/src/backend.cpp:520-523, 627-651未来接 WASM 时的绑定方案
WAMR AOT 落 PSRAM 配置wasm-micro-runtime/core/shared/platform/esp-idf/shared_platform.cmake:18-22、espidf_memmap.c:20-51引入 WAMR 的关键配置依据

4.2 需要实测验证的

验证项方法预期要回答的问题
WAMR 单独引入(不碰 IDF 6)依赖 wasm-micro-runtime(idf ≥5.1),照 runtime_wasm/src/backend.cpp:656-735 写加载器固件增量 / 执行耗时 / PSRAM 峰值 / 加载耗时
AOT vs interp 在 S3 上的实际表现用 wamrc 编译同一模块,分别加载AOT 落 PSRAM 后的 icache 影响、相对 native .so 与 Lua 的比值
每实例内存默认值是否过大对比 brookesia 默认 64 KB 栈/256 KB 堆(backend.cpp:682-683)与示例 32 KB/32 KB(external_examples/.../main.c:76-77)合理的最小配置
.bpk 验签与现有 AES 加密的叠加可行性参考 package_release_verify.cpp 实现独立验签函数是否需要在既有 .epm 外层再加签名清单

4.3 不建议直接采用的部分

项原因依据
整体迁移到 Brookesia v0.8IDF 需升到 6.0~6.2;缺 4 个组件;与自研体系重叠度高2.9
替换现有 ELF 加载器为官方 ELF 后端官方后端无加密、无宿主符号注册、不支持 call_function、不可中断2.3.1
用 runtime_lua 替换 lua_engine官方不支持异步 native 函数、无内置硬件模块、每 app 一 state2.3.2、3.4
采用编译期静态注册(-u 符号)会破坏 claw agent 的运行期脚本/技能加载范式2.2.3
移除共享内存改用服务框架v0.8.0 已移除跨进程 RPC,服务框架仅进程内2.4.2
使用旧线 esp-brookesia 0.5.0与 0.8 不同代;UI 资源 MB 级;无 .bpk 能力2.7

5. 附录

5.1 依据索引

elf_loader 基座架构

主题关键文件
基座配置bs_hmi_base_s3/sdkconfig、sdkconfig.defaults、partitions.csv、_run_build.bat
固件体积归因build/bs_hmi_base_s3.map、build/analyze_map.py(本次新增的分析脚本)
ELF 加载components/elf_loader/src/esp_elf.c、esp_elf_adapter.c、src/dlso/dlmod.c
符号导出components/elf_ext/CMakeLists.txt、src/elf_sym_register.c、src/elf_tab_syms.c、tools/filter_syms.py
.so 调度/加载components/elf_ext/src/elf_so_loader.c、src/elf_task_api.c
加密so_build/lua_engine/tools/encrypt_so.py、components/elf_ext/src/elf_so_crypt.c
Lua 引擎so_build/lua_engine/CMakeLists.txt、components/lua_engine/src/*.c、components/georgik__lua/lua/*.c
Lua 模块so_build/lua_engine/lua_mods/lua_module_*/src/*.c
共享内存components/shared_memory/src/shared_memory.c、include/shared_memory.h、lua_mods/lua_module_shared_memory/src/*.c
布局登记so_build/bs_hmi_1ch_480x272/main/state_layout.c、main/main.c;so_build/bs_hmi_1ch_320x240/main/*
.so 体积分析so_build/lua_engine/build/analyze_so_syms.py(本次新增)
claw agentdoc/so_lua_claw_integration_plan.md【待核实:实现代码位置】

Brookesia

主题关键文件
后端接口ref/brookesia_runtime_manager/include/brookesia/runtime_manager/{backend,types,runtime,host_bridge,function_bridge}.hpp
运行时实现ref/brookesia_runtime_manager/src/{runtime,host_bridge,function_bridge}.cpp、docs/main.md
ELF 后端ref/brookesia_runtime_elf/src/backend.cpp、idf_component.yml
Lua 后端ref/brookesia_runtime_lua/src/backend.cpp、idf_component.yml
JS 后端ref/brookesia_runtime_js/src/backend.cpp、idf_component.yml
WASM 后端ref/brookesia_runtime_wasm/src/backend.cpp、src/private/{import_descriptor,host_utils,native_call_utils}.hpp
WAMRref/wasm-micro-runtime/build-scripts/esp-idf/wamr/{Kconfig,CMakeLists.txt}、core/shared/platform/esp-idf/*、core/iwasm/aot/*、README.md
服务框架ref/brookesia_service_manager/include/brookesia/service_manager/service/base.hpp、src/service/{base,manager}.cpp、include/brookesia/service_manager/helper/base.hpp
服务契约ref/brookesia_service_helper/include/brookesia/service_helper/**
WiFi 服务范例ref/brookesia_service_wifi/{include,src}/**
Agentref/brookesia_agent_manager/include/brookesia/agent_manager/{base,manager,state_machine}.hpp、ref/brookesia_service_helper/include/brookesia/service_helper/agent/*.hpp
系统层ref/brookesia_system_core/include/brookesia/system_core/app/{types,package}.hpp、src/app/package.cpp、src/package_release_verify.cpp、Kconfig
HALref/brookesia_hal_interface/include/brookesia/hal_interface/**、ref/brookesia_hal_adaptor/CMakeLists.txt、ref/brookesia_hal_boards/boards/**
旧线ref/esp-brookesia/{README.md,CMakeLists.txt,CHANGELOG.md,idf_component.yml,src/systems/phone/**}
依赖与版本各组件 idf_component.yml、CHANGELOG.md

5.2 待核实清单

编号事项说明
Q1claw agent 的实现代码位置与能力边界目前仅见规划文档 doc/so_lua_claw_integration_plan.md 与 skills 目录,未做代码级核对
Q2so_build/ 下 .so 工程的完整清单已确认 lua_engine / bs_link_hmi / bs_link_scpi / ui_mirror / terminal;bs_hmi_320x240 与 bs_hmi_1ch_{480x272,320x240} 的目录关系需最终核对
Q3esp-brookesia-toolkit 的 tools/app_pack.pysystem_core 引用但不在 ref/ 中
Q4brookesia_gui_interface 的实现system_core 的 public 依赖,未获取
Q5WAMR 在 S3 上 AOT 的实测数据只有配置层面的源码依据,无实测
Q6esp_elf 组件版本与上游 elf_loader 1.* 的关系本仓库 components/elf_loader 与 ref/brookesia_runtime_elf/idf_component.yml:5-7 所依赖的 espressif/elf_loader 是否同源同版本,未核对
Q7基座固件的日志/断言裁剪收益曾改配置但构建受阻后已回退(sdkconfig 当前为原始值,见 1.2.1),收益未测出

文档变更记录

版本日期变更
v1.12026-09-19术语调整:“我方架构” → “elf_loader 基座架构”,并补充命名说明(1 章开头)
v1.02026-09-19首版:整合本次运行时架构研究(elf_loader 基座 + Brookesia + 对比 + 借鉴项)

📚 相关阅读