aidl實現hal

xiaowang_lj發表於2024-05-22

Stable AIDL HAL 實戰
背景:
官方:https://source.android.com/devices/architecture/aidl/aidl-hals.

Google 在Android 11引入了AIDL for HALs,旨在代替HIDL原先的作用。在之後的Android版本推薦使用AIDL 實現Hal層的訪問。
這樣做的原因,應該有以下幾點:

AIDL比HIDL存在的時間更長(僅從Android 8到Android 10),並在許多其他地方使用,如Android框架元件之間或應用程式中。既然AIDL具有穩定性支援,就可以用單一的IPC方式從HAL到框架程序或者應用程序。
AIDL還有一個比HIDL更好的版本控制系統。
再詳細的展開說就是:

AIDL 更成熟,使用更廣泛,如果HAL層也使用了AIDL的方式,那麼就可以直接從應用程序呼叫到HAL 程序,以前使用HIDL的時候實現應用程序訪問HAL的服務,需要在system server程序的中介。來個圖:

以前使用HIDL的方式,如果後續vendor HAL version需要迭代升級,那麼就需要再建立一個子目錄,過程中實際上做很多的重複工作,冗餘而效率不高。
值得注意的是:在HAL 層使用AIDL必須使用Stable AIDL, 和我們在應用層或者框架層稍微不同,因為和vendor的介面設計要兼顧穩定性,system和vendor的更新速率不一樣。

HALs using AIDL to communicate between framework components must use Stable AIDL.

使用AIDL for HALs
1. 定義HAL介面
建立對應的模組目錄:/hardware/interfaces/hongxi/aidl/
建立aidl檔案:/hardware/interfaces/hongxi/aidl/android/hardware/hongxi/IHongxi.aidl

package android.hardware.hongxi;

@VintfStability
interface IHongxi {
String getName();

void setName(in String msg);
}

每個型別定義都必須使用@VintfStability進行註釋。
如果想要定義型別,參考同用的AIDL的定義就行,同時比通用的AIDL多了列舉、結構體、parcelable型別(注意這些型別跟Android版本有關,13以下的版本不一定有全)

2. 配置Android.bp
建立頂層Android.bp:/hardware/interfaces/hongxi/aidl/Android.bp

aidl_interface {
   name: "android.hardware.hongxi",
   vendor: true,
   srcs: ["android/hardware/hongxi/*.aidl"],
   stability: "vintf",
   owner: "hongxi.zhu",
   backend: {
       cpp: {
           enabled: false,
       },
       java: {
              enabled: false,
       },
   },
}

backend: 服務的後端,AIDL支援四種後端,分別是C++/JAVA/NDK/RUST, 我們將使用NDK(谷歌推薦),因此將CPP和JAVA後端宣告為false

使用java的話會生成jar,apk可以直接引用 out\soong\.intermediates\hardware\interfaces\hongxi\aidl\android.hardware.hongxi-V1-java\android_common\javac\android.hardware.hongxi-V1-java.jar

java: {
            sdk_version: "module_current",
              
       },

為了方便測試,設定vendor:true並刪除vendor_available,因為這是一個自定義供應商HAL,刪除vndk部分,因此這個HAL僅位於vendor分割槽,不受VNDK限制,真正開發中,如需開啟需要自己解決VNDK的限制問題,這裡就不單獨列出。

3. 編譯模組
mmm hardware/interfaces/hongxi/


然後就會報錯:

[ 74% 227/303] echo "API dump for the current version of AIDL interface android.hardware.hongxi does not exist." && echo Run "m android.hardware.hongxi-update-api", or add "unstable: true" to the build ru
FAILED: out/soong/.intermediates/hardware/interfaces/hongxi/aidl/android.hardware.hongxi-api/checkapi_current.timestamp
echo "API dump for the current version of AIDL interface android.hardware.hongxi does not exist." && echo Run "m android.hardware.hongxi-update-api", or add "unstable: true" to the build rule for the inte
rface if it does not need to be versioned && false
API dump for the current version of AIDL interface android.hardware.hongxi does not exist.
Run m android.hardware.hongxi-update-api, or add unstable: true to the build rule for the interface if it does not need to be versioned
19:29:13 ninja failed with: exit status 1

原因是當前版本沒有這個介面,需要更新下API,按照提示來:

m android.hardware.hongxi-update-api

然後再重新編譯模組:

mmm hardware/interfaces/hongxi/

4. 實現HAL 介面
We will use the ndk_platfrom library, therefore, let check the generated code for ndk_platform.我們需要在實現的介面編譯指令碼中引用模組的ndk_platfrom, 且我們要實現的介面在編譯時都生成了對應的原始碼,我們只需要複製出來並實現,所以先看下,剛才的編譯都生成了什麼:

cd out/soong/.intermediates/hardware/interfaces/hongxi/aidl/android.hardware.hongxi-V1-ndk-source
find .
.
./gen
./gen/android
./gen/android/hardware
./gen/android/hardware/hongxi
./gen/android/hardware/hongxi/IHongxi.cpp.d
./gen/android/hardware/hongxi/IHongxi.cpp
./gen/include
./gen/include/aidl
./gen/include/aidl/android
./gen/include/aidl/android/hardware
./gen/include/aidl/android/hardware/hongxi
./gen/include/aidl/android/hardware/hongxi/BpHongxi.h
./gen/include/aidl/android/hardware/hongxi/BnHongxi.h
./gen/include/aidl/android/hardware/hongxi/IHongxi.h
./gen/timestamp

