19-03 Adaptive AUTOSAR 平台接口使用指南

1 本文的介绍

1.1 内容

虽然FC的SWS 是ARA接口规范,但有些接口需要如何使用的“指南”。这份指南确实跟规范相关,但是有些是间接的,并且在每个SWS中都包含这些信息,因此读者很难理解其用法。另一个重要的角度是这些指南是AA 遵守的需求,但是FC的SWS是FC的需求规范。因此,在SWS中包含这些内容不太合适,这就是这本文档的目的。

如上所述背景,这份文档的主要内容是应用程序遵守的指南。不是所有的FC在这份文档中有内。当它认为有效时,它们将被添加。

内容是按照相关的话题组织的,但是一般情况下,按照FC组合一起,每个都有独立的章节。并且,请注意这些内容提供在单独的AUTOSAR AP 文档中。如果是这种情况,这种文档会被列出来或引用这份指南。

1.2 预读

这份文档是AP SWS的补充文档。因此,这份文档里的话题相关的SWS应该同步阅读。并且,应该阅读的第一份文档是Explanations of Adaptive Platform Design, AUTOSAR_EXP_PlatformDesign.pdf.,这份文档介绍了AP的架构

1.3 和其他AUTOSAR规范的关系

参考内容和预读

2. 核心类型

2.1 错误处理

错误处理对任何软件开发都是重要的话题。对于安全关键软件,它更重要,因为软件生命要依靠它。但是,目前的标准对安全关键软件的开发加了很多的限制,比如创建工具链,特别是关于C++异常。对ASIL应用程序,使用C++异常通常是不可能的因为缺乏对asil认证的c++编译器的异常支持。

Adaptive平台介绍了一个概念使没有C++异常的错误处理成为可能并定义了大量的c++数据类型来辅助这个概念。

从应用程序编码者的观点来看,核心类型实现这个概念的是 ara::core::ErrorCode和ara::core::Result.

2.1.1 ErrorCode

ara::core::ErrorCode的实例表示软件内的一个特定的错误条件。和std::error_code类似,但是在很多方面都不相同。

ErrorCode一直包含一个枚举值(类型擦除为整型)和一个错误域的引用。这个枚举值描述了错误的特定类型。错误域引用定义了错误应用的上下文。其他可选的成员一个是用户定义的消息字符串,一个是厂商定义的补充错误描述值。

2.1.2 Result

类ara::core::Result遵守来自C++建议 p0786中“ValueOrError”的概念。它包含一个value或一个error。由于模板特性,value和error可以是任何类型。但是,错误类型默认为ara::core::ErrorCode,而且希望整个Adaptive平台都能保持这个分配。

因为ErrorType默认为ara::core::ErrorCode,ara::core::Result的大部分声明仅需要给一个ValueType,比如对Result类型ara::core::Result<int>包含一个int变量或一个ErrorCode.

ARA接口使用ara::core::Result作为可恢复错误函数的返回类型。这个类型或者用来从对象中生成C++异常,或通过未使用异常的观察者方法中提取错误信息。

这部分指导你在应用程序代码中如何处理从ARA接口中返回Result对象。并且指导你如何在自己的Adaptive应用程序中创建新的Result对象。

2.1.2.1 Result的创建

使用嵌入值创建Result,有构造函数允许从ValueType隐式转换。这样用value来定义Result非常直接。

Result<int> res1(42);

Result<int> res2 = 42;

从声明返回Result的函数中返回一个value也是同样的直接。

Result<int> myfunction()

{

return 42;

}

把error放进Result中需要调用显示构造函数,比如:

ErrorCode ec = MyEnum::some_error;

Result<int> res2(ec);

另外,在静态成员函数中构造Result对象也是可能的。比如:

Result<int> res1 = Result<int>::FromValue(42);

Result<int> res2 = Result<int>::FromError(ec);

当Value Type或ErrorType Copy 代价非常昂贵的时候,这些形式是非常有益的。比如,返回的Reslut包换一个BigClass的实例。这个BigClass有两个构造参数"a1"和"a2"构建。像这样:

return Result<BigClass>::FromValue(a1, a2);

