Implementing Custom Hardware Abstraction Layer (HAL) in Android with AIDL

ABOUT THE AUTHOR

Aakruti Saini
Aakruti Saini
Aakruti specializes in Qualcomm-based chipsets and possesses comprehensive knowledge of the entire Android stack, from Framework to HAL and Linux Kernel. She has a deep understanding of Android System UI and the Audio stack, with extensive experience in developing and debugging across these areas.

To know more – Click Here

A use of AIDL (Android Interface Definition Language) for a Custom Hardware Abstraction Layer (HAL) in Android allows developers to adjust interactions with the hardware according to the peculiarities of an application. With the assistance of AIDL, the developers have the possibility to create distinct links regarding the Android framework and device hardware, which eliminates the possibility of conflict and contributes to more efficient functioning. Besides, this approach contributes to the improvement of the flexibility of further development and the formation of the sets of optimized solutions regarding Android gadgets.

Overview of the Android Open-Source System Platform (AOSP)

The Android Open-Source Platform (AOSP) is built on the Linux kernel and other open-source components, each functioning as a module to create specific layers of functionality. This modular structure allows for extensive customization, enabling device manufacturers and app developers to integrate unique features and functionalities. Over time, the Android architecture has undergone significant changes and continues to evolve with contributions from companies and open-source developers.

Adding a Custom AIDL HAL to the Android Stack

To integrate a new custom AIDL HAL into the Android stack, it is crucial to comprehend the AOSP layers and the way a custom HAL may correspond with the rest of the stack. The next diagram represents the AOSP stack, where each layer is presented, as well as the moment of integration of the tested custom HAL along with the existing ones.

Implementing Custom Hardware Abstraction Layer (HAL) in Android with AIDL

Modularization and Evolution of HAL in Android

Android Hardware Abstraction Layer (HAL) is acculturation that relaxed the Android working structure by interfacing it with device’s firmware to expose fixed components like camera, GPS and Sensors. The HAL redefines configuration of all the hardware minutiae that the operating system interfaces with in simple interfaces that are easy to manage. This abstraction allows such manufacturers to implement their own HAL in ways that correspond to their own hardware along with the Android OS.

In Android 8. 0, also called Project Treble, the HAL layers were redesigned to be modular. Since Android Oreo (8. 0), HIDL (Hardware Interface Definition Language) HALs are fundamental to the system. HIDL was presented as a successor of the interface definition language which was employed for the hardware interactions in the framework of the Android Open Sources Project.

Originally, Android Interface Definition Language or AIDL was launched in Android 1. 0 for interprocess communication (IPC) within the context of the Android application framework. Beginning from Android 11, HALs that are implemented in AIDL are also supported, with all AIDL HALs being binderized.

Since Android 13 version, HIDL HAL is deprecated and higher version allows to add new HAL in AIDL only Overall, it can be noted that AIDL HAL is more stable and hence is the most favored for the task of hardware abstraction.

Analyzing the LED demo, it is possible to investigate how to add a custom AIDL HAL to drive the LED in Android 13 and how it communicates with other components of the AOSP stage.

Adopting Stable AIDL in HAL Implementations

Implementations of HAL in Android are found in the hardware/interface directory while the AIDL generated HAL interfaces are found in the aidl directory. For instance, the sslight AIDL HAL is at hardware/interfaces/sslight; the following shows the directory structure of the files.

HALs that use AIDL to communicate between framework components (for example, System. img) and hardware components (for example, vendor. img) must use Stable AIDL, It can be observed where there are interactions between system and vendor partition, these use Stable AIDL. The following changes are needed to make the use of an AIDL interface between the system and the vendor possible.

Annotate every type definition in the AIDL interface file with @VintfStability.
Include stability: “vintf” in the aidl_interface declaration within the Android.bp file.

Create AIDL interface by adding new file sslight/aidl/Android.bp.

				
					package {
    default_applicable_licenses: ["hardware_interfaces_license"],
}

