Skip to content

VHAL Deep Dive

Advanced11 min read
Assumes: 6.2 AAOS

Your AAOS app shows vehicle speed as zero, but the instrument cluster reads 60 km/h. Where’s the disconnect?

TL;DR

VHAL (Vehicle Hardware Abstraction Layer) is the AIDL-defined interface (android.hardware.automotive.vehicle) between Android and vehicle hardware. Data is modeled as properties: each has a VehicleProperty ID, value type, area IDs (which seat, which door), and access mode (read, write, read-write). On Qualcomm virtualized platforms, the VHAL client in AAOS talks to a VHAL server on QNX over gRPC on vsock; the server owns the actual bus connection. Adding a custom property means defining it in the HAL, implementing both client stub and server handler, and mapping it to a CAN/Ethernet signal.

VHAL is the seam where software meets the car. When speed is wrong, HVAC doesn’t respond, or a new sensor needs an Android-facing API, you’re working VHAL. It’s the most crossed boundary in your daily QNX + AAOS workflow.

Modern AAOS uses AIDL (Android Interface Definition Language) for VHAL, replacing the older HIDL interface. The canonical definition lives in AOSP: It’s the diplomatic translator between two countries that define “crash” very differently.

hardware/interfaces/automotive/vehicle/aidl/android/hardware/automotive/vehicle/

Key AIDL types:

Type Purpose
IVehicle Main HAL interface: get/set/subscribe to properties
VehiclePropValue Property ID + area ID + typed value payload
VehiclePropConfig Metadata: access mode, change mode, supported areas
SubscribeOptions Sample rate, flags for event delivery

The VHAL implementation is registered as a standard Android HAL service. Car Service binds to it at boot via IVehicle/default (or vendor-specific instance name).

Property Model: VehicleProperty, Types, Area IDs

Section titled “Property Model: VehicleProperty, Types, Area IDs”

Every piece of vehicle data is a property identified by a VehicleProperty enum value (integer constant):

PERF_VEHICLE_SPEED = 0x11600207
GEAR_SELECTION = 0x11400400
HVAC_TEMPERATURE_SET = 0x15600503
DOOR_LOCK = 0x16200001
Type AIDL Representation Example Properties
BOOLEAN boolValues Wiper on/off, trunk open
INT32 int32Values Gear enum, lock state
INT64 int64Values Odometer (large counter)
FLOAT floatValues Speed, temperature
STRING stringValue VIN, software version
BYTES byteValues Raw diagnostic payload
MIXED Multiple arrays Complex structured data

Vehicles aren’t flat. A property applies to specific areas:

Area Type Example Areas Property Example
GLOBAL (0) Whole vehicle PERF_VEHICLE_SPEED, GEAR_SELECTION
SEAT Row 1 left, Row 1 right, Row 2 HVAC_TEMPERATURE_SET per seat zone
DOOR Front left, front right, rear, hood, trunk DOOR_LOCK, DOOR_POS
WINDOW Per-window WINDOW_POS
MIRROR Left, right, center MIRROR_Z_POS
WHEEL Four corners TIRE_PRESSURE

Area IDs are encoded in the property config. When you get(PERF_VEHICLE_SPEED, areaId=0), you get global speed. When you get(HVAC_TEMPERATURE_SET, areaId=SEAT_ROW_1_LEFT), you get that zone’s target temp.

Think of each property as PID + payload type + place (area ID).

Each property declares how it can be accessed:

Access Mode Meaning Example
READ Android reads only; value originates on vehicle bus PERF_VEHICLE_SPEED, FUEL_LEVEL
WRITE Android sends commands; no read-back required One-shot actions (some OEM-specific)
READ_WRITE Android reads current state and sends set commands HVAC_TEMPERATURE_SET, DOOR_LOCK

Additionally, change mode defines update behavior:

Change Mode Behavior
STATIC Set once, rarely changes
ON_CHANGE Event pushed when value changes
CONTINUOUS Sampled at configured rate
Mental Model

VHAL properties are labeled pipes between Android and the car. Each pipe has a name tag (VehicleProperty ID), a size (value type), a destination address (area ID), and a one-way or two-way sign (access mode). Car Service is the plumber’s dispatcher — apps request water from a pipe; Car Service opens the right valve.

VHAL is the translator: car speaks CAN/SOME/IP, Android speaks AIDL properties.

