Back to Technology

Embedded Systems Series Part 10: Android HAL & Native Development

January 25, 2026 Wasil Zafar 60 min read

Master Android HAL and native development—HIDL/AIDL interfaces, HAL implementation, NDK programming, and JNI bindings.

Table of Contents

  1. Introduction to Android HAL
  2. HAL Evolution (Legacy to Treble)
  3. HIDL Interface Definition
  4. AIDL for HAL (Android 11+)
  5. HAL Implementation
  6. NDK Programming
  7. JNI Bindings
  8. Native Service Development
  9. Debugging HAL & Native Code
  10. Conclusion & Next Steps

Introduction to Android HAL

Series Navigation: This is Part 10 of the 12-part Embedded Systems Series. Review Part 9: Android System Architecture first.

The Hardware Abstraction Layer (HAL) bridges Android framework and kernel drivers. HALs define standardized interfaces—OEMs implement vendor-specific code while Android remains hardware-agnostic.

HAL Evolution (Legacy to Treble)

HAL Architecture Evolution

  • Legacy HAL (pre-8.0): .so libraries loaded into framework process
  • Treble/HIDL (8.0-10): Separate HAL processes, binderized IPC
  • AIDL HAL (11+): Unified AIDL for both framework and HAL
# HAL locations
/vendor/lib/hw/           # Legacy HAL .so files
/vendor/bin/hw/           # HIDL HAL services
/vendor/lib64/            # 64-bit HAL libraries

# HAL manifest (device capabilities)
/vendor/etc/vintf/manifest.xml

HIDL Interface Definition

HIDL (HAL Interface Definition Language) defines versioned, stable interfaces.

// hardware/interfaces/sensors/2.0/ISensors.hal
package android.hardware.sensors@2.0;

interface ISensors {
    getSensorsList() generates (vec<SensorInfo> list);
    activate(int32_t sensorHandle, bool enabled) generates (Result result);
    poll(int32_t maxCount) generates (vec<Event> events);
};

// Generate C++ from HIDL
hidl-gen -o output -L c++-impl \
    android.hardware.sensors@2.0

AIDL for HAL (Android 11+)

// hardware/interfaces/vibrator/aidl/android/hardware/vibrator/IVibrator.aidl
package android.hardware.vibrator;

@VintfStability
interface IVibrator {
    void on(int timeoutMs);
    void off();
    boolean supportsAmplitudeControl();
    void setAmplitude(int amplitude);
}

HAL Implementation

// Vibrator HAL implementation
#include <aidl/android/hardware/vibrator/BnVibrator.h>

using aidl::android::hardware::vibrator::BnVibrator;

class Vibrator : public BnVibrator {
public:
    ndk::ScopedAStatus on(int32_t timeoutMs) override {
        // Write to kernel driver
        write_to_sysfs("/sys/class/leds/vibrator/state", "1");
        write_to_sysfs("/sys/class/leds/vibrator/duration", timeoutMs);
        return ndk::ScopedAStatus::ok();
    }

    ndk::ScopedAStatus off() override {
        write_to_sysfs("/sys/class/leds/vibrator/state", "0");
        return ndk::ScopedAStatus::ok();
    }
};

NDK Programming

The NDK (Native Development Kit) enables C/C++ code in Android apps for performance-critical operations.

// native-lib.cpp
#include <jni.h>
#include <string>

extern "C" JNIEXPORT jstring JNICALL
Java_com_example_app_MainActivity_stringFromJNI(
    JNIEnv* env, jobject /* this */) {
    std::string hello = "Hello from C++";
    return env->NewStringUTF(hello.c_str());
}
# CMakeLists.txt
cmake_minimum_required(VERSION 3.10)
add_library(native-lib SHARED native-lib.cpp)
find_library(log-lib log)
target_link_libraries(native-lib ${log-lib})

JNI Bindings

// Java side
public class MainActivity extends Activity {
    static {
        System.loadLibrary("native-lib");
    }

    public native String stringFromJNI();
    public native int calculate(int a, int b);
    public native void processArray(int[] data);
}
// C++ JNI implementation
extern "C" JNIEXPORT jint JNICALL
Java_com_example_app_MainActivity_calculate(
    JNIEnv* env, jobject obj, jint a, jint b) {
    return a + b;
}

extern "C" JNIEXPORT void JNICALL
Java_com_example_app_MainActivity_processArray(
    JNIEnv* env, jobject obj, jintArray arr) {
    jint* data = env->GetIntArrayElements(arr, nullptr);
    jsize len = env->GetArrayLength(arr);
    
    for (int i = 0; i < len; i++) {
        data[i] *= 2;  // Process array
    }
    
    env->ReleaseIntArrayElements(arr, data, 0);
}

Native Service Development

// Native service main
#include <binder/ProcessState.h>
#include <binder/IServiceManager.h>

int main() {
    android::ProcessState::self()->startThreadPool();
    
    sp<MyService> service = new MyService();
    defaultServiceManager()->addService(
        String16("my_native_service"), service);
    
    android::IPCThreadState::self()->joinThreadPool();
    return 0;
}

Debugging HAL & Native Code

# List HAL services
lshal                    # List all HAL services
dumpsys hwservicemanager

# Native debugging
adb shell gdbserver64 :5039 /vendor/bin/hw/my_hal
adb forward tcp:5039 tcp:5039
arm-linux-gnueabihf-gdb
(gdb) target remote :5039

# Logcat for native
adb logcat -s "MY_HAL"
__android_log_print(ANDROID_LOG_INFO, "MY_HAL", "msg");

Conclusion & What's Next

You've learned Android HAL development—HIDL/AIDL interfaces, HAL implementation, NDK native programming, and JNI bindings. These skills enable custom hardware integration in Android.

Key Takeaways:
  • HAL bridges Android framework and kernel drivers
  • AIDL for HAL is the modern approach (Android 11+)
  • NDK enables C/C++ for performance-critical code
  • JNI bridges Java and native code

In Part 11, we'll explore Android BSP & Kernel—building board support packages and integrating custom kernels.

Next Steps

Technology