对于ErrorType,也允许ErrorCode实例的隐式构建,包含一个自定义错误消息和/或一个支持数据值。

return Result<BigClass>::FromError(

MyEnum::some_error, // ErrorCode enum value

"this operation did not work", // custom error message

0x12345678 // support data value

);

这种形式构建,只需要 执行一次构造函数。不像普通的构造函数调用,至少要执行两次构造操作,因为预先创建的值必须copy或move到Result实例中。

2.1.2.2 提取value和error

当试图从Result中提取value和error的时候,首先要考虑的是value或error是否真实可用。通常情况下,这是未知的,所以必须小心处理者两种情况。

当没有使用异常工作的时候, 要先查询Result对象是否包含value或error.

Result<int> some_function() { … }

Result<int> res = some_function();

if (res.HasValue()) {

int theValue = res.Value();

} else {

ErrorCode const& ec = res.Error();

}

这段代码在没有异常的环境中也可以完全工作,包括编译器完全不支持异常操作。

当处理异常工作流是,查询代码看起来更像普通的异常代码:

Result<int> some_function() { … }

int theValue = some_function().ValueOrThrow();

由some_function()返回的Result对象通过调用它的ValueOrThrow()成员函数快速归到它的ValueType(int)。事实上,如果Result确实包含一个ErrorCode,会立刻抛出一个对应到嵌入的ErrorCode对象的异常类型。自然,try...catch快应该添加到代码中一个合适的位置。

2.1.2.3 高级话题

提取嵌入的value或error两个借本的方法是Result::Value()和Result::Error()。但是,在调用任何这些函数时,必须确定Result对象确实包含调用这些函数之一所隐含的内容。在前面的部分,首先调用Result::HasValue(), Value()或Error()的调用依赖这个调用的输出。

另外一个访问嵌入value更方便的方式,之前的部分已经提过,通过调用Result::ValueOrThrow, 不需要if语句,整个调用只需要单行语句(不包含try...catch块,这个块可能在其他地方存在)。

其他方便的方法,比如Result::ValueOr提取value, 如果不存在就取默认值。比如:

int res = some_function().ValueOr(42);

Result :: ValueOr的一般化称为Result :: Resolve,它不使用默认值作为参数,而是一个Callable,它可按需创建默认值:

int res = some_function().Resolve([](ErrorCode const& ec){ return 42; });

对这种特殊的例子,使用Result::Resolve而不是Result::ValueOr没有意义。但是当常见默认值代价很昂贵的时候,可能是有意的。通过使用Result::Resolve,只有当确实需要的时候才会创建默认值。

另外一个方便的方法是Result::Bind,允许将包含的value转成另外一个value,甚至是另外一个类型,比如:

Result<String> res = some_function().Bind([](int v){ return v + 1; }).Bind([](int v){ return std::to_string(v); }).Bind([](String const& s) { return "'" + s + "'"); });

第一次调用Result::Bind()获取包含在Result对象中的value,加1之后,放入一个新的Result对象中并返回。

第二次调用Result::Bind()获取包含在Result对象中的value,将它转换成String,返回新的带有此字符串的Result<String>。

最后一次调用Result::Bind()获取包含在新的Result对象中的String对象,加上引号,放入其中并返回新的Result对象。

如果Result没有包含value, 那么这些可调用项都没有,Result对象仅进行类型转换,但保留原始的ErrorCode。

传递给Result :: Bind的Callables必须采用合适的类型作为参数,并且可以直接返回ValueType(如之前所说,或者和前面ValueType相同,或者一个新的,不同的ValueType),或Result<ValueType>。

3 执行管理

3.1 执行状态

执行状态描述了任何进程的内部生命周期。每个进程都需要给执行管理报告执行状态的变化,使用ExecutionClient::ReportExecutionState()接口。

一旦进程启动,当报告了KRunning状态,执行管理就认为进程初始化完成(见[SWS_EM_01053])。请注意Service Discovery会引入不确定性的延迟,因此建议在报告kRunning状态后进行;因此进程有可能在报告KRunning状态时初始化还没有完成。

