reverse-skills-max: initial public release (restored, redacted, hardened)

This commit is contained in:
baradok609hecl1pq6qi
2026-10-20 02:17:15 +03:00
commit da24c2bd20
2227 changed files with 443931 additions and 0 deletions

View File

@@ -0,0 +1,179 @@
---
name: re-automotive
description: >
汽车逆向:CAN 总线、ECU 固件、AUTOSAR Classic(RTE/runnable/BSW)与 Adaptive(执行管理/清单)。
触发词:汽车、CAN、ECU、车载、OBD、UDS、AUTOSAR、RTE、runnable、SWC、BSW、E_OS_ACCESS、
Adaptive、ARA、Execution Management、Function Group、Machine State、Execution Manifest
capabilities: [automotive-analysis]
---
# 汽车逆向(CAN 总线 / ECU / AUTOSAR Classic)
## 何时使用 / 何时不用
- 前置:拿到 ARXML 或车载软件包但不确定是 Classic 还是 Adaptive → [[re-analyze/system-fingerprints]] 的车载段
- 用:拿到车辆 CAN 总线流量(candump 日志 / .asc / .blf)需要解析报文与信号
- 用:车载设备(车机、T-Box、IVI、ECU 升级包)逆向
- 用:OBD-II / UDS 诊断会话分析(读 DTC、安全访问、标定读写)
- 用:ECU 固件提取与后续解包(配合 [[re-firmware]])
- 用:**AUTOSAR Classic 软件**(SWC/runnable/RTE/BSW)——执行图由配置与代码生成决定,不能用普通调用图理解([[autosar-classic]])
- 不用:只有 ECU 固件文件、没有总线访问(直接 [[re-fw-extract]])
- 不用:需要跑固件观察行为([[re-fw-emulate]])
- 不用:需要 JTAG/SWD 读 flash([[re-hardware-io]])
- 红线:只对自有/获授权车辆与测试台架测试(见步骤 5)
## 工具准备
所有工具先验证再使用。实车/实总线测试默认物理隔离——[[re-analyze/platform-tips]] 最高原则:仅自有或获授权测试车辆/台架可接入;实验室起步用 vcan 虚拟总线,不接真车。
### can-utils —— candump/cansend/cangen/canplayer 主力
- Linux: `apt install can-utils`(Debian/Ubuntu)/ `dnf install can-utils`(Fedora)/ Arch: 无官方包 → AUR(can-utils)或源码构建(`git clone https://github.com/linux-can/can-utils && cd can-utils && ./autogen.sh && ./configure && make`)
- macOS/Windows: 无官方包(SocketCAN 为 Linux 内核特性)→ WSL/虚拟机内 Linux 版
- 验证: `candump --help`;`cansend --help`
### socketcan —— Linux 内核 CAN 栈(vcan 虚拟总线 / can-isotp)
- Linux: 内核自带模块(5.10+ 内核含 can-isotp):`modprobe can vcan can-isotp`;`ip link` 来自 iproute2(基础系统自带)
- macOS/Windows: 不支持 → WSL2/虚拟机(需 Linux 5.10+)
- 验证: `modprobe vcan && ip link add dev vcan0 type vcan && ip link set up vcan0 && ip -details link show vcan0`
### USB-CAN 适配器 —— gs_usb 系(canable/candlelight)即插即用
- Linux: 内核自带 gs_usb 驱动(drivers/net/can/usb/gs_usb.c);插入后 `dmesg` 应注册 can0(个别发行版 CAN 驱动在 modules-extra 包,`modprobe gs_usb` 报错时装对应 extra 包)
- macOS/Windows: 用厂商驱动 + 厂商软件,或经虚拟机透传
- 验证: `modprobe gs_usb`;`ip -details link show can0`
### wireshark / tshark —— CAN/ISO-TP/UDS 解析
- 安装同 [[re-netcap]] 工具准备(apt/dnf/pacman/brew/choco);CAN(socketcan / Vector ASCII / BSLogger)、ISO-TP、UDS(ISO 14229)dissector 内置
- 验证: `tshark --version`;candump `-l` 日志可直接 File → Open 打开
### python-can —— 脚本化解析(跨平台)
- 全平台: `pip install python-can`
- Linux: `apt install python3-can`(Debian/Ubuntu)/ `dnf install python3-can`(Fedora)/ `pacman -S python-can`(Arch extra)
- 验证: `python3 -c "import can; print(can.__version__)"`
### OBD-II / UDS 诊断库
- python-obd(ELM327 适配器,OBD-II 标准服务): 无官方包 → `pip install obd`;验证 `python3 -c "import obd"`
- udsoncan(UDS ISO 14229 客户端): 无官方包 → `pip install udsoncan isotp`;验证 `python3 -c "import udsoncan, isotp"`
- 注意:udsoncan 用 IsoTPSocketConnection 需要 Linux can-isotp 内核模块(5.10+)或 socketcan;无内核模块时用 PythonIsoTpConnection(走 python-can,跨平台但时序略差)
### scapy —— 汽车协议层(automotive 包,可选)
- 全平台: `pip install scapy`(含 `scapy.contrib.automotive` 与 `scapy.layers.can`)
- 验证: `python3 -c "from scapy.contrib.automotive.uds import UDS; from scapy.contrib.automotive.doip import DoIP; from scapy.layers.can import CAN; print('ok')"`
## 操作步骤
按顺序执行,每步记下结果。
1. **CAN 接入(USB-CAN / socketcan)**:
- 无硬件起步(vcan 虚拟总线):
```sh
sudo modprobe can vcan can-isotp
sudo ip link add dev vcan0 type vcan
sudo ip link set up vcan0
```
- USB-CAN(gs_usb 系):
```sh
sudo modprobe gs_usb
sudo ip link set can0 up type can bitrate 500000 # 500 kbit/s 经典波特率
ip -details link show can0 # 确认 bitrate / state UP
```
- 波特率必须与总线一致(错误波特率 = 错误帧刷屏,见坑 3)
2. **candump 抓包**:
```sh
candump -t a can0 # 实时查看(绝对时间戳)
candump -l can0 # 落盘日志(默认文件名带时间戳;无轮转——需要轮转交给 logrotate/外部脚本;Wireshark 可直接打开)
candump can0 -n 100 # 只抓 100 帧
candump can0,7E0:7FF # ID 过滤:接口名后接 can_id:mask(逗号分隔);掩码 7FF = 精确匹配 7E0,区间过滤用 7F8(匹配 7E0~7E7);CAN 无地址(见坑 1)
candump -f can.log can0 # 注意 -f 是"日志写入文件",不是过滤参数
```
3. **报文 ID / 周期 / 信号解析**:
```sh
cansniffer can0 # 按 ID 聚类、周期与变化字节高亮
candump can0 | awk '{print $2}' | sort | uniq -c # 按 ID 统计帧数(默认输出第 2 列是 ID;注意 -c 是颜色模式,不是计数)
canbusload can0@500000 # 总线负载率 %
```
- 周期消息(固定间隔 10/50/100ms 常见)→ 转速/车速等连续信号;事件消息(无规律)→ 开关/按钮
- 信号解包:先定字节序(Intel 小端 vs Motorola 大端,见坑 2)→ 逐字节变化观察(cansniffer 高亮变化字节)→ 用 cantools 按 DBC 定义解包(`pip install cantools`)
- 产出 ID 表:ID / 周期 / 长度 / 疑似信号 / 字节序
4. **UDS / OBD 诊断**:
- OBD-II 快速体检(标准诊断对 0x7E0/0x7E8,ELM327 适配器):
```python
import obd
conn = obd.OBD() # 自动探测适配器串口
conn.query(obd.commands.SPEED) # 车速
conn.query(obd.commands.GET_DTC) # 故障码
```
- UDS(ISO 14229,厂商诊断 ID 不固定,先抓包确认):
```python
import udsoncan, isotp
from udsoncan.connections import IsoTPSocketConnection
from udsoncan.client import Client, ClientConfig
from udsoncan.services import DiagnosticSessionControl, DataIdentifier
# 关键:DID 的 payload 怎么编解码,由 config['data_identifiers'] 决定——
# 该 DID 不在映射里时,udsoncan 在发送请求**之前**就抛 ConfigError
#("contains no definition for data identifier 0xf190");映射里有但 codec 不是
# DidCodec 实例则抛 ValueError("is not a valid DidCodec")。
# 配置只需给出要覆盖的键:Client 会用 udsoncan.configs.default_client_config 补齐其余项,
# 所以 data_identifiers 之外不必逐项照抄默认值。
config = ClientConfig()
config['data_identifiers'] = {
0xF190: ..., # VIN 的标准 DID;codec = 17 字节 ASCII(用库自带的类型,或自定义 DidCodec 子类)
}
conn = IsoTPSocketConnection('can0', isotp.Address(isotp.AddressingMode.Normal_11bits, rxid=0x7E8, txid=0x7E0))
with Client(conn, request_timeout=2, config=config) as client:
client.change_session(DiagnosticSessionControl.Session.extendedDiagnosticSession)
vin = client.read_data_by_identifier(DataIdentifier.VIN)
```
- **读/写 DID 必须先配 codec**:`read_data_by_identifier` / `write_data_by_identifier` 依赖 client 配置里的 `data_identifiers`(DID → codec 映射)——**响应只是字节串,缺了 codec 就无从解码**,udsoncan 会以配置错误终止而不是"返回原始字节"。官方示例一律写成 `Client(..., config=MyCar.config)` 并注明 VIN 的 codec 配在 client 配置里。只想看原始载荷就别走 DID 解码路径,用不做解码的低层接口
- 服务速查:0x10 会话控制 / 0x22 读数据标识符 / 0x27 安全访问(seed-key)/ 0x2E 写数据 / 0x31 例程控制 / 0x3E 保持活动 / 0x11 ECU 复位 / 0x34-0x36-0x37 固件下载流程
- Wireshark 打开 candump 日志 → ISO-TP/UDS dissector 自动解码诊断会话
5. **ECU 固件**:
- UDS 下载流程:标准传输核心是 `0x34 RequestDownload → 0x36 TransferData × N → 0x37 RequestTransferExit`;实际 ECU 编程通常先按 OEM 要求进 `0x10` 编程会话,服务受安全级别保护时执行 `0x27`(安全访问),擦除/完整性校验多经 OEM 定义的 `0x31`(例程控制),过程可能需 `0x3E` 保活、结束可能 `0x11` 复位——具体序列从 ECU 行为/ODX/固件恢复,不假定固定顺序。或 `0x23` 读内存获取固件 → 转 [[re-fw-extract]] 解包(ECU/车机固件与 IoT 固件同流程)
- 直接拿到的升级包文件 → [[re-fw-extract]];固件 ELF → [[re-binary-core]];需硬件 flash 读取 → [[re-hardware-io]]
## IVI / T-Box / V2X 路径
按目标形态分流(判定规则):
- **IVI(车载娱乐系统)**:本质是 Android/Linux 系统——应用层走 [[re-apk]],系统镜像走 [[re-firmware]];关注 OEM 定制层(启动器、诊断接口、ADB/调试口)
- **T-Box(远程信息处理箱)**:蜂窝模组(AT 指令接口)、MCU 固件([[re-fw-extract]] 提取分析)、远程控制协议(车控指令——门锁/空调/启动,走 [[re-protocol]])
- **V2X(车联网通信)**:DSRC / C-V2X 帧结构 → [[re-protocol]] / [[re-ics]] 路径(协议状态机重建、PC5/Uu 接口区分);物理层信号采集走 [[re-sdr]]
- 判定规则:应用层 → 移动/系统路径([[re-apk]] / [[re-firmware]]);通信层 → 协议路径([[re-protocol]] / [[re-ics]]);固件层 → 固件路径([[re-fw-extract]] / [[re-fw-rootfs]])
## 分支(references)
- [[autosar-classic]] —— **配置驱动 + 代码生成**的执行图:RunnableEntity 由 **RTEEvent** 激活、经 RTE 胶水映射到 **OS Task 或 ISR2**(**RTE 没有独立调度能力**),**无 caller 的 runnable 不是死代码**;**隐式访问**(`Rte_IRead_*`/`Rte_IWrite_*`)在 runnable 边界做快照与写回("消费者看到旧值"可能是语义);`E_OS_ACCESS` 来自 **OS-Application 所有权/保护**(默认拒绝,授权来自配置),不是参数错误;并发异常先查 OS 配置(Task 映射、优先级、抢占)
- [[autosar-adaptive]] —— **清单驱动的生命周期**:POSIX 进程 + ARA 功能簇;**Modelled Process ≠ OS 进程**(不要 1:1 比较);**"bin 存在但进程不存在"先查 Function Group State / Machine State**(EM 把状态翻译成进程集合);Execution Manifest 可按状态给同一可执行文件不同配置;EM 切换时先终止再按依赖启动
## 跨域联合
- [[re-firmware]]:本技能是其汽车分支(ECU 固件提取后 → 解包 → rootfs → 仿真)
- [[re-fw-extract]] / [[re-fw-rootfs]] / [[re-fw-emulate]]:ECU/车机固件解包、文件系统分析、仿真
- [[re-hardware-io]]:OBD 口抓包(CAN/UART)、JTAG/SWD 读 flash
- [[re-protocol]]:DoIP(UDS over Ethernet,13400 端口)等车载以太网协议重建;CAN 私有协议转 [[re-proto-rev]]
- [[re-sandbox]]:虚拟 CAN / DoIP 测试床隔离;固件仿真默认网络隔离([[re-analyze/platform-tips]] 最高原则)
- [[re-binary-core]]:固件内 ELF 深度静态分析
- [[re-crypto-id]] / [[re-crypto-decrypt]]:seed-key 算法、CAN 加密变体
## 常见坑与陷阱
- **CAN 无地址概念 → 过滤/归因错**:现象——想"按目标 ECU 过滤"却要么漏帧要么全抓;原因——CAN 帧无源目地址,只有 11/29 位仲裁 ID,ID 兼具优先级与"身份"(ID 越小优先级越高);对策——先全量抓(candump)再按 ID 聚类归类(cansniffer,或对 candump 输出管道 awk/sort/uniq 统计),用 `candump can0,ID:mask` 过滤,不预设主机概念
- **信号位打包错**:现象——信号值乱(转速负值/巨大、多字节字段错位);原因——信号跨字节跨位打包,Intel(小端)/Motorola(大端)序混用,且信号不必对齐字节边界;对策——先定字节序再解包,用 DBC + cantools 定义位布局,与实车读数/已知量程交叉验证
- **波特率不符与总线负载**:现象——`candump` 错误帧刷屏(error frame),或高负载下周期抖动、抓到的周期不可信;原因——波特率与总线不一致;负载高(>60-70%)时仲裁延迟与丢帧;对策——接入前确认波特率(500 kbit/s 最常见,canbusload 看负载率),周期性分析排除高负载时段,需要精确时序用硬件时间戳
- **seed-key 安全访问被拒**:现象——UDS 读内存/写标定回 0x7F 27 33(SecurityAccessDenied);原因——0x27 需先解锁:服务端发 seed(0x27 01/03),客户端回 key(0x27 02/04),算法厂商私有(XOR/CRC/AES 常见);对策——有合法诊断仪/工具时先抓一次正常解锁流程,算法还原走 [[re-crypto-id]] / [[re-crypto-decrypt]];只在自有测试设备上做,不盲目爆破
- **固件校验/加密层**:现象——提取的固件在 [[re-fw-extract]] 解出垃圾,或烧回不工作;原因——ECU 固件带签名/CRC 校验、bootloader 验签或整体加密;对策——提取时按 0x34/0x36 会话完整传输并校验;分析时先区分加密/签名层再解包,解不开转 [[re-crypto-id]] / [[re-crypto-decrypt]];仅在授权测试床/设备上操作
- **把 AUTOSAR runnable 当死代码**:现象——某业务函数没有任何调用者,判为残留/无用代码;原因——runnable 由 RTEEvent 经生成的 RTE 胶水在某 OS Task 内被调用,**调用关系在配置里而不是在源码里**;对策——找 `Rte_*` 包装与 RTEEvent 映射、确认它被映射到哪个 OS Task([[autosar-classic]])
- **把隐式访问的"旧值"当一致性问题**:现象——生产者在运行中改了数据,消费者 runnable 执行期间一直读到旧值,怀疑 cache 或内存损坏;原因——隐式访问在 runnable 边界做快照与写回;对策——区分 `Rte_Read_*`(显式)与 `Rte_IRead_*`(隐式),按配置判定通信形式([[autosar-classic]])
- **把 `E_OS_ACCESS` 当参数错误**:现象——`ActivateTask` 一类服务返回访问错误,怀疑 task ID 写错或 OS 损坏;原因——OS-Application 的所有权/保护状态:未在配置时授予访问权,或对象属于另一个不可访问的应用;对策——查对象所属 OS-Application、应用状态、信任级别与当前调用上下文([[autosar-classic]])

