mmrnd.net · Technical Papers

Technical paper · 2026-03-12T10:28:54+00:00

Building Two Cooperative AAOS Native Services over SOME/IP

A Step-by-Step Generic Development Guide

This document is a practical development guide for building two Android Automotive OS (AAOS) native services that communicate over SOME/IP. It is intentionally product-neutral. Instead of describing a specific product, it explains a reusable pattern in which one native service

By momo

abstract

This document is a practical development guide for building two Android Automotive OS (AAOS) native services that communicate over SOME/IP.

It is intentionally product-neutral.

Instead of describing a specific product, it explains a reusable pattern in which one native service acts as a domain authority service and another native service acts as a bridge or consumer service.

The guide covers the entire path from interface definition to code generation, generated-code usage, Android.bp integration, runtime configuration, and init.rc startup.

The goal is that an engineer can follow the steps one by one and produce a working sample service pair.

abstract

What this guide builds

The sample in this guide contains two long-running native daemons.

enumerate leftmargin=1.5em

Authority service : publishes a SOME/IP service and owns the authoritative state.

Bridge service : connects to that SOME/IP service, reads snapshots, sends commands, and subscribes to change events.

enumerate

The domain is intentionally simple.

The authority service owns one piece of state called activeId .

The bridge service can:

itemize leftmargin=1.4em

query the current activeId ,

request an update, and

receive asynchronous change notifications.

itemize

This is enough to demonstrate the real engineering workflow without pulling in product-specific code.

Conceptual model

Even in a practical tutorial, the conceptual split still matters.

The two-service arrangement is:

lstlisting style=mmrndcode,caption= Generic architecture

AAOS client-facing logic

-> bridge native service

-> SOME/IP transport

-> authority native service

lstlisting

The authority service is the source of truth.

The bridge service is not the source of truth.

It is responsible for transport integration, retry behavior, event subscription, and optional local adaptation for Android-side clients.

This structure is consistent with public AAOS layering ideas where client-facing APIs remain stable while lower layers hide implementation details such as binder plumbing, service routing, or hardware integration aospcarframework,aospcarjava,aospcarpropertyservice,aospvhal .

Prerequisites

This guide assumes the following.

itemize leftmargin=1.4em

You can build modules inside an AOSP or AAOS tree.

CommonAPI C++ core runtime, CommonAPI SOME/IP runtime, and vsomeip are already present in the source tree or available as integrated third-party modules.

The CommonAPI code generators are available on the host machine.

You want a first sample that is easy to understand and easy to rebuild.

itemize

A practical recommendation for the first AAOS sample is this:

itemize leftmargin=1.4em

keep .fidl and .fdepl under source control,

run code generation through a small script,

check the generated code into src-gen/ ,

compile the generated code from Android.bp.

itemize

That is usually easier than trying to perfect Soong-host-generator automation on day one.

Once the sample is stable, you can migrate generation into a genrule or another build step.

Recommended sample directory layout

A small, understandable directory layout is better than a highly abstract one.

lstlisting style=mmrndcode,caption= Recommended project tree

vendor/example/someip-state/

Android.bp

authority/

main.cpp

StateAuthorityStubImpl.hpp

StateAuthorityStubImpl.cpp

authority.rc

bridge/

main.cpp

bridge.rc

config/

commonapi.ini

vsomeip-authority.json

vsomeip-bridge.json

fidl/

StateSync.fidl

StateSync.fdepl

src-gen/

core/

someip/

tools/

generate.sh

sepolicy/

file_contexts

someip_state_authority.te

someip_state_bridge.te

lstlisting

Step 1: Define the interface in FIDL

Start with the domain contract, not with service code.

The FIDL file defines the API that both sides share.

lstlisting style=mmrndcode,caption= fidl/StateSync.fidl

package example.vehiclesync

interface StateSync

version major 1 minor 0

method getSnapshot

out

String activeId

method setActiveId

in

String newActiveId

out

Boolean accepted

broadcast stateChanged

out

String activeId

lstlisting

Why this shape is useful