Virtualized Architecture: Client ↔ Server

Section titled “Virtualized Architecture: Client ↔ Server”

On non-virtualized AAOS (older platforms), VHAL talks to vehicle hardware directly via SPI, socket CAN, or Ethernet. On Qualcomm virtualized cockpit platforms, the architecture splits:

sequenceDiagram
    participant App as AAOS App
    participant CS as Car Service
    participant VC as VHAL Client (AAOS HAL)
    participant VS as VHAL Server (QNX)
    participant GW as Bus Gateway
    participant BUS as CAN / Ethernet

    App->>CS: CarPropertyManager.get(SPEED)
    CS->>VC: IVehicle.get(PERF_VEHICLE_SPEED)
    VC->>VS: gRPC GetProperty over vsock
    VS->>GW: Read cached signal / request frame
    GW->>BUS: CAN read (or subscribe)
    BUS-->>GW: Speed frame
    GW-->>VS: Parsed value
    VS-->>VC: VehiclePropValue (float)
    VC-->>CS: Return value
    CS-->>App: Speed in m/s

    Note over VC,VS: vsock = virtual socket between VMs<br/>gRPC = serialized protobuf messages
Component Location Role
VHAL Client AAOS guest VM Implements IVehicle AIDL; forwards to server
vsock Hypervisor virtual device VM-to-VM socket; no physical network needed
gRPC Over vsock Structured RPC: Get, Set, Subscribe, property configs
VHAL Server QNX VM Owns bus connections; maps properties ↔ signals
Bus Gateway QNX process CAN/Ethernet frame routing, signal database

Why split? QNX already owns the bus gateway with deterministic timing. Duplicating bus access inside AAOS would violate isolation and create two competing CAN masters.

Common Gotcha

If you design closed-loop control through VHAL, latency will bite you. Every AAOS property read crosses VM boundary (vsock + gRPC + server dispatch). Cached/subscribed properties are fine for UI. Hard RT belongs on QNX or MCU, not across a hypervisor IPC path.

Think About It

You add a new vehicle property — seat heater level — to AAOS. What layers need to change?

Reveal Answer

Define a vendor VehicleProperty ID, add it to the VHAL server (QNX) config with area IDs (per-seat), access mode (READ_WRITE), and a gateway signal mapping. Implement Get/Set/Subscribe handlers on the server; the VHAL client in AAOS is usually a generic proxy that forwards vendor IDs unchanged. The bus gateway needs the CAN/DBC decode, and apps consume it via CarPropertyManager through Car Service — no app-layer changes unless you add car_permission gating. Verify end-to-end with adb shell dumpsys IVehicle and QNX slog2info grep for the property.

Adding a property is a cross-team integration, not a one-file change. Typical steps:

Add to vendor extension range (avoid colliding with AOSP reserved IDs):

// Vendor range: 0x2140xxxx – 0x2FFFxxxx (check OEM allocation table)
VENDOR_TRAILER_TOW_STATUS = 0x21401001

Document: type (INT32), areas (GLOBAL), access (READ), change mode (ON_CHANGE).

In the QNX VHAL server process:

  • Add property config to the config list returned at init
  • Map property ID → gateway signal (CAN signal name, scaling factor, offset)
  • Implement GetProperty handler — read from gateway cache
  • Implement Subscribe — register for signal change callbacks, push events

Usually the client is a generic proxy: it forwards all property IDs to the server without per-property code. Verify your client passes through vendor IDs (some builds filter).

Apps use standard CarPropertyManager. For OEM-only access, restrict via car_permission and signature permissions.

Terminal window
# AAOS side: read your property
adb shell dumpsys android.hardware.automotive.vehicle.IVehicle/default | grep -i trailer
# QNX side: verify gateway has the signal
slog2info -w | grep -i trailer
Signal Scaling: Raw CAN to VHAL Float

CAN signals are rarely human units. A speed signal might be raw * 0.01 km/h. VHAL expects SI units: speed in m/s.

Conversion chain: CAN raw → gateway DBC decode → engineering value → VHAL server unit conversion → AIDL float → Car Service → app.

Document scaling in the signal database. “Speed is wrong by 3.6x” usually means someone forgot km/h ↔ m/s conversion.

