☰
UDS会话切换0x10服务详解:从报文格式到刷写链路实战
2026/9/27 1:09:46 网站建设 项目流程

做ECU测试这几年,我遇到过太多因为会话切换没搞明白导致的刷写失败、服务被拒。UDS诊断里,会话Session是比任何功能服务都靠前的一道门:门没开对,后面所有动作都白搭。这篇文章就用实际报文来拆解UDS诊断中最常被问到的会话切换,也就是0x10服务(DiagnosticSessionControl),从报文格式、状态机规则一直讲到刷写中的完整切换链路,适合刚接触诊断协议的同学,也适合已经在做台架测试但总被NRC卡住的朋友。

1. 先理解UDS会话:ECU并不会时刻开放全部权限

1.1 会话机制到底解决什么问题

UDS(Unified Diagnostic Services)是ISO 14229定义的一套汽车诊断协议,跑在CAN、CAN FD、DoIP或者LIN上,应用层通过SID(Service ID)区分功能。0x10这个SID负责的就是会话控制。

会话机制的本质,是给ECU内部划分了几个不同权限的运行模式。ECU在出厂、售后、产线、刷写、标定、防盗匹配这些不同场景下,开放给诊断仪的功能范围完全不同。如果一上电就把编程、安全访问、DTC写入这些高权限能力全部开放,那整车的网络安全风险会非常大。会话切换就是一把钥匙,把ECU从低权限模式切换到高权限模式。

常见的会话定义四个:

  • 0x01 默认会话:上电后通常停在这里,只有基础读操作,比如读版本、读DTC状态
  • 0x02 编程会话:允许使用0x34请求下载、0x36数据转移这类刷写服务
  • 0x03 扩展会话:允许标定、复杂例程控制、写入请求,也是进入编程会话前必经的中间态
  • 0x04 安全系统诊断会话:部分平台用于安全气囊、主动安全这类系统的特殊诊断

一个粗暴但好用的类比是门禁:默认会话就像大厅,扩展会话是办公区,编程会话是机房。没有刷卡(切会话)就硬闯机房,轻则被保安拦下(NRC否定响应),重则触发整车安全保护。

1.2 别被Web开发里的Session带跑偏

搜索UDS会话相关问题时,很容易看到一些Web领域的词条,比如“there is no session with id”“cookie和session的区别”。这里需要明确一点:UDS里的Session是ECU内部诊断状态机,和浏览器会话没有一点关系。UDS上下文里出现“session”字样,指的就是0x10服务控制的诊断会话状态。

容易混淆的还有0x29服务。0x29在ISO 14229里是Authentication(安全认证)服务,负责基于证书、挑战码的认证流程。0x29和会话切换相关,但执行时不能把它当成切会话的入口。切会话永远是0x10,0x29只是帮你在高权限会话里做身份确认。不少人以为“29服务”能切会话,实际是乌龙。

2. 会话切换的入口:0x10服务与应答逻辑

2.1 请求报文怎么组

0x10服务请求格式非常固定:

0x10 + Sub-function

Sub-function就是目标会话ID,常见值如下表格所示。

Sub-function会话名称典型用途
0x01defaultSession默认会话,上电初始态
0x02programmingSession编程会话,刷写固件
0x03extendedDiagnosticSession扩展诊断会话,标定/高级读写
0x04safetySystemDiagnosticSession安全系统诊断会话
0x40-0x7FOEM自定义厂家扩展会话,比如bootloader特殊态

这里有一个细节:Sub-function的bit7是suppressPosRspMsgIndicationBit,也就是抑制肯定响应位。比如你要切到扩展会话,但不想让ECU回肯定响应,可以发0x10 0x83而不是0x10 0x03。

请求1:10 03 // 切扩展会话,正常回正响应 请求2:10 83 // 切扩展会话,抑制正响应

