Android IoT, Automotive, & Smart TV Customizations

Extending Vehicle HAL in AAOS: A Practical Guide to Integrating Custom OEM Vehicle Properties into AOSP

Google AdSense Native Placement - Horizontal Top-Post banner

Extending Vehicle HAL in AAOS: A Practical Guide to Integrating Custom OEM Vehicle Properties into AOSP

Android Automotive OS (AAOS) provides a robust platform for in-vehicle infotainment and telematics. At its core, the Vehicle Hardware Abstraction Layer (VHAL) serves as the primary interface between Android services and the vehicle’s underlying hardware. While AAOS offers a comprehensive set of standard vehicle properties, original equipment manufacturers (OEMs) often require custom properties to expose unique vehicle functionalities or sensor data to the Android framework. This guide provides a practical, step-by-step approach to extending the VHAL to integrate such custom OEM vehicle properties directly into your AOSP build.

Understanding the Vehicle HAL Architecture

The VHAL defines the interface for interacting with vehicle properties, such as speed, gear, HVAC settings, and more. It is built around the IVehicle interface, which exposes methods like get, set, and subscribe to vehicle properties. Each property is identified by a unique ID and has an associated type (e.g., INT32, FLOAT, BYTE_ARRAY) and access permissions. OEMs are allocated a specific range of property IDs (OEM_PROPERTY_ID_BASE to OEM_PROPERTY_ID_MAX) to avoid conflicts with standard AOSP properties.

The core components involved in extending VHAL include:

  • types.hal (or types.aidl for AIDL VHAL): Defines vehicle property IDs, types, and enumerations.
  • VehicleHal.cpp / VehiclePropertyStore.cpp: Implements the VHAL interface, handling read/write operations for properties.
  • CarService: The Android framework service that interacts with the VHAL.
  • CarPropertyManager: The API used by Android applications to access vehicle properties.

Defining Your Custom OEM Vehicle Property

Let’s define a hypothetical custom property: OEM_DRIVING_MODE, which could represent an OEM-specific driving profile (e.g., ‘EcoPro’, ‘Sport+’, ‘Offroad’).

1. Choose a Property ID

OEM custom properties typically start from VEHICLE_PROPERTY_OEM_BASE. We’ll use an offset from this base.

// In hardware/interfaces/automotive/vehicle/2.0/types.hal or similar C++ header for VHAL properties
enum VehicleProperty : int32_t {
    ...
    // OEM properties start from 0x20000000
    OEM_PROPERTY_ID_BASE = 0x20000000,

    // Custom OEM Driving Mode property (e.g., 0x20000001)
    OEM_DRIVING_MODE = OEM_PROPERTY_ID_BASE + 0x0001,
    ...
};

enum OemDrivingMode : int32_t {
    OEM_DRIVING_MODE_DEFAULT = 0,
    OEM_DRIVING_MODE_ECOPRO = 1,
    OEM_DRIVING_MODE_SPORT_PLUS = 2,
    OEM_DRIVING_MODE_OFFROAD = 3,
    OEM_DRIVING_MODE_CUSTOM = 4,
};

2. Define Property Configuration

Each property requires a configuration that specifies its type, access permissions, change mode, and area type. For OEM_DRIVING_MODE, it would be an INT32, read/write, on-change property, and global (non-zoned).

Implementing the Custom Property in VHAL

This involves modifying the VHAL implementation, typically located in packages/services/Car/vehicled/src/ or a custom OEM VHAL module.

1. Add Property to Supported List

Locate the VehiclePropertyStore.cpp or your custom VHAL’s implementation of getSupportedProperties(). You’ll need to add a new VehiclePropConfig entry for your custom property.

// In VehiclePropertyStore.cpp or your VHAL's supported properties definition
#include <android/hardware/automotive/vehicle/2.0/types.h>
using namespace android::hardware::automotive::vehicle::V2_0;

...

std::vector<VehiclePropConfig> VehiclePropertyStore::getSupportedProperties() const {
    std::vector<VehiclePropConfig> configs = {
        // Existing standard properties...

        // Custom OEM_DRIVING_MODE property
        {
            .prop = static_cast<int32_t>(VehicleProperty::OEM_DRIVING_MODE),
            .access = VehiclePropertyAccess::READ_WRITE,
            .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
            .valueType = VehiclePropertyType::INT32,
            .areaType = VehicleArea::GLOBAL,
            .minSampleRate = 0.0f,
            .maxSampleRate = 0.0f,
            .configFlags = 0,
            .configArray = {},
            .vendorExtension = 0,
        },
        // ... other properties
    };
    return configs;
}

2. Implement Get and Set Handlers

Within the VHAL implementation (e.g., VehicleHal.cpp or a dedicated handler class), you need to provide logic for reading and writing the property. For simulation, you might use an in-memory variable; for real hardware, you’d interface with the vehicle’s ECUs.

// Example: In VehicleHal.cpp or a custom property handler class