aidl_interface {
    name: "android.hardware.sslight",
    vendor_available: true,
    srcs: ["android/hardware/sslight/*.aidl"],
    stability: "vintf",
    owner: "silicon signals",
    backend: {
        cpp: {
            enabled: false,
        },
        java: {
            sdk_version: "module_current",
        },
    },
}

				
			

Implement android/hardware/sslight/ISslight.aidl file

				
					package android.hardware.sslight;
@VintfStability
interface ISslight {
  int ledControl(in int state);
}

				
			

Freeze the API by running below command:

				
					m android.hardware.sslight-update-api

				
			

After completion, try to build the module with below command:

				
					mmm hardware/interfaces/sslight
				
			

Implement Android.bp file

				
					cc_binary {
    name: "android.hardware.sslight-service",
    vendor: true,
    relative_install_path: "hw",
    init_rc: ["android.hardware.sslight-service.rc"],
    vintf_fragments: ["android.hardware.sslight-service.xml"],
    srcs: [
        "Sslight.cpp",
        "service.cpp",
    ],

    cflags: [
        "-Wall",
        "-Werror",
    ],

    shared_libs: [
        "libbase",
        "liblog",
        "libhardware",
        "libbinder_ndk",
        "libbinder",
        "libutils",
        "android.hardware.sslight-V1-ndk",
    ],
}

				
			

Implement service.cpp hal service interface hal service with framework client using binder IPC

				
					#define LOG_TAG "Sslight"

#include <android-base/logging.h>
#include <android/binder_manager.h>
#include <android/binder_process.h>
#include <binder/ProcessState.h>
#include <binder/IServiceManager.h>
#include "Sslight.h"

using aidl::android::hardware::sslight::Sslight;
using std::string_literals::operator""s;

void loge(std::string msg) {
    std::cout << msg << std::endl;
    ALOGE("%s", msg.c_str());
}

int main() {

    ABinderProcess_setThreadPoolMaxThreadCount(0);
    ABinderProcess_startThreadPool();

    std::shared_ptr<Sslight> sslight = ndk::SharedRefBase::make<Sslight>();
    const std::string name = Sslight::descriptor + "/default"s;

    if (sslight != nullptr) {
        if(AServiceManager_addService(sslight->asBinder().get(), name.c_str()) != STATUS_OK) {
            loge("Failed to register Sslight service");
            return -1;
        }
    } else {
        loge("Failed to get ISslight instance");
        return -1;
    }

    loge("Sslight service starts to join service pool");
    ABinderProcess_joinThreadPool();

    return EXIT_FAILURE;  // should not reached
}

				
			

Implement .rc file and .xml files in aidl/default directory as mentioned below. 
default/android.hardware.sslight-service.rc

				
					service android.hardware.sslight-service /vendor/bin/hw/android.hardware.sslight-service
        interface aidl android.hardware.sslight.ISslight/default
        class hal
        user system
        group system

				
			

default/android.hardware.sslight-service.xml

				
					<manifest version="1.0" type="device">
    <hal format="aidl">
        <name>android.hardware.sslight</name>
        <version>1</version>
        <fqname>ISslight/default</fqname>
    </hal>
</manifest>

				
			

Implement hardware specific logic in Sslight.cpp

				
					#include <utils/Log.h>
#include <iostream>
#include <fstream>
#include "Sslight.h"