This interface intentionally separates three things.

itemize leftmargin=1.4em

getSnapshot : synchronous read path.

setActiveId : command path.

stateChanged : event path.

itemize

That separation is important in real systems.

If the interface does not distinguish reads, commands, and events, clients usually end up guessing state from partial responses.

Step 2: Add SOME/IP deployment information in FDEPL

FIDL defines the interface shape, but not the SOME/IP identifiers.

Those belong in .fdepl .

lstlisting style=mmrndcode,caption= fidl/StateSync.fdepl

import "platform:/plugin/org.genivi.commonapi.someip/deployment/CommonAPI-SOMEIP_deployment_spec.fdepl"

import "StateSync.fidl"

define org.genivi.commonapi.someip.deployment for interface example.vehiclesync.StateSync

SomeIpServiceID = 4660

method getSnapshot

SomeIpMethodID = 30000

SomeIpReliable = true

method setActiveId

SomeIpMethodID = 30001

SomeIpReliable = true

broadcast stateChanged

SomeIpEventID = 33000

SomeIpEventGroups = 33001

SomeIpReliable = true

define org.genivi.commonapi.someip.deployment for provider as StateAuthorityProvider

instance example.vehiclesync.StateSync

InstanceId = "example.vehiclesync.StateSync"

SomeIpInstanceID = 22136

SomeIpUnicastAddress = "127.0.0.1"

SomeIpReliableUnicastPort = 30501

SomeIpUnreliableUnicastPort = 30501

lstlisting

What belongs in FDEPL

The FDEPL file should contain values that are transport-facing, not business-facing.

itemize leftmargin=1.4em

service ID

instance ID

method IDs

event IDs and event groups

reliable or unreliable transport choice

address and port information, if your deployment model expects it

itemize

A practical rule is that these numeric IDs must be treated as part of the wire contract.

Do not reassign them casually after client and server are already deployed.

Step 3: Generate CommonAPI code

There are two practical ways to generate CommonAPI and CommonAPI SOME/IP code.

enumerate leftmargin=1.5em

Pre-generate with a script and check in the result.

Generate at build time from Android.bp.

enumerate

Both are valid.

For a first experiment, a script can be simpler.

For long-lived Android modules, build-time generation through Soong is often more convenient because interface changes are regenerated automatically during the build.

Option A: generate with a script

The practical first-step workflow is a small script.

The exact generator binary name may vary by package or release, but the flow is usually the same.

lstlisting style=mmrndcode,caption= tools/generate.sh

#!/bin/bash

set -euo pipefail

ROOT_DIR= (cd " (dirname " 0")/.." && pwd)

OUT_CORE=" ROOT_DIR/src-gen/core"

OUT_SOMEIP=" ROOT_DIR/src-gen/someip"

rm -rf " OUT_CORE" " OUT_SOMEIP"

mkdir -p " OUT_CORE" " OUT_SOMEIP"

commonapi-core-generator-linux-x86_64

-d " OUT_CORE"

-sk " ROOT_DIR/fidl/StateSync.fidl"

commonapi-someip-generator-linux-x86_64

-d " OUT_SOMEIP"

" ROOT_DIR/fidl/StateSync.fdepl"

lstlisting

Option B: generate at build time from Android.bp

A very practical Android-native pattern is to let Soong call the generators through genrule modules.

A useful split is:

itemize leftmargin=1.4em

one genrule for core FIDL-generated headers,

one genrule for SOME/IP-generated headers,

one genrule for SOME/IP-generated source files.

itemize

That split mirrors how the generators naturally separate common API declarations from transport-specific code.

lstlisting style=mmrndcode,caption= idl/commonapi/Android.bp

genrule

name: "state-sync.fidl",

srcs: "StateSync.fidl" ,

out:

"v1/example/vehiclesync/StateSync.hpp",

"v1/example/vehiclesync/StateSyncProxy.hpp",

"v1/example/vehiclesync/StateSyncProxyBase.hpp",

"v1/example/vehiclesync/StateSyncStub.hpp",