// Member variable to store the current driving mode
int32_t mOemDrivingMode = OemDrivingMode::OEM_DRIVING_MODE_DEFAULT;

// Implement the getProperty handler
VehiclePropValue VehicleHal::getProperty(const VehiclePropValue& request) {
    VehiclePropValue value = request; // Start with the request for common fields
    value.status = VehiclePropertyStatus::AVAILABLE;
    value.timestamp = elapsedRealtimeNano();

    switch (request.prop) {
        case static_cast<int32_t>(VehicleProperty::OEM_DRIVING_MODE):
            value.value.int32Values[0] = mOemDrivingMode;
            break;
        // ... handle other properties
        default:
            value.status = VehiclePropertyStatus::NOT_AVAILABLE;
            // Log error
            break;
    }
    return value;
}

// Implement the setProperty handler
void VehicleHal::setProperty(const VehiclePropValue& request) {
    if (request.status != VehiclePropertyStatus::AVAILABLE) {
        // Handle error
        return;
    }

    switch (request.prop) {
        case static_cast<int32_t>(VehicleProperty::OEM_DRIVING_MODE):
            if (request.value.int32Values.size() > 0) {
                int32_t newMode = request.value.int32Values[0];
                // Validate newMode if necessary
                mOemDrivingMode = newMode;
                // Optionally, notify subscribers of the change
                // mPropertyEventCallback->onPropertyEvent({&request});
            }
            break;
        // ... handle other properties
    }
}

Integrating into the Android Framework (Optional but Recommended)

While the VHAL handles the low-level communication, exposing this property conveniently to Android applications often involves the CarService and CarPropertyManager.

1. Define Custom Permissions (if needed)

For sensitive OEM properties, you might want to define a custom permission.


<permission name="com.oem.permission.ACCESS_OEM_DRIVING_MODE"
    android:protectionLevel="signature|privileged" /
>

2. Accessing from an Android Application

An Android application can access this property using CarPropertyManager. The application would need to declare the necessary permission in its AndroidManifest.xml.

// Example: Android App accessing OEM_DRIVING_MODE
import android.car.Car;
import android.car.hardware.property.CarPropertyManager;

public class OemCarManager {
    private Car mCar;
    private CarPropertyManager mCarPropertyManager;
    private static final int OEM_DRIVING_MODE_PROPERTY_ID = 0x20000001; // Your custom ID

    public OemCarManager(Context context) {
        mCar = Car.createCar(context, null);
        mCarPropertyManager = (CarPropertyManager) mCar.getCarManager(Car.PROPERTY_SERVICE);
    }

    public int getOemDrivingMode() {
        if (mCarPropertyManager != null) {
            return mCarPropertyManager.getIntProperty(OEM_DRIVING_MODE_PROPERTY_ID, 0); // global area
        }
        return -1; // Error or default
    }

    public void setOemDrivingMode(int mode) {
        if (mCarPropertyManager != null) {
            mCarPropertyManager.setIntProperty(OEM_DRIVING_MODE_PROPERTY_ID, 0, mode);
        }
    }

    public void registerDrivingModeListener(CarPropertyManager.CarPropertyEventCallback callback) {
        if (mCarPropertyManager != null) {
            mCarPropertyManager.registerCallback(callback, OEM_DRIVING_MODE_PROPERTY_ID, CarPropertyManager.SENSOR_RATE_ONCHANGE);
        }
    }
}

Building and Testing Your AOSP Image

1. Recompile AOSP

After making changes to the VHAL, you must recompile your AOSP image. Navigate to your AOSP root directory and run:

source build/envsetup.sh
lunch <your_target>  # e.g., aosp_car_x86_64-userdebug
m <your_vhal_module_name> # if your VHAL is a separate module
mma -j$(nproc) # build everything if changes are widespread

Then flash the new image to your target device or emulator.

2. Verify with vehicledemo or ADB Shell

You can use the vehicledemo application (available in AOSP) or adb shell cmd car_service to inspect or interact with vehicle properties.

# List supported properties (look for your OEM_DRIVING_MODE ID)
adb shell cmd car_service list_properties

# Get the current value of your OEM_DRIVING_MODE
adb shell cmd car_service get_property 0x20000001

# Set the value of your OEM_DRIVING_MODE to SPORT_PLUS (2)
adb shell cmd car_service set_property 0x20000001 2

# Get it again to confirm
adb shell cmd car_service get_property 0x20000001

These commands allow you to directly interact with the VHAL through CarService, confirming your property is correctly registered and its handlers are functional.

Conclusion

Extending the Vehicle HAL in AAOS to include custom OEM properties is a fundamental step for tailoring the Android Automotive experience to specific vehicle platforms. By carefully defining property IDs, implementing the necessary VHAL handlers, and optionally integrating with the Android framework, OEMs can seamlessly expose unique vehicle functionalities to the Android ecosystem. This robust mechanism ensures that custom hardware features are not only accessible but also maintain the high standards of performance and security expected from AAOS.

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