iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 13
1
  • Guide:
    • Treble 是什麼?
    • Treble 架構
    • HIDL 概述
    • HIDL 編碼規範
    • HIDL 中的 hidl-gen 使用
    • HIDL interface 和 package
    • HIDL import & inheritance
    • HIDL 實作

這部份就是 binderized 模式需要用到 service 相關的設定了,
假如是單純使用 passthrough 模式的話,就不需要。
因為我沒有特別實作這部份,所以要是想做的話可以先當參考,
有錯誤還請見諒和不吝告知小弟弟,
感謝各位大大。

Step 5. 創立 service & impl

其實當 IHelloworld.hal 創建完成,
就可以創建對應的 HIDL 實現代碼( impl 和 service),
hidl-gen 也提供了默認生成的方式,
詳細看 HIDL (4) hidl-genupdate-files.sh
執行後最終生成的文件為:

├── default
│   ├── Android.bp
│   ├── HelloWorld.cpp
│   └── HelloWorld.h

先來看下 HelloWorld.h

	1 #ifndef ANDROID_HARDWARE_HELLOWORLD_V1_0_HELLOWORLD_H                                                                                                                                
  2 #define ANDROID_HARDWARE_HELLOWORLD_V1_0_HELLOWORLD_H
  3  
  4 #include <android/hardware/helloworld/1.0/IHelloWorld.h>
  5 #include <hidl/MQDescriptor.h>
  6 #include <hidl/Status.h>
  7  
  8 namespace android {
  9 namespace hardware {
 10 namespace helloworld {
 11 namespace V1_0 {
 12 namespace implementation {
 13  
 14 using ::android::hardware::hidl_array;
 15 using ::android::hardware::hidl_memory;
 16 using ::android::hardware::hidl_string;
 17 using ::android::hardware::hidl_vec;
 18 using ::android::hardware::Return;
 19 using ::android::hardware::Void;
 20 using ::android::sp;
 21  
 22 struct HelloWorld : public IHelloWorld {
 23     // Methods from ::android::hardware::helloworld::V1_0::IHelloWorld follow.
 24     Return<void> justTest(const hidl_string& name, justTest_cb _hidl_cb) override;
 25     Return<void> justTest1(::android::hardware::helloworld::V1_0::HelloTest name) override;
 26  
 27     // Methods from ::android::hidl::base::V1_0::IBase follow.
 28  
 29 };
 30  
 31 // FIXME: most likely delete, this is only for passthrough implementations
 32 // extern "C" IHelloWorld* HIDL_FETCH_IHelloWorld(const char* name);
 33  
 34 }  // namespace implementation
 35 }  // namespace V1_0
 36 }  // namespace helloworld
 37 }  // namespace hardware
 38 }  // namespace android
 39  
 40 #endif  // ANDROID_HARDWARE_HELLOWORLD_V1_0_HELLOWORLD_H

如果是要用 passthrough 模式,則需要打開 HIDL_FETCH_IHelloWorld() 函數的註釋,
並且在 -impl 的 C++ 文件中實現,
例如這裡需要在 HelloWorld.cpp 中實現該函數,
詳細可以看 nfc 或 tv 等模塊中實現。

再來看下 HelloWorld.cpp

	1 #include "HelloWorld.h"                                                                                                                                                              
  2  
  3 namespace android {
  4 namespace hardware {
  5 namespace helloworld {
  6 namespace V1_0 {
  7 namespace implementation {
  8  
  9 // Methods from ::android::hardware::helloworld::V1_0::IHelloWorld follow.
 10 Return<void> HelloWorld::justTest(const hidl_string& name, justTest_cb _hidl_cb) {
 11     // TODO implement
 12     return Void();
 13 }
 14  
 15 Return<void> HelloWorld::justTest1(::android::hardware::helloworld::V1_0::HelloTest name) {
 16     // TODO implement
 17     return Void();
 18 }
 19  
 20  
 21 // Methods from ::android::hidl::base::V1_0::IBase follow.
 22  
 23 //IHelloWorld* HIDL_FETCH_IHelloWorld(const char* /* name */) {
 24     //return new HelloWorld();
 25 //}
 26 //
 27 }  // namespace implementation
 28 }  // namespace V1_0
 29 }  // namespace helloworld
 30 }  // namespace hardware
 31 }  // namespace android

這裡就是實現的地方,
其中使用 passthrough 的時候需要打開 HIDL_FETCH_IHelloWorld() 函數。

這時候新增一個 service.cpp 檔案如下:

	1 #define LOG_TAG "android.hardware.helloworld@1.0-service"
  2  
  3 #include <android/hardware/helloworld/1.0/IHelloWorld.h>
  4  
  5 #include <hidl/LegacySupport.h>
  6 #include "HelloWorld.h"
  7  
  8 // Generated HIDL files
  9 using android::hardware::helloworld::V1_0::IHelloWorld;
 10 using android::hardware::helloworld::V1_0::implementation::HelloWorld;
 11  
 12 using android::hardware::defaultPassthroughServiceImplementation; 
 13 using android::hardware::configureRpcThreadpool;
 14 using android::hardware::joinRpcThreadpool;
 15  
 16 int main() {
 17 #if 0
 18     return defaultPassthroughServiceImplementation<IHelloWorld>();
 19 #else
 20     sp<IHelloWorld> service = new HelloWorld();
 21     configureRpcThreadpool(1, true /*callerWillJoin*/);
 22     if(android::OK !=  service->registerAsService())
 23         return 1;
 24     joinRpcThreadpool();           
 25 #endif
 26 }

Android.bp 是為了編譯 HIDL 實現部分的代碼生成的默認編譯文件,
可以根據實際的情況修改:

	1 cc_library_shared {
  2     // FIXME: this should only be -impl for a passthrough hal.
  3     // In most cases, to convert this to a binderized implementation, you should:
  4     // - change '-impl' to '-service' here and make it a cc_binary instead of a
  5     //   cc_library_shared.
  6     // - add a *.rc file for this module.
  7     // - delete HIDL_FETCH_I* functions.
  8     // - call configureRpcThreadpool and registerAsService on the instance.
  9     // You may also want to append '-impl/-service' with a specific identifier like
 10     // '-vendor' or '-<hardware identifier>' etc to distinguish it.
 11     name: "android.hardware.helloworld@1.0-impl",
 12     relative_install_path: "hw",
 13     // FIXME: this should be 'vendor: true' for modules that will eventually be
 14     // on AOSP.
 15     proprietary: true,
 16     srcs: [
 17         "HelloWorld.cpp",
 18     ],
 19     shared_libs: [
 20         "libhidlbase",
 21         "libhidltransport",
 22         "libutils",
 23         "android.hardware.helloworld@1.0",
 24     ],
 25 }

如果其他模塊需要 so 則需要 share lib,
如果不需要刻意直接編譯 service,
修改後的 Android.bp 如下:

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

注意:

  • name
    為變成生成的庫文件名稱,
    -impl 為實現的庫文件,
    -service 為服務端的庫文件;
  • init_rc
    指定啟動 service 的 rc 名稱;
  • relative_install_path
    為生成庫文件路徑,
    通常與 proprietaryvendor 屬性配套,
    一般都設為 hw
  • proprietary
    標記默認生成路徑,設為 true 代表為系統默認路徑 system/lib64 下,
    通常和 relative_install_path 屬性搭配使用,
    沒有設定時默認放在 system/lib64 下;
  • vendor
    proprietary 相同,設為 true 代表路徑在 vendor 下,
    默認 OEM 都會設置在 vendor 下;

Step 6. 創建 rc 文件

在實現了 serivce 和 impl 代碼後需要添加 rc 文件,
文件名為 android.hardware.helloworld@1.0-service.rc

	1 service helloworld-hal-1-0 /vendor/bin/hw/android.hardware.helloworld@1.0-service
  2     class hal   
  3     user system 
  4     group system

Step 7. 啟動 service

需要注意的是,
在應用起來之前需要使能 service,一般有兩種方式:
一個是通過 rc 中的 service name,直接 start;
另外一種是通過 SELINUX 中添加 te 文件,設置 domain 信息。
對於 SELINUX 配置,這裡暫不分析,詳細看 SELINUX 相關文章。


Step 8. 實現 client 端

App 其他的代碼這裡不做展示,主要來看調用的地方:

private void test() {
        IHelloWorld service = null;
        try {
            service = IHelloWorld.getService(true);
        } catch (RemoteException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
 
        if (service == null) {
            Log.e(TAG, "test failed, service is null...");
            return;
        }
 
        try {
            service.justTest1((byte)123);
        } catch (RemoteException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

Android.mk 為:

LOCAL_PATH := $(call my-dir)
 
include $(CLEAR_VARS)
 
LOCAL_CERTIFICATE := platform
LOCAL_MODULE_TAGS := optional
 
LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
LOCAL_PACKAGE_NAME := TestHIDLClient
 
#LOCAL_PROGUARD_FLAG_FILES := proguard.flags
 
LOCAL_PRIVATE_PLATFORM_APIS := true
 
LOCAL_STATIC_JAVA_LIBRARIES := \
    android.hardware.helloworld-V1.0-java
 
include $(BUILD_PACKAGE)

之後你運行自己寫的 client 端應用,
就可以看到類似下面的 log 啦!

I android_os_HwBinder: HwBinder: Starting thread pool for default::android.hardware.helloworld@1.0::IHelloWorld
... ...
D HelloWorldImpl: justTest1, name = 123

Reference :

HIDL C++ | Android Open Source Project

Implementing the Service | Android Open Source Project


上一篇
[Day-12] Android HIDL (7) 實作 (上)
下一篇
[Day-14] Android Pie NFC (1) 介紹
系列文
Android Pie 底層開發學習心得30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言