"v1/example/vehiclesync/StateSyncStubDefault.hpp",

,

cmd: "external/commonapi-tools/commonapi-core-generator (in) -sk -d (genDir) -data (genDir)/metadata",

genrule

name: "state-sync.fdepl.header",

srcs: "StateSync.fdepl" ,

out:

"v1/example/vehiclesync/StateSyncSomeIPProxy.hpp",

"v1/example/vehiclesync/StateSyncSomeIPStubAdapter.hpp",

"v1/example/vehiclesync/StateSyncSomeIPDeployment.hpp",

,

cmd: "external/commonapi-tools/commonapi-someip-generator (in) -d (genDir) -data (genDir)/metadata",

genrule

name: "state-sync.fdepl.code",

srcs: "StateSync.fdepl" ,

out:

"v1/example/vehiclesync/StateSyncSomeIPProxy.cpp",

"v1/example/vehiclesync/StateSyncSomeIPStubAdapter.cpp",

"v1/example/vehiclesync/StateSyncSomeIPDeployment.cpp",

,

cmd: "external/commonapi-tools/commonapi-someip-generator (in) -d (genDir) -data (genDir)/metadata",

lstlisting

With this arrangement, the build graph owns the generated artifacts.

Client and server modules can then consume the generated headers and sources through generated _headers and generated _sources .

Typical generated output includes:

itemize leftmargin=1.4em

common headers such as StateSync.hpp

proxy-side headers and sources

stub-side headers and adapter sources

deployment mapping code for SOME/IP

itemize

Generated file names and namespaces can vary slightly by generator version.

The generated headers are the final source of truth for exact class names and exact method signatures.

When build-time generation is a good choice

Build-time generation is especially useful when:

itemize leftmargin=1.4em

several binaries share the same transport contract,

interface files change during active development,

you want the AOSP build graph to own dependency ordering,

you want to avoid committing large generated trees.

itemize

The main tradeoff is that the out: list must enumerate the generated files you expect.

That means generator version changes may require Android.bp updates.

In practice, this is still often worth it for AAOS native service development.

Step 4: Understand what the generators produced

After generation, inspect the headers before writing application code.

In practice, you usually care about the following classes.

itemize leftmargin=1.4em

StateSyncProxy.hpp : used by the bridge service.

StateSyncStub.hpp : service-side contract.

StateSyncStubDefault.hpp : convenient base class for your implementation.

StateSyncSomeIPProxy.cpp/.hpp : SOME/IP-specific proxy glue.

StateSyncSomeIPStubAdapter.cpp/.hpp : SOME/IP-specific service glue.

itemize

Before writing your own code, answer these two questions from the generated headers.

enumerate leftmargin=1.5em

What exact namespace did the generator emit.

What exact callback signature does each stub method require.

enumerate

This avoids many early integration mistakes.

Step 5: Implement the authority-side stub

The authority service owns the canonical state.

Its implementation should be simple, deterministic, and clearly separated from transport details.

lstlisting style=mmrndcode,caption= authority/StateAuthorityStubImpl.hpp

#pragma once

#include <mutex>

#include <string>

#include <v1/example/vehiclesync/StateSyncStubDefault.hpp>

class StateAuthorityStubImpl :

public v1::example::vehiclesync::StateSyncStubDefault

public:

StateAuthorityStubImpl();

void getSnapshot(

const std::shared_ptr<CommonAPI::ClientId> client,

getSnapshotReply_t reply) override;

void setActiveId(

const std::shared_ptr<CommonAPI::ClientId> client,

const std::string& newActiveId,

setActiveIdReply_t reply) override;

private:

std::mutex mutex_;

std::string activeId_;

;

lstlisting

lstlisting style=mmrndcode,caption= authority/StateAuthorityStubImpl.cpp

#include "StateAuthorityStubImpl.hpp"

StateAuthorityStubImpl::StateAuthorityStubImpl()

: activeId_("boot-default")

void StateAuthorityStubImpl::getSnapshot(

const std::shared_ptr<CommonAPI::ClientId>,

getSnapshotReply_t reply)