namespace aidl {
namespace android {
namespace hardware {
namespace sslight {

ndk::ScopedAStatus Sslight::ledControl(int32_t in_state, int32_t* _aidl_return) {
    constexpr char LED_FILE_PATH[] = "/sys/class/leds/blue/brightness";
    constexpr char LED_ON_VALUE[] = "255";
    constexpr char LED_OFF_VALUE[] = "0";

    int fd = open(LED_FILE_PATH, O_WRONLY);
    if (fd < 0) {
        ALOGE("Failed to open %s", LED_FILE_PATH);
        return ndk::ScopedAStatus::fromServiceSpecificError(-1);
    }

    int ret = 0;
    if (in_state > 0) {
        ret = write(fd, LED_ON_VALUE, sizeof(LED_ON_VALUE) - 1); // Write "255" (LED ON)
    } else {
        ret = write(fd, LED_OFF_VALUE, sizeof(LED_OFF_VALUE) - 1); // Write "0" (LED OFF)
    }

    close(fd);

    if (ret < 0) {
        ALOGE("Failed to write to %s", LED_FILE_PATH);
        return ndk::ScopedAStatus::fromServiceSpecificError(-1);
    }

    *_aidl_return = true;
    return ndk::ScopedAStatus::ok();
}

}  // namespace sslight
}  // namespace hardware
}  // namespace android
}


				
			

Add package in device make file present at device/<product>/<device_name>/device.mk

				
					PRODUCT_PACKAGES += \
    android.hardware.sslight-service


				
			

Application to Device Driver Communication in Android

Android framework has an API layer through which applications built on Android operate through the HAL layer. Typically, the data flow from an application to a device driver follows this path: Application -> System Service -> JNI CPP -> HAL -> Driver.

This process involves several components:

  • AIDL Interface: Determines how the two units will communicate with each other.
  • Custom System Service and Manager Implementation: Coordinates the relationships between applications and the system’s other subcomponents.
  • JNI Interface Implementation in Native CPP: The JNI to bridge the Java and native C++ code.
  • Service Registration: Is why Sslight is guaranteed that the service can be found and used by Android applications and that goes to the lower level.

To implement system services, service managers, and native CPP JNI interfaces in the framework, modifications are required in the frameworks/base directory to reflect these changes in the system.img. The following files need to be updated:

				
					core/api/current.txt
core/java/Android.bp
core/java/android/app/SystemServiceRegistry.java
core/java/android/content/Context.java
core/java/android/os/ISslightService.aidl
core/java/android/os/SslightManager.java
services/core/java/com/android/server/SslightService.java
services/core/jni/Android.bp
services/core/jni/com_android_server_SslightService.cpp
services/core/jni/onload.cpp
services/java/com/android/server/SystemServer.java
				
			
 Developing an Android Application: LedControl

The Android application serves as the user interface. Using the LedControl application, users can toggle the LED light on and off. To integrate this application into the AOSP tree, it should be located at packages/apps/LedControl.

LedControl App Structure

In the LedControl app:

  • MainActivity.java: Implement functionality to control the LED.
  • res directory: Add necessary resources to create a custom user interface.

Accessing System Service Interface

To access the sslight service method from the frameworks:

  • Obtain the system service interface to facilitate communication with the sslight service

file : MainActivity.java

				
					public class MainActivity extends AppCompatActivity {

    private boolean isLEDOn = false;
    private static SslightManager mManager;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mManager = (SslightManager)getSystemService(Context.SSLIGHT_SERVICE);
        if(mManager == null) {
			Log.e("sslight_apk", "Error: service object is null");
            return;
        }
    }
} 

				
			

Finally, add application package in device make file present at device/<product>/<device_name>/device.mk

				
					PRODUCT_PACKAGES += \
    LedControl \
				
			

Conclusion

Implementing an own AIDL HAL into the Android stack expands the agendas of the platform and gives more options for individualization. Thus, the use of AIDL enables the control of a device’s hardware to be built with concrete considerations in mind and thus become intertwined with the rest of the Android environment. This enhances the stability of the system and encourages the growth of new innovations since the applications are in a position to communicate directly with the hardware. The use of AIDL HALs in Android also suggests the OS’s consistent growth in offering cutting-edge, and highly elastic solutions to technological challenges.

Let’s Get In Touch

Interested in collaborating with Silicon Signals on your next big idea? Please contact us and let us know how we can help you.

    Name
    Email
    Subject
    Message