Android IoT, Automotive, & Smart TV Customizations

Mastering Custom VHAL: A Step-by-Step Guide to Implementing New Android Automotive Properties

Google AdSense Native Placement - Horizontal Top-Post banner

Introduction

Android Automotive OS (AAOS) provides a robust platform for in-vehicle infotainment systems. At its core, the Vehicle Hardware Abstraction Layer (VHAL) serves as the primary interface between the Android framework and the underlying vehicle hardware. While VHAL defines a comprehensive set of standard vehicle properties, automotive OEMs often require custom properties to expose unique vehicle functionalities or sensor data to Android applications. This guide provides an expert-level, step-by-step walkthrough on how to define, implement, and expose a custom VHAL property, enabling powerful new interactions with your vehicle’s hardware.

We will focus on creating a hypothetical custom property: VEHICLE_PROPERTY_CUSTOM_ENGINE_TEMPERATURE, a read-only float property representing the engine temperature from a custom sensor.

Understanding VHAL Architecture

Before diving into implementation, it’s crucial to grasp VHAL’s architecture. VHAL is a HAL (Hardware Abstraction Layer) module that exposes vehicle properties through an interface defined in AIDL or HIDL. The Android Framework’s CarService interacts with the VHAL implementation, providing a consistent API for apps via CarPropertyManager. Properties are identified by unique integer IDs, data types, and access permissions.

  • CarService: Android framework service managing vehicle interaction.
  • CarPropertyManager: Java API for apps to access vehicle properties.
  • VHAL Interface (e.g., IVehicle.hal): Defines the contract between CarService and VHAL implementation.
  • VHAL Implementation (e.g., DefaultVehicleHal.cpp): OEM-specific code that interfaces with actual hardware.

Defining Your Custom Property

The first step is to define your custom property within the VHAL specification. Custom properties must use vendor-specific IDs to avoid conflicts with standard Android properties. The recommended range for vendor properties is 0x2000 through 0x2000 + 0xFFFF - 1 for vendor properties in the `VEHICLE_PROPERTY_VENDOR_EXTENSION_START` range (or 0x10000000 for direct OEM properties using `VEHICLE_PROPERTY_OEM_EXTENSION_START`).

1. Choose a Unique Property ID

Let’s define our custom engine temperature property ID:

// hardware/interfaces/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehiclePropertyUtils.h or a new vendor-specific header
enum VehicleProperty : int32_t {
// ... existing properties ...

// Custom Vendor Properties (start from a unique offset)
VEHICLE_PROPERTY_CUSTOM_ENGINE_TEMPERATURE = 0x2100,
// Or using the OEM extension range:
// VEHICLE_PROPERTY_OEM_ENGINE_TEMPERATURE = 0x10000000 + 0x0001,
};

It’s generally safer to define these in a custom header file or append them to a suitable vendor-specific definition file if your VHAL implementation is already separate from AOSP defaults.

2. Define Property Metadata

Next, we need to provide metadata for our property. This includes its data type, access mode, change mode, and potentially an initial value. We’ll add this to the VHAL implementation’s property list, typically found in DefaultVehicleHal.cpp or a similar file.

// hardware/interfaces/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultVehicleHal.cpp
const std::vector<VehiclePropConfig> DefaultVehicleHal::getAllPropertyConfigs() {
std::vector<VehiclePropConfig> configs = {
// ... existing property configs ...

// Our custom property
{
.prop = VEHICLE_PROPERTY_CUSTOM_ENGINE_TEMPERATURE,
.access = VehiclePropertyAccess::READ,
.changeMode = VehiclePropertyChangeMode::ON_CHANGE,
.valueType = VehiclePropertyType::FLOAT,
.areaType = VehicleAreaType::GLOBAL,
.minSampleRate = 1.0F, // Sample rate in Hz
.maxSampleRate = 10.0F,
},
};
return configs;
}

Here:

  • prop: Our custom property ID.
  • access: READ (read-only from CarService).
  • changeMode: ON_CHANGE (events are sent only when the value changes).
  • valueType: FLOAT.
  • areaType: GLOBAL (applies to the entire vehicle).
  • minSampleRate/maxSampleRate: Define the acceptable range for event subscription rates.

Implementing the Custom Property in VHAL

Now, we’ll implement the logic to handle read requests for our new property. This involves modifying the VHAL’s get and set methods (though for a read-only property, set won’t do anything). We also need a mechanism to generate ON_CHANGE events.

