Blok Memori HIDL

HIDL MemoryBlock adalah lapisan abstrak yang dibangun di atas hidl_memory , HIDL @1.0::IAllocator , dan HIDL @1.0::IMapper . Ini dirancang untuk layanan HIDL yang memiliki banyak blok memori untuk berbagi satu tumpukan memori.

Peningkatan kinerja

Menggunakan MemoryBlock dalam aplikasi dapat secara signifikan mengurangi jumlah mmap / munmap dan kesalahan segmentasi ruang pengguna, sehingga meningkatkan kinerja. Misalnya:

  • Penggunaan per hidl_memory untuk setiap alokasi buffer rata-rata 238 alokasi us/1.
  • Menggunakan MemoryBlock dan berbagi satu hidl_memory rata-rata alokasi 2,82 us/1.

Arsitektur

Arsitektur HIDL MemoryBlock mencakup layanan HIDL dengan beberapa blok memori yang berbagi satu tumpukan memori:

Blok Memori HIDL

Gambar 1. Arsitektur HIDL MemoryBlock

Penggunaan normal

Bagian ini memberikan contoh penggunaan MemoryBlock dengan terlebih dahulu mendeklarasikan HAL kemudian mengimplementasikan HAL.

Mendeklarasikan HAL

Untuk contoh berikut IFoo HAL:

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

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

Android.bp adalah sebagai berikut:

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

Melaksanakan HAL

Untuk mengimplementasikan contoh HAL:

  1. Dapatkan hidl_memory (untuk detailnya, lihat 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. Buat HidlMemoryDealer dengan hidl_memory yang diperoleh:

    #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. Alokasikan MemoryBlock , yang merupakan struct yang didefinisikan dengan HIDL.

    Contoh MemoryBlock :

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

    Contoh penggunaan MemoryDealer untuk mengalokasikan 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. Batalkan alokasi MemoryBlock :

    Return<void> Foo::giveBack(const MemoryBlock& block) {
        memory_dealer->deallocate(block.offset);
    ...
    
  5. Memanipulasi data:

    #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. Konfigurasi Android.bp :

    shared_libs: [
            "android.hidl.memory@1.0",
    
            "android.hidl.memory.block@1.0"
    
            "android.hidl.memory.token@1.0",
            "libhidlbase",
            "libhidlmemory",
    
  7. Tinjau alur untuk menentukan apakah Anda perlu lockMemory .

    Biasanya, MemoryBlock menggunakan jumlah referensi untuk mempertahankan hidl_memory bersama yang mmap() -ed saat pertama kali salah satu MemoryBlock -nya dipetakan dan munmap() -ed ketika tidak ada yang merujuk ke sana. Agar hidl_memory selalu dipetakan, Anda dapat menggunakan lockMemory , objek gaya RAII yang menjaga hidl_memory terkait tetap dipetakan sepanjang siklus hidup kunci. Contoh:

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

Penggunaan yang diperluas

Bagian ini memberikan detail tentang perpanjangan penggunaan MemoryBlock .

Menggunakan jumlah referensi untuk mengelola Memoryblock

Dalam kebanyakan situasi, cara paling efisien untuk menggunakan MemoryBlock adalah dengan mengalokasikan/membatalkan alokasi secara eksplisit. Namun, dalam aplikasi yang rumit, menggunakan jumlah referensi untuk pengumpulan sampah mungkin merupakan ide yang lebih baik. Untuk menghitung jumlah referensi di MemoryBlock, Anda dapat mengikat MemoryBlock dengan objek pengikat, yang membantu menghitung referensi dan membatalkan alokasi MemoryBlock ketika jumlah berkurang menjadi nol.

Mendeklarasikan HAL

Saat mendeklarasikan HAL, jelaskan struct HIDL yang berisi MemoryBlock dan IBase:

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

struct MemoryBlockAllocation {
    MemoryBlock block;
    IBase refcnt;
};

Gunakan MemoryBlockAllocation untuk menggantikan MemoryBlock dan hapus metode untuk mengembalikan MemoryBlock . Itu akan dibatalkan alokasinya dengan penghitungan referensi dengan MemoryBlockAllocation . Contoh:

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

Melaksanakan HAL

Contoh penerapan sisi layanan 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);

Contoh implementasi HAL di sisi klien:

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

Melampirkan/mengambil metadata

Beberapa aplikasi memerlukan data tambahan untuk diikat dengan MemoryBlock yang dialokasikan. Anda dapat menambahkan/mengambil metadata menggunakan dua metode:

  • Jika aplikasi mengakses metadata sesering blok itu sendiri, tambahkan metadata dan teruskan semuanya dalam sebuah struct. Contoh:

    import android.hidl.memory.block@1.0::MemoryBlock;
    
    struct MemoryBlockWithMetaData{
        MemoryBlock block;
        MetaDataStruct metaData;
    };
    
  • Jika aplikasi mengakses metadata lebih jarang dibandingkan blok, akan lebih efisien jika meneruskan metadata secara pasif dengan antarmuka. Contoh:

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

    Selanjutnya, ikat metadata dengan MemoryBlock menggunakan Memory Dealer. Contoh:

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