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. Dịch vụ này được thiết kế cho các dịch vụ HIDL có nhiều khối bộ nhớ dùng chung một vùng nhớ khối xếp bộ nhớ.

Cải thiện hiệu suất

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

  • Việc sử dụng trên mỗi hidl_memory cho mỗi mức phân bổ vùng đệm trung bình là 238 us/1 thời gian phân bổ.
  • Việc sử dụng MemoryBlock và chia sẻ một hidl_memory duy nhất có trung bình 2,82 chúng tôi/1 thời gian phân bổ.

Kiến trúc

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

Bộ nhớ HIDL

Hình 1. Cấu trúc HIDL MemoryBlock

Mức sử dụng thông thường

Phần này đưa ra ví dụ về cách sử dụng MemoryBlock bằng cách khai báo trước thuộc tính HAL sau đó triển khai HAL.

Khai báo HAL

Trong ví dụ sau đây về 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",
        ...
};

Triển khai HAL

Cách triển khai HAL (Lớp trừu tượng phần cứng) mẫu:

  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 một thực thể HidlMemoryDealer bằng hidl_memory đã thu nạp đượ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 (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ụ về cách 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úng 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 xét 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ố lượng tham chiếu để duy trì hidl_memory được mmap()-ed lần đầu tiên một trong những MemoryBlock instances is mapped and ismunmap()-ed when nothing refers to it. To keephidl_memoryalways mapped, you can uselockMemory, a RAII style object that keeps the correspondinghidl_memory` được ánh xạ trong toàn bộ khoá vòng đời. 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ố lượng tham chiếu để quản lý MemoryBlock

Trong hầu hết trường hợp, cách hiệu quả nhất để sử dụng MemoryBlock là nêu rõ phân bổ/phân bổ. Tuy nhiên, trong những ứng dụng phức tạp sử dụng số lượng tham chiếu để thu gom rác có thể là ý 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 bằng một đối tượng liên kết để đếm các tệp tham chiếu và phân loại MemoryBlock khi số lượng giảm xuống về 0.

Khai báo HAL

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

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

struct MemoryBlockAllocation {
    MemoryBlock block;
    IBase refcnt;
};

Sử dụng MemoryBlockAllocation để thay thế MemoryBlock và xoá phương thức để hoàn lại MemoryBlock. Nó được giải phóng bằng cách tính tham chiếu cùng với MemoryBlockAllocation. Ví dụ:

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

Triển khai HAL

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

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ề cách triển khai HAL (Lớp trừu tượng phần cứng) phía máy khách:

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

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

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

  • Nếu ứng dụng truy cập vào siêu dữ liệu thường xuyên như chính khối, thêm siêu dữ liệu và truyền tất cả 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 so với thì sẽ hiệu quả hơn nếu truyền siêu dữ liệu một cách thụ động bằng . Ví dụ:

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

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

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