1. Modify VHAL Getters and Setters

Within your VHAL implementation (e.g., DefaultVehicleHal::get and DefaultVehicleHal::set), add handling for your custom property ID.

// hardware/interfaces/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultVehicleHal.cpp
StatusCode DefaultVehicleHal::get(const VehiclePropValue& request, VehiclePropValue* output) {
switch (request.prop) {
case toInt(VehicleProperty::VEHICLE_PROPERTY_CUSTOM_ENGINE_TEMPERATURE):
// Simulate reading from a hardware sensor
output->prop = request.prop;
output->timestamp = elapsedRealtimeNano();
output->value.floatValues.push_back(mEngineTemperatureSensor.readTemperature());
return StatusCode::OK;
// ... existing properties ...
default:
// Handle other properties or return NOT_AVAILABLE/NOT_SUPPORTED
return StatusCode::NOT_AVAILABLE;
}
}

StatusCode DefaultVehicleHal::set(const VehiclePropValue& request) {
switch (request.prop) {
case toInt(VehicleProperty::VEHICLE_PROPERTY_CUSTOM_ENGINE_TEMPERATURE):
// This is a read-only property, so setting is not allowed
return StatusCode::ACCESS_DENIED;
// ... existing properties ...
default:
return StatusCode::NOT_AVAILABLE;
}
}

You’ll need to define mEngineTemperatureSensor.readTemperature() to simulate or actually read from your hardware.

2. Implement Event Reporting

For ON_CHANGE properties, the VHAL implementation is responsible for detecting changes and pushing events to CarService. This typically involves a background thread or a hardware interrupt handler that periodically checks the sensor value.

// Example of a simplified polling mechanism within DefaultVehicleHal.cpp
void DefaultVehicleHal::startEngineTempMonitor() {
mEngineTempPollingThread = std::thread([this]() {
float lastReportedTemp = 0.0F;
while (mIsRunning) {
// Simulate reading from hardware sensor
float currentTemp = mEngineTemperatureSensor.readTemperature();

if (std::abs(currentTemp - lastReportedTemp) > 0.1F) { // Threshold for change
VehiclePropValue propValue{};
propValue.prop = toInt(VehicleProperty::VEHICLE_PROPERTY_CUSTOM_ENGINE_TEMPERATURE);
propValue.timestamp = elapsedRealtimeNano();
propValue.value.floatValues.push_back(currentTemp);

// Send event to CarService
mEventCallback->onPropertyEvent({propValue});
lastReportedTemp = currentTemp;
}
std::this_thread::sleep_for(std::chrono::milliseconds(100)); // Poll every 100ms
}
});
}

// In DefaultVehicleHal constructor, call startEngineTempMonitor()
// In DefaultVehicleHal destructor or on shutdown, join the thread and set mIsRunning to false.

Exposing to CarService (Java Layer)

Now that the VHAL can handle your custom property, you need to make it accessible to Android applications through the Java framework.

1. Define Java Constants for Property IDs

Create a new Java class or extend an existing one (e.g., CarPropertyIds or a custom VendorCarPropertyIds) to hold your custom property ID. This class should reside within your vendor’s Android framework extensions.

// frameworks/base/packages/Car/service/src/com/android/car/CarPropertyIds.java (or similar vendor file)
package com.android.car;

public final class CarPropertyIds {
// ... existing property IDs ...

/**
* Custom Engine Temperature property. Float, read-only.
* Range: Vendor property (0x2100).
*/
@SystemApi
public static final @VehiclePropertyConfig.VehiclePropertyType int CUSTOM_ENGINE_TEMPERATURE = 0x2100;

private CarPropertyIds() {}
}

Use @SystemApi to make it available to system apps and privileged apps.

2. Accessing from an Android Application

Applications can now use CarPropertyManager to interact with your custom property, just like any standard property.

// An Android application example
import android.car.Car;
import android.car.VehiclePropertyIds;
import android.car.hardware.CarPropertyConfig;
import android.car.hardware.CarPropertyManager;
import android.car.hardware.CarPropertyValue;
import android.content.Context;

public class CustomVehicleApp {

private Car mCar;
private CarPropertyManager mCarPropertyManager;
private static final String TAG =

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 →
Google AdSense Inline Placement - Content Footer banner