One of the problems in Android is the fact that when a new version is released only a few devices can be updated. Actually, if you want to enjoy the latest version, you need to buy a new smartphone every 6 months. Google solution is the Project trebel that separates the vendor implementation from the Android OS framework via a new vendor interface

HIDL

HAL interface definition language used to describe the interface between the framework and the vendor. All hardware interfaces are located in hardware/interfaces in .hal files

Let’s go over simple example

Create all the path

# cd ~/aosp # mkdir -p hardware/interfaces/simple/2.0/default 1 2 # cd ~/aosp # mkdir -p hardware/interfaces/simple/2.0/default

Create a hal file in ISimphw.hal in hardware/interfaces/simple/2.0

package android.hardware.simple@2.0; interface ISimphw { simpfn(int32_t valueIn) generates (int32_t valueRet); }; 1 2 3 4 5 package android . hardware . simple @2 . 0 ; interface ISimphw { simpfn ( int32_t valueIn ) generates ( int32_t valueRet ) ; } ;

Generate the HAL files

To generate the HAL files you need to use the hidl-gen tool run:

# PACKAGE=android.hardware.simple@2.0 # LOC=hardware/interfaces/simple/2.0/default/ # make hidl-gen -j64 # hidl-gen -o $LOC -Lc++-impl -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport $PACKAGE # hidl-gen -o $LOC -Landroidbp-impl -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport $PACKAGE 1 2 3 4 5 # PACKAGE=android.hardware.simple@2.0 # LOC=hardware/interfaces/simple/2.0/default/ # make hidl-gen -j64 # hidl-gen -o $LOC -Lc++-impl -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport $PACKAGE # hidl-gen -o $LOC -Landroidbp-impl -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport $PACKAGE

And to update all makefile (Android.mk, Android.bp) run:

# ./hardware/interfaces/update-makefiles.sh 1 # ./hardware/interfaces/update-makefiles.sh

Now add 2 empty files to hardware/interfaces/simple/2.0/default:

android.hardware.simple@2.0-service.rc

service.cpp

Now the directory hardware/interfaces/simple should look like this:

Implementing the HAL shared object:

we need to add a new static function to return the service object (usually as a singleton)

Simphw.h

#ifndef ANDROID_HARDWARE_SIMPLE_V2_0_SIMPHW_H #define ANDROID_HARDWARE_SIMPLE_V2_0_SIMPHW_H #include <android/hardware/simple/2.0/ISimphw.h> #include <hidl/MQDescriptor.h> #include <hidl/Status.h> namespace android { namespace hardware { namespace simple { namespace V2_0 { namespace implementation { using ::android::hardware::hidl_array; using ::android::hardware::hidl_memory; using ::android::hardware::hidl_string; using ::android::hardware::hidl_vec; using ::android::hardware::Return; using ::android::hardware::Void; using ::android::sp; struct Simphw : public ISimphw { // Methods from ISimphw follow. Return<int32_t> simpfn(int32_t valueIn) override; // Methods from ::android::hidl::base::V1_0::IBase follow. static ISimphw* getInstance(void); }; // FIXME: most likely delete, this is only for passthrough implementations //extern "C" ISimphw* HIDL_FETCH_ISimphw(const char* name); } // namespace implementation } // namespace V2_0 } // namespace simple } // namespace hardware } // namespace android #endif // ANDROID_HARDWARE_SIMPLE_V2_0_SIMPHW_H 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 #ifndef ANDROID_HARDWARE_SIMPLE_V2_0_SIMPHW_H #define ANDROID_HARDWARE_SIMPLE_V2_0_SIMPHW_H #include <android/hardware/simple/2.0/ISimphw.h> #include <hidl/MQDescriptor.h> #include <hidl/Status.h> namespace android { namespace hardware { namespace simple { namespace V2_0 { namespace implementation { using :: android :: hardware :: hidl_array ; using :: android :: hardware :: hidl_memory ; using :: android :: hardware :: hidl_string ; using :: android :: hardware :: hidl_vec ; using :: android :: hardware :: Return ; using :: android :: hardware :: Void ; using :: android :: sp ; struct Simphw : public ISimphw { // Methods from ISimphw follow. Return < int32_t > simpfn ( int32_t valueIn ) override ; // Methods from ::android::hidl::base::V1_0::IBase follow. static ISimphw * getInstance ( void ) ; } ; // FIXME: most likely delete, this is only for passthrough implementations //extern "C" ISimphw* HIDL_FETCH_ISimphw(const char* name); } // namespace implementation } // namespace V2_0 } // namespace simple } // namespace hardware } // namespace android #endif // ANDROID_HARDWARE_SIMPLE_V2_0_SIMPHW_H

