一文轻松理解AUTOSAR之Watchdog协议栈
2023-8-21 18:15:2 Author: 谈思实验室(查看原文) 阅读量:6 收藏

点击上方蓝字谈思实验室

获取更多汽车网络安全资讯

正文

Watchdog基本功能

众所周知,Watchdog,中文名为看门狗,就是为了实现在设备无人值守的情况下系统出现异常时能够自动完成系统复位操作保证整个功能的持续使用。

看门狗功能对于关键安全系统是必须的,对于非关键安全系统也是很有必要的。

为什么这么讲?原因是运行在硬件世界中的软件会受到各种外界因素的影响,如硬件自身老化损坏,外部电磁干扰等,这些都有可能导致程序在运行过程中发生不可预知的行为,而这些不可预知的行为如果没有看门狗,那么就完犊子了,要是你这个设备在人迹罕见的沙漠地带,毫无疑问就增加了很多不必要的维护成本。

对于汽车上使用的诸多零部件,鉴于汽车环境的恶劣,各类ECU中的软件均有可能遭受如外部电磁干扰,高温等环境因素的影响,从而导致程序“跑飞”或者“死机”现象,此时如果有看门狗的存在,便可以主动触发系统复位机制保证能够再次正常使用,而不是只能眼睁睁的看着被送到4S店进行维修,影响产品口碑或是增加不必要的售后维护成本。

基于看门狗的实现逻辑,一般意义上我们可以将看门狗分为硬件看门狗与软件看门狗。

顾名思义,硬件看门狗就是通过硬件自身的机制来实现看门狗功能,其本质也是通过定时器原理来实现,只不过此时软件的角色仅仅是使能定时器,定时器自身的变化与更新由硬件自身完成;软件看门狗则是整个定时器的使能与更新完全由软件来做,当然软件也是通过定时器完成,只不过是间接方式。

硬件看门狗

如上所述,硬件看门狗依赖自身定时器来完成看门狗功能,俗称“硬狗”。常见的硬件看门狗比如MCU内部自带的看门狗,PMIC中内嵌的看门狗以及外部的独立看门狗等。

至于选用何种的硬件看门狗,完全取决于自身系统设置需要,无法千篇一律。不过在使用硬件看门狗的时候需要特别考虑以下两点:

  • 该硬件看门狗的最大超时时间能否满足系统设计需求,如果该超时时间过小,就会导致整个系统的不稳定性,误触发看门狗;

  • 该硬件看门狗是否可以进行关闭,对于关键安全系统,一般都要求看门狗一旦打开将不允许被关闭;

  • 该硬件看门狗系统上电后默认处于开狗还是关狗状态,如果是默认开狗,那么对于软件而言,需考虑芯片上电后便要进行喂狗或者重置看门狗行为,同时设计一种在刷件或者调试软件前的物理关狗动作。

  • 该硬件看门狗是采用哪种方式进行喂狗,如通过GPIO,IIC或者SPI等通讯方式来喂狗,因为不同的通讯喂狗方式对芯片的硬件资源均有要求,尽可能采用相对简单可靠的通讯方式来喂狗即可,小T认为GPIO优于IIC,IIC优于SPI。

如下图1列举了市面上存在的不同通讯方式喂狗的硬件看门狗:

GPIO喂狗硬件看门狗:

IIC喂狗硬件看门狗:


  • SPI喂狗硬件看门狗:


图1 各类喂狗方式硬件看门狗

软件看门狗

软件看门狗如上所述,属于通过软件定时器的方式来实现看门狗功能,俗称“软狗”。软件看门狗的时间本质上也需要依赖硬件外设上的硬件定时器。

比如常见的我们会通过ostick的方式来进行记时功能,通过一个task运行软狗监控的定时器不断递减的主程序,其他task程序则是重置定时器,如果软件监控主程序某个task的定时器归零,那么此时可以便可以判断其他task并没有被正常的执行,此时便可以通过主动复位的方式来实现看门狗功能。

一般而言,运行软狗的主任务的优先级不应设置比被监控的任务优先级低,跟硬件看门狗搭配在一起使用,一般将软狗的主任务与硬件看门狗喂狗的主任务放入同一个任务,这样可以保证如下图2所示的这种层级关系:


图2 软狗与硬狗层级关系图