View File

@@ -0,0 +1,198 @@
# AUTOSAR Adaptive:清单驱动的生命周期 / 服务发现 / PHM / 更新
<CORE RULE>
底层通常确实是 POSIX OS,**但应用生命周期、服务发现、更新、健康监控都不是由 ELF 与进程树决定的**:
```
Executable
├─ Execution Manifest → Modelled Process / 启动参数 / 优先级 / 资源组 / FG State 映射
├─ Service Instance Manifest → 服务部署 / SOME-IP 或 DDS 绑定 / 安全与 E2E / 实例映射
└─ Machine Manifest → 网络 / 服务发现 / Machine State / Function Groups / PHM / 平台配置
State Management → Execution Management → start/stop Processes
ara::com → service discovery / IPC
PHM → supervision → State Management
UCM → software cluster install / update / rollback
```
所以:
```
binary 明明装好了,进程却完全不存在
→ 先查当前 Machine State / Function Group State / Execution Manifest
→ 不要先判 crash 或 loader failure
```
**这个进程按设计当前就不应该运行。**
</CORE RULE>
> 版本提示:公开版本已推进到 R25-11,本节多数细节来自完整公开的 R24-11 规范;核心模型仍适用,**具体条目要按目标版本做指纹**。
## 一、Modelled Process ≠ OS 进程
- 元模型里的 **Process(Modelled Process)**是 ARXML 模型元素:"可执行文件在 Machine 上执行的一个被加载的实例"
- 规范用不带前缀的 "process" 指 **POSIX 意义上的运行中进程**,以此区分两者
- 运行期:EM 为**每个 modelled Process 建立一个 OS 进程**;之后 EM 只在状态管理与确定性执行方面与之相关
- 变体:**上报型**(经 ExecutionClient 上报执行状态)、**不上报型**(可用于非 AP 适配的二进制)、**自终止型**(自己退出或被 EM 以信号终止)
- **`identity = Executable + Modelled Process 实例 + Function Group State`**,而不是 ELF 哈希
## 二、同一个 ELF 可以有多个不同行为的进程
规范明确允许**一个 Executable 二进制的每个启动实例分别配置**,且**不同 Machine State / FG State 可以采用不同配置集**。所以:
```
foo
├─ Process A 优先级 20
├─ Process B 优先级 40
└─ Process C 不同 args / resource group
```
可以都是同一 executable 的不同 Modelled Process。**不要假设 1 executable = 1 process configuration。**
## 三、生命周期调用者不在目标进程自身
进程"无故"被终止、另一批进程随即启动,正常路径可以是:
```
外部事件 → State Management → SetState(FunctionGroupState X)
→ Execution Management → terminate A/B → start C/D
```
- FG State 本身定义了"**哪些 Process 此时应该运行、哪些不应该**"
- 状态切换时 EM **先终止正在运行的进程,再按执行依赖顺序启动新状态下活动的进程**,最后才向 SM 确认
- 规范覆盖终止超时、启动超时、重启尝试等失败情形
- 启动时 EM 由 OS 作为初始进程之一拉起(**不一定是第一个进程**),自行把 MachineFG 转到 **Startup**;此后**不再自行发起**状态切换——要由 SM 请求
**动态分析要求**:除了 fork/exec/exit 图,还必须建立 **state transition graph**。
## 四、服务发现:空结果与重复回调都可能正常
- **`FindService()` 明确允许返回空集合**——当前没有匹配的 service instance 可用而已
- **`StartFindService()` 本身就是持续的异步可用性监控**:
```
StartFindService() → callback([]) → 服务出现 → callback([service]) → 服务消失 → callback([])
```
**第一次回调本来就允许是空的**。所以"发现服务返回零"不能立即判网络故障 / 清单损坏 / provider 崩溃,**必须观察 availability 生命周期**。
- 规范要求:**每当匹配 service instance 的可用性变化时重新调用 handler**,且**实现负责串行化同一个 handler**——因此同一个回调被调用多次**不是重复注册 bug**
## 五、handle 可以指向远端实例
拿到 service handle 却在本地找不到 provider 进程**完全正常**:
```
Proxy handle 存在 + 本机没有 provider executable
→ 不能判服务表被伪造
→ 应追:Service Instance Manifest → 网络绑定 → 实例映射 → 远端机器
```
## 六、`ara::com` ≠ 必然 SOME/IP
Adaptive service 可以部署到不同通信技术——公开模型中同时明确描述了 **SOME/IP 与 DDS** 的 service-instance deployment。
```
ara::com API → binding → 可能是 DDS,而不是 UDP/TCP SOME/IP
```
**所以:搜不到 SOME/IP 流量时先查 Service Instance Manifest**;分析器若写死"ara::com → SOME/IP"会直接产生事实性错误。
推论:跨 ECU 建图时把 **logical service interface** 与 **technical binding/deployment** 分开恢复——**接口相同而底层协议不同**可以正常。
## 七、PHM:没有 crash 不等于健康
- PHM 以**进程粒度**监督(不同于 Classic 的 WdgM 任务级 + 硬件看门狗复位)
- 基本单位是 **Supervised Entity(SE)**:可映射到一个进程**或进程的一部分**;应用经 `ReportCheckpoint` 上报进度
- **三类监督**:
| 监督 | 判据 |
|---|---|
| **Alive** | 周期内上报的检查点数量是否在期望范围内(过多/过少都算) |
| **Deadline** | 起止检查点之间的执行时间是否落在配置区间 |
| **Logical** | 检查点上报顺序是否符合预定义监督图(与时间无关) |
- 状态:本地状态 OK / FAILED / **EXPIRED(终态,不能回到 OK)**;全局状态在聚合之外还含 STOPPED(超过容忍期后)
- **监督模式定义为 `<machine state, function group state>`**,由状态管理通知
- **恢复动作**(在清单里定义):请求 SM 切 FG 状态、请求 EM 重启进程或进入不可恢复状态、**请求看门狗驱动复位**、上报诊断、转发给安全应用做复杂响应
- **PHM 自身不启停进程**——由 EM 代为执行
- PHM 还会监督 EM 守护进程的存活;其失败会升级为看门狗/机器复位(因为经 EM/SM 的常规恢复已不可靠)
**所以**:
```
process wasn't segfaulted ≠ process was healthy
系统重启了但找不到 reboot 调用者 → 查 PHM 监督状态 / SM 反应 / 看门狗路径
```
## 八、UCM 与 Persistency:装上 ≠ 生效
- UCM 把 **transfer/install、verify、activate** 分开;激活前检查 Software Cluster 依赖,EM 在 Verify 阶段发现执行依赖不满足时可通过 SM/UCM 导致 **rollback**
- 所以"磁盘上有新包"**不能**推出"新版本已生效";要分别确认:package received? installed? verified? **activated?** rollback?
- **Persistency 的更新策略**(按元素/文件):
| 策略 | 含义 |
|---|---|
| `keepExisting` | 保留既有数据,忽略清单初始值(用户数据) |
| `overwrite` | 用清单值替换(强制配置同步) |
| `delete` | 删除既有元素(用于废弃配置) |
- 清单约束:`keepExisting`/`overwrite` 要求存在初始值;`delete` 要求不存在
- **版本处理**:清单版本 > 存储版本 → 更新;相等 → 不操作;**更低 → 回滚**(存在有效备份时)
- **部署期设置可以覆盖设计期设置**:逆向量产系统时,**目标部署产物优先于设计仓库里的默认配置**
**所以**:更新后"新程序 + 旧数据"可能是 `keepExisting`,"数据突然消失"可能是 `delete`。**这两种都不是更新失败。**
## 决策树
```
Process 不存在
├─ 当前 Function Group State?
├─ 当前 Machine State?
├─ Execution Manifest 里的 StartupConfiguration?
└─ UCM 是否已 activate?
Service 找不到
├─ FindService 本来可以返回空?
├─ StartFindService 尚未出现 provider(availability 生命周期)?
├─ 是 remote service instance?
├─ 绑定是 SOME/IP 还是 DDS?
└─ Service Instance Manifest 怎么写的?
Process 无 crash 却重启/复位
├─ PHM Alive / Deadline / Logical 哪一类?
├─ SM 的状态迁移?
├─ PHM→看门狗复位路径?
└─ EM 自身是否被监督?
更新行为奇怪
├─ package 是 installed 还是 activated?
├─ 依赖 Verify 是否通过?
├─ 是否 rollback?
└─ Persistency 策略是 keep / overwrite / delete?
```
## 工具与验证
- 清单三件套:Execution Manifest(Modelled Process、启动参数、资源组、FG State 映射)、Service Instance Manifest(部署、绑定、E2E/安全、实例映射)、Machine Manifest(网络、服务发现、Machine State、FG、PHM)
- 状态:当前 Machine State 与 Function Group State;supervision mode = `<machine state, function group state>`
- 健康:SE 的监督类型与本地/全局状态、恢复动作定义
- 更新:UCM 的阶段状态、Persistency 策略与版本比较结果
- 验证:能同时说清「当前状态是什么 + 清单规定哪些进程/服务应活动 + 该行为来自清单还是实现」
## 该平台的坑(汇总)
- **把"bin 存在但进程不存在"当崩溃或加载失败**:先看 Function Group/Machine State
- **把 Modelled Process 与 OS 进程 1:1 比较**:规范明确区分
- **假设 1 个 executable 只有 1 种进程配置**:可按状态给不同配置
- **把生命周期当作目标进程自己的责任**:真正的调用者是 SM→EM
- **用 fork/exec/exit 图代替状态迁移图**
- **把"发现服务返回空"当故障**:空结果是合法值,且首次回调可以为空
- **把重复回调当重复注册**:规范要求可用性变化时回调,且实现负责串行化
- **在本地找不到 provider 就判伪造**:handle 可指向远端实例
- **写死 ara::com = SOME/IP**:也可能是 DDS
- **把没有 crash 当健康**:Logical/Alive/Deadline 监督与崩溃是两回事
- **只搜 reboot 调用者找复位原因**:看门狗路径由 PHM 触发
- **把"包已安装"当"新版本生效"**:install/verify/activate 分开,还可能 rollback
- **把更新后的数据保留或消失当更新失败**:keepExisting / delete 都是策略
- **拿设计期 ARXML 当量产行为的依据**:部署期设置优先

