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 beberapa blok memori untuk berbagi tumpukan memori tunggal.

Peningkatan kinerja

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

  • Menggunakan per hidl_memory untuk setiap alokasi buffer rata-rata 238 us/1 alokasi.
  • 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 tumpukan memori tunggal:

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",
        ...
};

Menerapkan 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 menggunakan 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. 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 yang dibagikan yaitu mmap() -ed pertama kali salah satu MemoryBlock s dipetakan dan munmap() -ed ketika tidak ada yang merujuk padanya. Agar hidl_memory selalu dipetakan, Anda dapat menggunakan lockMemory , objek gaya RAII yang membuat hidl_memory yang sesuai dipetakan sepanjang siklus hidup kunci. Contoh:

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

Penggunaan yang diperpanjang

Bagian ini memberikan detail tentang penggunaan MemoryBlock yang diperpanjang.

Menggunakan jumlah referensi untuk mengelola Memoryblock

Dalam kebanyakan situasi, cara paling efisien untuk menggunakan MemoryBlock adalah dengan mengalokasikan/mengalokasikan secara eksplisit. Namun, dalam aplikasi yang rumit menggunakan jumlah referensi untuk pengumpulan sampah mungkin merupakan ide yang lebih baik. Untuk memiliki jumlah referensi di MemoryBlock, Anda dapat mengikat MemoryBlock dengan objek pengikat, yang membantu menghitung referensi dan membatalkan alokasi MemoryBlock saat hitungan menurun ke 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 mengganti MemoryBlock dan hapus metode untuk mengembalikan MemoryBlock . Itu akan dibatalkan alokasinya dengan penghitungan referensi dengan MemoryBlockAllocation . Contoh:

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

Menerapkan HAL

Contoh penerapan HAL sisi pelayanan:

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 sisi klien dari HAL:

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 jauh lebih jarang daripada blok, lebih efisien untuk melewatkan metadata secara pasif dengan sebuah 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(...);