一、一辆汽车里有多少个"电脑"?
现代汽车早已不是简单的机械装置,而是一个移动的计算中心。
惊人的数字
| 车型级别 | ECU 数量 | 代码行数 |
|---|---|---|
| 经济型轿车 | 30-50 个 | 1 亿行 |
| 中高端轿车 | 50-80 个 | 1.5 亿行 |
| 豪华/电动车 | 80-150 个 | 2 亿行+ |
对比:一架波音 787 客机只有约 1400 万行代码!
这些 ECU 都在做什么?
汽车 ECU 分布示例: ┌─────────────────────────────────────────────────────────┐ │ 车身控制域 │ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │ │ 车门控制 │ │ 车窗控制 │ │ 座椅控制 │ │ 空调控制 │ │ │ │ (ECU) │ │ (ECU) │ │ (ECU) │ │ (ECU) │ │ │ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │ ├─────────────────────────────────────────────────────────┤ │ 动力系统域 │ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │ │ 引擎控制 │ │ 变速箱 │ │ 电池管理 │ │ 电机控制 │ │ │ │ (ECU) │ │ (ECU) │ │ (BMS) │ │ (ECU) │ │ │ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │ ├─────────────────────────────────────────────────────────┤ │ 底盘控制域 │ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │ │ 刹车控制 │ │ 转向控制 │ │ 悬挂控制 │ │ 稳定控制 │ │ │ │ (ABS) │ │ (EPS) │ │ (ECU) │ │ (ESC) │ │ │ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │ ├─────────────────────────────────────────────────────────┤ │ 信息娱乐域 │ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │ │ 中控大屏 │ │ 仪表盘 │ │ 导航系统 │ │ 音响系统 │ │ │ │ (IVI) │ │ (IC) │ │ (ECU) │ │ (ECU) │ │ │ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │ ├─────────────────────────────────────────────────────────┤ │ 智能驾驶域 │ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │ │ 摄像头 │ │ 雷达 │ │ 激光雷达 │ │ 自动驾驶 │ │ │ │ (ECU) │ │ (ECU) │ │ (ECU) │ │ (ECU) │ │ │ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │ └─────────────────────────────────────────────────────────┘二、为什么需要分 Primary 和 Secondary?
问题的复杂性
如果每个 ECU 都独立去服务器下载更新:
❌ 方案 1:每个 ECU 独立更新 ┌─────────┐ ┌─────────┐ ┌─────────┐ │ ECU 1 │◄───►│ ECU 2 │◄───►│ ECU 3 │ │ (独立) │ 网 │ (独立) │ 网 │ (独立) │ └────┬────┘ 络 └────┬────┘ 络 └────┬────┘ │ │ │ └──────────────┼──────────────┘ ▼ ┌─────────────┐ │ 4G/5G │ ← 50 个 ECU 同时下载! │ 网络 │ 带宽爆炸、费用高昂 └─────────────┘问题:
- 💸 流量费用:50 个 ECU × 1GB 固件 = 50GB 流量/次更新
- 🐌 网络拥塞:同时下载导致速度极慢
- 🔒 安全风险:50 个攻击面,每个都要保护
- ⚡ 功耗问题:同时联网耗电巨大
Uptane 的解决方案:主从架构
✅ 方案 2:Primary + Secondary 架构 ┌─────────────────────────────────────────┐ │ Primary ECU (主) │ │ ┌─────────┐ ┌─────────┐ │ │ │ 网络模块 │ │ OTA客户端 │ │ │ │ (4G/5G) │ │aktualizr│ │ │ └────┬────┘ └────┬────┘ │ │ │ │ │ │ └──────────────┘ │ │ │ │ │ ┌──────┴──────┐ │ │ ▼ ▼ │ │ ┌─────────┐ ┌─────────────┐ │ │ │ 下载更新 │ │ 验证并分发 │ │ │ │ 从服务器 │ │ 给 Secondary│ │ │ └─────────┘ └─────────────┘ │ └────────┬────────────────────────────────┘ │ 车内网络 (CAN/LIN/Ethernet) │ ┌────┴────┬────────┬────────┐ ▼ ▼ ▼ ▼ ┌───────┐ ┌───────┐ ┌───────┐ ┌───────┐ │ ECU 1 │ │ ECU 2 │ │ ECU 3 │ │ ECU n │ │(Secondary)│(Secondary)│(Secondary)│(Secondary)│ │ 刹车 │ │ 转向 │ │ 空调 │ │ 其他 │ └───────┘ └───────┘ └───────┘ └───────┘优势:
- ✅ 只有一个设备联网,节省流量
- ✅ 集中管理安全,减少攻击面
- ✅ 车内网络更快更稳定
- ✅ Secondary 可以更简单、更便宜
三、Primary ECU:更新的"指挥官"
核心职责
Primary ECU 的五大职责: ┌─────────────────────────────────────────┐ │ 1. 网络通信 │ │ • 连接 OTA 服务器 │ │ • 下载元数据和固件 │ │ • 上报设备状态和安装结果 │ ├─────────────────────────────────────────┤ │ 2. 安全验证 │ │ • 验证 Uptane 元数据签名 │ │ • 检查固件完整性(哈希) │ │ • 防回滚、防重放攻击 │ ├─────────────────────────────────────────┤ │ 3. 更新决策 │ │ • 决定何时下载更新 │ │ • 决定何时安装更新 │ │ • 处理用户确认(如果需要) │ ├─────────────────────────────────────────┤ │ 4. 分发管理 │ │ • 将固件分发给各个 Secondary │ │ • 管理分发进度和状态 │ │ • 处理 Secondary 的响应 │ ├─────────────────────────────────────────┤ │ 5. 安装协调 │ │ • 协调多 ECU 的安装顺序 │ │ • 处理安装失败和回滚 │ │ • 生成安装报告 │ └─────────────────────────────────────────┘硬件要求
| 资源 | 典型配置 | 原因 |
|---|---|---|
| 处理器 | ARM Cortex-A53/A72 | 运行 Linux,处理加密 |
| 内存 | 512MB - 2GB | 存储固件、运行 aktualizr |
| 存储 | 4GB+ eMMC/SD | 存放数据库、缓存固件 |
| 网络 | 4G/5G + WiFi | 连接 OTA 服务器 |
| 安全 | HSM/TEE | 保护密钥和加密操作 |
典型实例
- 特斯拉:中央计算模块(CCM)
- 大众:ICAS3(In Car Application Server)
- 通用:VIP(Vehicle Intelligence Platform)
四、Secondary ECU:更新的"执行者"
两种类型的 Secondary
Uptane 根据计算能力,将 Secondary 分为两类:
┌─────────────────────────────────────────────────────┐ │ Full Verification Secondary │ │ (完整验证型 Secondary) │ ├─────────────────────────────────────────────────────┤ │ 能力: │ │ • 完整的 Uptane 元数据验证 │ │ • 独立验证固件签名和哈希 │ │ • 支持复杂的加密操作 │ │ │ │ 硬件要求: │ │ • 较强的处理器(ARM Cortex-M4+/A 系列) │ │ • 较大的内存(>256KB RAM, >1MB Flash) │ │ • 可以运行完整的 Uptane 客户端库 │ │ │ │ 示例: │ │ • 信息娱乐系统 │ │ • 自动驾驶控制器 │ │ • 高级车身控制器 │ └─────────────────────────────────────────────────────┘ ┌─────────────────────────────────────────────────────┐ │ Partial Verification Secondary │ │ (部分验证型 Secondary) │ ├─────────────────────────────────────────────────────┤ │ 能力: │ │ • 验证固件哈希(从 Primary 接收) │ │ • 简单的版本号检查 │ │ • 依赖 Primary 进行完整的 Uptane 验证 │ │ │ │ 硬件要求: │ │ • 有限的处理器(ARM Cortex-M0/M3) │ │ • 较少的内存(<256KB RAM, <1MB Flash) │ │ • 只能运行轻量级代码 │ │ │ │ 示例: │ │ • 车窗控制器 │ │ • 座椅控制器 │ │ • 简单的传感器 ECU │ └─────────────────────────────────────────────────────┘核心职责
Secondary ECU 的三大职责: ┌─────────────────────────────────────────┐ │ 1. 接收固件 │ │ • 从 Primary 接收固件数据 │ │ • 本地存储(通常写入临时区域) │ │ • 验证数据完整性(哈希检查) │ ├─────────────────────────────────────────┤ │ 2. 安装固件 │ │ • 将固件写入目标区域(Flash) │ │ • 更新版本号 │ │ • 重启(如果需要) │ ├─────────────────────────────────────────┤ │ 3. 报告状态 │ │ • 向 Primary 报告当前版本 │ │ • 报告安装成功/失败 │ │ • 提供诊断信息 │ └─────────────────────────────────────────┘五、Primary 与 Secondary 的通信协议
通信方式
车内网络类型: ┌─────────────────────────────────────────┐ │ CAN (Controller Area Network) │ │ • 速度:125Kbps - 1Mbps │ │ • 用途:传统汽车控制(刹车、引擎) │ │ • 特点:可靠、实时、低成本 │ │ • 限制:带宽低、数据包小(8字节) │ ├─────────────────────────────────────────┤ │ CAN FD (Flexible Data-rate) │ │ • 速度:最高 8Mbps │ │ • 用途:新一代汽车网络 │ │ • 特点:向后兼容 CAN,带宽更高 │ │ • 限制:仍有一定限制 │ ├─────────────────────────────────────────┤ │ LIN (Local Interconnect Network) │ │ • 速度:最高 20Kbps │ │ • 用途:低成本传感器、执行器 │ │ • 特点:极低成本、单线通信 │ │ • 限制:速度很慢 │ ├─────────────────────────────────────────┤ │ Ethernet │ │ • 速度:100Mbps - 1Gbps+ │ │ • 用途:ADAS、信息娱乐、OTA │ │ • 特点:高带宽、标准协议 │ │ • 限制:成本较高、需要交换机 │ └─────────────────────────────────────────┘Uptane 的 Secondary 协议
Uptane 定义了标准化的 Primary-Secondary 通信协议:
通信消息类型: ┌─────────────────────────────────────────┐ │ 1. Discovery(发现) │ │ Primary: "有哪些 Secondary 在线?" │ │ Secondary: "我在这里,我的信息是..." │ ├─────────────────────────────────────────┤ │ 2. Metadata Distribution(元数据分发) │ │ Primary: "这是最新的 Uptane 元数据" │ │ Secondary: "收到,验证通过/失败" │ ├─────────────────────────────────────────┤ │ 3. Firmware Distribution(固件分发) │ │ Primary: "这是给你的固件(分片发送)" │ │ Secondary: "收到第 X 片,校验正确" │ ├─────────────────────────────────────────┤ │ 4. Installation Request(安装请求) │ │ Primary: "请安装这个固件" │ │ Secondary: "安装成功/失败,原因是..." │ ├─────────────────────────────────────────┤ │ 5. Status Report(状态报告) │ │ Secondary: "我的当前版本是..." │ │ Primary: "收到,已记录" │ └─────────────────────────────────────────┘ASN.1 消息格式
Uptane 使用 ASN.1(Abstract Syntax Notation One)定义消息格式:
-- 简化的 Secondary 消息定义 SecondaryMessage ::= CHOICE { discoveryRequest [0] DiscoveryRequest, discoveryResponse [1] DiscoveryResponse, firmwareRequest [2] FirmwareRequest, firmwareResponse [3] FirmwareResponse, ... } DiscoveryResponse ::= SEQUENCE { ecuSerial UTF8String, hardwareId UTF8String, currentVersion INTEGER, supportedTypes SEQUENCE OF UTF8String } FirmwareRequest ::= SEQUENCE { ecuSerial UTF8String, targetFilename UTF8String, offset INTEGER, -- 用于断点续传 chunkSize INTEGER }六、aktualizr 中的实现
代码架构
aktualizr 中的 Primary/Secondary 实现: src/ ├── aktualizr_primary/ # Primary ECU 主程序 │ └── main.cc ├── aktualizr_secondary/ # Secondary ECU 主程序 │ └── main.cc ├── libaktualizr/ │ ├── primary/ # Primary 相关代码 │ │ ├── aktualizr.cc # 主类实现 │ │ ├── sotauptaneclient.cc # Uptane 客户端 │ │ └── secondary.cc # Secondary 管理 │ └── secondary/ # Secondary 相关代码 │ ├── secondary_interface.h # 接口定义 │ ├── ipc_secondary.cc # IPC 实现 │ ├── socket_secondary.cc # Socket 实现 │ └── ...关键类解析
Primary 端:SecondaryInterface
// 简化版接口定义classSecondaryInterface{public:virtual~SecondaryInterface()=default;// 发现 Secondaryvirtualstd::stringgetSerial()=0;virtualstd::stringgetHwId()=0;// 发送元数据virtualboolsendMetadata(constUptane::MetaCollection&meta)=0;// 发送固件virtualboolsendFirmware(conststd::string&filename,conststd::string&data)=0;// 安装请求virtualdata::ResultCodeinstall()=0;// 获取状态virtualSecondary::VersiongetVersion()=0;};Secondary 端:AktualizrSecondary
// Secondary 主类classAktualizrSecondary{public:// 初始化voidinitialize();// 处理 Primary 的请求voidhandleDiscovery();voidhandleMetadata(constUptane::MetaCollection&meta);voidhandleFirmware(conststd::string&data);voidhandleInstall();// 验证(根据类型)boolverifyMetadata(constUptane::MetaCollection&meta);boolverifyFirmware(conststd::string&data);private:SecondaryConfig config_;// 配置INvStorage&storage_;// 存储KeyManager&keys_;// 密钥管理};七、动手实验:配置虚拟 Secondary
实验 1:查看 Secondary 配置
cd~/test/aktualizr/demo# 查看虚拟 Secondary 配置文件catvirtualsec.json输出示例:
{"virtual":[{"ecu_serial":"demo-vsec1","ecu_hardware_id":"demo-virtual","partial_verifying":false,"ecu_private_key":"sec.private","ecu_public_key":"sec.public","firmware_path":"storage/demo-vsec1/firmware.bin","metadata_path":"storage/demo-vsec1/metadata","target_name_path":"storage/demo-vsec1/target_name"}]}实验 2:启动带 Secondary 的 aktualizr
cd~/test/aktualizr/demo# 确保目录结构正确mkdir-pstorage/demo-vsec1/metadatachmod-R700storage/# 查看配置文件catsota-local.toml配置内容:
[provision] mode = "AutoProvision" primary_ecu_hardware_id = "local-fake" [logger] loglevel = 1 [storage] path = "storage" type = "sqlite" [pacman] type = "none" images_path = "storage/images" [uptane] secondary_config_file = "virtualsec.json" # 关键配置!实验 3:运行并观察
cd~/test/aktualizr/demo# 运行 aktualizr(单次模式)sudo../build/src/aktualizr_primary/aktualizr--configsota-local.toml once观察输出:
Initializing virtual Secondaries... Adding Secondary with ECU serial: demo-vsec1 with hardware ID: demo-virtual ...实验 4:配置多个 Secondary
cd~/test/aktualizr/demo# 创建多 Secondary 配置cat>virtualsec-multi.json<<'EOF' { "virtual": [ { "ecu_serial": "demo-vsec1", "ecu_hardware_id": "demo-virtual", "partial_verifying": false, "ecu_private_key": "sec1.private", "ecu_public_key": "sec1.public", "firmware_path": "storage/demo-vsec1/firmware.bin", "metadata_path": "storage/demo-vsec1/metadata", "target_name_path": "storage/demo-vsec1/target_name" }, { "ecu_serial": "demo-vsec2", "ecu_hardware_id": "demo-virtual-2", "partial_verifying": true, "ecu_private_key": "sec2.private", "ecu_public_key": "sec2.public", "firmware_path": "storage/demo-vsec2/firmware.bin", "metadata_path": "storage/demo-vsec2/metadata", "target_name_path": "storage/demo-vsec2/target_name" } ] } EOF# 创建目录mkdir-pstorage/demo-vsec2/metadatachmod-R700storage/# 修改配置使用新文件sed-i's/virtualsec.json/virtualsec-multi.json/'sota-local.toml# 运行sudo../build/src/aktualizr_primary/aktualizr--configsota-local.toml once八、本章小结
核心概念回顾
| 概念 | 一句话解释 |
|---|---|
| ECU | 电子控制单元,汽车里的"小电脑" |
| Primary ECU | 主 ECU,负责联网、验证、分发更新 |
| Secondary ECU | 次 ECU,从 Primary 接收并安装更新 |
| Full Verification | 完整验证,能独立验证所有 Uptane 元数据 |
| Partial Verification | 部分验证,依赖 Primary 进行主要验证 |
| 车内网络 | CAN/CAN FD/LIN/Ethernet,连接各个 ECU |
架构优势
Primary + Secondary 架构的优势: ✅ 安全性 • 只有一个联网点,减少攻击面 • 集中管理安全策略和密钥 ✅ 经济性 • Secondary 可以更简单、更便宜 • 节省流量费用(只下载一次) ✅ 可靠性 • 车内网络比公网更稳定 • 可以协调多 ECU 的更新顺序 ✅ 灵活性 • 支持不同能力的 ECU • 可以混合使用不同验证级别下一步
在下一篇文章《动手搭建第一个 OTA 客户端——aktualizr 编译与运行》中,我们将:
- 完整编译 aktualizr 项目
- 配置并运行第一个可用的 demo
- 理解配置文件的每个参数
- 排查常见问题
九、延伸阅读与资源
官方文档
- Uptane 部署指南: https://uptane.github.io/deployment/best-practices.html
- aktualizr Secondary 文档:
docs/ota-client-guide/modules/ROOT/pages/virtual-secondaries.adoc
推荐阅读
- 《汽车电子架构演进》了解域控制器架构
- 《CAN 总线协议详解》了解车内通信
思考题
- 为什么 Full Verification Secondary 需要更强的硬件?
- 设计一个场景:如果 Primary ECU 被攻破,Secondary 如何保护自己?
- 在电动车中,BMS(电池管理系统)应该作为 Primary 还是 Secondary?为什么?
目标读者:理解基础概念的开发者
上一篇:《Uptane 安全框架初探——比 HTTPS 更安全的更新机制》
下一篇:《动手搭建第一个 OTA 客户端——aktualizr 编译与运行》
希望这篇文章让你理解了 Primary/Secondary 架构的设计思想。有任何问题,欢迎在评论区留言讨论!