Introduction to Android Automotive VHAL Extensions
Android Automotive OS provides a robust platform for in-vehicle infotainment and control. At its core, the Vehicle Hardware Abstraction Layer (VHAL) serves as the primary interface between Android services and the vehicle’s underlying hardware. The VHAL defines a set of standard vehicle properties, such as speed, gear, and HVAC settings, which applications can access. However, modern vehicles often feature unique functionalities not covered by these standard properties. This is where custom VHAL extensions become indispensable, allowing OEMs and developers to expose proprietary vehicle data or control unique hardware features directly to the Android Automotive stack.
This guide delves into the process of developing custom VHAL extensions, providing a step-by-step approach from defining new properties to implementing their behavior within the VHAL service. Understanding this process is crucial for creating highly integrated and feature-rich Android Automotive experiences that leverage the full potential of vehicle-specific hardware.
Understanding the VHAL Architecture
The VHAL operates on a client-server model. Android services act as clients, requesting or subscribing to vehicle properties, while the VHAL implementation (typically running as a separate native service) interacts with the vehicle’s actual hardware via a vendor-specific interface (e.g., CAN bus, Ethernet, or proprietary APIs). Key components include:
- Vehicle Properties: Defined by a unique integer ID, type (e.g., INT32, FLOAT), access permissions (read/write), and change mode (e.g., ON_CHANGE, CONTINUOUS).
- HIDL (HAL Interface Definition Language): Used to define the interfaces between Android framework and HAL implementations. For VHAL, this is primarily
hardware/interfaces/automotive/vehicle/2.0/IVehicle.haland related files. - VHAL Service: The native C++ implementation that provides the actual logic for getting and setting property values.
Why Extend VHAL? Use Cases for Custom Properties
Extending the VHAL is necessary when a vehicle has unique features or data that the standard VHAL properties do not cover. Common use cases include:
- Proprietary HVAC Zones: Vehicles with more granular climate control than standard definitions.
- Custom Lighting Controls: Ambient lighting, specific exterior lights not covered by standard properties.
- Advanced Driver-Assistance Systems (ADAS) Data: Exposing sensor data or control parameters for custom ADAS features.
- Unique Powertrain Metrics: Specific engine or battery performance metrics.
- Specialized Actuators: Controlling unique vehicle components like custom aerodynamic elements or specific accessory power outlets.
Defining Your Custom VHAL Property (HIDL)
The first step is to define your custom property using HIDL. This involves modifying existing VHAL definition files or creating new ones within the appropriate namespace.
1. Identify a Property ID Range
Custom properties must use a specific ID range to avoid conflicts with standard properties. OEM-defined properties typically reside in the range 0x2000 to 0x2FFF. Let’s define a custom property for a ‘Custom Heating Zone Temperature’.
2. Modify types.hal
Navigate to hardware/interfaces/automotive/vehicle/2.0/types.hal. Here, you’ll add your new property ID and any custom enums or structs it might require. For our example, we’ll add a simple integer property:
// hardware/interfaces/automotive/vehicle/2.0/types.hal
...
enum VehicleProperty: int32 {
...
// OEM-defined properties start from 0x2000
CUSTOM_HEATING_ZONE_TEMPERATURE = 0x2000 | VehiclePropertyType.INT32 | VehiclePropertyArea.ZONE_HVAC | VehiclePropertyChangeMode.ON_CHANGE,
// Define other custom properties here
...
};
...
In this definition:
0x2000is our chosen base ID.VehiclePropertyType.INT32indicates it’s an integer property.VehiclePropertyArea.ZONE_HVACspecifies it relates to a specific HVAC zone.VehiclePropertyChangeMode.ON_CHANGEmeans the property value is only broadcast when it changes.
3. (Optional) Define Custom Structures or Enums
If your property requires more complex data types, define them in types.hal or a new `.hal` file and import it. For example:
// hardware/interfaces/automotive/vehicle/2.0/types.hal
...
enum CustomHeatingZoneId: int32 {
FRONT_LEFT = 0x01,
FRONT_RIGHT = 0x02,
REAR_LEFT = 0x04,
REAR_RIGHT = 0x08,
};
...
Implementing the Custom Property (C++)
After defining the property in HIDL, the next step is to implement its behavior in the VHAL service. This typically involves modifying the default VHAL implementation.
1. Locate the VHAL Implementation
The primary VHAL implementation resides in hardware/interfaces/automotive/vehicle/2.0/default/VehicleHal.cpp or a similar vendor-specific directory. This file contains the logic for handling `get` and `set` requests for vehicle properties.
2. Declare the Custom Property
You need to add your custom property to the list of supported properties that the VHAL service reports. This is usually done in a function like `getAllProperties()` or a similar initializer.
// hardware/interfaces/automotive/vehicle/2.0/default/VehicleHal.cpp
...
std::vector VehicleHal::getAllProperties() const {
std::vector properties = {
// Standard properties
{
.property = VehicleProperty::HVAC_FAN_SPEED,
.access = VehiclePropertyAccess::READ_WRITE,
.changeMode = VehiclePropertyChangeMode::ON_CHANGE,
.area = VehiclePropertyArea::ZONE_HVAC,
.minStreamRate = 0.0f,
.maxStreamRate = 0.0f,
.configFlags = 0,
.configArray = {},
.initialAreaValues = {},
},
// Custom property
{
.property = VehicleProperty::CUSTOM_HEATING_ZONE_TEMPERATURE,
.access = VehiclePropertyAccess::READ_WRITE,
.changeMode = VehiclePropertyChangeMode::ON_CHANGE,
.area = VehiclePropertyArea::ZONE_HVAC,
.minStreamRate = 0.0f,
.maxStreamRate = 0.0f,
.configFlags = 0,
.configArray = {
static_cast(CustomHeatingZoneId::FRONT_LEFT),
static_cast(CustomHeatingZoneId::FRONT_RIGHT)
},
.initialAreaValues = {},
},
// ... other properties
};
return properties;
}
...
Here, `configArray` specifies the supported areas for our custom property, mapping to `CustomHeatingZoneId` from our `types.hal` modification.
3. Implement Get and Set Logic
You’ll need to modify the `get` and `set` methods (e.g., `handleSetProperty` and `handleGetProperty`) in `VehicleHal.cpp` to properly handle your new custom property. These methods will interact with the actual vehicle hardware to read or write the value.
// hardware/interfaces/automotive/vehicle/2.0/default/VehicleHal.cpp
...
// Example storage for custom property values
std::map mCustomHeatingZoneTemperatures;
void VehicleHal::handleSetProperty(const VehiclePropValue& value) {
// ... handle standard properties ...
if (value.prop == VehicleProperty::CUSTOM_HEATING_ZONE_TEMPERATURE) {
if (value.areaId == static_cast(CustomHeatingZoneId::FRONT_LEFT)) {
mCustomHeatingZoneTemperatures[value.areaId] = value.value.int32Values[0];
// Simulate hardware interaction or send to CAN bus
ALOGI("Set custom heating zone FRONT_LEFT to %d", value.value.int32Values[0]);
// Report the change back to subscribers (important for ON_CHANGE properties)
onPropertyEvent({value});
} else if (value.areaId == static_cast(CustomHeatingZoneId::FRONT_RIGHT)) {
mCustomHeatingZoneTemperatures[value.areaId] = value.value.int32Values[0];
ALOGI("Set custom heating zone FRONT_RIGHT to %d", value.value.int32Values[0]);
onPropertyEvent({value});
} else {
ALOGE("Unsupported areaId for CUSTOM_HEATING_ZONE_TEMPERATURE: %d", value.areaId);
}
return;
}
// ...
}
VehiclePropValue VehicleHal::handleGetProperty(const VehiclePropValue& requestedValue) {
VehiclePropValue value = requestedValue;
value.status = VehiclePropertyStatus::AVAILABLE;
// ... handle standard properties ...
if (requestedValue.prop == VehicleProperty::CUSTOM_HEATING_ZONE_TEMPERATURE) {
if (requestedValue.areaId == static_cast(CustomHeatingZoneId::FRONT_LEFT)) {
value.value.int32Values.push_back(mCustomHeatingZoneTemperatures[requestedValue.areaId]);
} else if (requestedValue.areaId == static_cast(CustomHeatingZoneId::FRONT_RIGHT)) {
value.value.int32Values.push_back(mCustomHeatingZoneTemperatures[requestedValue.areaId]);
} else {
ALOGE("Unsupported areaId for CUSTOM_HEATING_ZONE_TEMPERATURE: %d", requestedValue.areaId);
value.status = VehiclePropertyStatus::NOT_AVAILABLE;
}
return value;
}
// ...
return value;
}
...
In a real-world scenario, the `ALOGI` statements would be replaced by calls to a hardware interface layer (e.g., a CAN bus driver or a proprietary HAL). The `onPropertyEvent()` call is crucial for `ON_CHANGE` properties, notifying all subscribed clients about the change.
Building and Integrating the Custom VHAL Module
Once your HIDL definitions and C++ implementation are complete, you need to build the Android Automotive OS with your changes.
1. Modify Android.bp (or Android.mk)
Ensure that your modified VHAL service is correctly built as part of the Android system. If you created new `.hal` files, you might need to add them to the `hidl_interface` definitions. For modifications to `default/VehicleHal.cpp`, the existing build rules should suffice.
// Example modification in a relevant Android.bp file
hidl_interface {
name: "[email protected]",
...
srcs: [
"IVehicle.hal",
"IVehicleCallback.hal",
"types.hal",
// If you created a new .hal file for custom types, add it here
// "my_custom_vehicle_types.hal",
],
...
}
2. Build Android Automotive OS
Navigate to your Android source root and initiate a full build. This will compile your VHAL changes into the system image.
source build/envsetup.sh
lunch aosp_car-userdebug # Or your specific device target
make -j$(nproc)
This process can take a significant amount of time, depending on your system’s resources.
Deploying and Testing Your Custom VHAL Extension
After a successful build, the next steps involve deploying the new system image and verifying the custom property’s functionality.
1. Flash the Device/Emulator
Flash the newly built Android Automotive OS image to your target hardware device or emulator.
adb reboot bootloader
fastboot flashall -w
2. Verify Property Existence
Once the device boots, you can use `adb shell` to interact with the VHAL service and verify that your custom property is recognized.
adb shell cmd vehicle list properties
Look for `0x2000` or `CUSTOM_HEATING_ZONE_TEMPERATURE` in the output. If found, your HIDL definition and declaration were successful.
3. Test Get and Set Operations
Use `adb shell cmd vehicle` to test setting and getting your custom property. Remember to specify the `areaId` if your property is area-specific.
# Set custom heating zone FRONT_LEFT temperature to 25 degrees
adb shell cmd vehicle set 0x2000 25 --area-id 0x01
# Get custom heating zone FRONT_LEFT temperature
adb shell cmd vehicle get 0x2000 --area-id 0x01
You should see the value `25` returned if the `set` operation was successful and the `get` logic is correctly implemented. Monitor `logcat` for any errors from the `vehicle-hal-service` process.
Conclusion
Developing custom VHAL extensions is a critical skill for anyone building specialized Android Automotive experiences. By following these steps – from defining properties in HIDL to implementing their C++ logic and finally building and testing – you can effectively bridge the gap between Android and unique vehicle hardware. This capability unlocks a vast array of possibilities, allowing for the creation of truly integrated and innovative in-car applications that leverage the full potential of modern vehicle platforms.
Android Mobile Specs & Compare Directory
Are you researching mobile hardware properties, processor SoCs, GPU chipsets, or RAM configurations? Access our complete specs catalog to compare up to 5 devices side-by-side!
Compare Devices Specs →