Khối bộ nhớ HIDL

HIDL MemoryBlock là một lớp trừu tượng được xây dựng trên hidl_memory , HIDL @1.0::IAllocatorHIDL @1.0::IMapper . Nó được thiết kế cho các dịch vụ HIDL có nhiều khối bộ nhớ để chia sẻ một đống bộ nhớ.

Cải tiến hiệu suất

Sử dụng MemoryBlock trong các ứng dụng có thể giảm đáng kể số lượng lỗi mmap / munmap và phân đoạn không gian người dùng, do đó cải thiện hiệu suất. Ví dụ:

  • Sử dụng mỗi hidl_memory cho mỗi lần phân bổ bộ đệm trung bình là 238 us/1 lần phân bổ.
  • Sử dụng MemoryBlock và chia sẻ một hidl_memory trung bình phân bổ 2,82 us/1.

Ngành kiến ​​​​trúc

Kiến trúc HIDL MemoryBlock bao gồm các dịch vụ HIDL với nhiều khối bộ nhớ chia sẻ một đống bộ nhớ duy nhất:

Khối bộ nhớ HIDL

Hình 1. Kiến trúc HIDL MemoryBlock

Sử dụng bình thường

Phần này cung cấp ví dụ về cách sử dụng MemoryBlock bằng cách khai báo HAL trước tiên sau đó triển khai HAL.

Khai báo HAL

Đối với ví dụ sau IFoo HAL:

import android.hidl.memory.block@1.0::MemoryBlock;

interface IFoo {
    getSome() generates(MemoryBlock block);
    giveBack(MemoryBlock block);
};

Android.bp như sau:

hidl_interface {
    ...
    srcs: [
        "IFoo.hal",
    ],
    interfaces: [
        "android.hidl.memory.block@1.0",
        ...
};

Thực hiện HAL

Để triển khai ví dụ HAL:

  1. Lấy hidl_memory (để biết chi tiết, hãy tham khảo HIDL C++ ).

    #include <android/hidl/allocator/1.0/IAllocator.h>
    
    using ::android::hidl::allocator::V1_0::IAllocator;
    using ::android::hardware::hidl_memory;
    ...
      sp<IAllocator> allocator = IAllocator::getService("ashmem");
      allocator->allocate(2048, [&](bool success, const hidl_memory& mem)
      {
            if (!success) { /* error */ }
            // you can now use the hidl_memory object 'mem' or pass it
      }));
    
  2. Tạo HidlMemoryDealer với hidl_memory có được:

    #include <hidlmemory/HidlMemoryDealer.h>
    
    using ::android::hardware::HidlMemoryDealer
    /* The mem argument is acquired in the Step1, returned by the ashmemAllocator->allocate */
    sp<HidlMemoryDealer> memory_dealer = HidlMemoryDealer::getInstance(mem);
    
  3. Phân bổ MemoryBlock , là một cấu trúc được xác định bằng HIDL.

    Ví dụ MemoryBlock :

    struct MemoryBlock {
    IMemoryToken token;
    uint64_t size;
    uint64_t offset;
    };
    

    Ví dụ sử dụng MemoryDealer để phân bổ MemoryBlock :

    #include <android/hidl/memory/block/1.0/types.h>
    
    using ::android::hidl::memory::block::V1_0::MemoryBlock;
    
    Return<void> Foo::getSome(getSome_cb _hidl_cb) {
        MemoryBlock block = memory_dealer->allocate(1024);
        if(HidlMemoryDealer::isOk(block)){
            _hidl_cb(block);
        ...
    
  4. Phân bổ MemoryBlock :

    Return<void> Foo::giveBack(const MemoryBlock& block) {
        memory_dealer->deallocate(block.offset);
    ...
    
  5. Thao tác dữ liệu:

    #include <hidlmemory/mapping.h>
    #include <android/hidl/memory/1.0/IMemory.h>
    
    using ::android::hidl::memory::V1_0::IMemory;
    
    sp<IMemory> memory = mapMemory(block);
    uint8_t* data =
    
    static_cast<uint8_t*>(static_cast<void*>(memory->getPointer()));
    
  6. Cấu hình Android.bp :

    shared_libs: [
            "android.hidl.memory@1.0",
    
            "android.hidl.memory.block@1.0"
    
            "android.hidl.memory.token@1.0",
            "libhidlbase",
            "libhidlmemory",
    
  7. Xem lại quy trình để xác định xem bạn có cần lockMemory hay không.

    Thông thường, MemoryBlock sử dụng số tham chiếu để duy trì hidl_memory được chia sẻ, đó là mmap() -ed trong lần đầu tiên một trong MemoryBlock s của nó được ánh xạ và là munmap() -ed khi không có gì đề cập đến nó. Để giữ cho hidl_memory luôn được ánh xạ, bạn có thể sử dụng lockMemory , một đối tượng kiểu RAII giữ cho hidl_memory tương ứng được ánh xạ trong suốt vòng đời khóa. Ví dụ:

    #include <hidlmemory/mapping.h>
    
    sp<RefBase> lockMemory(const sp<IMemoryToken> key);
    

Sử dụng mở rộng

Phần này cung cấp thông tin chi tiết về việc sử dụng mở rộng MemoryBlock .

Sử dụng số tham chiếu để quản lý Memoryblock

Trong hầu hết các trường hợp, cách hiệu quả nhất để sử dụng MemoryBlock là phân bổ/giải phóng rõ ràng. Tuy nhiên, trong các ứng dụng phức tạp sử dụng số tham chiếu để thu gom rác có thể là một ý tưởng tốt hơn. Để có số lượng tham chiếu trên MemoryBlock, bạn có thể liên kết MemoryBlock với một đối tượng liên kết, giúp đếm các tham chiếu và phân bổ MemoryBlock khi số lượng giảm xuống 0.

Khai báo HAL

Khi khai báo HAL, hãy mô tả cấu trúc HIDL chứa MemoryBlock và IBase:

import android.hidl.memory.block@1.0::MemoryBlock;

struct MemoryBlockAllocation {
    MemoryBlock block;
    IBase refcnt;
};

Sử dụng MemoryBlockAllocation để thay thế MemoryBlock và xóa phương thức trả lại MemoryBlock . Nó sẽ được giải phóng bằng cách đếm tham chiếu với MemoryBlockAllocation . Ví dụ:

interface IFoo {
    allocateSome() generates(MemoryBlockAllocation allocation);
};

Thực hiện HAL

Ví dụ về việc triển khai HAL phía dịch vụ:

class MemoryBlockRefCnt: public virtual IBase {
   MemoryBlockRefCnt(uint64_t offset, sp<MemoryDealer> dealer)
     : mOffset(offset), mDealer(dealer) {}
   ~MemoryBlockRefCnt() {
       mDealer->deallocate(mOffset);
   }
 private:
   uint64_t mOffset;
   sp<MemoryDealer> mDealer;
};

Return<void> Foo::allocateSome(allocateSome_cb _hidl_cb) {
    MemoryBlockAllocation allocation;
    allocation.block = memory_dealer->allocate(1024);
    if(HidlMemoryDealer::isOk(block)){
        allocation.refcnt= new MemoryBlockRefCnt(...);
        _hidl_cb(allocation);

Ví dụ về việc triển khai HAL phía khách hàng:

ifoo->allocateSome([&](const MemoryBlockAllocation& allocation){
    ...
);

Đính kèm/truy xuất siêu dữ liệu

Một số ứng dụng cần dữ liệu bổ sung để liên kết với MemoryBlock được phân bổ. Bạn có thể thêm/truy xuất siêu dữ liệu bằng hai phương pháp:

  • Nếu ứng dụng truy cập siêu dữ liệu thường xuyên như chính khối đó, hãy nối thêm siêu dữ liệu và chuyển tất cả chúng vào một cấu trúc. Ví dụ:

    import android.hidl.memory.block@1.0::MemoryBlock;
    
    struct MemoryBlockWithMetaData{
        MemoryBlock block;
        MetaDataStruct metaData;
    };
    
  • Nếu ứng dụng truy cập siêu dữ liệu ít thường xuyên hơn khối thì việc truyền siêu dữ liệu một cách thụ động bằng giao diện sẽ hiệu quả hơn. Ví dụ:

    import android.hidl.memory.block@1.0::MemoryBlock;
    
    struct MemoryBlockWithMetaData{
        MemoryBlock block;
        IMetaData metaData;
    };
    

    Tiếp theo, liên kết siêu dữ liệu với MemoryBlock bằng Memory Dealer. Ví dụ:

    MemoryBlockWithMetaData memory_block;
    memory_block.block = dealer->allocate(size);
    if(HidlMemoryDealer::isOk(block)){
        memory_block.metaData = new MetaData(...);