1. 程式人生 > >Android 8.0之後版本新增Hidl Service

Android 8.0之後版本新增Hidl Service

原址

本文以LED為例在aosp上新增HIDL,以熟悉整個過程。

1. 編寫hal檔案並編譯
    在hardware/interfaces/目錄下建立led資料夾和基版本1.0,這個版本號分為兩部分,major.minor。major版本不變得話,只能新增api,不能修改。

建立ILed.hal和types.hal

hardware/interfaces/led/1.0/ILed.hal

package [email protected];
 
interface ILed
{
  //get led status 
  get() generates (LedStatus result);
  
  
  //set led status 
  set(LedStatus  val) generates(int32_t  ret);
  
  getBrightnessRange() generates(bool ret,BrightnessRange range);
  
  setBrightnessValue(vec<int32_t> range) generates(bool ret);
  
  on() ;
  
  off() ;
 
};
 
hardware/interfaces/led/1.0/types.hal

package [email protected];
 
 
enum LedStatus : uint32_t {
    LED_ON,
    LED_OFF,
    LED_BAD_VALUE,
};
 
 
struct BrightnessRange {
    uint32_t min;
 
    uint32_t max;
};
新增完後,執行hardware/interfaces/update-makefiles.sh 會自動生成編譯編譯指令碼,然後在

hardware/interfaces/led/1.0/ 路徑下執行mm,會生成所需要得hidl庫,接下來我們需要實現hidl interface,供client呼叫。

 

2. 實現Hidl Interface

首先實現ILed interface的子類ledImpl 得標頭檔案和對應得cpp。

hardware/interfaces/led/1.0/default/ledImpl.h

#ifndef ANDROID_HARDWARE_LED_V1_0_LED_H
#define ANDROID_HARDWARE_LED_V1_0_LED_H
#include <android/hardware/led/1.0/ILed.h>
 
#include <hidl/Status.h>
 
#include <hidl/MQDescriptor.h>
 
 
 
 
namespace android {
namespace hardware {
namespace led {
namespace V1_0 {
namespace implementation {
 
using ::android::hardware::led::V1_0::LedStatus;
using ::android::hardware::led::V1_0::BrightnessRange;
using ::android::hardware::led::V1_0::ILed;
using ::android::hardware::hidl_array;
using ::android::hardware::hidl_string;
using ::android::hardware::hidl_vec;
using ::android::hardware::Return;
using ::android::hardware::Void;
using ::android::sp;
    
    
struct ledImpl : public ILed {
    public:
        ledImpl();
        Return<LedStatus>  get() override ;
        Return<int32_t> set(LedStatus val) override;
        Return<void> on() override;
        Return<void> off() override;
        Return<void> getBrightnessRange(getBrightnessRange_cb _hidl_cb) override;
        Return<bool> setBrightnessValue(const hidl_vec<int32_t>& range) override;
    private:
        LedStatus state;
};
    
extern "C" ILed* HIDL_FETCH_ILed(const char* name);
}  // namespace implementation
}  // namespace V1_0
}  // namespace led
}  // namespace hardware
}  // namespace android
 
#endif //ANDROID_HARDWARE_LED_V1_0_LED_H
hardware/interfaces/led/1.0/default/ledImpl.cpp
#define LOG_TAG "LedService"
 
#include <log/log.h>
#include "ledImpl.h"
 
namespace android {
namespace hardware {
namespace led {
namespace V1_0 {
namespace implementation {
 
ledImpl::ledImpl() {
    state = LedStatus::LED_BAD_VALUE;
    ALOGE("ledImpl Init status:%d", state);
}
 
Return<void> ledImpl::on() {
    state = LedStatus::LED_ON;
    ALOGE("ledImpl on status:%d", state);
    return Void();
}
 
Return<void> ledImpl::off() {
    state = LedStatus::LED_OFF;
    ALOGE("ledImpl off status:%d", state);    
    return Void();
}
 
Return<LedStatus>  ledImpl::get() {
    return state;
}
Return<int32_t> ledImpl::set(LedStatus val) {
    if(val == LedStatus::LED_OFF || val == LedStatus::LED_ON)
        state = val;
    else
        return -1;
    return 0;
}
 
Return<void> ledImpl::getBrightnessRange(getBrightnessRange_cb _hidl_cb)
{
    ALOGE("ledImpl getBrightnessRange ");
    BrightnessRange range;
    range.max = 100;
    range.min = 1;
    _hidl_cb(true,range);
    return Void();
    
}
  
Return<bool> ledImpl::setBrightnessValue(const hidl_vec<int32_t>& range)
{
    ALOGE("ledImpl getBrightnessValue ");
    auto iter = range.begin();
    ALOGE("ledImpl getBrightnessValue range.begin: %d",*iter);
    iter = range.end();
    ALOGE("ledImpl getBrightnessValue range.end: %d",*iter);
    ALOGE("ledImpl getBrightnessValue range.size: %zu",range.size());
    return true;
}
 
ILed* HIDL_FETCH_ILed(const char * /*name*/) {
    ALOGE("ledImpl HIDL_FETCH_ILed ");    
    return new ledImpl();
}
 
}  // namespace implementation
}  // namespace V1_0
}  // namespace led
}  // namespace hardware
}  // namespace android
hardware/interfaces/led/1.0/default/Android.bp

