Almost every AAOS bug you will ever debug comes down to one question: which layer is lying to you?
A number on the screen is wrong. Is the sensor wrong? Is the car's own computer sending the wrong value? Is Android misreading it? Is the app displaying it badly? Until you can name the layers, you cannot answer that, and you end up guessing.
So this page is the map. Take your time with it — everything else in the curriculum refers back to it.
First, the shape of the problem#
A car contains dozens of small computers called s. One controls the engine, another the doors, another the climate system. They were designed decades before Android existed and they know nothing about it.
Android needs to show the driver what those computers know, and sometimes tell them to do something. But Android cannot simply "read the car" — there is no such thing. It has to go through several translation steps.
The stack is those translation steps, stacked up.
Walking down the layers#
Layer 1 — Automotive apps#
These are ordinary Android apps, with two extra rules.
First, they cannot touch the vehicle directly. There is no way for an app to open the car's wiring and read a message. It must ask the platform.
Second, they must obey the driver distraction rules covered later in the curriculum — limits on what may be displayed while the car is moving.
Layer 2 — The Car API (android.car)#
This is a library your app links against. It is the public face of everything car-related.
You already know this pattern from ordinary Android: to play a sound you use
android.media; to send a notification you use android.app. To read the cabin
temperature you use .
The two names worth knowing here:
VehiclePropertyIds— the catalogue of every piece of vehicle data Android defines, as a long list of constants.- — the object you actually call to read or watch a value.
Layer 3 — The Android framework#
The ordinary Android you already know: activity management, window management, the package manager. AAOS does not replace this. It adds to it.
Layer 4 — Car Service#
Now we are into the genuinely automotive part.
is a single process — com.android.car — that holds about a
dozen smaller services inside it. It is the centre of gravity of the whole
platform.
| Inside Car Service | What it owns |
|---|---|
CarPropertyService | All vehicle data, and who is allowed to see it |
CarAudioService | Which speakers a sound comes out of |
CarPowerManagementService | What happens when the car is switched off |
CarUserService | Driver profiles and switching between them |
CarUxRestrictionsManagerService | What the screen may show while moving |
CarWatchdogService | Noticing when something has stopped responding |
Layer 5 — The Vehicle HAL#
The is the narrowest point in the entire stack, and deliberately so.
It offers exactly one thing: a list of named values — — each of which can be read, written, or watched for changes. That is the whole interface.
Layer 6 — The vendor vehicle network service#
This layer is not in AOSP. It is written by the car maker or their supplier, and it is different on every vehicle.
Its job is to actually talk to the car: open the connection, read messages, and convert raw numbers into the units the VHAL promised.
Layer 7 — The buses and ECUs#
The car's own electronics. Dozens to hundreds of small computers, wired together with and other networks, running software that is not Android and was often written before Android existed.
The dashed line: Treble#
The dashed line in the diagram is the most important architectural fact in AAOS, and it has a name: .
Android is split into separate storage areas called partitions:
/systemholds the Android framework. Google and the car maker's platform team update this./vendorholds hardware-specific code — including the VHAL. The supplier writes this, and it is often frozen for years.
They are only allowed to talk to each other through fixed, versioned interfaces. Not by sharing code. Not by sharing data structures. Not by one calling a function in the other.
Following one value all the way down#
Here is the whole stack in one worked example. Your app wants to display the cabin temperature.
val car = Car.createCar(context)
val propertyManager = car.getCarManager(Car.PROPERTY_SERVICE) as CarPropertyManager
val temperature = propertyManager.getFloatProperty(
VehiclePropertyIds.HVAC_TEMPERATURE_CURRENT, // which value
VehicleAreaSeat.SEAT_ROW_1_LEFT, // for which seat
)Three lines. Here is what actually happens:
1. Your app asks the Car API. getFloatProperty is a normal method call
inside your own process. Nothing has left your app yet.
2. The request crosses to Car Service. This is — Android's way for one process to ask another process to do something. Your app pauses while it waits for an answer.
3. Car Service checks permission. Does this app hold
android.car.permission.CONTROL_CAR_CLIMATE? If not, it stops here and your app
receives a SecurityException.
4. Car Service asks the VHAL. "Give me property
HVAC_TEMPERATURE_CURRENT for area SEAT_ROW_1_LEFT."
5. The VHAL answers from its cache. It does not go and ask the car right now — its own background thread has been listening to the vehicle network and keeping a recent value. It hands back what it last heard.
6. The value travels back up through the same path, and getFloatProperty
returns 21.5f.
Layers you are allowed to change#
Worth knowing early, because it shapes what job you are actually doing:
| Layer | Can you change it? |
|---|---|
| Apps | Yes — this is ordinary app development |
| Car API | Only if you work on the platform |
| Framework | Only if you work on the platform, and it risks CTS failures |
| Car Service | Yes, if you are the car maker — but it is an AOSP fork to maintain |
| Vehicle HAL | Yes — this is the supplier's code |
| Vendor network service | Yes — this is entirely the supplier's |
| ECUs | A different team, often a different company |
Next#
Getting a build running on your own machine, so you can try all of this.