View File

@@ -0,0 +1,117 @@
# AUTOSAR Classic:RTE 执行图 / 隐式访问 / OS-Application 保护
<CORE RULE>
AUTOSAR Classic 里**大量真正的控制流是配置驱动 + 代码生成出来的**:
```
TimingEvent / DataReceivedEvent / OperationInvokedEvent / ...
↓
RTE(生成的胶水代码)
↓
AUTOSAR Task 或 ISR2
↓
RunnableEntity(业务函数)
```
所以:
```
void Runnable_10ms(void); ← 0 个交叉引用
```
**绝不能直接判死代码。** 先找 `Rte_*` 包装、OS Task、`ActivateTask` / `SetEvent` / `WaitEvent` / Alarm / ScheduleTable,以及生成配置。
</CORE RULE>
## 一、执行图:RTE 没有独立调度能力
- RunnableEntity 由 **RTEEvent** 激活;事件类型包括定时、数据接收/接收错误、数据发送完成/写入完成、操作调用、异步服务调用返回、模式切换(及其确认/错误)、外部与内部触发、初始化事件、OS 任务执行事件等
- **RTE 不做调度**:每个 RTE Event 必须映射到一个具体的 OS Task,**RTE 在该 Task 被 OS 调度时按配置顺序调用相应 runnable**;映射必须写进 ECU 配置描述,作为 RTE 生成器的输入
- RunnableEntity 在 **OS Task 或 ISR2** 中执行
- 区分两个时刻:**activation**(RTEEvent 指向的事件发生)与 **start**(它的 C 函数在已启动的 task/ISR2 内被调用)
- 若某 runnable 没有被任何 RTEEvent 以 `startOnEvent` 角色引用,RTE **永远不会**激活它(但映射到 BSW 可调度实体的 runnable 仍可由 BSW 调度器激活)
## 二、隐式访问:消费者看到"旧值"可能是设计
- **隐式读**生成 `Rte_IRead_<port>_<data_element>`;**隐式写**生成 `Rte_IWrite_<port>_<data_element>`;显式读是 `Rte_Read_<port>_<data_element>(DataType*)`
- 隐式通信下,**RTE 在 runnable 被调用前自动读数据、在 runnable 结束后写回**;runnable 自身不主动发起传输;**写操作在 runnable 结束时才算完成**
- 可观察到的顺序:先为隐式读做数据元素拷贝,**之后**才触发 runnable 调用事件;runnable 终止事件**先于**隐式写回
- 隐式 S/R 通信**不支持 RTE API 的 trace 事件**
**所以**:
```
Producer: x = 10; x = 20;
Consumer runnable 执行期间一直看到 x = 10
```
**可能完全符合 RTE 语义**,不是 cache/一致性 bug。
**分析要求**:区分 `Rte_Read_*` / `Rte_IRead_*` / `Rte_Write_*` / `Rte_IWrite_*`,而不是只追底层 RAM 地址。通信形式由配置固定,**不能事后在代码里"改掉"**。
## 三、`E_OS_ACCESS` 不一定是"对象坏了"
AUTOSAR OS 的**分区表示是 OS-Application**,带所有权与保护状态:
- 若某 OS 对象标识被传给系统服务(例如 `ActivateTask`),而**调用方在配置时没有被授予对该对象的访问权**(如 `OsTaskAccessingApplication`),服务**返回 `E_OS_ACCESS`**
- 若服务调用针对**属于另一个、且不处于可访问状态的 OS-Application** 的对象,同样返回 `E_OS_ACCESS`
- **信任(trusted)与非信任(non-trusted)应用一视同仁**:默认拒绝,只有配置显式授予才能跨应用访问
- 例外:检查类服务(`CheckObjectAccess` 等)不需要授权——可用于调用前预判
- 信任级别只影响少数服务(例如终止应用:受信任应用的任务/中断可终止任意 OS-Application)
- 访问错误也可能触发保护钩子
**所以排查顺序是**:
```
对象属于哪个 OS-Application?应用状态?trusted / non-trusted?
内存保护?当前调用上下文?
↓
而不是先判"task ID 写错了"
```
- 另外:**Category 1 ISR 并不由 OS 完整管理**,因此常规 OS 保护不能简单覆盖这种上下文
## 四、并发问题多半在 OS 配置,不在应用逻辑
大量互斥区处理是**生成**的(RTE 自动保护、OS 资源、BSW 临界区),而不是手写。出现并发异常时,先核对 OS 配置:**runnable 映射到哪个 Task、优先级、ISR 抢占关系**,再看应用代码。
## 决策树
```
拿到 AUTOSAR Classic 目标
├─ 某个 runnable 没有调用者
│ ├─ 找 Rte_* 包装与 RTEEvent 映射
│ ├─ 找它被映射到的 OS Task(ActivateTask/SetEvent/Alarm/ScheduleTable)
│ └─ 别标 dead code
├─ 变量值与预期不符
│ ├─ 区分显式访问(Rte_Read_/Rte_Write_)与隐式访问(Rte_IRead_/Rte_IWrite_)
│ ├─ 隐式访问在 runnable 边界做快照/写回 → "看到旧值"可能是语义
│ └─ 别先判 cache 一致性或内存损坏
├─ 服务调用返回 E_OS_ACCESS
│ ├─ 查对象所属 OS-Application 与其实例状态
│ ├─ 查当前调用上下文(哪个 task/ISR)与信任级别
│ └─ 别先判参数错误
├─ 进程/任务不运行
│ ├─ 查 runnable 到 Task 的映射与 Task 是否被激活
│ └─ 查初始化/模式相关事件
└─ 并发异常
└─ 先核对 OS 配置(Task 映射、优先级、抢占),再谈应用逻辑
```
## 工具与验证
- 执行图:ECU 配置描述(runnable → RTEEvent → OS Task 的映射)与生成的 RTE 胶水代码
- 访问语义:`Rte_Read_*` / `Rte_IRead_*` / `Rte_Write_*` / `Rte_IWrite_*` 的调用点与端口配置
- 保护:OS-Application 归属与访问权配置、状态检查服务、保护钩子
- 验证:能同时说清「runnable 由谁激活、在哪个 Task 里跑 + 数据是显式还是隐式访问 + 跨应用访问是否被授权」
## 该平台的坑(汇总)
- **把没有 caller 的 runnable 当死代码**:它由 RTEEvent 经 RTE 激活,映射在配置里
- **以为 RTE 会自己调度**:RTE 无独立调度能力,事件必须映射到 OS Task
- **混淆 activation 与 start 两个时刻**
- **把隐式访问的"旧值"当 cache/一致性 bug**:隐式访问在 runnable 边界做快照与写回
- **只追 RAM 地址不看 Rte_I* 系列**:无法区分显式/隐式语义
- **把 `E_OS_ACCESS` 当参数错误**:先查 OS-Application 归属与访问权配置
- **以为 trusted 应用可以随意跨应用访问**:默认拒绝,授权来自配置
- **忽略 Category 1 ISR 不受 OS 完整管理**:常规保护假设在这里不成立
- **在应用代码里找并发根因**:先核对 Task 映射、优先级与抢占配置