cc_library_shared {
    name: "[email protected]",
    defaults: ["hidl_defaults"],
    srcs: ["ledImpl.cpp"],
    shared_libs: [
        "libhidlbase",
        "libhidltransport",
        "libhardware",
        "liblog",
        "libutils",
        "[email protected]",
    ], 
}
 
cc_binary {
    name: "[email protected]",
    init_rc: ["[email protected]"],
    srcs: ["service.cpp",
      "ledImpl.cpp"],
 
    shared_libs: [
        "liblog",
        "libhardware",
        "libhidlbase",
        "libhidltransport",
        "libutils",
        "[email protected]",
    ], 
 
}
3. 編寫hdil service

  接下來,使用相應功能填寫存根並設定守護程序。可以使用passthrough方式和binder方式,示例:

hardware/interfaces/led/1.0/default/service.cpp

 
 #define LOG_TAG "[email protected]"
 
#include <android/hardware/led/1.0/ILed.h>
#include <hidl/LegacySupport.h>
#include "ledImpl.h"
using android::hardware::led::V1_0::ILed;
using android::hardware::led::V1_0::implementation::ledImpl;
using android::hardware::defaultPassthroughServiceImplementation;
using android::hardware::configureRpcThreadpool;
using android::hardware::joinRpcThreadpool;
using android::sp;
 
 
int main() {
#if 0 
// Passthrough   dlopen so方式
    return defaultPassthroughServiceImplementation<Iled>(); 
#else
// Binder 方式
  sp<ILed> service = new ledImpl();
  configureRpcThreadpool(1, true /*callerWillJoin*/);
    if(android::OK !=  service->registerAsService())
      return 1; 
    joinRpcThreadpool();
#endif
}
4. 配置manifest.xml

  add the code to the manifest.xm 以至於hwservicemanager 查詢到指定的hidl service

   About HIDL configures

   device/<vendorxxx>/<devicexxx>/manifest.xml

 <hal format="hidl">
    <name>android.hardware.led</name>
    <transport>hwbinder</transport>  //hwbinder 或者passthrough (直通模式)  
    <version>1.0</version>
    <interface>
     <name>ILed</name>
     <instance>default</instance>
    </interface>
   </hal>
  5. hidl client端呼叫

  hidl service執行後,可以通過C++和Java兩種方式呼叫,非常方便,通過java直接訪問,就省去了jni。

 5.1 實現java呼叫hidl service的例子

  將以下內容新增到 Android.mk 中:

 LOCAL_JAVA_LIBRARIES += android.hardware.led-V1.0-java
 
/*
 LOCAL_STATIC_JAVA_LIBRARIES += android.hardware.led-V1.0-java-static
*/
  或將以下內容新增到 Android.bp 中:

  shared_libs: [
   /* … */
   "android.hardware.led-V1.0-java",
  ],
  該庫還存在靜態版:android.hardware.led-V1.0-java-static。

  將以下內容新增到您的 Java 檔案中:

  import android.hardware.led.V1_0.ILed;
  ...
  // retry to wait until the service starts up if it is in the manifest
  ILed server = ILed.getService(/* retry */); // throws NoSuchElementException if not available
  server.on();
 

5.2 實現C++ 呼叫hidl service的例子

 首先將 HAL 庫新增到 makefile 中:

  Make:LOCAL_SHARED_LIBRARIES += [email protected]
  Soong:shared_libs: [ …, [email protected] ]
 接下來,新增 HAL 標頭檔案:

  #include <android/hardware/led/1.0/ILed.h>
  …
  // in code:
  sp<ILed> client = ILed::getService();
  client->on();
下面是我的Demo clinet

 #define LOG_TAG "LED_CLINET"
#include <android/hardware/led/1.0/ILed.h>
#include <log/log.h>
 
using android::hardware::led::V1_0::ILed;
using android::hardware::led::V1_0::LedStatus;
using android::hardware::led::V1_0::BrightnessRange;
using android::hardware::hidl_vec;
using android::sp;
 
 
int main(){
    // BrightnessRange range;
    sp<ILed> service = ILed::getService();
    if( service == nullptr ){
        ALOGE("Can't find ILed service...");
        return -1;
    }
    ALOGE("ILed ON");
    service->on();
    
    ALOGE("ILed OFF");
    service->off();
    
    ALOGE("ILed set");
    service->set(LedStatus::LED_ON);
 
    ALOGE("ILed get");
    LedStatus ret = service->get();
    ALOGE("ILed get: %d",ret);
    
    service->getBrightnessRange([](bool ret1,BrightnessRange range){
        ALOGE("ILed getBrightnessRange ret: %d",ret1);
        ALOGE("ILed getBrightnessRange Max: %d",range.max);
        ALOGE("ILed getBrightnessRange Min: %d",range.min);
    });
    int32_t array[] = {5, 6, 7};
    hidl_vec<int32_t> hv1 = std::vector<int32_t>(array, array + 3);
    bool ret2 = service->setBrightnessValue(hv1);
    ALOGE("ILed getBrightnessValue bool: %d",ret2);
    return 0;
}
6. github地址
 需要看程式碼的可以去我的github,裡面有相關的hidl程式碼,和C++呼叫示例

github地址連結