抑制位生效后,ECU不会回50 03,但如果切换失败,否定响应7F 10 xx还是会回的。这个行为需要特别注意:很多上位机脚本只看有没有响应帧判断成功,结果把否定响应也当成成功,看着像是切过去了,实际状态没变。

2.2 肯定响应与两个关键定时器

0x10服务成功后,肯定响应格式是:

50 + Sub-function + P2_Server_max(2字节) + S3_Server_max(2字节)

举个例子,实际抓包经常看到:

TX: 10 03 RX: 50 03 00 32 13 88

展开解读:

  • 50是肯定响应SID,等于请求SID+0x40
  • 03表示当前已进入扩展会话
  • 00 32表示P2_Server_max,单位ms,换算后是50ms
  • 13 88表示S3_Server_max,单位ms,换算后是5000ms

P2_Server_max的含义是:非默认会话下,ECU处理新请求后,需要在50ms内给出首次响应;如果处理时间超过50ms,必须先回一帧7F xx 78(ResponsePending),让诊断仪知道请求还在处理,防止诊断仪超时误判。

S3_Server_max的含义是:在这个会话下,如果超过5000ms没有收到任何新的诊断请求,ECU会自动跳回默认会话。这就是诊断协议里保活的根源:切到扩展会话后,工具必须周期性发送诊断请求来维持会话状态,否则ECU就悄悄退出了。

P2和S3的具体值在不同ECU上不一样,但通常符合ISO 14229的默认推荐:非默认会话P2=50ms,S3=5000ms。有些OEM自定义值可能不同,要以车型规范为准。

2.3 否定响应:被拒了要知道为什么

切换失败时,ECU回的是:

7F + 10 + NRC

常用NRC整理如下:

NRC名称含义与常见场景
0x12subFunctionNotSupported子功能不支持,比如直接发10 02但ECU不支持
0x13incorrectMessageLengthOrInvalidFormat报文长度或格式错误,比如发了10 03 01多一个字节
0x22conditionsNotCorrect条件不满足,比如整车状态不允许编程
0x33securityAccessDenied安全访问被拒,通常对应编程会话要求先解锁
0x34authenticationRequired要求先走0x29认证,新一代安全架构常见
0x78requestCorrectlyReceivedResponsePending不是错误,是ECU还在处理,稍后会再补响应
0x7EsubFunctionNotSupportedInActiveSession当前会话不支持该子功能切换,常见于部分特殊会话

遇到7F 10 33,基本说明你试图切入的会话需要更高安全等级;遇到7F 10 22,则说明ECU认为当前整车条件不满足,比如车速不为零、挡位不在P挡、点火开关不在ON挡,都会导致条件不满足。

3. 会话状态机:谁可以切到谁是有规矩的

3.1 标准切换规则与工程实践

ISO 14229里会话切换不是一个任意矩阵,标准Annex A定义了会话状态图,工程实现上一般遵循这么几条不成文但很常见的规则。

当前会话目标会话普遍行为
默认会话0x01扩展会话0x03允许,不需要解锁
默认会话0x01编程会话0x02多数ECU拒绝,NRC 0x22或0x33
默认会话0x01安全系统诊断0x04需要特定条件,通常拒绝
扩展会话0x03默认会话0x01允许
扩展会话0x03编程会话0x02允许,但通常需要先通过0x27安全访问或0x29认证
扩展会话0x03扩展会话0x03多数ECU直接成功,相当于重置S3定时器
编程会话0x02默认会话0x01允许
编程会话0x02扩展会话0x03允许,部分ECU需要先回默认再切
编程会话0x02编程会话0x02多数成功,相当于重置定时器

关键点在于:默认会话直接切编程会话,在国产车和合资车的实际标定中大多走不通。如果你在工程规范里看到“programming session shall only be entered from extended session”,意思是编程会话只能从扩展会话进入,那就必须先10 03再10 02。