以上图作为一个实践案例,仅供大家参考,具体实现方式可以依照项目需求来定。图中Task A,B ,C 优先级均比Task D要低,如果在Task D中喂硬狗,那么有可能会出现Task D运行正常,其他任务挂死而系统始终运行正常的状态,这样就起不到硬件看门狗的保护功能。

因此为了避免喂硬狗的任务优先级过高,导致其他低优先级任务挂死而无法察觉,因此有必要添加软狗来实现对低优先级任务的保护。

通过Task A,B,C针对各自的计数器来进行重置,该重置的值设定需要结合各自task的最大运行时间及周期来决定,Task D则是在运行软狗监控主体来实现各个Task计数器的递减动作,如果在重置的值时间内所有task计数器都不等于0,也就意味着其他低优先级任务运行正常,此时便可以正常通过GPIO或IIC或SPI进行喂硬狗,否则有任意计数器为0,那么就需要停止喂狗或者主动触发复位行为。

AUTOSAR Watchdog协议栈介绍

其实,针对上述软狗与硬狗相结合使用的应用场景,AUTOSAR架构也已经将其标准化考虑在整个Watchdog协议栈中来实现,因此在实际项目的开发过程中,大家可以通过以下的学习来进一步了解基于AUTOSAR的Watchdog协议栈工作原理与使用方法。

如下图3展示了AUTOSAR架构针对Watdog协议栈的软件层级拓扑关系图:


图3 AUTOSAR架构下的Watchdog协议栈

如上图3所示,在AUTOSAR架构下,Watchdog协议栈可以分为如下三个软件模块:

  • Watchdog Driver:用于实现针对硬件看门狗的寄存器操作与控制,可以分为MCU内部看门狗(Internal Watchdog)与外部看门狗(External Watchdog),该外部看门狗可以通过GPIO或者IIC或者SPI来实现喂狗;

  • Watchdog Interface:Watchdog If作为整个Watchdog Stack的一部分,其主要功能则是为了实现上层Watchdog Manager与底层Watchdog Driver的连接,当然其连接的底层Watchdog Driver可以存在多个,这在多核设计中较为常见。

  • Watchdog Manager:Watchdog Manger模块作为整个看门狗协议栈中的服务层,Watchdog Manager的主体功能就是为了负责整个程序执行的正确性,并触发相应的硬件看门狗的喂狗动作,扮演了整个监控的核心角色。

通过上述AUTOSAR架构下的三个模块便可以实现整个AUTOSAR Watchdog Stack的功能,接下来小T将针对这三个模块进行详细讲解,保证我们都能够对这三个模块有个较为清晰的认识与理解,更好的运用到实战中。

理解Watchdog Driver模块

该模块提供了初始化硬件看门狗,改变操作模式,设置触发看门狗喂狗方式等功能。同时,可以按照该看门狗是否位于芯片内部,可以将位于芯片内部的看门狗称为内部看门狗,位于芯片外部的看门狗称为外部看门狗。

不论是内部看门狗还是外部看门狗,对于Watchdog Driver而言其使用的看门狗驱动的API应始终保持一致。只不过内部看门狗而言,其驱动属于MCAL层,而对于外部看门狗则属于ECU硬件抽象层,该外部看门狗驱动需调用MCAL中其他驱动来实现喂狗动作,如GPIO,IIC或者SPI等驱动。

内部看门狗

内部看门狗如前所述为芯片内部的硬件看门狗,该内部看门狗驱动一般由芯片厂商提供,不过值得注意的是在使用芯片内部看门狗前需确认该看门狗触发的复位动作是否是冷复位,是否存在复位不完全等场景,否则可能就达不到安全监控的目的。

内部看门狗由于其涉及到芯片内部本身,如果芯片本身硬件存在问题,可能会导致内部看门狗自身失效,从而出现自身难保的困境,所以从某种程度来讲,对于关键安全系统,仅使用内部看门狗显得并不安全,此时还是需要依赖于外部看门狗来保证其功能安全。

外部看门狗

外部看门狗是位于被保护芯片外部的看门狗,该看门狗可以是独立硬件看门狗,即该类看门狗仅提供看门狗功能,但是一般都是QM等级,还有一类便是集成在PMIC内部的看门狗,该类看门狗一般都可以达到ASIL B或者ASIL D功能安全等级要求。

外部看门狗对于关键安全系统而言,一般都是必需的,从某种意义上来讲,内部看门狗其实可有可无,外部看门狗才至关重要。

