天天看點

AOSP添加新硬體裝置開發-HIDL層

目錄

一 ,準備

二,添加hal檔案

三,實作hal檔案

四,添加service

五,啟動rc檔案

六,生成Android.bp檔案

七,SELinux權限

八,編譯

android裝置添加一個外圍裝置,不像嵌入式那麼簡單,系統越複雜加入的方式越雜,但是萬物都有規矩可尋,有方法可走。這篇文章就說說HAL和使用者之間的接口HIDL。

Google:https://source.android.google.cn/devices/architecture/hidl

google 官方這樣解釋 :HAL 接口定義語言(簡稱 HIDL,發音為“hide-l”)是用于指定 HAL 和其使用者之間的接口的一種接口描述語言 (IDL)。

HIDL 允許指定類型和方法調用(會彙集到接口和軟體包中)。從更廣泛的意義上來說,HIDL 是用于在可以獨立編譯的代碼庫之間進行通信的系統。

HIDL 旨在用于程序間通信 (IPC)。程序之間的通信采用 Binder 機制。對于必須與程序相關聯的代碼庫,還可以使用直通模式(在 Java 中不受支援)。

HIDL 可指定資料結構和方法簽名,這些内容會整理歸類到接口(與類相似)中,而接口會彙集到軟體包中。盡管 HIDL 具有一系列不同的關鍵字,但 C++ 和 Java 程式員對 HIDL 的文法并不陌生。此外,HIDL 還使用 Java 樣式的注釋。

在Android8.0開始,google引入了Treble機制,為了友善Android系統的快速移植、更新、穩定,Android引入了HAL Binder機制,把framework和HAL進行隔離,減少了之間的耦合性,使得framework可以被覆寫更新,不用對HAL編譯更新。

用圖檔展示一下兩者的差别:

AOSP添加新硬體裝置開發-HIDL層

Android8.0之前,HAL的調用方式為Legacy HAL, HAL都是編譯成so,然後動态連結到各個frameworks service中去,到了8.0,google為了給廠商一些修改時間,保持了Android的向前相容性,另外設計了一套直通式(Passthrough)的HAL,保留動态庫的HAL調用方式,

binderservice連結動态庫Hal的實作。

8.0之後,google規定廠商新增的HAL都需要切換到綁定式HAL(Binderized)。

在從 

libhardware

 HAL 轉換為 HIDL HAL 的過程中,HAL 實作成為伺服器,而調用 HAL 的程序則成為用戶端。預設實作可提供直通和 Binder 化 HAL,并可能會随着時間而發生變化:

AOSP添加新硬體裝置開發-HIDL層

                                                 Hal的發展曆程

Legacy Hal:Android 8.0 之前版本的 HAL 都是編譯成 so,然後動态連結到各個 frameworks service 中去。

Passthrough Hal:該模式是為了相容舊版的 HAL,舊版 HAL 實作仍以動态庫的方式提供,隻是 binder service 連結了動态庫 HAL 實作,即 binder service 通過 hw_get_module 連結了舊版的 hal 實作,而使用者端通過與 binder service IPC 通信,間接實作了與舊版 HAL 的互動。

Binderized HAL:HAL 與 使用者調用在不同的程序中,HAL 被寫成 binder service,而使用者接口如 frameworks 作為 binder client 通過 IPC 機制實作跨程序接口調用。

概念介紹到這裡,了解更清楚的話,可以去google官網閱讀相關内容。

實作一個回調案例

代碼結構

├── bearpi

│   └── 1.0

│       ├── Android.bp

│       ├── current.txt

│       ├── default

│       │   ├── Android.bp

│       │   ├── [email protected]

│       │   ├── BearPi.cpp

│       │   ├── BearPi.h

│       │   └── service.cpp

│       ├── IBearPiClientCallback.hal

│       ├── IBearPi.hal

│       ├── test

│       │   ├── Android.bp

│       │   └── BearPiTest.cpp

│       └── types.hal

一 ,準備

我們需要用的hidl-gen 工具去生成檔案,這個工具可以通過編譯得到

source build/envsetup.sh

lunch xxx

make

先整編一下需要添加的aosp。

二,添加hal檔案

在hardware/interfaces目錄下建立bearpi,我們從1.0版本開始,default目錄為實作hal的存放路徑

mkdir -p bearpi/1.0/default

很多現有的HAL實作會與硬體異步通信,需要以異步的方式通知用戶端發生的事件,比如,指令下發後傳回執行狀态。HIDL接口可以用作異步回調。