std::lock_guard<std::mutex> lock(mutex_);

reply(activeId_);

void StateAuthorityStubImpl::setActiveId(

const std::shared_ptr<CommonAPI::ClientId>,

const std::string& newActiveId,

setActiveIdReply_t reply)

std::lock_guard<std::mutex> lock(mutex_);

activeId_ = newActiveId;

fireStateChanged(activeId_);

reply(true);

lstlisting

Practical considerations for the stub

The authority stub should follow a few rules.

itemize leftmargin=1.4em

Keep transport callbacks short.

Protect shared state with a mutex or another clear ownership model.

Emit events only after the authoritative state has actually changed.

Keep business validation here, not in the bridge service.

itemize

If later you add persistence, write-through storage should also happen on this side.

Step 6: Write the authority service main

The service process creates the runtime, creates the stub implementation, and registers the service.

lstlisting style=mmrndcode,caption= authority/main.cpp

#include <CommonAPI/CommonAPI.hpp>

#include <android-base/logging.h>

#include <chrono>

#include <memory>

#include <thread>

#include "StateAuthorityStubImpl.hpp"

int main()

android::base::InitLogging(nullptr);

std::shared_ptr<CommonAPI::Runtime> runtime = CommonAPI::Runtime::get();

std::shared_ptr<StateAuthorityStubImpl> service =

std::make_shared<StateAuthorityStubImpl>();

const std::string domain = "local";

const std::string instance = "example.vehiclesync.StateSync";

const std::string connection = "state-authority";

while (!runtime->registerService(domain, instance, service, connection))

LOG(WARNING) << "registerService failed, retrying";

std::this_thread::sleep_for(std::chrono::milliseconds(200));

LOG(INFO) << "StateAuthority service registered";

while (true)

std::this_thread::sleep_for(std::chrono::seconds(60));

lstlisting

The exact overload of registerService() may vary by runtime version.

Use the generated and runtime headers in your tree as the final reference.

The key point is that the service registers the stub against the same CommonAPI instance name used in deployment.

Step 7: Write the bridge service

The bridge service behaves like a long-running SOME/IP client.

It connects to the authority service, obtains a proxy, subscribes to events, and may mirror the state into a local Android-facing abstraction later.

lstlisting style=mmrndcode,caption= bridge/main.cpp

#include <CommonAPI/CommonAPI.hpp>

#include <android-base/logging.h>

#include <chrono>

#include <memory>

#include <thread>

#include <v1/example/vehiclesync/StateSyncProxy.hpp>

int main()

android::base::InitLogging(nullptr);

std::shared_ptr<CommonAPI::Runtime> runtime = CommonAPI::Runtime::get();

auto proxy = runtime->buildProxy<v1::example::vehiclesync::StateSyncProxy>(

"local",

"example.vehiclesync.StateSync",

"state-bridge");

while (!proxy->isAvailable())

LOG(INFO) << "Waiting for authority service";

std::this_thread::sleep_for(std::chrono::milliseconds(200));

proxy->getStateChangedEvent().subscribe(

(const std::string& activeId)

LOG(INFO) << "stateChanged event: activeId=" << activeId;

);

CommonAPI::CallStatus status;

std::string snapshot;

proxy->getSnapshot(status, snapshot);

LOG(INFO) << "Initial snapshot status=" << static_cast<int>(status)

<< " activeId=" << snapshot;

bool accepted = false;

proxy->setActiveId("bridge-requested-id", status, accepted);

LOG(INFO) << "setActiveId status=" << static_cast<int>(status)

<< " accepted=" << accepted;

while (true)

std::this_thread::sleep_for(std::chrono::seconds(60));

lstlisting

Practical considerations for the bridge

A production bridge service typically needs more than the minimal code above.

itemize leftmargin=1.4em

reconnect handling if the provider disappears,

resubscription after reconnect,

explicit local cache freshness rules,

transport timeout handling,

local permission checks if Android clients call into this bridge.