看门狗控制模式

在AUTOSAR架构中,针对Watchdog Driver而言,定义了看门狗控制模式存在如下三种模式:

  • Off Mode:表示看门狗关闭状态,对于关键安全系统,一般不能将其切换至Off状态,即一旦打开,将不能被关闭;

  • Slow Mode:表示看门狗的一个长时间喂狗窗口,该模式一般用于系统启动初始化过程中;

  • Fast Mode:表示看门狗的正常喂狗窗口喂狗模式,该模式运用在系统正常运行的过程中。

看门狗喂狗时序

如下图4所示为Watchdog初始化,触发看门狗喂狗以及改变看门狗模式的的三类函数调用场景。

  • Watchdog初始化:通过EcuM模块调用函数Wdg_Init来完成Watchdog的初始化配置;

  • 触发看门狗喂狗:通过WdgM模块调用WdgIf模块提供的函数WdgIf_SetTriggerCondition来触发底层驱动进行喂狗动作;

  • 改变看门狗模式:通过WdgM模块调用WdgIf模块提供的函数WdgIf_SetMode来实现看门狗模式的改变。


图4 看门狗初始化,触发看门狗以及设置看门狗模式时序图

如下图5为Wathdog 驱动与底层看门狗硬件交互的时序图,从下图可以看出WdgIf_SetTriggerCondition中会继续调用Wdg驱动中函数Wdg_SetTriggerCondition来实现喂狗动作。


图5 看门狗驱动与底层硬件看门狗交互时序关系图

常见函数API与配置参数

为了便于大家能够快速的对这个模块的重点函数调用,有个较为清楚的了解,小T通过表格的方式进行了如下总结:


图6 看门狗驱动模块常用函数接口说明


图7 看门狗驱动模块常用配置参数说明

理解Watchdog If模块

Watchdog If模块功能描述

Watchdog If模块全称为Watchdog Interface接口,该接口作为底层Watchdog Driver的抽象,是为了实现底层硬件与软件之间的解耦。

该模块的基本功能仅仅作为底层驱动的抽象层来实现底层看门狗驱动与上层看门狗管理模块的交互,底层看门狗驱动的特性,如窗口控制,时间周期等设置都不能通过Watchdog If模块来完成。

如果超过一个看门狗驱动被上层Watchdog Manager进行管理,那么DeviceIndex将需要被检查,如果出现错误,需要及时上报。

常见函数API与配置参数

为了便于大家能够快速的对这个模块的重点函数调用,有个较为清楚的了解,小T通过表格的方式进行了如下总结:


图8 Watchdog If模块常用函数说明


图8 Watchdog If模块常用配置参数说明

理解Watchdog Manager模块

Watchdog Manager模块工作原理

Watchdog Manager可以理解为一种应用层软狗机制,该软件机制监控的对象被称为“监控实体”。其监控方式可以分为如下三种:

  • Alive Supervision: 用于监控周期性任务是否周期性运行;

  • Deadline Supervision:用于监控事件型任务的运行时间是否超时;

  • logical supervision: 用于监控任务的执行时序是否正确;

    通过在每个监控实体中打上对应的Checkpoint,每一个监控实体可以有一个或者多个Checkpoint,在一个监控实体内部的Checkpoint及其转换关系称为内图,如果是来自不同监控实体的Checkpoint及其转换关系则为外图

上述这三种监控机制用于监控每一个实体,每一个被监控的实体可能会有其中一个或者多个甚至三个机制全部使能,这个取决于具体的需求。基于上述三种监控机制的监控结果,每一个监控实体便可以计算得出,被称为Local Status

当每一个监控实体的状态得到确定,那么整个MCU的监控结果便可以最终确定,这个最终确定的状态被称为Global Status

Watchdog Manager具体工作流程:

S1:Watchdog Manager模块负责通过Watchdog If以及Watchdog Driver来实现设置Watchdog Driver喂狗的触发条件,该触发条件就是通过Watchdog Manager的函数接口来重置Counter值;

S2:若Counter不为0,那么Watchdog Driver就会进行一次喂狗,同时将Counter值减一;

S3:若Counter值没有被Watchdog Manager进行及时重置,那么就会减少至0,那么Watchdog Driver就会停止喂狗,从而看门狗就会触发系统复位,否则继续执行S2;

值得注意的是如果触发条件不满足,没法进行正常喂狗,那么存在两种方式进行系统喂狗:

  • 等待看门狗超时复位:停止喂狗,等待看门狗超时复位;

  • 主动立即触发系统复位:当Watchdog Manager发生错误时可以主动触发系统复位;

上述两种复位方式都是可以共存的,具体执行哪个复位方式都可以按需执行。

在使用Watchdog Manager时,Watchdog Driver初始化不能由Watchdog Manager来完成,而应该由EcuM模块来完成,而Watchdog Manager初始化应该在OS开启之后执行。

Alive Supervision

如上所述,针对周期性任务的监控实体,在给定的时间范围内对应监控实体执行的次数是确定的,通过这个监控机制可以用于检测某些周期性任务运行太过频繁或者过少。

在使用AliveSupervision过程中,有以下几点需要注意:

  • 对于一个监控实体,采用Alive监控机制,就不要超过1个checkpoit,当前仅支持一个Checkpoint。

  • 根据如下四个参数进行调整使用来决定Alive Supervision如何进行监控,如何有效。


Deadline Supervision

如上所述,针对非周期性任务的监控实体,其监控实体对应的两个checkpoint之间的时间应该在一定范围内,从而可以通过判断两个checkpoint之间的时间是否位于设定的最小值与最大值之间。

在使用Deadline Supervision过程中,有以下几点需要注意:

  • 该监控机制只能监控到延迟,无法检测到超时,如End Checkpoint未执行;

  • 该监控机制不支持嵌套,如start 1,start2, end2, end1;

  • 如下图为Deadline Supervision 逻辑图,通过计算两个Checkpoint的时间差值来得到是否满足设定的要求。


Logic Supervision

如前所述,logic supervision则用于来实现程序流运行时序是否正确,这对于满足功能安全的ECU而言至关重要,通过将实际运行过程中的checkpoint之间的切换关系是否满足设定的checkpoint切换关系来进行判断,如果不在设定的checkpoint关系之内,那么就会上报错误,如果均在checkpoint之内,那么则一切运行正常。

如下图为Logic Supervision的拓扑结构,通过识别两两checkpoint之间的切换关系是否属于静态配置的切换关系Group内,来决定是否执行的是正常的序列行为。


如下图9所示,为整个Watchdog Manager模块的运行机理:


图9 Watchdog manager模块作用机理

基于上述图9,我们可以得出如下几个重要的结论:

  • 采用Alive Supervision的监控实体,其判断结果在WdgM_Mainfunction中得出;

  • 采用Deadline Supervision或者Logical Supervision的监控实体,其判断结果则在函数WdgM_CheckpointReached中得出;

  • 每个监控实体均存在一个Local Status,该Local Status的最终结果将决定最终ECU的Global Status,因此有必要搞清楚WdgM的Local Status如何发生变化,如下图10为Local Status状态机:


图10 Watchdog manager中Local Status变化状态机/center>

通过上述图10 ,我们可以得出如下几个基本结论:
  • 如图中执行序列10,在执行完WdgM_Init函数后,便会将每个监控实体的Local Status将会变成WDGM_LOCAL_STATUS_OK

  • 如图中执行序列11, 若在执行WdgM_Init中,存在没有被WdgMInitialMode 参考的监控实体,那么这些监控实体的值将会被默认设置为WDGM_LOCAL_STATUS_DEACTIVATED;同时被WdgMInitialMode 参考的监控实体的WdgMInitialMode并没有设置成WDGM_LOCAL_STATUS_OK,那么也会被设置成WDGM_LOCAL_STATUS_DEACTIVATED

  • 如果所有监控实体的监控结果都OK且监控实体的Local Status都是WDGM_LOCAL_STATUS_OK,那么就会执行序列1

  • 如果某监控实体状态为WDGM_LOCAL_STATUS_OK,但是其对应的Alive Supervision或者Deadline Supervision或者Logical supervision的结果为incorrect,那么状态机就会执行序列2

  • 由于监控实体的Alive Supervision的结果允许存在错误门限值,因此若某监控实体所有的Deadline Supervision或者Logical supervision的结果均为correct,但是存在某次Alive Supervision的结果错误但并没有超出设定的错误门限值时,那么就会执行序列3进入到WDGM_LOCAL_STATUS_FAILED。

  • 若当前监控实体(SE)的状态处于WDGM_LOCAL_STATUS_FAILED状态,除了Deadline Supervision或者Logical supervision的结果均为correct以外,但至少存在一次Alive Counter错误却并未超过错误门限值,那么就会执行序列4

  • 若SE Local Status == WDGM_LOCAL_STATUS_FAILED状态,该SE的Alive Supervision均正确,且当前失败的次数大于1,同时对应的Deadline Supervision或者Logical supervision的结果均为correct,那么就会继续保持在WDGM_LOCAL_STATUS_FAILED状态,不过会将错误次数减1,如序列4

  • 若SE Local Status == WDGM_LOCAL_STATUS_FAILED状态,该SE的Alive Supervision均正确,且当前失败的次数等于1,同时对应的Deadline Supervision或者Logical supervision的结果均为correct,那么就会在 WdgM_MainFunction中将状态切换至WDGM_LOCAL_STATUS_OK状态,同时将错误次数减小至0,如序列5

  • 若SE Local Status == WDGM_LOCAL_STATUS_FAILED状态,该SE的Alive Supervision为incorrect,且当前失败的次数大于其阈值,或者至少存在一个对应的Deadline Supervision或者Logical supervision的结果为incorrect,那么就会在 WdgM_MainFunction中将状态切换至WDGM_LOCAL_STATUS_EXPIRED状态,如序列6

  • 若SE Local Status == WDGM_LOCAL_STATUS_OK状态,同时执行了WdgM_SetMode切换状态至OFF状态,那么就会改变状态机状态为WDGM_LOCAL_STATUS_DEACTIVATED状态,如序列7

  • 若SE Local Status == WDGM_LOCAL_STATUS_FAILED状态,同时执行了WdgM_SetMode切换状态至抑制状态,那么就会改变状态机状态为WDGM_LOCAL_STATUS_DEACTIVATED状态,如序列8

  • 若SE Local Status == WDGM_LOCAL_STATUS_DEACTIVATED状态,WdgM_CheckpointReached以及WdgM_MainFunction函数将不会启动任何监控作用,如序列8

  • 若SE Local Status == WDGM_LOCAL_STATUS_DEACTIVATED状态,同时执行了WdgM_SetMode切换状态至激活状态,那么就会改变状态机状态为WDGM_LOCAL_STATUS_OK状态,如序列9

  • 在从其他状态切换至WDGM_LOCAL_STATUS_EXPIRED状态时,Watchdog Manager提供一定的时间保留机制能够允许你做一些特别的操作,如设置看门狗模式或者写入NVM数据,复位原因等。

讲完了上述监控实体的Local Status 状态机变换条件,接下来我们来进一步了解下监控实体的Global Status状态机,该状态机如下图11所示:


图10 Watchdog manager中Global Status变化状态机

如上图10所示,对于整个受监控的软件,Watchdog Manager仅会存在唯一的一个Global Status。该状态机的变化具体规则如下:

  • 如果执行了WdgM_Init函数,那么Global Status == WDGM_GLOBAL_STATUS_OK,如序列13;

  • 如果Global Status == WDGM_GLOBAL_STATUS_OK阶段,执行了函数WdgM_DeInit,那么就会导致状态机切换:Global Status == WDGM_GLOBAL_STATUS_ DEACTIVATED,如序列14;

  • 若Global Status == WDGM_GLOBAL_STATUS_OK,且所有SE的Local Status == WDGM_LOCAL_STATUS_OK或者WDGM_LOCAL_STATUS_DEACTIVATED,那么Global Status将保持不变,如序列1;

  • 若Global Status == WDGM_GLOBAL_STATUS_OK,至少存在一个SE的Local Status ==  WDGM_LOCAL_STATUS_FAILED,且没有SE的结果==WDGM_LOCAL_STATUS_EXPIRED,那么Global Status将会切换至WDGM_GLOBAL_STATUS_FAILED状态,如序列2;

  • 若Global Status == WDGM_GLOBAL_STATUS_OK,至少存在一个SE的Local Status ==  WDGM_LOCAL_STATUS_EXPIRED且WdgMExpiredSupervisionCycleTol设置大于0,那么Global Status将会切换至WDGM_GLOBAL_STATUS_EXPIRED状态,如序列3;

  • 若Global Status == WDGM_GLOBAL_STATUS_OK,至少存在一个SE的Local Status ==  WDGM_LOCAL_STATUS_EXPIRED且WdgMExpiredSupervisionCycleTol设置等于0,那么Global Status将会切换至WDGM_GLOBAL_STATUS_STOPPED状态,如序列4;

  • 若Global Status == WDGM_GLOBAL_STATUS_FAILED,至少存在一个SE的Local Status ==  WDGM_LOCAL_STATUS_FAILED且不存在等于WDGM_LOCAL_STATUS_EXPIRED的SE时,Global Status状态将保持不变,如序列5;

  • 若Global Status == WDGM_GLOBAL_STATUS_FAILED,且所有SE的== WDGM_LOCAL_STATUS_OK或者WDGM_LOCAL_STATUS_DEACTIVATED,那么Global Status将切换成WDGM_GLOBAL_STATUS_OK,如序列6;

  • 若Global Status == WDGM_GLOBAL_STATUS_FAILED,至少存在一个SE的Local Status ==  WDGM_LOCAL_STATUS_EXPIRED且WdgMExpiredSupervisionCycleTol设置大于0,那么Global Status将切换成WDGM_GLOBAL_STATUS_EXPIRED,如序列7;

  • 若Global Status == WDGM_GLOBAL_STATUS_FAILED,至少存在一个SE的Local Status ==  WDGM_LOCAL_STATUS_EXPIRED且WdgMExpiredSupervisionCycleTol设置等于0,那么Global Status将切换成WDGM_GLOBAL_STATUS_STOPPED,如序列8;

  • 若Global Status == WDGM_LOCAL_STATUS_EXPIRED,且超时Counter计数小于WdgMExpiredSupervisionCycleTol设定的值,那么其状态将保持不变,如序列9;

  • 若Global Status == WDGM_LOCAL_STATUS_EXPIRED,且至少存在一个SE的计数大于WdgMExpiredSupervisionCycleTol,其状态将切换成 WDGM_GLOBAL_STATUS_STOPPED,在这种状态下,看门狗驱动将停止喂狗,等待看门狗超时复位,如序列10;

  • 若Global Status == WDGM_GLOBAL_STATUS_STOPPED,其状态将会一直保持不变,如序列11;

  • 若执行调用函数 WdgIf_SetMode失败,那么也会导致Global Status切换成WDGM_GLOBAL_STATUS_STOPPED状态,如序列12。

常见函数API与配置参数

为了便于大家能够快速的对这个模块的重点函数调用,有个较为清楚的了解,小T通过表格的方式进行了如下总结:


Watchdog与功能安全关系

在ISO26262中,程序流监控是其中最为重要的一项,通过程序流监控可以发现软件运行过程中可能违法设计意图的错误,从而采取相应的措施,确保行车安全。

在AUTOSAR软件架构中,程序流的监控功能实现主要由Watchdog 协议栈来实现,自上而下包括WdgM模块,WdgIf模块以及Wdg驱动模块,对于应用层而言,这三个模块通过RTE给到应用层提供接口服务,由此来实现底层监控应用层软件的目的。

Watchdog使用实践心得

  • 通过EcuM模块来完成看门狗初始化之后,刚开始设置的看门狗Counter初始值尽可能能够Cover住Watchdog Driver初始化至Watchdog Manager初始化的时间,否则容易造成狗超时。

  • 在OS shutdown之前Watchdog Manager去初始化,在去初始化过程中需要设置成较大的Timeout值,以确保能够覆盖住Watchdog Manager去初始化至系统power down或者再次reset的过程。

  • 如果ECU支持休眠模式,如果在ECU休眠情况下看门狗仍保持在活跃状态,那么就需要在EcuM模块中来完成看门狗的喂狗操作。

  • 在系统初始化以及休眠两个阶段应重点考虑看门狗是否会存在超时的可能,如果底层硬件都无法来得及喂狗,将会对系统造成重大影响。

码上报名

AutoSec 2023 第七届中国汽车网络安全周暨第四届智能汽车数据安全展,9月13-15日,上海


文章来源: http://mp.weixin.qq.com/s?__biz=MzIzOTc2OTAxMg==&mid=2247525295&idx=1&sn=792e0caca7a70b8e5981ea9e41bac375&chksm=e9272774de50ae6282c104f1237076273793cf40fc578d3a91824c857d0eac33d1b14bab37a0&scene=0&xtrack=1#rd
如有侵权请联系:admin#unsafe.sh