在bearpi/1.0路徑下建立兩個hal檔案,

IBearPi.hal

package [email protected];   ----------------------------------------------------------------------------------------------->軟體包名

import IBearPiClientCallback; --------------------------------------------------------------------------------------------------------------->

import

 語句是用于通路其他軟體包中的軟體包接口和類型的 HIDL 機制

interface IBearPi{

    setNotify(IBearPiClientCallback callback)  generates (uint64_t bearpiId); --------------------------------------------------->設定回調

    test() generates (uint64_t testresult);

};

IBearPiClientCallback.hal

package [email protected];

interface IBearPiClientCallback {

    oneway onResult(uint64_t deviceId, BearPiAcquiredInfo acquiredInfo, uint32_t vendorCode);------------------------>回調函數

};

types.hal --------------------------------------------------------------------------------------------------------------------------------------------->

types.hal

 檔案并不定義接口,而是定義軟體包中每個接口可以通路的資料類型

package [email protected];

enum BearPiAcquiredInfo : int32_t {

  ACQUIRED_GOOD = 0,

  ACQUIRED_PARTIAL = 1,

  ACQUIRED_INSUFFICIENT = 2,

  ACQUIRED_IMAGER_DIRTY = 3,

  ACQUIRED_TOO_SLOW = 4,

  ACQUIRED_TOO_FAST = 5,

  ACQUIRED_VENDOR = 6

};

注意軟體包字首對應的位置,android.hardware.*  -----hardware/interfaces) {---------------------------------------------->打開就是直通模式,注釋使用綁定式

    //return new BearPi();

//}

//

}  // namespace implementation

}  // namespace V1_0

}  // namespace bearpi

}  // namespace hardware

}  // namespace android

四,添加service

在default路徑下建立service.cpp

#define LOG_TAG "fht"

#include <android/log.h>

#include <hidl/HidlSupport.h>

#include <hidl/HidlTransportSupport.h>

#include <android/hardware/bearpi/1.0/IBearPi.h>

#include <android/hardware/bearpi/1.0/types.h>

#include "BearPi.h"

using android::hardware::bearpi::V1_0::IBearPi;

using android::hardware::bearpi::V1_0::implementation::BearPi;

using android::hardware::configureRpcThreadpool;

using android::hardware::joinRpcThreadpool;

using android::sp;

int main(){

    ALOGD("Bearpi service start ");

    android::sp<IBearPi> bear = BearPi::getInstance();

//綁定式服務

// This function must be called before you join to ensure the proper
// number of threads are created. The threadpool will never exceed
// size one because of this call.
           

 //如果“callerWillJoin”為true,則表示調用方将加入線程池,是以核心需要少建立一個線程。

//如果“callerWillJoin”為false,我們仍然會在本地生成一個線程,我們還應該告訴核心建立的線程比這裡請求的少一個。

    configureRpcThreadpool(1, true ); //  用于設定 目前程序用于hwbinder通信的最大線程數

    if (bear != nullptr) {

        if (::android::OK != bear->registerAsService()) { //注冊服務

            return 1;

        }

    } else {

        ALOGE("Can't create instance of bearpi, nullptr");

    }

    ALOGD("Bearpi service registerAsService ");

// Adds this thread to the threadpool, resulting in one total
 // thread in the threadpool. We could also do other things, but
 // would have to specify 'false' to willJoin in configureRpcThreadpool
           

    joinRpcThreadpool();

    return 0; // should never get here

//直通式服務,

defaultPassthroughServiceImplementation

 将對提供的 

-impl

 庫執行 

dlopen()

 操作,并将其作為 Binder 化服務提供

//return defaultPassthroughServiceImplementation<IBearPi>("BearPi");

}

五,啟動rc檔案

在default路徑下建立 [email protected]

service vendor.bear_hal /vendor/bin/hw/[email protected]

    # "class hal" causes a race condition on some devices due to files created

    # in /data. As a workaround, postpone startup until later in boot once

    # /data is mounted.

    class hal

    user system

    group system system

六,生成Android.bp檔案

檔案建立成功後,需要加入編譯,下面我們使用hidl-gen生成對應的Android.bp檔案

生成1.0架構接口庫

hidl-gen -Landroidbp -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport [email protected]

生成impl 庫的 Android.bp

hidl-gen -Landroidbp-impl -o /home/ubuntu/data/LG/hardware/interfaces/bearpi/1.0/default/  -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport [email protected]

修改default下面Android.bp,生成service bin

cc_binary {

    name: "[email protected]",

    defaults: ["hidl_defaults"],

    init_rc: ["[email protected]"],

    vendor: true,

    relative_install_path: "hw",

    srcs: [

        "BearPi.cpp",

        "service.cpp",

    ],

    shared_libs: [

        "libcutils",

        "liblog",

        "libhidlbase",

        "libhardware",

        "libutils",

  1.         "[email protected]",

    ],

}

七,SELinux權限

以mtk平台為例,添加bearpi相應權限

路徑:device/mediatek/sepolicy/basic/non_plat

1,建立bearpi.te

type bearpi, domain;

type bearpi_exec, exec_type, vendor_file_type, file_type;

hwbinder_use(bearpi);

init_daemon_domain(bearpi)

add_hwservice(bearpi, hal_bearpi_hwservice)

allow bearpi hwservicemanager_prop:file { read open getattr map };

2,file_contexts中添加

/(vendor|system/vendor)/bin/hw/android\.hardware\[email protected]\.0-service     u:object_r:bearpi_exec:s0

3,hwservice.te中定義hwservice manager類型

type hal_bearpi_hwservice, hwservice_manager_type;

4,hwservice_contexts中添加接口通路權限

android.hardware.bearpi::IBearPi                            u:object_r:hal_bearpi_hwservice:s0

八,編譯

1,添加系統編譯,使系統整編後能主動編譯,在device/xx/device.mk中添加包編譯

PRODUCT_PACKAGES += \

    [email protected] \

   [email protected] \

   test_bearpi \

   bearpi.default

DEVICE_MANIFEST_FILE += device/xiaomi/lancelot/manifest_bearpi.xml

2,在項目地下建立manifest_bearpi.xml接口注冊檔案,如果沒有注冊檔案,用戶端和服務端将無法通信,getService()将傳回null。

<manifest version="1.0" type="device">

    <hal format="hidl">

        <name>android.hardware.bearpi</name>

        <transport>hwbinder</transport>

        <version>1.0</version>

        <interface>

            <name>IBearPi</name>

            <instance>default</instance>

        </interface>

    </hal>

</manifest>

3,添加啟動服務,在init.project.rc内添加bearpi 的rc檔案,保證開機能夠啟動服務

import /vendor/etc/init/[email protected]

----------------------------------------------------------我------------是-------------分-----------割------------線---------------------------------------------------------------

如上服務端寫好後,我們寫用戶端測試下

在1.0路徑下建立test目錄

建立BearPiTest.cpp

//

// Created by ubuntu on 2020/12/25.

//

#define LOG_TAG "fht"

#define LOG_VERBOSE "fht"

#include <android/hardware/bearpi/1.0/IBearPi.h>

#include <hidl/Status.h>

#include <log/log.h>

#include <android/log.h>

using android::hardware::bearpi::V1_0::BearPiAcquiredInfo;

using android::hardware::bearpi::V1_0::IBearPi;

using android::hardware::bearpi::V1_0::IBearPiClientCallback;

using android::sp;

using android::hardware::hidl_string;

using android::hardware::Return; // 命名空間

using android::hardware::Void;  // Void函數

//實作回調

class BearPiClientCallback : public IBearPiClientCallback { 

public:

      BearPiClientCallback() {}

      ~BearPiClientCallback() {}

      Return<void> onResult(uint64_t deviceId, const ::android::hardware::bearpi::V1_0::BearPiAcquiredInfo acquiredInfo,uint32_t vendorCode) override {

          ALOGD("onResult deviceid =%lu, vendorCode = %d, info = %d", deviceId, vendorCode, acquiredInfo);

          return Void();

      };

};

int main() {

//獲得服務

    sp <IBearPi> bear = IBearPi::getService();

    if (bear == nullptr) {

        ALOGE("Can't find IBearPi service ...");

        return -1;

    }

    ALOGD("IBearPi ON");

    sp <BearPiClientCallback> callback = new BearPiClientCallback();

//注冊回調

    bear->setNotify(callback);

    bear->test();

    return 0;

}

在test目錄下建立Android.bp

cc_binary {

     name: "test_bearpi",

     srcs: [

     "BearPiTest.cpp",

     ],

     shared_libs: [

          "libcutils",

         "liblog",

         "libhidlbase",

         "libhardware",

         "libutils",

         "[email protected]",

     ],

}