Simphw.cpp

#include "Simphw.h" namespace android { namespace hardware { namespace simple { namespace V2_0 { namespace implementation { // Methods from ISimphw follow. Return<int32_t> Simphw::simpfn(int32_t valueIn) { // TODO implement return valueIn+100; } ISimphw *Simphw::getInstance(void){ return new Simphw(); } // Methods from ::android::hidl::base::V1_0::IBase follow. //ISimphw* HIDL_FETCH_ISimphw(const char* /* name */) { // return new Simphw(); //} } // namespace implementation } // namespace V2_0 } // namespace simple } // namespace hardware } // namespace android 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 #include "Simphw.h" namespace android { namespace hardware { namespace simple { namespace V2_0 { namespace implementation { // Methods from ISimphw follow. Return < int32_t > Simphw :: simpfn ( int32_t valueIn ) { // TODO implement return valueIn + 100 ; } ISimphw * Simphw :: getInstance ( void ) { return new Simphw ( ) ; } // Methods from ::android::hidl::base::V1_0::IBase follow. //ISimphw* HIDL_FETCH_ISimphw(const char* /* name */) { // return new Simphw(); //} } // namespace implementation } // namespace V2_0 } // namespace simple } // namespace hardware } // namespace android

Note that if you want to support pass-through mode, you need to uncomment the HIDL_FETCH_ISimphw function

In this example, we implemented the function as simple as possible (usually we will load the hardware module here)

The generated Android.bp file build a shared library with the implementation – android.hardware.simple@2.0-impl

Creating the Service

To host the library we need to create a simple executable:

service.cpp

#define LOG_TAG "android.hardware.graphics.allocator@2.0-service" #include <android/hardware/simple/2.0/ISimphw.h> #include <hidl/LegacySupport.h> #include "Simphw.h" using android::hardware::simple::V2_0::ISimphw; using android::hardware::simple::V2_0::implementation::Simphw; using android::hardware::configureRpcThreadpool; using android::hardware::joinRpcThreadpool; using android::sp; int main() { int res; android::sp<ISimphw> ser = Simphw::getInstance(); ALOGE("simp main"); configureRpcThreadpool(1, true /*callerWillJoin*/); if (ser != nullptr) { res = ser->registerAsService(); if(res != 0) ALOGE("Can't register instance of SimpleHardware, nullptr"); } else { ALOGE("Can't create instance of SimpleHardware, nullptr"); } joinRpcThreadpool(); return 0; // should never get here } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 #define LOG_TAG "android.hardware.graphics.allocator@2.0-service" #include <android/hardware/simple/2.0/ISimphw.h> #include <hidl/LegacySupport.h> #include "Simphw.h" using android :: hardware :: simple :: V2_0 :: ISimphw ; using android :: hardware :: simple :: V2_0 :: implementation :: Simphw ; using android :: hardware :: configureRpcThreadpool ; using android :: hardware :: joinRpcThreadpool ; using android :: sp ; int main ( ) { int res ; android :: sp < ISimphw > ser = Simphw :: getInstance ( ) ; ALOGE ( "simp main" ) ; configureRpcThreadpool ( 1 , true /*callerWillJoin*/ ) ; if ( ser != nullptr ) { res = ser -> registerAsService ( ) ; if ( res != 0 ) ALOGE ( "Can't register instance of SimpleHardware, nullptr" ) ; } else { ALOGE ( "Can't create instance of SimpleHardware, nullptr" ) ; } joinRpcThreadpool ( ) ; return 0 ; // should never get here }

We create an instance of our implementation, Create a thread pool for the binder and register the current process as a service

Note that the function regsiterAsService() is auto-generated by hidl-gen tool

To make this service run automatically add init file:

android.hardware.simple@2.0-service.rc

service simphwserv /vendor/bin/hw/android.hardware.simple@2.0-service class hal user root group root seclabel u:r:su:s0 1 2 3 4 5 service simphwserv / vendor / bin / hw / android . hardware . simple @ 2.0 - service class hal user root group root seclabel u : r : su : s0

For testing purpose I set the security label to su , we need to set SE Linux rules (I wrote it in the init.te file):

allow init vendor_file:file { execute }; allow init su:process { transition }; 1 2 allow init vendor_file : file { execute } ; allow init su : process { transition } ;

To tell the build system to build the service add the following to Android.bp (in directory default)