在IHongxi.h標頭檔案中找到我們要實現的介面:

virtual ::ndk::ScopedAStatus getName(std::string* _aidl_return) = 0;
virtual ::ndk::ScopedAStatus setName(const std::string& in_msg) = 0;

接下來就需要建立後端原始碼檔案,來實現這些介面:
/hardware/interfaces/hongxi/aidl/default/Hongxi.h

#pragma once

#include <aidl/android/hardware/hongxi/BnHongxi.h>

namespace aidl {
namespace android {
namespace hardware {
namespace hongxi {

class Hongxi : public BnHongxi {
    public:
        //String getName();
        ndk::ScopedAStatus getName(std::string* _aidl_return);

        //void setName(in String msg);
        ndk::ScopedAStatus setName(const std::string& in_msg);

    private:
        std::string name = "";
};

}  // namespace hongxi
}  // namespace hardware
}  // namespace android
}  // namespace aidl

/hardware/interfaces/hongxi/aidl/default/Hongxi.cpp

#define LOG_TAG "Hongxi"

#include <utils/Log.h>
#include <iostream>
#include "Hongxi.h"

namespace aidl {
namespace android {
namespace hardware {
namespace hongxi {

ndk::ScopedAStatus Hongxi::getName(std::string* _aidl_return) {

    *_aidl_return = name;

    return ndk::ScopedAStatus::ok();
}

ndk::ScopedAStatus Hongxi::setName(const std::string& in_msg) {

    name = in_msg;

    return ndk::ScopedAStatus::ok();
}

}  // namespace hongxi
}  // namespace hardware
}  // namespace android
}  // namespace aidl

5. 實現服務:
/hardware/interfaces/hongxi/aidl/default/main.cpp

#define LOG_TAG "Hongxi"

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

using aidl::android::hardware::hongxi::Hongxi;
using std::string_literals::operator""s;

int main() {
    // Enable vndbinder to allow vendor-to-venfor binder call
    android::ProcessState::initWithDriver("/dev/vndbinder"); //使用vnbinder的配置

    ABinderProcess_setThreadPoolMaxThreadCount(0); // vnbinder的執行緒池獨立,需要單獨配置 
    ABinderProcess_startThreadPool();

    std::shared_ptr<Hongxi> hongxi = ndk::SharedRefBase::make<Hongxi>();
    const std::string desc = Hongxi::descriptor + "/default"s;

    if (hongxi != nullptr) {
        if(AServiceManager_addService(hongxi->asBinder().get(), desc.c_str()) != STATUS_OK) {
            ALOGE("Failed to register IHongxi service");
            return -1;
        }
    } else {
        ALOGE("Failed to get IHongxi instance");
        return -1;
    }

    ALOGD("IHongxi service starts to join service pool");
    ABinderProcess_joinThreadPool();

    return EXIT_FAILURE;  // should not reached
}

8. 編寫服務啟動的rc指令碼
/hardware/interfaces/hongxi/aidl/default/android.hardware.hongxi-service.rc

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


9. 宣告VINTF AIDL 介面
/hardware/interfaces/hongxi/aidl/default/android.hardware.hongxi-service.xml

<manifest version="1.0" type="device">
    <hal format="aidl">
        <name>android.hardware.hongxi</name>
        <fqname>IHongxi/default</fqname>
    </hal>
</manifest>

7. 編寫服務構建指令碼
/hardware/interfaces/hongxi/aidl/default/Android.bp

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

    srcs: [
        "Hongxi.cpp",
        "main.cpp",
    ],

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

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

將模組加入系統中
device\rockchip\rk356x\device.mk

# add for Hongxi
PRODUCT_PACKAGES += \
android.hardware.hongxi \
android.hardware.hongxi-service \

將模組新增到相容性矩陣中
# (選下標最新的那個)
hardware/interfaces/compatibility_matrices/compatibility_matrix.5.xml
#(這個不一定有,如果沒有就不加)
hardware/interfaces/compatibility_matrices/compatibility_matrix.current.xml

    <hal format="aidl" optional="true">
        <name>android.hardware.hongxi</name>
        <version>1.0</version>
        <interface>
            <name>IHongxi</name>
            <instance>default</instance>
        </interface>
    </hal>

解決Selinux許可權
這個後續補充,測試中,會有宏版本和直接新增的版本

客戶端測試
cpp-client(user process)
apk-client(user process)

app的libs引入jar包

使用

IHongxi hongxi;
        IBinder binder = ServiceManager.getService(IINVCASE_AIDL_INTERFACE);
        if (binder == null) {
            Log.e(TAG, "Getting " + IINVCASE_AIDL_INTERFACE + " service daemon binder failed!");
        } else {
            hongxi = IHongxi.Stub.asInterface(binder);
            if (hongxi == null) {
                Log.e(TAG, "Getting IInvcase AIDL daemon interface failed!");
            } else {
                Log.d(TAG, "IInvcase AIDL daemon interface is binded!");
                try {
                    hongxi.setName("aaaa");
                } catch (RemoteException e) {
                    throw new RuntimeException(e);
                }
            }
        }

SystemService-client(system server process)

https://blog.csdn.net/qq_40731414/article/details/126823262

相關文章