itemize

But as a first sample, the above is enough to validate the end-to-end path.

Step 8: Add runtime configuration files

In most practical SOME/IP integrations, you need at least:

itemize leftmargin=1.4em

a CommonAPI configuration file,

a vsomeip configuration file for each process.

itemize

CommonAPI configuration

lstlisting style=mmrndcode,caption= config/commonapi.ini

default

binding=someip

lstlisting

If your integration links the generated SOME/IP glue directly into the executable and uses an internal-compilation mode, this file may become less important.

However, for an understandable first sample, keeping the explicit binding configuration is useful.

vsomeip configuration for authority

lstlisting style=mmrndcode,caption= config/vsomeip-authority.json

"unicast": "127.0.0.1",

"applications":

"name": "state-authority",

"id": "0x1111"

,

"services":

"service": "0x1234",

"instance": "0x5678",

"unreliable": "30501",

"reliable": "30501"

,

"routing": "state-authority",

"service-discovery":

"enable": true,

"multicast": "224.224.224.245",

"port": "30490",

"protocol": "udp"

lstlisting

vsomeip configuration for bridge

lstlisting style=mmrndcode,caption= config/vsomeip-bridge.json

"unicast": "127.0.0.1",

"applications":

"name": "state-bridge",

"id": "0x2222"

,

"routing": "state-bridge",

"service-discovery":

"enable": true,

"multicast": "224.224.224.245",

"port": "30490",

"protocol": "udp"

lstlisting

Important alignment rule

The FDEPL values, runtime code, and vsomeip configuration must agree.

At minimum, align:

itemize leftmargin=1.4em

service ID,

instance ID,

application name used as connection or routing identity,

ports and addresses.

itemize

Misalignment here is one of the most common reasons a first sample does not communicate.

Step 9: Write Android.bp

The sample needs to build generated code, local code, and configuration artifacts.

There are two valid Android.bp shapes depending on whether you pre-generated code or generate it during the build.

Pattern A: Android.bp consuming a checked-in generated tree

A practical Android.bp can look like this.

lstlisting style=mmrndcode,caption= Android.bp with checked-in generated tree

cc_defaults

name: "someip_state_defaults",

vendor: true,

cflags:

"-Wall",

"-Wextra",

"-Werror",

,

cpp_std: "c++17",

shared_libs:

"liblog",

"libbase",

"libutils",

"libCommonAPI",

"libCommonAPI-SomeIP",

"libvsomeip3",

,

export_include_dirs:

".",

"src-gen/core",

"src-gen/someip",

,

cc_library_static

name: "libsomeip_state_generated",

defaults: "someip_state_defaults" ,

srcs:

"src-gen/core/**/*.cpp",

"src-gen/someip/**/*.cpp",

,

prebuilt_etc

name: "someip_state_commonapi_ini",

vendor: true,

src: "config/commonapi.ini",

sub_dir: "someip-state",

filename_from_src: true,

prebuilt_etc

name: "someip_state_vsomeip_authority_json",

vendor: true,

src: "config/vsomeip-authority.json",

sub_dir: "someip-state",

filename_from_src: true,

prebuilt_etc

name: "someip_state_vsomeip_bridge_json",

vendor: true,

src: "config/vsomeip-bridge.json",

sub_dir: "someip-state",

filename_from_src: true,

cc_binary

name: "someip-state-authority",

defaults: "someip_state_defaults" ,

srcs:

"authority/main.cpp",

"authority/StateAuthorityStubImpl.cpp",

,

static_libs:

"libsomeip_state_generated",

,

init_rc: "authority/authority.rc" ,

required:

"someip_state_commonapi_ini",

"someip_state_vsomeip_authority_json",

,

cc_binary

name: "someip-state-bridge",

defaults: "someip_state_defaults" ,

srcs:

"bridge/main.cpp",

,

static_libs:

"libsomeip_state_generated",

,

init_rc: "bridge/bridge.rc" ,

required:

"someip_state_commonapi_ini",

"someip_state_vsomeip_bridge_json",

