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
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