顺带一提,很多ECU进入编程会话后会短暂屏蔽部分常规诊断服务,甚至有些ECU在编程会话下会自动让出总线调度,避免刷写过程被干扰。测试时如果发现进入编程会话后,之前能用的服务突然回NRC 0x11(serviceNotSupported),不要惊讶,这是正常的权限收窄。

3.2 S3超时回退:ECU的“自动锁门”

S3定时器的存在让很多新手栽跟头。CANoe或PCAN里做了很久的标定,中间停下来喝口水,回来继续发请求发现响应全部变成NRC 0x11。原因很简单:扩展会话5秒超时已经回默认会话了,默认会话根本不支持标定服务。

这个“自动锁门”是ISO强制的安全设计,防止诊断仪异常掉线后ECU一直暴露在高权限状态。刷写过程中,一段数据转移完成后,如果上位机处理文件需要几秒钟,而ECU已经回默认,后续下载流程立刻断链,整个刷写包都要从头来过。

维护会话的办法有两种:

  • 周期性发送任意受支持的服务,比如10 03重发切扩展会话,或者22 F1 90读软件版本号之类的无副作用请求
  • 上位机内置S3心跳线程,保证请求间隔小于S3值,通常保守做法是间隔1000ms到2000ms发一次心跳

实测经验:不要卡着4500ms去发心跳,网络抖动、CAN总线繁忙都可能让你错过窗口。宁可每1000ms发一个轻量读服务。

3.3 条件不满足与会话切换的关联

前面提到的NRC 0x22,往往不是单纯“你权限不够”,而是外部条件没达标。比如:

  • 整车电源模式不在KL15 ON
  • 车速不满足安全条件
  • 挡位不在允许范围
  • 发动机转速不为零(刷写时不允许发动机运行)
  • 安全访问未完成(部分ECU把未解锁也归到0x22而不是0x33)

所以排查0x22时,不能只盯诊断层,还要看ECU输入状态。用CANoe里增加环境变量或者读取ECU的电源模式、挡位信号,能快速定位。

此外,部分ECU有“引脚拉低进入特殊模式”的机制。例如某些MCU的Bootloader里,编程会话可能还要求物理引脚状态配合。这时候单纯发0x10 02进不去是正常的,需要硬件搭接。这是厂家特定的行为,操作前一定先看Bootloader规范。

4. 完整实例:从默认会话一路切到编程会话

4.1 场景设定

假设我现在要给一块VCU刷写Bootloader,工具用的是CANoe + CANcaseXL,ECU地址按标准设置。刷写前置流程是:

默认会话 -> 扩展会话 -> 安全访问解锁 -> 编程会话 -> 传输数据

这个过程里,每一步的报文我都从日志里截出来,带着解释过一遍。

4.2 从默认会话切到扩展会话

第一步发送:

TX: 10 03

ECU响应:

RX: 50 03 00 32 13 88

说明:50 03表示进入扩展会话成功。00 32是P2_Server_max=50ms,13 88是S3_Server_max=5000ms。响应回来后,ECU已经把S3定时器启动,接下来5秒内必须维持请求。

这里我习惯在做完切换后立刻用一个22服务读版本号,一方面是确认会话确实生效,另一方面也能顺带保活。比如:

TX: 22 F1 90 RX: 62 F1 90 01 02 03

能正常读到版本号,说明当前确实在扩展会话下,22服务是被允许的。如果还在默认会话,22服务很多ECU是不可用的,会回7F 22 11。

4.3 安全访问:进编程会话前的必经之路

扩展会话不代表你能刷写。0x10 03只打开了扩展诊断的门,编程会话还需要安全访问解锁。标准流程是seed-key机制,用0x27服务。

日志如下:

TX: 27 01 // 请求seed(level 01) RX: 67 01 11 22 33 44 // 返回seed 0x11223344 TX: 27 02 55 66 77 88 // 发送通过算法计算出的key RX: 67 02 // 解锁成功

如果key算错了,ECU会回:

RX: 7F 27 35