,

lstlisting

Pattern B: Android.bp generating code during the build

A more integrated Soong pattern is to let a generated-code library depend directly on the genrule outputs.

This pattern is very practical in real AAOS projects and is commonly easier to maintain once the interface is stable.

lstlisting style=mmrndcode,caption= Android.bp with build-time generated headers and sources

cc_library

name: "libsomeip_state_generated",

vendor: true,

generated_headers:

"state-sync.fidl",

"state-sync.fdepl.header",

,

export_generated_headers:

"state-sync.fidl",

"state-sync.fdepl.header",

,

generated_sources:

"state-sync.fdepl.code",

,

cppflags:

"-fexceptions",

"-Wno-overloaded-virtual",

"-Wno-unused-parameter",

,

rtti: true,

cpp_std: "c++20",

shared_libs:

"libCommonAPI",

"libCommonAPI-SomeIP",

"libvsomeip3",

"libvsomeip3-cfg",

"libvsomeip3-sd",

,

cc_library

name: "libsomeip_state_authority_impl",

vendor: true,

srcs:

"authority/StateAuthorityStubImpl.cpp",

,

local_include_dirs:

"authority",

,

generated_headers:

"state-sync.fidl",

"state-sync.fdepl.header",

,

shared_libs:

"libCommonAPI",

"libCommonAPI-SomeIP",

"libvsomeip3",

"libsomeip_state_generated",

,

cpp_std: "c++20",

rtti: true,

cppflags: "-fexceptions" ,

cc_binary

name: "someip-state-authority",

vendor: true,

srcs: "authority/main.cpp" ,

init_rc: "authority/authority.rc" ,

required:

"someip_state_commonapi_ini",

"someip_state_vsomeip_authority_json",

,

shared_libs:

"libbase",

"liblog",

"libutils",

"libCommonAPI",

"libCommonAPI-SomeIP",

"libvsomeip3",

"libvsomeip3-cfg",

"libvsomeip3-sd",

"libsomeip_state_authority_impl",

,

cpp_std: "c++20",

lstlisting

The bridge binary can follow the same pattern: consume generated _headers and link the generated-code library instead of depending on a checked-in src-gen/ tree.

Why the build-time generation pattern is attractive

This layout follows a few useful rules.

itemize leftmargin=1.4em

The build graph owns interface generation order.

Generated headers are exported cleanly to handwritten libraries.

Generated transport sources compile in one dedicated library.

Handwritten client and server code stay small and focused.

Configuration files are still installed by prebuilt _etc .

The init _rc property still packages the init scripts with the binaries.

itemize

Practical guidance on choosing between the two

Use script-based generation when:

itemize leftmargin=1.4em

you are still exploring the interface,

you want very explicit diffs for generated code,

generator setup in the build is not ready yet.

itemize

Use build-time generation when:

itemize leftmargin=1.4em

the service contract has stabilized,

multiple modules consume the same interface,

you want fewer manual regeneration mistakes,

your AAOS build already contains the host-side generator tools.

itemize

In practice, both patterns are common.

A team often starts with script generation, proves the service behavior, and then moves to Soong-driven generation once the interface settles.

Step 10: Add init.rc scripts

Both services should start under init.

A simple first version can start both at boot.

lstlisting style=mmrndcode,caption= authority/authority.rc

service someip-state-authority /vendor/bin/someip-state-authority

class main

user system

group system inet

setenv COMMONAPI_CONFIG /vendor/etc/someip-state/commonapi.ini

setenv VSOMEIP_CONFIGURATION /vendor/etc/someip-state/vsomeip-authority.json

oneshot

disabled

on property:sys.boot_completed=1

start someip-state-authority

lstlisting

lstlisting style=mmrndcode,caption= bridge/bridge.rc

service someip-state-bridge /vendor/bin/someip-state-bridge

class main

user system

group system inet

setenv COMMONAPI_CONFIG /vendor/etc/someip-state/commonapi.ini

setenv VSOMEIP_CONFIGURATION /vendor/etc/someip-state/vsomeip-bridge.json