flowchart LR
    subgraph AAOS["AAOS Guest VM"]
        APP["Apps"]
        CAR["Car Service"]
        CLIENT["VHAL Client<br/>(AIDL IVehicle)"]
        APP --> CAR --> CLIENT
    end

    subgraph IPC["VM Boundary"]
        VSOCK["vsock"]
        GRPC["gRPC"]
        VSOCK --- GRPC
    end

    subgraph QNX["QNX Host / Safety VM"]
        SERVER["VHAL Server"]
        GW["Bus Gateway"]
        DBC["Signal Database<br/>(DBC / ARXML)"]
        SERVER --> GW --> DBC
    end

    subgraph Vehicle["Vehicle"]
        CAN["CAN Bus"]
        ETH["Automotive Ethernet"]
    end

    CLIENT <-->|"Get / Set / Subscribe"| GRPC
    GRPC <-->|"VehiclePropValue"| SERVER
    GW <--> CAN
    GW <--> ETH
Where You'll See This

Daily VHAL debug split by symptom:

Symptom Check AAOS Check QNX
Property always 0 dumpsys IVehicle, logcat VhalClient VHAL server logs, gateway signal cache
Property stale (not updating) Subscription sample rate, Car Service cache Gateway RX counters, bus silence
Set command ignored Access mode (READ-only?), permission Server Set handler, actuator path
Intermittent timeouts vsock connectivity, HAL thread blocked Server load, gateway priority

Useful logcat filters:

Terminal window
adb logcat -s VhalClient:V VehicleHal:V CAR.HAL:V

On QNX, the VHAL server process name varies by BSP. Grep slog2 for vhal, vehicle, or your OEM service name.

When integrating a new property, write the signal trace document first: CAN ID → signal name → gateway mapping → VHAL property ID → Car API constant. Future-you will thank present-you.

Connect the Dots

Module 6.1 (QNX) hosts the VHAL server and gateway. Module 6.2 (AAOS) shows how Car Service consumes VHAL. Module 6.4 (Display & Audio) uses separate HALs but the same virtualization pattern. Module 3 (Signals to Services) explains the CAN signals underneath the gateway.

  1. VHAL is AIDL: properties, not raw CAN frames, face Android.
  2. Property = ID + type + area + access mode. Know all four before debugging.
  3. Virtualized split: client in AAOS, server on QNX, gRPC over vsock between them.
  4. Custom properties: define ID, implement server mapping, verify client passthrough, test both sides.
  5. Don’t put hard RT through VHAL. It’s a display/control API, not a safety loop.

Check Your Understanding

1. In a virtualized Qualcomm cockpit platform, where does the VHAL server that owns the CAN bus connection typically run?

Recall

2. What does an area ID specify for a VHAL property?

Recall

3. An app needs to read PERF_VEHICLE_SPEED. Which access mode and change mode combination is typical?

Applied

4. Modern AAOS VHAL uses AIDL (`IVehicle`) instead of the older HIDL interface. What does this mean for integrators?

Applied

5. You add VENDOR_TRAILER_TOW_STATUS (vendor property ID 0x21401001). Gateway slog2 shows correct CAN decode, but dumpsys IVehicle returns 'property not found.' Most likely gap?

Applied

6. Engineering proposes a 5 ms closed-loop steering assist running through VHAL Get/Set over gRPC/vsock. Why is this architecturally unsound?

Synthesis

Connects to: Module 1 — Safety Isolation

Further Reading
  • Vehicle HAL (VHAL) Overview — Official AOSP introduction to the Vehicle HAL property model and how Car Service consumes vehicle data.
  • VHAL AIDL Interface Reference — AIDL-based IVehicle interface, property types, area IDs, and access modes — the spec behind every property on this page.
  • Vehicle Property Definitions (AOSP) — Canonical enum of standard VehicleProperty IDs, types, and area configurations in the AOSP source tree.
  • Car Service and Car API — How apps reach VHAL through Car Service and CarPropertyManager rather than calling the HAL directly.
  • Vendor VHAL Extensions — Guidelines for defining OEM-specific properties in the vendor ID range without colliding with AOSP reserved IDs.
  • Android HAL Interface Definition (AIDL) — Background on AIDL HAL services, including how VHAL registers as IVehicle/default.
  • gRPC Documentation — Reference for the RPC layer used between VHAL client (AAOS) and VHAL server (QNX) over vsock on virtualized platforms.