NRC 0x35表示invalidKey。连续多次错误key还会触发延时锁定机制,锁定时长从几十毫秒到几秒不等,这是防止暴力破解seed-key的既定设计。

安全访问解锁和会话切换是两件事,但要注意顺序。多数ECU要求先在扩展会话下做安全访问,解锁成功后才允许切编程会话。如果你在默认会话直接发27服务,大概率被拒,因为默认会话根本不开放安全访问服务。

还有一点:安全访问解锁状态不跟随会话切换而永久保留。部分ECU设计成一旦退出到默认会话,安全解锁状态也随之清除,重新进入扩展后需要再次解锁。我测试中遇到不少这样的实现,所以刷写脚本里“10 03 -> 27 -> 10 02”的顺序必须严格串行,不能提前切默认会话。

4.4 从扩展会话切编程会话

安全访问解锁成功后,发送:

TX: 10 02

正常响应:

RX: 50 02 00 32 13 88

这说明已经进入编程会话,P2_Server_max=50ms,S3_Server_max=5000ms。此时0x34、0x36、0x37这类传输服务才被允许执行。

如果在未解锁时强行发送10 02,会遇到两种典型回报:

TX: 10 02 RX: 7F 10 33 // securityAccessDenied

或者某些ECU统一归为条件不满足:

RX: 7F 10 22 // conditionsNotCorrect

这两种都是“没有资格进入编程会话”的信号,区别只是NRC分类策略不同。遇到0x22时尤其先确认自己的安全访问状态。

进入编程会话后,刷写基础链路一般是这样:

10 02 -> 34 00 44 ... -> 36 01 data -> 36 02 data -> 37 -> 31 01 FF 00

34请求下载、36数据传输、37请求退出传输、31例程控制做刷写完成校验。整套动作里所有请求都必须卡在编程会话有效期内,一旦S3超时回到默认,后面所有SID都会被打回。

4.5 会话切换时序上的一个坑

有些ECU对于“扩展会话->安全访问->编程会话”这一串动作有时间限制。比如规范里会写:安全访问解锁成功后,必须在例如200ms内发起编程会话切换,否则解锁状态自动失效。

这个限制在一些老式Bootloader里非常常见,因为Bootloader本身不跑完整操作系统,内存里的解锁状态是靠RAM保持的,掉电或者看门狗复位都会清掉。如果是这种ECU,你的上位机在解锁后不能有任何多余的延时代码,必须在最短时间内把10 02发出去。

实测中我还遇到过一个ECU,编程会话切换成功后会自动执行一个内部复位,复位期间总线上会有几百ms的静默。上位机如果没有处理好这个静默窗口,会误以为ECU掉线了,然后主动断开连接。正确的做法是在切编程会话成功后,等待一段明确的静默时间,再发送第一个刷写请求。

5. 会话切换常见问题与排查经验

5.1 NRC速查与排查优先级

会话切换失败,先看NRC,再结合整车条件查,效率最高。我整理了一张实际排查顺序表:

现象优先排查方向
7F 10 12目标子功能根本不存在,查规范中的会话定义
7F 10 13请求长度或者格式错了,比如多发了字节
7F 10 22整车条件不满足,查电源模式、车速、挡位、安全状态
7F 10 33安全访问未解锁,先做27服务,再切会话
7F 10 34需要0x29认证流程,查证书和挑战码流程
7F 10 11目标服务在当前会话下不支持,注意是否已回默认

实际排查时,我经常先怀疑是不是S3超时偷偷退了会话,再怀疑条件不满足。因为日志里可能几十秒前还是扩展会话,但是中间没有任何请求,等再次发请求时ECU已经回默认。这种问题不是诊断逻辑错了,是保活没做。

5.2 案例:刷写流程中段突然NRC 0x11

一次项目里,刷写脚本每次跑到第4包数据就失败,日志如下:

TX: 10 02 RX: 50 02 00 32 13 88 TX: 27 01 ... TX: 34 ... RX: 74 ... TX: 36 01 ... RX: 76 ... TX: 36 02 ... RX: 7F 36 11

跑到36第二包就回NRC 0x11。最初怀疑是36报文格式问题,但检查发现36请求格式完全正确。后来把每条请求的时间戳拉出来看,才发现34和36之间隔了整整6.2秒。问题在于上位机在34请求后花了几秒钟计算内存分配,然后跳过35直接发36,中间没有保活请求,S3超时导致ECU退回了默认会话,36自然不被支持。

解决方式就是在传输过程中也要周期保活,或者在34请求之前临时把S3心跳间隔调小。这类“莫名其妙NRC 0x11”的问题,八成都是会话超时导致。

5.3 案例:编程会话每次进不了,复位一下就好

另一个客户报障说,ECU每次切编程会话都失败,NRC不是0x22就是0x33,但复位后第一次能成功,再次失败。查下来是两个原因叠加:

  • 上一次刷写异常退出,ECU还停留在编程会话,部分服务被锁存
  • 再次切编程会话时,安全访问解锁状态混乱,ECU判定为非法重复切换

解决办法是先发10 01回默认,等待一段明确时间,再重新执行“扩展->解锁->编程”的完整链路。有些ECU需要掉电重启才能彻底恢复正常,这时按规范流程走一遍电源循环即可。

这个案例给了一个通用经验:切会话失败时,先不要猜,把“当前会话确认”作为第一步。用10 01切回默认是成本最低的自愈手段。

5.4 0x29认证服务与0x10会话的关系

新一代安全架构下,0x29服务越来越常见。很多人在刷写或者在线配置时看到0x29,以为能替代0x10切会话,这是理解偏差。

0x29是Authentication服务,做的是身份认证,基于公钥基础设施和挑战码,认证成功后可以获取某种角色权限,比如“刷写允许”的权限。0x10是DiagnosticSessionControl,做的是会话状态切换。两者协同的典型流程是:

10 03 -> 29 02 ... -> 29 04 ... -> 10 02

也就是说,先切到扩展会话,然后走0x29认证流程,拿到“allowed to program”的授权,再去切编程会话。如果ECU要求0x34而你没走0x29,切换会话时可能被回0x34。

要特别记住:0x29认证结果有时和会话的S3超时绑定。认证成功后如果迟迟没切编程会话,超时后认证授权也会一并失效。

5.5 工具与链路层面的会话状态干扰

最后说一个工具层面的问题。CANoe、PCAN、智己诊断仪这类工具,有的会内置自动保活机制,有的不会。如果你在CANoe里开了“TP层自动心跳”功能,它可能在会话状态里自动来回发送请求,掩盖了协议栈真实状态,导致问题只在实车上出现。

另一个常见干扰是ECU的看门狗复位。刷写过程中ECU如果因为地址校验失败等原因复位,会话状态会重置到默认。此时从工具侧看,总线连接还在,但会话已经变了。遇到刷写中途“掉线”又“自动恢复”,一定要检查ECU有没有复位过,最简单的方法就是读ECU启动时间或者上电计数器。

收个尾

会话切换看起来就是几条报文的组合,但真正考验人的是对ECU状态机的理解。我自己做测试的体会是:凡是刷写、标定、配置类问题,先花一分钟确认当前会话状态和S3超时,再谈后续。把0x10的报文格式、NRC含义、切换规则、保活策略这几件事刻在脑子里,能少踩很多坑。

最后分享一个小技巧:在写测试脚本时,把会话切换封装成一个原子函数,内部自动完成“读当前状态->切目标会话->确认响应->记录时间戳”,任何一次切换都会留下日志。这样不仅方便排查,也方便在回归测试里快速定位到底是ECU问题还是脚本问题。千万别图省事直接在测试用例里裸发10 03、10 02,脚本越随意,问题越难查。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询