oneshot

disabled

on property:sys.boot_completed=1

start someip-state-bridge

lstlisting

Why start both from init

Starting both binaries from init gives you a repeatable boot-time environment.

It also matches how native long-running services are commonly integrated into Android partitions aospinitreadme,aospandroidbp .

In practice you may later refine the startup trigger.

For example:

itemize leftmargin=1.4em

start at a specific boot phase,

start on a property change,

separate provider and consumer startup timing.

itemize

For a first sample, boot-complete start is easy to reason about.

Step 11: Add the modules to the product

If the services are meant to land in the image, add them to the product packages list.

lstlisting style=mmrndcode,caption= device or product makefile snippet

PRODUCT_PACKAGES +=

someip-state-authority

someip-state-bridge

lstlisting

If CommonAPI and vsomeip runtimes are not already pulled into the image by dependency closure, ensure those packages are included as well.

The CommonAPI SOME/IP runtime project documents Android source-tree integration through its provided Android.bp covesasomeipruntime .

Step 12: Add minimal SELinux policy

For a real AAOS bring-up, init and binary install are not enough.

You usually also need service domains and file labels.

A minimal sketch is below.

lstlisting style=mmrndcode,caption= sepolicy/file _contexts

/vendor/bin/someip-state-authority u:object_r:someip_state_authority_exec:s0

/vendor/bin/someip-state-bridge u:object_r:someip_state_bridge_exec:s0

lstlisting

lstlisting style=mmrndcode,caption= sepolicy/someip _state _authority.te

type someip_state_authority, domain;

type someip_state_authority_exec, exec_type, vendor_file_type, file_type;

init_daemon_domain(someip_state_authority)

lstlisting

lstlisting style=mmrndcode,caption= sepolicy/someip _state _bridge.te

type someip_state_bridge, domain;

type someip_state_bridge_exec, exec_type, vendor_file_type, file_type;

init_daemon_domain(someip_state_bridge)

lstlisting

Actual policy requirements depend on how your runtime libraries use sockets, properties, and files.

But even a simple sample should acknowledge SELinux early, because many first-boot failures are policy failures rather than C++ logic failures.

Step 13: Build and verify the sample

A practical bring-up checklist is:

enumerate leftmargin=1.5em

Run tools/generate.sh .

Build the two binaries in the Android tree.

Flash or sync the new image.

Confirm both init services are installed and started.

Verify that the authority service registers before or shortly after the bridge service begins retrying.

Check logs for the initial snapshot and later stateChanged events.

enumerate

Typical commands during verification include:

lstlisting style=mmrndcode,caption= Typical verification commands

adb shell getprop | grep boot_completed

adb shell ps -A | grep someip-state

adb logcat | grep -E "StateAuthority|stateChanged|someip-state"

lstlisting

A successful first run usually looks like this.

itemize leftmargin=1.4em

authority service starts,

authority registers the SOME/IP service,

bridge service connects and sees the proxy become available,

bridge reads the initial snapshot,

bridge sends a command,

authority emits stateChanged ,

bridge receives the event.

itemize

Step 14: Practical issues to handle before calling the sample production-ready

Reconnect and resubscribe

If the provider restarts, the bridge must:

itemize leftmargin=1.4em

detect loss of availability,

rebuild or revalidate the proxy,

resubscribe to events,

refresh any local cache.

itemize

Do not split authority

The bridge service should not make final state decisions independently.

Its local cache is for adaptation and availability, not for competing ownership.

Version and ID stability

Once IDs in FDEPL are shared across more than one process or ECU, changing them becomes an interface compatibility event.

Treat them as versioned wire-level identifiers.

Generated code is version-sensitive

The generated method signatures, namespace structure, and adapter file set may vary slightly across CommonAPI generator releases.

For that reason:

itemize leftmargin=1.4em

use the generated headers in your tree as the truth source,

document the generator version you used,

regenerate and review diffs deliberately.

itemize

Bridge-side Android adaptation

