MemoryBlock של HIDL

HIDL MemoryBlock היא שכבה מופשטת שמבוססת על hidl_memory, HIDL @1.0::IAllocator ו-HIDL @1.0::IMapper. הוא מיועד לשירותי HIDL שיש להם כמה בלוקים של זיכרון שישתפו ערימת זיכרון אחת.

שיפורי ביצועים

שימוש ב-MemoryBlock באפליקציות עשוי להפחית באופן משמעותי את מספר שגיאות פילוח mmap/munmap ומרחב המשתמשים, דבר שגורם לשיפור הביצועים. לדוגמה:

  • השימוש הממוצע של כל hidl_memory להקצאת מאגר נתונים זמני הוא 238 דולר 1
  • שימוש ב-MemoryBlock ושיתוף hidl_memory אחד בממוצע עולה 2.82 דולר ל-1

ארכיטקטורה

ארכיטקטורת HIDL MemoryBlock כוללת שירותי HIDL עם מספר זיכרון בלוקים שחולקים ערימת זיכרון אחת:

MemoryBlock של HIDL

איור 1. ארכיטקטורת HIDL MemoryBlock

שימוש רגיל

הקטע הזה מספק דוגמה לשימוש ב-MemoryBlock באמצעות ההצהרה הראשונה לאחר מכן אנחנו מטמיעים HAL.

הצהרה על HAL

לדוגמה הבאה של IFoo HAL:

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

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

כך מופיע Android.bp:

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

הטמעת תקן HAL

כדי להטמיע את טקסט ה-HAL לדוגמה:

  1. אפשר להוריד את hidl_memory (לפרטים, אפשר לעיין ב-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. יוצרים מכונה של HidlMemoryDealer עם הערך hidl_memory שצורף:

    #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. מקצים את MemoryBlock, שהוא מבנה שמוגדר באמצעות HIDL.

    דוגמה MemoryBlock:

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

    דוגמה לשימוש ב-MemoryDealer כדי להקצות 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. Deallocate MemoryBlock:

    Return<void> Foo::giveBack(const MemoryBlock& block) {
        memory_dealer->deallocate(block.offset);
    ...
    
  5. לבצע מניפולציות על הנתונים:

    #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. הגדרה Android.bp:

    shared_libs: [
            "android.hidl.memory@1.0",
    
            "android.hidl.memory.block@1.0"
    
            "android.hidl.memory.token@1.0",
            "libhidlbase",
            "libhidlmemory",
    
  7. בודקים את התהליך כדי להבין אם צריך lockMemory.

    בדרך כלל, מערכת MemoryBlock משתמשת בספירת ההפניות כדי לשמור את hidl_memory שהוא mmap()- בפעם הראשונה שאחת מ-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 ממופה לאורך במחזור החיים. דוגמה:

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

שימוש מורחב

בקטע הזה מופיעים פרטים על השימוש המורחב ב-MemoryBlock.

שימוש בספירת ההפניות לניהול MemoryBlock

ברוב המקרים, הדרך היעילה ביותר להשתמש ב-MemoryBlock היא להקצות/הקצאה. לעומת זאת, באפליקציות מורכבות שמשתמשות בספירת הפניות יכול להיות רעיון טוב יותר לאיסוף אשפה. כדי שספירת ההפניות תופעל MemoryBlock, אפשר לקשר את MemoryBlock לאובייקט קישור, שעוזר סופרים את ההפניות ומחלקים את השדה MemoryBlock כשהמספר יורד לאפס.

הצהרה על HAL

כשמצהירים על HAL, צריך לתאר מבנה HIDL שמכיל MemoryBlock ו-IBase:

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

struct MemoryBlockAllocation {
    MemoryBlock block;
    IBase refcnt;
};

צריך להשתמש ב-MemoryBlockAllocation כדי להחליף את MemoryBlock ולהסיר את השיטה כדי להחזיר MemoryBlock. הוא מתבסס על ספירת הפניות עם MemoryBlockAllocation. דוגמה:

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

הטמעת תקן HAL

דוגמה להטמעה של 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);

דוגמה להטמעה בצד הלקוח של HAL:

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

צירוף ואחזור של מטא-נתונים

אפליקציות מסוימות צריכות נתונים נוספים כדי לבצע קישור ל-MemoryBlock שהוקצה. אפשר להוסיף ולאחזר מטא-נתונים בשתי שיטות:

  • אם האפליקציה ניגשת למטא-נתונים באותה תדירות כמו הבלוק עצמו, להוסיף את המטא-נתונים ולהעביר את כולם במבנה. דוגמה:

    import android.hidl.memory.block@1.0::MemoryBlock;
    
    struct MemoryBlockWithMetaData{
        MemoryBlock block;
        MetaDataStruct metaData;
    };
    
  • אם האפליקציה ניגשת למטא-נתונים בתדירות הרבה יותר נמוכה יעיל יותר להעביר את המטא-נתונים באופן פסיבי גרפי. דוגמה:

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

    בשלב הבא, מקשרים את המטא-נתונים עם MemoryBlock באמצעות MemoryDealer. דוגמה:

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