Android platform-architecture simulation for marine bridge electronics — a reusable SDK, a privileged Binder/AIDL platform service, and product surfaces (launcher, chartplotter, sonar, command deck, settings, device management, OTA).
Built to demonstrate how launcher / settings / device / data / OTA can share one coherent platform boundary (the same separation you’d enforce on a real MFD running an AOSP-derived image).
Honest scope: This is an Android Studio multi-module app simulation, not a full AOSP fork or flashed
system.img. The architecture mirrors a real platform service + SDK + product apps stack; hardware and UpdateEngine are simulated.
Marine / automotive / CE platform teams need engineers who can:
- Own product surfaces (launcher, settings, device UI) without leaking HAL details into apps
- Define a stable SDK contract that multiple product lines can reuse
- Run privileged work in a platform service over Binder/AIDL
- Reason about OTA state machines, alerts, and process boundaries
Marine Command OS is a concrete, runnable demo of that stack.
flowchart TB
subgraph Product["Product layer — :launcher"]
HOME[HOME / MainActivity]
CHART[Chartplotter]
SONAR[Sonar]
DECK[Command Deck]
SETTINGS[Settings]
DEVICES[Device Management]
OTAUI[Firmware and OTA]
end
subgraph SDK[":sdk — stable contract"]
MM[MarineManager facade]
AIDL[IMarineDataService / IMarineDataListener]
VS[VesselState]
end
subgraph Platform[":platform-service — privileged process"]
SVC[MarinePlatformService]
OTA[OtaStateMachine]
SIM[Simulated Marine HAL]
end
HOME --> MM
CHART --> MM
SONAR --> MM
DECK --> MM
SETTINGS --> MM
DEVICES --> MM
OTAUI --> MM
MM --> AIDL
AIDL -->|Binder + signature permission| SVC
SVC --> OTA
SVC --> SIM
SIM -->|VesselState callbacks| AIDL
Product surfaces talk only through MarineManager.
They never import service internals or touch the simulated HAL directly.
| Layer | Module | Responsibility |
|---|---|---|
| Product UI | :launcher (com.zhk.marine.launcher) |
HOME launcher + Chartplotter, Sonar, Command Deck, Settings, Device Management, OTA screens |
| SDK | :sdk (library) |
AIDL contracts, VesselState, MarineManager facade |
| Platform | :platform-service (com.zhk.marine.platformservice) |
Privileged service, telemetry simulation, OTA state machine |
Signature permission: com.zhk.marine.permission.BIND_MARINE_SERVICE
sequenceDiagram
participant UI as CommandDeckActivity
participant SDK as MarineManager
participant SVC as MarinePlatformService
participant HAL as Simulated HAL loop
UI->>SDK: bind()
SDK->>SVC: bindService (BIND_AUTO_CREATE)
SVC-->>SDK: onServiceConnected (IBinder)
SDK->>SVC: registerListener(IMarineDataListener)
loop every 1.5s
HAL->>SVC: update latestVesselState
SVC-->>SDK: onStateChanged(VesselState)
SDK-->>UI: Flow emission
UI->>UI: render gauges / alert if temp > 220°F
end
UI->>SDK: unbind()
| Surface | What it shows |
|---|---|
| HOME | Pictorial tiles, platform online status, live SOG / HDG / depth snapshot |
| Chartplotter | Demo chart canvas, fishing spots, waypoints, AIS targets, layer toggles |
| Sonar | Fishfinder water-column view, live depth from platform, frequency / range controls |
| Command Deck | 8-gauge instrument grid via AIDL callbacks; over-temp alert banner |
| Settings | Vessel profile, units, night / keep-awake, NMEA & spot-sync demo prefs, alerts |
| Device Management | Connected-device inventory, diagnostics, entry to Firmware & OTA |
| Firmware & OTA | Device health + OTA progress UI |
AVAILABLE → DOWNLOADING → VERIFYING → READY → INSTALLING → REBOOT_REQUIRED
Same vocabulary you’d use when talking about staged updates / health checks / rollback on a real UpdateEngine path.
| Marine Command OS | Full AOSP platform | |
|---|---|---|
| Goal | Prove product↔platform boundary quickly | Build / flash entire Android OS image |
| Build | Gradle (Android Studio) | repo + Soong/Make (lunch / m) |
| Runtime | App process(es) on phone / emulator | system_server + system/vendor partitions |
| Trust model | Signature permission (simulates platform trust) | priv-app, SELinux, signature|privileged |
| Hardware | Simulated telemetry + OTA machine | HALs (AIDL/HIDL) + kernel drivers |
| Updates | In-process OTA state machine demo | UpdateEngine, A/B slots, recovery |
Mapping to a real MFD image: product UIs → packages/apps (or vendor apps); SDK → framework stubs / client lib; service → SystemService or privileged app; sim HAL → NMEA 2000 / CAN / sonar HALs.
MarineCommandOS/
├── sdk/ # AIDL + MarineManager + VesselState
├── platform-service/ # Privileged Binder service + OTA + sim telemetry
├── launcher/ # All product surfaces (single demo APK)
├── gradle/
├── build.gradle.kts
├── settings.gradle.kts
└── README.md
- Android Studio Ladybug+ (or equivalent) / JDK 17
- Android SDK 35
- Device or emulator API 26+
- Prefer a dedicated test phone if you set Marine Command as the default HOME launcher
./gradlew :sdk:assembleDebug \
:platform-service:assembleDebug \
:launcher:assembleDebugWindows:
.\gradlew :sdk:assembleDebug :platform-service:assembleDebug :launcher:assembleDebug.\gradlew :platform-service:installDebug :launcher:installDebugOpen Marine Command OS from the app drawer.
adb shell cmd package set-home-activity com.zhk.marine.launcher/.MainActivityThen press Home.
Restore stock launcher (Pixel example):
adb shell cmd role add-role-holder android.app.role.HOME com.google.android.apps.nexuslauncherOn Samsung / other OEMs, use Settings → Apps → Default apps → Home app.
Do not leave this as Home on a daily-driver phone unless you intend to.
- HOME shows ONLINE and live snapshot once the platform service binds
- Command Deck — gauges update; wait for engine-temp alert (> 220°F)
- Chartplotter — spots / waypoints / AIS; toggle layers
- Sonar — water column + live depth
- Settings — flip units / connectivity toggles
- Device Management → Firmware & OTA — tap Check for Update and walk the state machine
- UI: Material Views + ViewBinding (Compose avoided for Windows classpath reliability on this machine)
- IPC: AIDL +
RemoteCallbackListfor multi-listener fan-out - Async: Kotlin coroutines + Flow from
MarineManager.stateUpdates() - Settings persistence: DataStore Preferences (demo shortcut; production would route config through the platform service)
- Kotlin / AIDL caveat: do not name service fields
currentState/otaState— they collide with generated getters and recurse
- AIDL-backed
FishingSpotsManager(spots versioned in the platform layer — Navico-style phone↔MFD sync) - Real NMEA 2000 / CAN HAL behind the same AIDL
- SELinux / priv-app packaging on an AOSP derivative
- Wire OTA demo vocabulary to UpdateEngine on a device image
Personal / portfolio project. Add a license of your choice before publishing if you want redistribution terms (e.g. MIT / Apache-2.0).