If the bridge later exposes a binder or another Android-local manager API, keep that adaptation layer above the SOME/IP proxy logic.

Do not leak SOME/IP-specific identifiers into the Android client contract.

Recommended development sequence for real teams

A practical sequence for a real project is:

enumerate leftmargin=1.5em

define a very small FIDL,

add FDEPL with stable IDs,

generate code and read the generated signatures,

implement the provider stub first,

implement a tiny bridge next,

verify boot-time startup from init,

only then add richer local APIs, persistence, or UI integration.

enumerate

This order minimizes moving parts while the service contract is still being proven.

Conclusion

A clean AAOS plus SOME/IP sample is not just a transport demo.

It is a layered service design exercise.

The authority service owns state.

The bridge service owns transport adaptation and local integration.

FIDL and FDEPL define the shared contract.

Generated code defines the exact C++ boundaries.

Android.bp packages the binaries and generated code.

init.rc brings the services up at runtime.

If you follow the steps in this guide in order, you can produce a working two-service sample that is generic, product-neutral, and aligned with public Android and CommonAPI design materials.

Practical tips

When to move from script generation to build-time generation

itemize leftmargin=1.4em

Start with script generation while the interface is still changing quickly.

Move to Android.bp-based generation when multiple modules share the same contract.

Treat the generated file list in genrule out: as part of build maintenance.

itemize

How to scale beyond one interface

itemize leftmargin=1.4em

Keep one fidl/ directory for the contract source.

Split genrule modules by interface and by generator output type.

Aggregate shared generated outputs into one dedicated generated-code library.

Keep each handwritten client or server target dependent on that generated-code library rather than regenerating the same interface in multiple places.

itemize

How to keep client and service code maintainable

itemize leftmargin=1.4em

Keep generated code in its own library.

Keep handwritten bridge and authority logic in separate libraries.

Do not mix transport mapping, business logic, and init packaging in one target.

Treat the generated headers as the source of truth for signatures and namespaces, not old handwritten assumptions.

itemize

What usually breaks first

itemize leftmargin=1.4em

FDEPL identifiers and vsomeip configuration values do not match.

Generated headers are not exported correctly to handwritten code targets.

The bridge starts correctly but never resubscribes after reconnect.

init and SELinux are individually correct, but the configuration files are not installed at the path the process expects.

A generator upgrade changes the emitted file set, but the Android.bp out: list or generated _sources list is not updated.

itemize

thebibliography 9

aospcarframework

Android Open Source Project,

Car framework core ,

https://source.android.com/docs/automotive/car-framework-core .

aospvhal

Android Open Source Project,

Vehicle HAL overview ,

https://source.android.com/docs/automotive/vhal .

aospcarjava

Android Open Source Project,

Car.java ,

https://android.googlesource.com/platform/packages/services/Car/+/master/car-lib/src/android/car/Car.java .

aospcarpropertyservice

Android Open Source Project,

CarPropertyService.java ,

https://android.googlesource.com/platform/packages/services/Car/+/refs/heads/main/service/src/com/android/car/CarPropertyService.java .

aospinitreadme

Android Open Source Project,

Android Init Language README ,

https://android.googlesource.com/platform/system/core.git/+/8b47d316d253d05f92cf853d5b44cc28666848fe/init/README.md .

aospandroidbp

Android Open Source Project,

Android.bp file format ,

https://source.android.com/docs/setup/reference/androidbp .

covesacore

COVESA,

CommonAPI C++ ,

https://covesa.github.io/capicxx-core-tools/ .

covesasomeip

COVESA,

CommonAPI C++ SOME/IP ,

https://covesa.github.io/capicxx-someip-tools/ .

covesasomeipruntime

COVESA,

capicxx-someip-runtime ,

https://github.com/COVESA/capicxx-someip-runtime .

covesa10min

COVESA,

CommonAPI C++ SOME/IP in 10 minutes ,

https://github-wiki-see.page/m/COVESA/capicxx-someip-tools/wiki/CommonAPI-C---SomeIP-in-10-minutes .

thebibliography