Android HIDL and Project Treble

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

 

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

package [email protected];

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:

# [email protected]
# 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

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

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

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

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 – [email protected]

Creating the Service

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

service.cpp

#define LOG_TAG "[email protected]"

#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:

[email protected]

service simphwserv /vendor/bin/hw/[email protected]
    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 };

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

cc_binary {
    name: "[email protected]",
    defaults: ["hidl_defaults"],
    proprietary: true,
    relative_install_path: "hw",
    srcs: ["service.cpp"],
    init_rc: ["[email protected]"],

    shared_libs: [
        "[email protected]",
        "[email protected]",
        "libhidlbase",
        "libhidltransport",
        "liblog",
        "libutils",
    ],
}

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

    [email protected] \
    [email protected] \

 

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

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();

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

Add the source and Android.bp files:

#define LOG_TAG "[email protected]"

#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\n",res);

      return 0; 
}

Android.bp

cc_binary {
    name: "mysimptest",
    defaults: ["hidl_defaults"],
    proprietary: true,
    srcs: ["servtest.cpp"],

    shared_libs: [
        "[email protected]",
        "[email protected]",
        "libhidlbase",
        "libhidltransport",
        "liblog",
        "libutils",
    ],
}

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

    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>

Build the ROM again and test our service:

 

Tagged , ,

