2. 自适应应用的生命周期管理

任务说明

本案例目标是在AUTOSAR AP中间件框架下,基于ara::com通信模型实现一个服务发布(Service Provider)与订阅(Service Subscriber)的最小可运行闭环。服务端发布一个计算两数之和的服务接口,客户端通过服务发现机制找到该服务并远程调用,最终在客户端侧获得计算结果。

实现方案

采用AUTOSAR AP标准中ara::com的Skeleton(服务端)与Proxy(客户端)模式。服务接口使用IDL定义,通过aracom代码生成器生成骨架代码。本案例直接提供生成后的C++实现代码,并配套JSON格式的服务清单(Service Manifest)用于服务发现配置。通信中间件基于SOME/IP协议,通过本地回环地址(127.0.0.1)完成进程间通信。

代码实现

1. 服务接口定义(CalculatorInterface.idl)

// 服务接口IDL定义
interface CalculatorService {
    method uint32 Add(uint32 a, uint32 b);
};

2. 服务端实现(service_provider.cpp)

#include <ara/com/skeleton/ServiceSkeletonImpl.h>
#include <ara/com/runtime.h>
#include <memory>
#include <thread>
#include <chrono>
#include <iostream>

// 生成代码头文件(由aracom工具从IDL生成)
#include "gen/CalculatorServiceSkeleton.h"

using namespace ara::com;

// 服务端Skeleton实现类
class CalculatorServiceImpl : public CalculatorServiceSkeleton {
public:
    explicit CalculatorServiceImpl(ara::core::InstanceSpecifier instance)
        : CalculatorServiceSkeleton(instance) {}

    // 实现Add方法
    ara::core::Future<uint32_t> Add(uint32_t a, uint32_t b) override {
        ara::core::Promise<uint32_t> promise;
        promise.set_value(a + b);
        return promise.get_future();
    }
};

int main() {
    // 初始化运行时
    ara::com::Runtime::GetInstance().Initialize();

    // 服务实例标识(需与Manifest中一致)
    ara::core::InstanceSpecifier specifier("provider/root/CalculatorService");

    // 创建并注册服务
    auto service = std::make_shared<CalculatorServiceImpl>(specifier);
    auto offerHandle = service->OfferService();

    std::cout << "[Provider] Service offered. Waiting for requests..." << std::endl;

    // 保持进程运行
    while (true) {
        std::this_thread::sleep_for(std::chrono::seconds(1));
    }

    return 0;
}

3. 客户端实现(service_subscriber.cpp)

#include <ara/com/runtime.h>
#include <ara/com/proxy/ServiceProxyImpl.h>
#include <memory>
#include <iostream>
#include <thread>
#include <chrono>

// 生成代码头文件
#include "gen/CalculatorServiceProxy.h"

using namespace ara::com;

int main() {
    // 初始化运行时
    ara::com::Runtime::GetInstance().Initialize();

    // 服务实例标识(需与Provider一致)
    ara::core::InstanceSpecifier specifier("provider/root/CalculatorService");

    // 创建Proxy并查找服务
    auto proxy = std::make_shared<CalculatorServiceProxy>(specifier);
    
    // 等待服务发现完成(最多等待5秒)
    bool found = false;
    for (int i = 0; i < 50; ++i) {
        auto state = proxy->GetServiceHandle().GetState();
        if (state == ServiceHandle::State::kAvailable) {
            found = true;
            break;
        }
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
    }

    if (!found) {
        std::cerr << "[Client] Service not found after timeout." << std::endl;
        return -1;
    }

    std::cout << "[Client] Service discovered. Calling Add(3, 5)..." << std::endl;

    // 调用远程方法
    auto future = proxy->Add(3, 5);
    auto result = future.get();

    std::cout << "[Client] Add(3, 5) = " << result << std::endl;

    return 0;
}

4. 服务清单配置(manifest.json)

{
  "serviceInterfaces": [
    {
      "name": "CalculatorService",
      "methods": [
        {
          "name": "Add",
          "parameters": [
            {"name": "a", "type": "uint32"},
            {"name": "b", "type": "uint32"}
          ],
          "return": {"type": "uint32"}
        }
      ]
    }
  ],
  "serviceInstances": [
    {
      "name": "provider/root/CalculatorService",
      "interface": "CalculatorService",
      "communication": {
        "kind": "someip",
        "network": "local",
        "port": 30509
      }
    }
  ]
}

构建与运行

# 1. 使用aracom工具从IDL生成骨架代码
aracom --idl CalculatorInterface.idl --output-dir gen

# 2. 编译服务端
g++ -std=c++17 -I. -Igen service_provider.cpp gen/CalculatorServiceSkeleton.cpp \
    -L/usr/local/lib -lara_com -lsomeip -o provider

# 3. 编译客户端
g++ -std=c++17 -I. -Igen service_subscriber.cpp gen/CalculatorServiceProxy.cpp \
    -L/usr/local/lib -lara_com -lsomeip -o subscriber

# 4. 启动服务端(终端1)
./provider

# 5. 启动客户端(终端2)
./subscriber

验证方法

在终端1中启动provider后,观察输出显示服务已注册。在终端2中启动subscriber,若客户端输出[Client] Add(3, 5) = 8,则说明服务发布、服务发现、远程调用全链路工作正常。判定标准:客户端成功获取到计算结果8,且服务端无异常退出。

ara::com 服务发布与订阅时序 服务端 (Provider) 客户端 (Subscriber) SOME/IP 通信中间件 CalculatorServiceSkeleton OfferService() Add() 方法实现 CalculatorServiceProxy FindService() Add(3,5) 远程调用 ① 注册 ② 发现 ③ 可用 ④ Add(3,5) 请求 ⑤ 返回结果 8 输出: Add(3,5) = 8 服务注册 服务发现 远程调用

关键点说明

  • 服务标识一致性:Provider和Proxy必须使用相同的InstanceSpecifier字符串,且与manifest.json中的服务实例名称完全匹配,否则服务发现会失败。
  • 服务发现机制:客户端通过Proxy的GetServiceHandle().GetState()轮询服务状态,实际项目中可注册状态变更回调实现异步通知。
  • 通信配置:本案例使用本地回环地址和固定端口30509,实际部署时需根据网络环境调整manifest中的通信参数。