执行管理通过向进程发送SIGTERM信号来启动进程终止。一旦收到SIGTERM,进程通过向执行管理报告kTerminating状态确认状态变化请求(见SWS_EM_01070)。

如果是自终止进程,进程会通过想执行管理报告kTerminating状态来启动自终止(见[SWS_EM_01071)。

报告kTerminating之后,进程会保存持久数据并释放所有内部使用的资源。进程通过简单的推出表明Terminating状态的完成(伴随合适的退出码)。执行管理不需要进程本身明确的进程终止的通知。

3.2 确定性执行

执行管理支持完全确定的进程多线程执行,因此处理给定的输入数据会在限定的时间内产生一直的输出,比如行为是可重现的。

在AUTOSAR Adaptive平台中,要求这种确定性的用例包括在高安全目标系统的软件Lockstep框架中的冗余执行和重用已验证的软件。更多的细节可以见Specification of Execution Management, AUTOSAR_SWS_StateManagement.pdf,“Deterministic Execution”部分。

可以完全确定地执行的进程必须以某种方式设计,实施和集成,使其独立于其他功能和计算,零星无关事件,竞争条件,偏差随机数等导致的处理器负载。

不确定行为可能有不同的原因造成,比如,计算资源不足或数据的不协调访问,很可能是由多个处理器内核上运行的多个线程造成的。线程访问数据的顺序也会影响结果,是结果不确定。

完全确定的执行包括:

*时间确定。计算的输出一直在给定的最后期限前产生。进程的资源需求需要以标准的方式描述,所以集成者能给进程分配足够的资源。(见Specification of Execution Management, AUTOSAR_SWS_StateManagement.pdf,“Real-Time Resources”部分)。

*数据确定。给定相同的输入和内部状态,计算也一直会产生相同的输出。这个部分剩下的部分将会描述如何达到数据确定。

执行管理提供DeterministicClient库功能来支持确定执行。

* 通过等待点API控制流程内部周期WaitForNextActivation()([SWS_EM_01301])。当API返回时,进程应执行一个循环,然后再次调用API以等待下一次激活。这个API的返回值控制进程的内部生命周期(比如:初始化,运行,终止),必须对其进行相应的准备。([SWS_EM_01302], [SWS_EM_01303] and [SWS_EM_01304]).

* 阻塞确定性工作程序池API RunWorkerPool()([SWS_EM_01305]),用于执行一组容器元素([SWS_EM_01306]),这些容器元素由同一工作程序运行对象(即应用程序功能)并行或顺序处理。

* APIs GetActivationTime() ([SWS_EM_01310]) 和 GetNextActivationTime() ([SWS_EM_01311]) 提供激活时间戳。这个时间戳不会改变指导进程达到下一个等待点。

* API GetRandom()提供随机数([SWS_EM_01308])。如果从工作程序池中使用,则将随机数分配给特定的容器元素,以允许确定性的冗余执行。

为了保证确定行为,确定性用户进程只可使用只有所有可用API的“确定性”子集,包括工作程序运行对象:

* 进程不允许通过自己使用普通POSIX进程创建线程或直接访问任何其他POSIX APIs,以规避包含不确定行为的风险。

* 进程只允许使用所有可用的ara::com机制的“确定性子集”。稍后将提供此类API和机制的详细列表。

* 只有下面的ara::exec接口被使用:DeterministicClient和ExecutionClient。

* 用户进程不允许访问其他ARA接口。

如果使用工作程序池API RunWorkerPool(),处理容器元素的工作程序运行对象,比如计算工作,需要满足某些实现规则来确保数据确定性:

* 运行对象在它运行的时候不允许交换任何信息。比如,它不会访问可运行对象的其他实例可以更改的数据,以避免出现竞争情况。

原理:运行对象可以物理的并行运行或以任何顺序有序运行。不能保证单个工作程序的时间。操作系统单个调度线程。相同数据的同时影响会导致不确定的结果。

* 除了通过从RunWorkerPool()返回对于所有工作程序来说通用的联接,没有锁和同步点(例如,没有信号/互斥量,没有锁/阻塞)。

原理:锁定/阻止使Process运行时不确定。提供了工作程序以增加运行时的利用率。 如果需要同步,则必须从RunWorkerPool()返回。

工作程序池不能用来并行处理多个不同的任务。使用多个可能不同的显式函数(工作程序可运行的对象)可能会增加不必要的复杂性,并可能导致运行时间利用率极不相同,因为每个工作程序有不同的计算时间。这会使资源部署的计划复杂化,这对于黑盒集成来说是必需的。

工作程序池用户的实现例子。比如:工作程序运行对象的例子:

class MyWorker1

: public DeterministicClient::WorkerrunnableBase<myContainer::

value_type, MyWorker1>

{

public:

void worker_runnable(myContainer::value_type& container_element,

DeterministicClient::WorkerThread& t)

{

// Get a unique and deterministic pseudo-random number}

uint64_t random_number = t.GetRandom();

}

};

工作程序线程对象:

class DeterministicClient::WorkerThread

{

// returns a deterministic pseudo-random number}

// which is unique for each container element}

uint64_t GetRandom();

...

};

4 状态管理

4.1 AUTOSAR Adaptive(平台)应用程序的交互

4.1.1 基本的状态管理功能

状态管理通过ara :: com提供了一组“Trigger”和“Notifier”字段。状态管理本质上侦听“Trigger”,并在内部执行特定实现的状态机处理,并在“Notifier”字段(如果有)中提供效果。状态管理还通过它们提供的标准接口与其他FC进行交互。

使用这个机制还可以达到下面的效果:

* 可以要求将功能组设置为专用状态。

* (部分)可以请求取消/激活网络

* 可以请求机器关闭或重启。

* 其他Adaptive(平台)应用程序的行为可能会受到影响

* 可以执行项目特定的动作

其中一些功能至关重要。因此,集成者必须通过IAM管理适当地保护对“Trigger”字段的访问,以免意外更改状态管理的内部状态(并因此而改变相关影响)。

状态管理的内部状态通过其提供的“Notifier”字段通知到系统。对这些字段的读取访问权限不太重要,因此,每当状态管理的内部状态发生更改时,每个Adaptive(平台)应用程序都可以注册其事件以收到通知。

因此,当状态管理的状态发生变化时,每个Adaptive(平台)应用程序都可以执行操作(需要时)。

4.1.2 高级状态管理功能

AUTOSAR Adaptive中的一些用例需要在状态管理所管理的状态中支持同步行为。。比如低功耗模式:一个示例可能是低功耗模式:只有当所有参与此低功耗模式场景的Adaptive(平台)应用程序都最终准备好用于低功耗时,状态管理才能最终切换到低功耗状态(例如,持续存在 其信息)。

因此每个要求支持这种同步工作模式的Adaptive(平台)应用程序必须通过ara::com提供这个字段。状态管理器可以通过FindService找到这个字段,状态管理器可以在以后注册,以便在Adaptive(平台)应用程序执行其操作时收到通知。

Adaptive(平台)应用程序必须完成的三件事,才能支持同步方案:

* Adaptive(平台)应用程序应注册状态管理器的相应“触发”现场事件(在满足状态管理中的条件时通知)

* Adaptive(平台)应用程序应为最终状态做任何准备工作

* Adaptive(平台)应用程序应将先前操作的结果写入其提供的字段

为了使状态管理认识到一个Adaptive(平台)应用程序想要成为同步场景的一部分,Adaptive(平台)应用程序不得不尽可能的提供它的字段服务使非常有必要的。并且当Adaptive(平台)应用程序不想再成为其中的一部分时,它不得不停止提供服务(例如 申请将完成)。

Adaptive(平台)应用程序的接口应该遵循状态管理的“TriggerOut”接口的模式。

5. 参考文档

[1]Explanations of Adaptive Platform Design, AUTOSAR_EXP_PlatformDesign.pdf.

[2]Specification of Execution Management, AUTOSAR_SWS_StateManagement.pdf.

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,980评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,178评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,868评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,498评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,492评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,521评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,910评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,569评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,793评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,559评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,639评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,342评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,931评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,904评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,144评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,833评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,350评论 2 342