48 thoughts on “Android HIDL and Project Treble

  1. This is the best DEMONSTRATION of How to get a HAL going I have found, Unfortunately When following it through on OREO my service fails to load the impl library from the ‘HW’ dir, if I push the library up a level to the lib64, it is found. I see nearly all the other standard(or BSP) HALS are lOAded from ‘HW’ but I cant see what they have different. Whats the trick ?
    I get:
    “library “[email protected]” not found”
    Although it is clearly there and it does load if I move it up to lib64

    1. Hello,
      HAVE you FIGURED OUT WHY THIS IS HAPPENING? I AM CURRENTLY HAVING THIS ISSUE. PLEASE LET ME KNOW IF YOU FIND ANY SOLUTION.
      THANKS

      1. hi

        i also have this problem.
        a simple way to avoid it, just copy so file to /system/lib. then it’s gone.
        but it seems not a good way. if anyone knows it.
        please share.

        1. Hi I resolved it by avoding linking *-impl.so file.
          I removed getInstance method and added below method

          ISimphw* HIDL_FETCH_ISimphw(const char* /* name */) {
          return new Simphw();
          }
          and modified service.cpp as below.

          int main() {
          return defaultPassthroughServiceImplementation();
          }
          maybe linking *-impl.so in /vendor/lib/hw is not allowed.
          instead, I’m guessing that it’s automatically loaded by using HIDL_FETCH_ISIMPHW.

          1. @JIHYUN: I followed your steps but still get the following error.
            hwservicemanager: getTransport: Cannot find entry [email protected]::ISimphw/default in either framework or device manifest.
            10-18 01:06:20.990 1577 1577 E ServiceManagement: Passthrough lookup opened [email protected] but could not find symbol HIDL_FETCH_ISimphw: undefined symbol: HIDL_FETCH_ISimphw
            10-18 01:06:20.990 1577 1577 E [email protected]: Could not get passthrough implementation for [email protected]::ISimphw/default.

            I do the the hidl fetch method but don’t know why it is coming this way. Any suggestions? I have been stuck in this.

          2. Please note the error is not with the naming convention.
            So the proper error would be:
            @JIHYUN: I followed your steps but still get the following error.
            hwservicemanager: getTransport: Cannot find entry [email protected]::ISimphw/default in either framework or device manifest.
            10-18 01:06:20.990 1577 1577 E ServiceManagement: Passthrough lookup opened [email protected] but could not find symbol HIDL_FETCH_ISimphw: undefined symbol: HIDL_FETCH_ISimphw
            10-18 01:06:20.990 1577 1577 E [email protected]: Could not get passthrough implementation for [email protected]::ISimphw/default.

            Kindly ignore the part where the name is [email protected]. I have the correct impl file name.

  2. What IDE to run the code?

  3. thanks a lot, works great. Required to update dev/*/* in Android.bp in root directory to dev/*/*/* to access the Android.bp created in device/generic/goldfish/simphaltest.

  4. hI,

    I tried steps given for “[email protected]″ HIDL interface and thats worked. I like the simple steps/command to generate HIDL impl and HIDL service, it really gives the confidence for who are new into Android HAL framework.

    Thanks a lot.

    One more change is required to build HIDL impl lib, just add “2.0/default” into Android.bp to include default dir Android.bp

    hardware/interfaces/simple/Android.bp

    subdirs = [
    “2.0”,
    “2.0/default”,
    ]

    @CHRIS_CW,

    As per hardware/interfaces/simple/2.0/default/Android.bp rule,

    name: “[email protected]”,
    relative_install_path: “hw”,
    proprietary: true,

    the impl lib should build at below location in vendor.img

    vendor/lib/hw
    vendor/lib64/hw

    can check your HIDL package name ? from error it seems to be UPPER case string issue “library “[email protected]” not found”

    and also check product packages should include in devicexx.mk

    PRODUCT_PACKAGES += \
    [email protected] \
    [email protected] \

  5. it so good refference. thanks

  6. Hi
    I followed the steps given above but i am getting following error while trying to generate the HIDL files:

    ERROR: Unable to automatically import ‘[email protected]::IBase’ at /home/AOSP/hardware/interfaces/simple/2.0/ISimple.hal
    ERROR: Could not parse [email protected]::ISimple Aborting

  7. hello.
    i have a question.
    i dont make android.mk files about simple directory.
    i try to execute hardware/interfaces/update-makefiels.sh
    and i got a message about this.
    Updating [email protected]

    but in the directory of simple/2.0/
    dont find a android.mk file.

    1. Same problem. Just BP file but no mk.

      Do you have any solution?

  8. In service.cpp, should “return 1” “if(res != 0)”, else would “joinRpcThreadpool();” without a registered instance of SimpleHardware.

    P/S: Sorry about all caps. something wrong somewhere i can’t type in lowercase.

  9. Also need “return 1” “if(ser == nullptr)”.

  10. @Rakesh Verma
    How did you get “hidl-gen” and “update-makefiles.sh” to detect your *.hal files if you put your source code under device/generic/goldfish/simphaltest? or did you generate everything under hardware/interfaces and moved them to device/generic/goldfish/simphaltest later?

    1. update-makefiles.sh only generates the makefiles under hardware/interfaces
      follow the instructions and create the testapp makefile manually

      1. Thanks! IS THERE A WAY TO IMPLEMENT A BOARD/TARGET SPECIFIC VERSION OF THIS AND ‘OVERWRITE’ (OR NOT USE) THE DEFAULT IMPLEMENTATION? E.g. using device/generic/marlin/SIMPLE rather than hardware/interfaces/SIMPLE? As you’d mentioned, update-makefiles.sh doesn’t seem to detect *.hal files under devices/*, so this has to be done manually, but how should the terms [email protected] and [email protected] AND [email protected] be renamed for the BOARD/TARGET? Thanks in advance.

        1. Sorry again for caps!

    2. Hope you resolved your error, I follow the same instruction everything is working fine but try to run test code getting error. I could not understand the mean so please help me,
      My test code path is here aosp8/device/generic/goldfish/mysimptest.
      127|generic_x86:/ $ mysimptest/
      mysimptest/
      /system/bin/sh: mysimptest/: not found
      127|generic_x86:/ $

      1. Hi Ratnesh , is your Hal running in Full binderized mode or passthrough mode ?

        1. passthrough mode

  11. superb link till now.

  12. The best tutorial of hidl so far got in the internet. Thanks

  13. it’s a great tutorial to get started with HIDL implementation.

    I am just facing an issue, while build the hidl modules.

    ERROR: Could not open package path hardware/interfaces/simple/2.0/ for package [email protected]:

  14. Hi All,

    I am trying to implement an I2C DAC in android to allow the driving of specific voltages from an app. This isn’t a DAC for audio etc, it is an embedded application. I will also be implementing ADC, GPIO etc.

    I have found a kernel driver for the specific DAC I am using, and can control the DAC via the sysfs interface, e.g. “echo 3000 > /sys/bus/iio/devices/iio:device0/out_voltage0_raw”

    Now I am trying to understand how HIDL, HAL etc fit in to this.

    – I have found an example (https://elinux.org/images/f/fb/Android_Customization-_From_the_Kernel_to_the_Apps.pdf) which seems to create a custom service to control a hardware device, however this edits some of the internal files in android to start the service etc, and therefore I think this is NOT the “Andriod Oreo” way of doing it, since these modifications will be wiped during an upgrade.

    – Other examples I have found seem to be for sensor implementation. Since the DAC is an output, I don’t think the sensor API is compatible with what I am trying to achieve.

    As I understand it, Android Oreo 8.0 introduced the treble concept to allow the operating system to be updated while keeping the vendor specific changes intact. Am I correct in saying that this example is compatible with communicating with a custom device? e.g. instead of doing “return valueIn+100;”, I could “open(DEV, O_WRONLY);” etc and interface with my device?

  15. Does anyone know how I would call the function from within an Android App using Android Studio? I have generated an SDK after implementing this but I don’t know what Java API is exposed, if any?

  16. I am not able to send data to another shared library from my HIDL server, I am sending some data form client to server, from server i am trying to send to another library which is normal C implementation, i am able to call but data is not reaching. Can you please help.

  17. Hi,
    Thanks for the detailed documentation. A question regarding the init_rc file and SELinux init.te rule. As you mentioned:

    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 };

    Could you please clarify what should be the setting for normal use case? I have tried to copy the init_rc file from audio, omx HAL and the service won’t load up unless I use your sepolicy here. Is there a formal way to tell the system to load up the hal service while booting?

  18. hi
    as you said “we need to set SE Linux rules (I wrote it in the init.te file):”
    i don’t know which init.te file should config, could you tell me the location of init.te file?
    thank you very much!

  19. When I do an lshal I can see that it is getting generated as passthrough and not binderized

    All available passthrough implementations (all -impl.so files).
    These may return subclasses through their respective HIDL_FETCH_I* functions.
    R Interface
    [email protected]::I*/* (/vendor/lib/hw/)

    Should I not get this in the category binderized as default and looking something like what you have shown in the figure:
    [email protected]::ISimphw/default

    What I am missing here if anyone can help?
    Sorry for the capslock. i could not change the case

    1. Also i cannot see the same in ls -a. However I can see the so file in system/lib and in lshal as above.

  20. IMPORTANT :

    I NEED to use an HIDL service( in CPP) while my client is in java (telephony fw).

    I need to register call backs in the service from my java module, so that i can receive notifications in telephony when there is an update in the c++ service.

    thanks

  21. Nice post

  22. Hi,
    Thank you very much for nice tutorial, I am stuck in init.te file.
    Can you please tell me location of init.te file so i will set the given rules.
    allow init vendor_file:file { execute };
    allow init su:process { transition };
    Waiting for your response!

  23. After Adding
    allow init vendor_file:file { execute };
    allow init su:process { transition };
    at bottom of /system/sepolicy/public/init.te
    …………………………………………….
    PRODUCT_PACKAGES += \
    [email protected] \
    [email protected] \
    and also added emualtor.mk

    after build rom getting this error

    rudra@rudra-ThinkPad-E470:~/android8$ make -j4
    ============================================
    PLATFORM_VERSION_CODENAME=REL
    PLATFORM_VERSION=8.1.0
    TARGET_PRODUCT=aosp_x86_64
    TARGET_BUILD_VARIANT=eng
    TARGET_BUILD_TYPE=release
    TARGET_ARCH=x86_64
    TARGET_ARCH_VARIANT=x86_64
    TARGET_2ND_ARCH=x86
    TARGET_2ND_ARCH_VARIANT=x86_64
    HOST_ARCH=x86_64
    HOST_2ND_ARCH=x86
    HOST_OS=linux
    HOST_OS_EXTRA=Linux-4.18.0-16-generic-x86_64-with-Ubuntu-18.04-bionic
    HOST_CROSS_OS=windows
    HOST_CROSS_ARCH=x86
    HOST_CROSS_2ND_ARCH=x86_64
    HOST_BUILD_TYPE=release
    BUILD_ID=OPM7.181205.001
    OUT_DIR=out
    ============================================
    [2/2] bootstrap out/soong/.minibootstrap/build.ninja.in
    [1/1] out/soong/.bootstrap/bin/minibp out/soong/.bootstrap/build.ninja
    [78/79] glob hardware/interfaces/wifi/1.1/Android.bp
    [4/4] out/soong/.bootstrap/bin/soong_build out/soong/build.ninja
    FAILED: out/soong/build.ninja
    out/soong/.bootstrap/bin/soong_build -t -b out/soong -d out/soong/build.ninja.d -o out/soong/build.ninja Android.bp
    error: hardware/interfaces/simple/2.0/default/Android.bp:1:1: “[email protected]” depends on undefined module “[email protected]
    ninja: build stopped: subcommand failed.
    23:45:48 soong failed with: exit status 1

    1. have you got the solution as i am also stuck at same plac.

  24. Hello, this is a really good tutorial .Thanks!

    I have a question here. How do I write a client service on a different HW/board?
    so instead of adding a directory in device/generic/goldfish – simphaltest, how do i add for a different board and build the respective for same?

    Regards,
    Ron

  25. Thank you so much for writing this article, there is no other article explained hidl so clearly. Good job.

  26. I am getting this error
    A/linker: CANNOT LINK EXECUTABLE “/vendor/bin/hw/[email protected]”: library “[email protected]” not found

    can anyone help

    1. remove ‘ relative_install_path: “hw” ‘ for lib in Android.bp/mk for success link.

      `impl` libraries using only for ‘dlopen’ with ‘ relative_install_path: “hw” ‘ flags, or must be static.
      Shared library variant was deprecated and must be included on self-binary services.

      Look for this example:
      hardware/interfaces/biometrics/fingerprint/2.1/default/
      hardware/interfaces/automotive/vehicle/2.0/default/

      Also you can see the VNDK-way implementation.

      1. Thank you. I encountered the same issue. Now solved 🙂

  27. Great article. Thanks a lot!

  28. Great tutorial, step by step has been really helpful. I am porting my hidl to Android Q. Anything I should keep in mind in terms of running hidl-gen command, or the location of the hidl? Currently we are using /vendor/vendor_name/sources/hidl_name/.

  29. Can I return a string value from an interface in Simhw.cpp file.While doing so I am getting Error : hidden overloaded virtual function

  30. Does not work, it is not listed under “ps -A”.

    Someone who could support me? Would even donate some cash 🙂

    1. Hi,

      Have you got the solution for this? My HAL Service is also not listed under “ps -A”.

  31. Hi , Can we implement same setup in android 13 source code

Comments are closed.