cc_binary { name: "android.hardware.simple@2.0-service", defaults: ["hidl_defaults"], proprietary: true, relative_install_path: "hw", srcs: ["service.cpp"], init_rc: ["android.hardware.simple@2.0-service.rc"], shared_libs: [ "android.hardware.simple@2.0", "android.hardware.simple@2.0-impl", "libhidlbase", "libhidltransport", "liblog", "libutils", ], } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 cc_binary { name : "android.hardware.simple@2.0-service" , defaults : [ "hidl_defaults" ] , proprietary : true , relative_install_path : "hw" , srcs : [ "service.cpp" ] , init_rc : [ "android.hardware.simple@2.0-service.rc" ] , shared_libs : [ "android.hardware.simple@2.0" , "android.hardware.simple@2.0-impl" , "libhidlbase" , "libhidltransport" , "liblog" , "libutils" , ] , }

Add the following components to build/make/target/product/emulator.mk

android.hardware.simple@2.0-impl \ android.hardware.simple@2.0-service \ 1 2 android . hardware . simple @ 2.0 - impl \ android . hardware . simple @ 2.0 - service \

Now build the ROM and run it, connect with adb and run ps -A to see all the hardware services:

The lshal tool list all the hardware services by categories:

# lshal 1 # lshal

Writing the Client

To use the service we will write a simple client application. Usually, it will be part of the Android framework written by Google. For example, if the generic framework wants to access the vibrator service:

In file frameworks/base/services/core/jni/com_android_server_VibratorService.cpp

static sp<IVibrator> mHal; ... mHal = IVibrator::getService(); ... Status retStatus = mHal->on(timeout_ms); ... Status retStatus = mHal->off(); 1 2 3 4 5 6 7 8 9 static sp < IVibrator > mHal ; . . . mHal = IVibrator :: getService ( ) ; . . . Status retStatus = mHal -> on ( timeout_ms ) ; . . . Status retStatus = mHal -> off ( ) ;

Add a new directory in device/generic/goldfish – simphaltest

Add the source and Android.bp files:

#define LOG_TAG "android.hardware.graphics.allocator@2.0-service" #include <android/hardware/simple/2.0/ISimphw.h> #include <hidl/Status.h> #include <hidl/LegacySupport.h> #include <utils/misc.h> #include <utils/Log.h> #include <hardware/hardware.h> #include <hidl/HidlSupport.h> #include<stdio.h> using android::hardware::simple::V2_0::ISimphw; using android::sp; int main() { int res; android::sp<ISimphw> ser = ISimphw::getService(); res = ser->simpfn(200); printf("val=%d

",res); return 0; } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 #define LOG_TAG "android.hardware.graphics.allocator@2.0-service" #include <android/hardware/simple/2.0/ISimphw.h> #include <hidl/Status.h> #include <hidl/LegacySupport.h> #include <utils/misc.h> #include <utils/Log.h> #include <hardware/hardware.h> #include <hidl/HidlSupport.h> #include<stdio.h> using android :: hardware :: simple :: V2_0 :: ISimphw ; using android :: sp ; int main ( ) { int res ; android :: sp < ISimphw > ser = ISimphw :: getService ( ) ; res = ser -> simpfn ( 200 ) ; printf ( "val=%d

" , res ) ; return 0 ; }

Android.bp

cc_binary { name: "mysimptest", defaults: ["hidl_defaults"], proprietary: true, srcs: ["servtest.cpp"], shared_libs: [ "android.hardware.simple@2.0", "android.hardware.simple@2.0-impl", "libhidlbase", "libhidltransport", "liblog", "libutils", ], } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 cc_binary { name : "mysimptest" , defaults : [ "hidl_defaults" ] , proprietary : true , srcs : [ "servtest.cpp" ] , shared_libs : [ "android.hardware.simple@2.0" , "android.hardware.simple@2.0-impl" , "libhidlbase" , "libhidltransport" , "liblog" , "libutils" , ] , }

Add the client test to build/make/target/product/emulator.mk

mysimptest \ 1 mysimptest \

Add hal entry to the Manifest.xml file of your device (device/generic/goldfish/Manifest.xml in this case)

<hal format="hidl"> <name>android.hardware.simple</name> <transport>hwbinder</transport> <version>2.0</version> <interface> <name>ISimphw</name> <instance>default</instance> </interface> </hal> 1 2 3 4 5 6 7 8 9 <hal format = "hidl" > <name> android.hardware.simple </name> <transport> hwbinder </transport> <version> 2.0 </version> <interface> <name> ISimphw </name> <instance> default </instance> </interface> </hal>

Build the ROM again and test our service: