HIDL學習總結--擴展ICameraProvider.hal接口實現跨進程向CameraProvider進程傳遞兆級別數據的實現方案

CameraAPI2 向Camera HAL 傳遞數據如相機參數主要是通過camera_metadata實現的,最近項目有個需求是向Camera HAL 傳遞一個YUV數據,大小是幾兆左右,使用現有的camera_metadata來實現困難(需要以後研究下其可行性1)。

爲實現該功能,進一步提升CameraAPI2 向Camera HAL傳遞數據的能力,本文通過擴展ICameraProvider.hal接口向CameraProvider進程傳遞一個匿名共享內存(Ashmem)來實現該功能。

主要實現如下:
修改ICameraProvider.hal文件

//hardware\interfaces\camera\provider\2.4\ICameraProvider.hal
--- a/camera/provider/2.4/ICameraProvider.hal
+++ b/camera/provider/2.4/ICameraProvider.hal
@@ -185,4 +185,7 @@ interface ICameraProvider {
             (Status status,
              android.hardware.camera.device@3.2::ICameraDevice device);
 //擴展的接口registerMemory
 //descriptor爲共享內存句柄
 //bufferSize爲共享內存大小
 //bufferCount共享內存個數
 //memId?
+    registerMemory(handle descriptor, uint32_t bufferSize, uint32_t bufferCount)
+            generates (uint32_t memId);
+
 };

重新編譯下CameraProvider(可能需要修改下hardware\interfaces\current.txt才能編譯過2)

--- a/current.txt
+++ b/current.txt
@@ -58,7 +58,6 @@ b32f9aeaf1c442195eb06ffc7600968c919d005b2718874f09c57287fae55918 android.hardwar
 0fa3e1e64819283b8737fc4e5ab759f0cb4ac1a996e8a51cc4aa8025a457208e android.hardware.camera.device@3.2::ICameraDeviceSession
 030be3d2b159cbde7920485807140f6b6064ef4a5de4a40a6c4bc8d2c72f7cd3 android.hardware.camera.device@3.2::types
 5ba7947cee515d7a2359bfcbfb9678c1c3a768c288471919ac095b96ae6f3d40 android.hardware.camera.metadata@3.2::types
 //刪除該行
-f7e299d85033ac52d1095a35784fcfeaff43603f58c751e4153c85bbade3b330 android.hardware.camera.provider@2.4::ICameraProvider

重新生成的CameraProvider接口如下:

struct ICameraProvider : public ::android::hidl::base::V1_0::IBase {
    virtual bool isRemote() const override { return false; }
...
    using getCameraDeviceInterface_V3_x_cb = std::function<void(::android::hardware::camera::common::V1_0::Status status, const ::android::sp<::android::hardware::camera::device::V3_2::ICameraDevice>& device)>;
    virtual ::android::hardware::Return<void> getCameraDeviceInterface_V3_x(const ::android::hardware::hidl_string& cameraDeviceName, getCameraDeviceInterface_V3_x_cb _hidl_cb) = 0;
//新添加的接口
    virtual ::android::hardware::Return<uint32_t> registerMemory(const ::android::hardware::hidl_handle& descriptor, uint32_t bufferSize, uint32_t bufferCount) = 0;
....

還需要在實現了ICameraProvider抽象類的CameraProvider類中實現新定義的registerMemory方法
CameraProvider.h頭文件中添加registerMemory的聲明

//hardware\interfaces\camera\provider\2.4\default\CameraProvider.h
--- a/camera/provider/2.4/default/CameraProvider.h
+++ b/camera/provider/2.4/default/CameraProvider.h
@@ -68,7 +68,7 @@ struct CameraProvider : public ICameraProvider, public camera_module_callbacks_t
     Return<void> getCameraDeviceInterface_V3_x(
             const hidl_string& cameraDeviceName,
             getCameraDeviceInterface_V3_x_cb _hidl_cb) override;
//新接口聲明聲明
+    Return<uint32_t> registerMemory(const hidl_handle& descriptor, uint32_t bufferSize, uint32_t bufferCount) override;
 private:
     Mutex mCbLock;
     sp<ICameraProviderCallback> mCallbacks = nullptr;

CameraProvider.cpp中實現該registerMemory

--- a/camera/provider/2.4/default/CameraProvider.cpp
+++ b/camera/provider/2.4/default/CameraProvider.cpp
@@ -24,6 +24,8 @@
 #include <cutils/properties.h>
 #include <string.h>
 #include <utils/Trace.h>
+#include <binder/MemoryBase.h>
+#include <binder/MemoryHeapBase.h>
 
 
 namespace android {
@@ -523,6 +525,60 @@ Return<void> CameraProvider::getCameraDeviceInterface_V3_x(
     return Void();
 }
// 添加局部dumpImage方法,檢驗數據是否傳遞正確
+void dumpImage(unsigned char* pData,
+        uint32_t frameid,uint32_t stride,uint32_t height,uint32_t bytePerPixe) {
+    ALOGE("%s,%d E .", __FUNCTION__,__LINE__);
+
+    char buf[255];
+    memset(buf, 0, sizeof(buf));
+    snprintf(buf, sizeof(buf),  "/data/misc/camera/frame_%dx%d_%d.raw",
+             stride,height,frameid);
+    ALOGE("%s,%d buf : %s", __FUNCTION__,__LINE__,buf);
+    int file_fd = open(buf, O_RDWR | O_CREAT, 0666);
+    uint32_t size = stride*height*bytePerPixe;
+    if (file_fd >= 0)
+    {
+        ssize_t written_Len    = write(file_fd, pData, size);
+        ALOGE("%s,%d : written number of %zd bytes to file %s", __FUNCTION__,__LINE__,written_Len,buf);
+        close(file_fd);
+    }
+    else
+    {
+        ALOGE("%s,%d : failed to write data to %s", __FUNCTION__,__LINE__,buf);
+    }
+    ALOGE("%s,%d X .", __FUNCTION__,__LINE__);
+}
+
// registerMemory接口實現
+Return<uint32_t> CameraProvider::registerMemory(const hidl_handle& descriptor, uint32_t bufferSize, uint32_t bufferCount) {
+    ALOGE("%s:%d,%d,%d", __FUNCTION__,bufferSize,bufferCount,descriptor->data[0]);
+    if (descriptor->numFds != 1) {
+        ALOGE("%s: camera memory descriptor has numFds %d (expect 1)",
+                __FUNCTION__, descriptor->numFds);
+        return 0;
+    }
+    if (descriptor->data[0] < 0) {
+        ALOGE("%s: camera memory descriptor has FD %d (expect >= 0)",
+                __FUNCTION__, descriptor->data[0]);
+        return 0;
+    }
+    
+    sp<android::MemoryHeapBase> mHeap;
+    //由hidl_handle descriptor轉換生成MemoryHeapBase
+    //MemoryHeapBase是內名共享內存定義的方法,以後會單獨研究下MemoryHeapBase MemoryBase
+    mHeap = new android::MemoryHeapBase(descriptor->data[0], bufferSize * bufferCount,0,0);
+    sp<MemoryBase> *mBuffers;
+    mBuffers = new sp<MemoryBase>[bufferCount];
+    for (uint_t i = 0; i < bufferCount; i++) {
+        mBuffers[i] = new MemoryBase(mHeap,i * bufferSize, bufferSize);
+    }
+    ssize_t offset;
+    size_t size;
+    sp<IMemoryHeap> heap = mBuffers[0]->getMemory(&offset, &size);
+    void* heapBase = heap->base();
+    //dump傳遞進CameraProvider的數據,檢查數據是否正確
+    dumpImage((unsigned char*)heapBase,1,bufferSize,bufferCount,1);
+    //將由descriptor轉換生成的MemoryHeapBase對象的HeapID放回給client用戶
+    return mHeap->getHeapID();
+};
+

然後修改下編譯文件

//hardware\interfaces\camera\provider\2.4\default\Android.bp
--- a/camera/provider/2.4/default/Android.bp
+++ b/camera/provider/2.4/default/Android.bp
@@ -23,7 +23,8 @@ cc_library_shared {
         "[email protected]",
         "liblog",
         "libhardware",
-        "libcamera_metadata"
+        "libcamera_metadata",
+        "libbinder"
     ],
     static_libs: [
         "[email protected]"

至此CameraProvider的修改完成。

接着介紹下新定義的registerMemory如何使用,即如何將一個帶有用戶數據的Ashmem傳遞給CameraProvider
本文在CameraService中使用該方法,當然也可以在任何可以獲得CameraProvider服務代理的地方使用,如相機應用。

--- a/services/camera/libcameraservice/common/CameraProviderManager.cpp
+++ b/services/camera/libcameraservice/common/CameraProviderManager.cpp
@@ -25,11 +25,20 @@
 #include <hidl/ServiceManagement.h>
 #include <functional>
 #include <camera_metadata_hidden.h>
 //添加必要的頭文件
+#include <android/hidl/memory/1.0/IMemory.h>
+#include <android/hidl/allocator/1.0/IAllocator.h>
+#include <hidlmemory/mapping.h>
 
 namespace android {
 
 using namespace ::android::hardware::camera;
 using namespace ::android::hardware::camera::common::V1_0;
+using ::android::hardware::camera::device::V1_0::MemoryId;
//將必要的名稱空間添加到本類中
+using ::android::hidl::allocator::V1_0::IAllocator;
+using ::android::hidl::base::V1_0::IBase;
+using ::android::hidl::memory::V1_0::IMemory;
+using ::android::hardware::hidl_memory;

 
 namespace {
 // Hardcoded name for the passthrough HAL implementation, since it can't be discovered via the
@@ -522,6 +531,35 @@ status_t CameraProviderManager::ProviderInfo::initialize() {
         return mapToStatusT(status);
     }
 
+    // Shared memory related members
+    size_t buf_size = 1024 * 1024;// 1m
+    uint_t num_bufs = 1;
+    hidl_memory      mHidlHeap;
+    native_handle_t* mHidlHandle; // contains one shared memory FD
+    sp<IAllocator>   ashmemAllocator;
+    sp<IMemory>      mHidlHeapMemory; // munmap happens in ~IMemory()
+    void*            mHidlHeapMemData;
+   //獲取IAllocator服務代理,IAllocator需要以後研究下
+    ashmemAllocator = IAllocator::getService("ashmem");
+    const size_t pagesize = getpagesize();
+    //大小對其到pagesize的整數倍
+    size_t size = ((buf_size * num_bufs + pagesize-1) & ~(pagesize-1));
+    //分配匿名共享內存
+    ashmemAllocator->allocate(size,
+        [&](bool success, const hidl_memory& mem) {
+            mHidlHandle = native_handle_clone(mem.handle());
+            mHidlHeap = hidl_memory("ashmem", mHidlHandle, size);
+            ALOGI("allocate %d", success);
+        });
+    //將內存映射到當前進程,mapMemory需要以後研究下
+    mHidlHeapMemory = mapMemory(mHidlHeap);
+    mHidlHeapMemData = mHidlHeapMemory->getPointer();
+    uint8_t*temp = (uint8_t*)mHidlHeapMemData;
+    //測試內容,如果在CameraProvider dumpImage方法保存的數據全部是0xFE,說明功能實現成功
+    memset(temp,0xFE,size);
+    //將帶有用戶數據的內名共享內存註冊給CameraProvider
+    uint32_t memid = mInterface->registerMemory(mHidlHandle, buf_size, num_bufs);
+    ALOGI("memid %d", memid);
+
+
     sp<StatusListener> listener = mManager->getStatusListener();
     for (auto& device : devices) {
         std::string id;

修改下編譯文件

//frameworks\av\services\camera\libcameraservice\Android.mk
--- a/services/camera/libcameraservice/Android.mk
+++ b/services/camera/libcameraservice/Android.mk
@@ -99,9 +99,12 @@ LOCAL_SHARED_LIBRARIES:= \
     android.hardware.camera.device@1.0 \
     vendor.qti.hardware.camera.device@1.0 \
     android.hardware.camera.device@3.2 \
-    android.hardware.camera.device@3.3
+    android.hardware.camera.device@3.3 \
+    android.hidl.allocator@1.0 \
+    android.hidl.memory@1.0\
+    libhidlmemory \
 
-LOCAL_EXPORT_SHARED_LIBRARY_HEADERS := libbinder libcamera_client libfmq
+LOCAL_EXPORT_SHARED_LIBRARY_HEADERS := libbinder libcamera_client libfmq android.hidl.allocator@1.0 android.hidl.memory@1.0 libhidlmemory
 
 LOCAL_C_INCLUDES += \
     system/media/private/camera/include \

重新編譯,將生成的so push到手機中,重啓手機,發現在/data/misc/camera目錄下生成了
frame_1048576x1_1.raw文件

打開查看其內如如下:
在這裏插入圖片描述
從dump數據看,其內容和CameraService傳遞的值是相同的。功能基本實現3


  1. 驗證不可行,原因請查看android framework CameraMetadata與HIDL CameraMetadata的區別及相互轉換 ↩︎

  2. 編譯時會檢查下當前的Hash和hardware\interfaces\current.txt是否匹配
    代碼在system\tools\hidl\Coordinator.cpp Coordinator::enforceHashes(…)。 ↩︎

  3. 查看log時,發現SELinux : avc: denied { find } for interface=android.hidl.memory::IMapper相關的Log,可能還需要修改SELinux 權限問題,我們的項目已經將SELinux關閉了,哈哈。還有現在只實現了註冊方法,應該還需要反註冊,之後再完善吧。 ↩︎

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章