Android 12(S) 圖形顯示系統 – 簡述Allocator/Mapper HAL服務的獲取過程(十五)


必讀:

Android 12(S) 圖形顯示系統 – 開篇


 

一、基本概念

在上一篇文章中,我們有簡單介紹過 Gralloc Allocator/Mapper HAL的內容。Gralloc HAL 分為了兩部分:一個是 allocator ,一個是 mapper。Android系統定義了標準的 Gralloc HAL interface,具體實現有OEM/晶片廠商完成。

1.1 allocator HAL interface 的定義

Allocator 實現為一個 Binderized HAL Service(綁定式HAL),運行在獨立的進程中,使用者通過 HwBinder 與之建立連接,類似與AIDL獲取服務的方式。

/hardware/interfaces/graphics/allocator/4.0/IAllocator.hal

1.2 mapper HAL interface 的定義

Mapper 實現為一個 Passthrough HAL Service(直通式HAL), 運行在調用它的進程中。本質上 Mode of HIDL in which the server is a shared library, dlopened by the client. In passthrough mode, client and server are the same process but separate codebases. 

/hardware/interfaces/graphics/mapper/4.0/IMapper.hal

1.3 Binderized HALs(綁定式HAL)

Indicates HIDL is being used for remote procedure calls between processes, implemented over a Binder-like mechanism. See also passthrough.

[email protected] ==> Required to be binderized in Android 8.0 so file descriptors don't have to be shared between trusted and untrusted processes.

Android 8.0之後的版本要求,allocator實現為 Binderized HAL,用於分配圖形快取,即為GraphicBuffer分配實際記憶體。

Mode of HIDL in which the server is a shared library, dlopened by the client. In passthrough mode, client and server are the same process but separate codebases. Used only to bring legacy codebases into the HIDL model. See also Binderized.

[email protected] ==> Maps memory into the process it lives in.

 

二、GraphicBufferMapper的創建流程

創建GraphicBufferMapper對象時,其構造函數中會去創建GrallocMapper對象,系統中會有不同版本的 grolloc-mapper,優先使用高版本,所以創建 Gralloc4Mapper 對象

[/frameworks/native/libs/ui/GraphicBufferMapper.cpp]

GraphicBufferMapper::GraphicBufferMapper() {
    // 優先選擇高版本的 gralloc-mapper
    mMapper = std::make_unique<const Gralloc4Mapper>();
    if (mMapper->isLoaded()) {
        mMapperVersion = Version::GRALLOC_4;
        return;
    }
    ...
}

 

Gralloc4Mapper的構造函數中去獲取 gralloc-mapper hal service,這是一個 passthrough hal service

Gralloc4Mapper::Gralloc4Mapper() {
    mMapper = IMapper::getService(); // 去獲取服務,
    ...
}

 

IMaper::getService() 是編譯系統根據 IMapper HIDL interface 自動生成的。

IMapper HIDL interface 的定義位於:

/hardware/interfaces/graphics/mapper/4.0/IMapper.hal

編譯完源碼後,out目錄下會生成根據 IMapperHDIL interface 生成的頭文件和源碼文件

android/out/soong/.intermediates/hardware/interfaces/graphics/mapper/4.0

IMaper::getService()可以在 [email protected]_genc++ 目錄下的 MapperAll.cpp 中看到其定義,如下:

::android::sp<IMapper> IMapper::getService(const std::string &serviceName, const bool getStub) {
    return ::android::hardware::details::getServiceInternal<BpHwMapper>(serviceName, true, getStub);
}

其中還有一個標識字元串:

const char* IMapper::descriptor("[email protected]::IMapper");

 

流程開始進入到Android系統原生的獲取服務的流程 ::android::hardware::details::getServiceInternal 這個函數定義在:

/system/libhidl/transport/include/hidl/HidlTransportSupport.h

template <typename BpType, typename IType = typename BpType::Pure,
          typename = std::enable_if_t<std::is_same<i_tag, typename IType::_hidl_tag>::value>,
          typename = std::enable_if_t<std::is_same<bphw_tag, typename BpType::_hidl_tag>::value>>
sp<IType> getServiceInternal(const std::string& instance, bool retry, bool getStub) {
    using ::android::hidl::base::V1_0::IBase;
    // getRawServiceInternal 去獲取服務
    sp<IBase> base = getRawServiceInternal(IType::descriptor, instance, retry, getStub);
    ...// 省略一些檢查過程
    return IType::castFrom(base);
}

緊接著往下走,就進入到 getRawServiceInternal方法中

[/system/libhidl/transport/ServiceManagement.cpp]

sp<::android::hidl::base::V1_0::IBase> getRawServiceInternal(const std::string& descriptor,
                                                             const std::string& instance,
                                                             bool retry, bool getStub) {
    using Transport = IServiceManager1_0::Transport;
    sp<Waiter> waiter;

    sp<IServiceManager1_1> sm;
    Transport transport = Transport::EMPTY;
    // 判斷要獲取這個service是那種模式:passthroght mode(直通式HAL) or binderized mode(綁定式HAL)
    if (kIsRecovery) {
        transport = Transport::PASSTHROUGH;
    } else {
        sm = defaultServiceManager1_1();
        Return<Transport> transportRet = sm->getTransport(descriptor, instance);
        transport = transportRet;
    }
    ...
    for (int tries = 0; !getStub && (vintfHwbinder || vintfLegacy); tries++) {
        //  binderized mode(綁定式HAL),使用 defaultServiceManager 去檢索、獲取服務
        Return<sp<IBase>> ret = sm->get(descriptor, instance);
        sp<IBase> base = ret;
        if (base != nullptr) {
            Return<bool> canCastRet =
                details::canCastInterface(base.get(), descriptor.c_str(), true /* emitError */);
                ...
            if (canCastRet.isOk() && canCastRet) {
                ...
                return base; // still needs to be wrapped by Bp class.
            }
        }
    }
    ...
    if (getStub || vintfPassthru || vintfLegacy) {
        //  passthroght mode(直通式HAL),使用 defaultServiceManager 去檢索、獲取服務
        const sp<IServiceManager1_0> pm = getPassthroughServiceManager();
        if (pm != nullptr) {
            sp<IBase> base = pm->get(descriptor, instance).withDefault(nullptr);
            if (!getStub || trebleTestingOverride) {
                // 封裝
                base = wrapPassthrough(base);
            }
            return base;
        }
    }

    return nullptr;
}

大概講一下它的做的事情:

1. 判斷要獲取的HAL服務的類型,是直通式HAL–Transport::PASSTHROUGH,還是綁定式HAL — Transport::HWBINDER

2. 如果是binderized mode綁定式HAL — Transport::HWBINDER,則會通過 defaultServiceManager 去獲取這個服務的代理,這個過程類似與框架層的binder service,比如 gralloc-allocator hal

3. 如果是passthrough mode直通式HAL–Transport::PASSTHROUGH,則會通過 PassthroughServiceManager 去獲取這個服務,這個過程本質上是在當前進程中使用 dlopen/dlsym載入HAL動態庫並獲取函數 HIDL_FETCH_interfaceName  的地址,HAL library中會去實現這個FETCH方法,比如  gralloc-mapper hal ,下面 arm gralloc 的實現,可以自行去官網下載源碼:Open Source Mali GPUs Android Gralloc Module

extern "C" IMapper *HIDL_FETCH_IMapper(const char * /* name */)
{
	MALI_GRALLOC_LOGV("Arm Module IMapper %d.%d , pid = %d ppid = %d ", GRALLOC_VERSION_MAJOR,
	                  (HIDL_MAPPER_VERSION_SCALED - (GRALLOC_VERSION_MAJOR * 100)) / 10, getpid(), getppid());

	return new arm::mapper::GrallocMapper();
}

4. 不管是binderized還是passthrough ,最後得到都是一個進程了 ::android::hidl::base::V1_0::IBase的HIDL Interface對象,經過適當處理,就可以返回給使用者了

 

對於 gralloc-mapper hal 因為採用的是passthrough mode,我們繼續看看 PassthroughServiceManager 去獲取服務是大概是做了什麼事情。

主要是去看 PassthroughServiceManager::get() 方法

[/system/libhidl/transport/ServiceManagement.cpp]

Return<sp<IBase>> get(const hidl_string& fqName,
                      const hidl_string& name) override {
    sp<IBase> ret = nullptr;
    // 載入動態庫,主要openLibs第二個參數是函數指針
    openLibs(fqName, [&](void* handle, const std::string &lib, const std::string &sym) {
        IBase* (*generator)(const char* name);
        // 去已載入的動態庫中檢索指定函數的地址,sym是HIDL_FETCH_xxx,比如HIDL_FETCH_IMapper
        *(void **)(&generator) = dlsym(handle, sym.c_str());
        ...
        // 調用找到的函數,比如 HIDL_FETCH_IMapper
        ret = (*generator)(name.c_str());
        ...
        return false;
    });

    return ret;
}

PassthroughServiceManager::get() 方法中首先就是去調用 openLibs 去尋找和載入動態庫,openLibs 定義如下:

[/system/libhidl/transport/ServiceManagement.cpp]

static void openLibs(
    const std::string& fqName,
    const std::function<bool /* continue */ (void* /* handle */, const std::string& /* lib */,
                                             const std::string& /* sym */)>& eachLib) {
    //fqName looks like [email protected]::IFoo
    // fqName 就是要找的服務的標識符,[email protected]::IMapper
    size_t idx = fqName.find("::");
    // 分離出包名和版本 == [email protected]
    std::string packageAndVersion = fqName.substr(0, idx);
    // 分離出介面名字 == IMapper
    std::string ifaceName = fqName.substr(idx + strlen("::"));
    // 要找的動態庫名字的前綴 == [email protected]
    const std::string prefix = packageAndVersion + "-impl";
    // 要找的動態庫中的函數名字 == HIDL_FETCH_IMapper
    const std::string sym = "HIDL_FETCH_" + ifaceName;
    // dlopen 選項
    constexpr int dlMode = RTLD_LAZY;
    void* handle = nullptr;

    dlerror(); // clear

    static std::string halLibPathVndkSp = details::getVndkSpHwPath();
    // 查找路徑 "/odm/lib/hw/", "/vendor/lib/hw/", "/system/lib/hw/"
    std::vector<std::string> paths = {
        HAL_LIBRARY_PATH_ODM, HAL_LIBRARY_PATH_VENDOR, halLibPathVndkSp,
#ifndef __ANDROID_VNDK__
        HAL_LIBRARY_PATH_SYSTEM,
#endif
    };
    ...
    // 開始查找
    for (const std::string& path : paths) {
        // findFiles就是在path目錄下,查找名字的前綴是prefix,後綴是.so的庫
        std::vector<std::string> libs = findFiles(path, prefix, ".so");

        for (const std::string &lib : libs) {
            const std::string fullPath = path + lib;

            if (kIsRecovery || path == HAL_LIBRARY_PATH_SYSTEM) {
                handle = dlopen(fullPath.c_str(), dlMode);
            } else {
#if !defined(__ANDROID_RECOVERY__) && defined(__ANDROID__)
                // 載入動態庫, 比如 /vendor/lib/hw/[email protected]
                handle = android_load_sphal_library(fullPath.c_str(), dlMode);
#endif
            }
            // 載入失敗,繼續載入找到的滿足條件的其它庫
            if (handle == nullptr) {
                const char* error = dlerror();
                LOG(ERROR) << "Failed to dlopen " << lib << ": "
                           << (error == nullptr ? "unknown error" : error);
                continue;
            }
            // 載入成功,函數eachLib中去找sym這個函數的地址,並執行
            if (!eachLib(handle, lib, sym)) {
                return;
            }
        }
    }
}

openLibs 函數的處理邏輯也很清晰,主要工作就是:

1. 根據要檢索的服務的 descriptor ,去指定的目錄下(/odem/lib/hw or /vendor/lib/hw or /system/lib/hw)尋找對應的動態庫;

2. 找到動態庫後,載入 android_load_sphal_library / dlopen ;

3. 調用eachLib這個函數,去動態庫中找到 HIDL_FETCH_xxx 這個函數的地址;

4. eachLib就是在PassthroughServiceManager::get() 方法中調用 openLibs 時設置的,其中就會調用 HIDL_FETCH_xxx 這個函數去創建服務對象。

經過上面的流程,載入了動態庫,找到了HIDL_FETCH_xxx 這個函數,並且調用它創建了一個服務對象,然後再經過必要處理 wrapPassthrough(base)就把這個服務的代理返回給了使用者。

 

三、GraphicBufferAllocator的創建流程

GraphicBufferAllocator 構造函數中會去創建一個Gralloc4Allocator對象,並且傳遞一個Gralloc4Mapper參數

[/frameworks/native/libs/ui/GraphicBufferAllocator.cpp]

GraphicBufferAllocator::GraphicBufferAllocator() : mMapper(GraphicBufferMapper::getInstance()) {
    mAllocator = std::make_unique<const Gralloc4Allocator>(
            reinterpret_cast<const Gralloc4Mapper&>(mMapper.getGrallocMapper()));
    ...
}

Gralloc4Allocator的構造函數如下:

[/frameworks/native/libs/ui/Gralloc4.cpp]

Gralloc4Allocator::Gralloc4Allocator(const Gralloc4Mapper& mapper) : mMapper(mapper) {
    mAllocator = IAllocator::getService();
    if (mAllocator == nullptr) {
        ALOGW("allocator 3.x is not supported");
        return;
    }
}

上述程式碼的是不是和Gralloc4Mapper很相似,區別在於 gralloc-allocator 是 Binderied HAL,在獲取服務時有所區別,前面的分析中也有提到,在這裡就不繼續深入講解了。Binderied HAL 實現部分會作為一個service獨立運行在一個進程中,非常類似 Binder IPC的機制,可以僅作高度概括的理解即可。

 

五、小結

本文只是一點關於 Gralloc Allocator/Mapper HAL的補充知識,簡單分析獲取 HAL service的一些流程。到這關於GraphicBuffer及Gralloc的大概的知識點就講完了,後續學習中會再根據自己遇到的實際問題及思考,陸續補充心得及細節。

 

 

個人對 IMapper Interface的一點註解,非常淺顯的認知

/hardware/interfaces/graphics/mapper/4.0/IMapper.hal

 

package [email protected];

import [email protected]::BufferUsage;
import [email protected]::PixelFormat;
import [email protected]::Rect;

interface IMapper {
    // BufferDescriptorInfo用於描述圖形buffer的屬性(寬、高、格式...)
    struct BufferDescriptorInfo {
        /**
         * The name of the buffer. Useful for debugging/tracing.
         * buffer的名字,用於debugging/tracing
         */
        string name;

        /**
         * The width specifies how many columns of pixels must be in the
         * allocated buffer, but does not necessarily represent the offset in
         * columns between the same column in adjacent rows. The rows may be
         * padded.
         * width說明了分配的buffer中有多少個像素列,但它並不表示相鄰行的同一列元素的偏移量。
         * 為了位元組對齊,width可能並不是實際的大小,參考stride
         */
        uint32_t width;

        /**
         * The height specifies how many rows of pixels must be in the
         * allocated buffer.
         * height說明了分配的buffer中有多少像素行
         */
        uint32_t height;

        /**
         * The number of image layers that must be in the allocated buffer.
         * 必須在分配的緩衝區中的影像層數。
         */
        uint32_t layerCount;

        /**
         * Buffer pixel format.
         * 像素格式 (參見/frameworks/native/libs/ui/include/ui/PixelFormat.h中的定義)
         */
        PixelFormat format;

        /**
         * Buffer usage mask; valid flags can be found in the definition of
         * BufferUsage.
         * buffer使用方式的標誌位(參見/frameworks/native/libs/ui/include/ui/GraphicBuffer.h的定義)。
         */
        bitfield<BufferUsage> usage;

        /**
         * The size in bytes of the reserved region associated with the buffer.
         * See getReservedRegion for more information.
         * 與緩衝區關聯的保留區域的大小(位元組)。
         */
        uint64_t reservedSize;
    };

    struct Rect {
        int32_t left;
        int32_t top;
        int32_t width;
        int32_t height;
    };

    /**
     * Creates a buffer descriptor. The descriptor can be used with IAllocator
     * to allocate buffers. 
     * 創建一個 buffer descriptor,這個descriptor可以用於IAllocator分配buffer
     *
     * Since the buffer descriptor fully describes a buffer, any device
     * dependent or device independent checks must be performed here whenever
     * possible. 
     *
     * 由於buffer descriptor完全描述了一個緩衝區,因此必須儘可能在此處執行任何與設備相關或與設備無關的檢查。
     *
     * When layered buffers are not supported, 當分層緩衝區不支援時
     * this function must return `UNSUPPORTED` if `description.layers` is great than 1. 
     * This function may return `UNSUPPORTED` if `description.reservedSize` is larger than a page.
     *
     * @param description Attributes of the descriptor.
     * @return error Error status of the call, which may be
     *     - `NONE` upon success.  成功
     *     - `BAD_VALUE` if any of the specified attributes are invalid or
     *       inconsistent.         指定的屬性非法或不一致
     *     - `NO_RESOURCES` if the creation cannot be fullfilled due to
     *       unavailability of resources. 由於資源不可用而無法完成創建
     *     - `UNSUPPORTED` when any of the specified attributes are not
     *       supported.            不支援指定的屬性
     * @return descriptor Newly created buffer descriptor. 
     *
     * 返回新創建的BufferDescriptor(定義typedef vec<uint8_t> BufferDescriptor;)
     */
     * 主要完成兩個工作:
     * 1. 檢查參數的合法性(設備是否支援);
     * 2. 把BufferDescriptorInfo這個結構體變數進行重新的包裝,本質就是轉化為byte stream,這樣可以傳遞給IAllocator
    createDescriptor(BufferDescriptorInfo description)  
            generates (Error error,
                       BufferDescriptor descriptor);

    /**
     * Imports a raw buffer handle to create an imported buffer handle for use
     * with the rest of the mapper or with other in-process libraries.
     *
     * 把raw buffer handle轉為imported buffer handle,這樣就可以在進程使用了
     *
     * A buffer handle is considered raw when it is cloned (e.g., with
     * `native_handle_clone()`) from another buffer handle locally, or when it
     * is received from another HAL server/client or another process. A raw
     * buffer handle must not be used to access the underlying graphic
     * buffer. It must be imported to create an imported handle first.
     *
     * buffer handle被視作raw : 1. 從本地buffer handle做native_handle_clone
     *                          2. 接收到的來自另一個HAL server/client或其它進程的buffer handle     
     *
     * This function must at least validate the raw handle before creating the
     * imported handle. It must also support importing the same raw handle
     * multiple times to create multiple imported handles. The imported handle
     * must be considered valid everywhere in the process, including in
     * another instance of the mapper.
     *
     * 1. 在創建imported handle前,這個函數必須對raw handle進行raw handle
     * 2. 這個函數必須支援對同一個raw handle進行多次import來產生多個imported handles
     * 3. imported handle在進程內的任何地方或對於不同的mapper對象都是合法有效的
     *
     * Because of passthrough HALs, a raw buffer handle received from a HAL
     * may actually have been imported in the process. importBuffer() must treat
     * such a handle as if it is raw and must not return `BAD_BUFFER`. The
     * returned handle is independent from the input handle as usual, and
     * freeBuffer() must be called on it when it is no longer needed.
     *
     * 由於passthrough HAL,從HAL接收的raw buffer handle實際上可能已在該進程中imported。
     * importBuffer()必須將此類句柄視為原始句柄,並且不能返回'BAD_BUFFER'。
     * 返回的句柄獨立於輸入句柄,當不再需要時,必須對其調用freeBuffer()。
     *
     * @param rawHandle Raw buffer handle to import.
     * @return error Error status of the call, which may be
     *     - `NONE` upon success.  成功
     *     - `BAD_BUFFER` if the raw handle is invalid. 參數無效/非法
     *     - `NO_RESOURCES` if the raw handle cannot be imported due to
     *       unavailability of resources. 資源不可用導致import失敗
     * @return buffer Imported buffer handle that has the type
     *     `buffer_handle_t` which is a handle type.
     */
    importBuffer(handle rawHandle) generates (Error error, pointer buffer);

    /**
     * Frees a buffer handle. Buffer handles returned by importBuffer() must be
     * freed with this function when no longer needed.
     *
     * importBuffer()返回的buffer handle不再使用後必須調用freeBuffer()釋放
     *
     * This function must free up all resources allocated by importBuffer() for
     * the imported handle. For example, if the imported handle was created
     * with `native_handle_create()`, this function must call
     * `native_handle_close()` and `native_handle_delete()`.
     *
     * 釋放掉所有importBuffer中分配的資源
     *
     * @param buffer Imported buffer handle.
     * @return error Error status of the call, which may be
     *     - `NONE` upon success.
     *     - `BAD_BUFFER` if the buffer is invalid.
     */
    freeBuffer(pointer buffer) generates (Error error);

    /**
     * Validates that the buffer can be safely accessed by a caller who assumes
     * the specified @p description and @p stride. This must at least validate
     * that the buffer size is large enough. Validating the buffer against
     * individual buffer attributes is optional.
     *
     * 驗證buffer是否可以被調用者已指定的description&stride進行安全訪問。
     * 至少要驗證buffer size是足夠的。
     *
     * @param buffer Buffer to validate against. 驗證的buffer
     * @param description Attributes of the buffer. buffer屬性
     * @param stride Stride returned by IAllocator::allocate(). 步長
     * @return error Error status of the call, which may be
     *     - `NONE` upon success.
     *     - `BAD_BUFFER` if the buffer is invalid.
     *     - `BAD_VALUE` if the buffer cannot be safely accessed.
     */
    validateBufferSize(pointer buffer,
                       BufferDescriptorInfo description,
                       uint32_t stride)
            generates (Error error);

    /**
     * Calculates the transport size of a buffer. An imported buffer handle is a
     * raw buffer handle with the process-local runtime data appended. This
     * function, for example, allows a caller to omit the process-local runtime
     * data at the tail when serializing the imported buffer handle.
     *
     * 計算buffer傳輸數據的大小。imported buffer handle是在raw buffer handle基礎上附加了
     * 進程本地運行時數據。例如,此函數允許調用方忽略進程本地運行時
     * 序列化導入的緩衝區句柄時尾部的數據。 
     *
     * Note that a client might or might not omit the process-local runtime data
     * when sending an imported buffer handle. The mapper must support both
     * cases on the receiving end.
     *
     * @param buffer Buffer to get the transport size from.
     * @return error Error status of the call, which may be
     *     - `NONE` upon success.
     *     - `BAD_BUFFER` if the buffer is invalid.
     * @return numFds The number of file descriptors needed for transport.需要傳遞的文件描述符個數
     * @return numInts The number of integers needed for transport.需要傳遞的整數個數
     */
    getTransportSize(pointer buffer)
            generates (Error error,
                       uint32_t numFds,
                       uint32_t numInts);

    /**
     * Locks the given buffer for the specified CPU usage.
     * 鎖定指定CPU usage的緩衝區。
     * Locking the same buffer simultaneously from multiple threads is
     * permitted, but if any of the threads attempt to lock the buffer for
     * writing, the behavior is undefined, except that it must not cause
     * process termination or block the client indefinitely. Leaving the
     * buffer content in an indeterminate state or returning an error are both
     * acceptable.
     *
     * 允許多個執行緒同時lock同一個buffer
     * 如果任意個執行緒試圖lock後寫buffer,這個行為沒有定義
     * 但它不能導致進程終止或無限期地阻止客戶端。
     * 將緩衝區內容保持在不確定狀態或返回錯誤都是可以接受的。
     *
     * 1D buffers (width = size in bytes, height = 1, pixel_format = BLOB) must
     * "lock in place". The buffers must be directly accessible via mapping.
     *
     * The client must not modify the content of the buffer outside of
     * @p accessRegion, and the device need not guarantee that content outside
     * of @p accessRegion is valid for reading. The result of reading or writing
     * outside of @p accessRegion is undefined, except that it must not cause
     * process termination.
     *
     * client禁止調整accessRegion以外的內容,該設備無需保證accessRegion之外的內容可以有效讀取。
     * 在accessRegion之外讀取或寫入的結果未定義,但它不得導致進程終止。
     *
     * An accessRegion of all-zeros means the entire buffer. That is, it is
     * equivalent to '(0,0)-(buffer width, buffer height)'.
     *
     * accessRegion(0,0,0,0)全是0,意味是整個buffer (0,0,width,height)
     *
     * This function can lock both single-planar and multi-planar formats. The caller
     * should use get() to get information about the buffer they are locking.
     * get() can be used to get information about the planes, offsets, stride,
     * etc.
     *
     * This function must also work on buffers with
     * `AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_*` if supported by the device, as well
     * as with any other formats requested by multimedia codecs when they are
     * configured with a flexible-YUV-compatible color format.
     *
     * 如果設備支援,此功能還必須適用於「AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_*」格式的緩衝區,
     * 以及多媒體編解碼器配置靈活的YUV兼容顏色格式時所需的任何其他格式。
     *
     * On success, @p data must be filled with a pointer to the locked buffer
     * memory. This address will represent the top-left corner of the entire
     * buffer, even if @p accessRegion does not begin at the top-left corner.
     *
     * The locked buffer must adhere to the format requested at allocation time
     * in the BufferDescriptorInfo.
     *
     * 鎖定的緩衝區必須符合分配時請求的格式BufferDescriptorInfo。 
     *
     * @param buffer Buffer to lock.
     * @param cpuUsage CPU usage flags to request. See +ndk
     *     libnativewindow#AHardwareBuffer_UsageFlags for possible values.
     * @param accessRegion Portion of the buffer that the client intends to
     *     access. 客戶端打算訪問的緩衝區部分。
     * @param acquireFence Handle containing a file descriptor referring to a
     *     sync fence object, which will be signaled when it is safe for the
     *     mapper to lock the buffer. @p acquireFence may be an empty fence if
     *     it is already safe to lock.
     * @return error Error status of the call, which may be
     *     - `NONE` upon success.
     *     - `BAD_BUFFER` if the buffer is invalid or is incompatible with this
     *       function.
     *     - `BAD_VALUE` if @p cpuUsage is 0, contains non-CPU usage flags, or
     *       is incompatible with the buffer. Also if the @p accessRegion is
     *       outside the bounds of the buffer or the accessRegion is invalid.
     *     - `NO_RESOURCES` if the buffer cannot be locked at this time. Note
     *       that locking may succeed at a later time.
     * @return data CPU-accessible pointer to the buffer data. CPU可訪問的buffer數據地址
     */
    lock(pointer buffer,
         uint64_t cpuUsage,
         Rect accessRegion,
         handle acquireFence)
            generates (Error error,
                       pointer data);

    /**
     * Unlocks a buffer to indicate all CPU accesses to the buffer have
     * completed.
     * 解鎖緩衝區以指示對緩衝區的所有CPU訪問都已完成
     * 
     * @param buffer Buffer to unlock.
     * @return error Error status of the call, which may be
     *     - `NONE` upon success.
     *     - `BAD_BUFFER` if the buffer is invalid or not locked.
     * @return releaseFence Handle containing a file descriptor referring to a
     *     sync fence object. The sync fence object will be signaled when the
     *     mapper has completed any pending work. @p releaseFence may be an
     *     empty fence.
     */
    unlock(pointer buffer) generates (Error error, handle releaseFence);

    /**
     * Flushes the contents of a locked buffer. 刷新鎖定緩衝區的內容。
     *
     * This function flushes the CPUs caches for the range of all the buffer's
     * planes and metadata. This should behave similarly to unlock() except the
     * buffer should remain mapped to the CPU.
     *
     * 此函數用於刷新所有緩衝區平面和元數據範圍的CPU快取。
     * 這應該類似於unlock(),只是緩衝區應該保持映射到CPU
     *
     * The client is still responsible for calling unlock() when it is done
     * with all CPU accesses to the buffer.
     *
     * 完成對緩衝區的所有CPU訪問後,客戶端仍負責調用unlock()。
     * 
     * If non-CPU blocks are simultaneously writing the buffer, the locked
     * copy should still be flushed but what happens is undefined except that
     * it should not cause any crashes.
     8
     * 如果非CPU塊同時寫入緩衝區,則仍應刷新鎖定的副本,但所發生的情況尚未定義,除非不會導致任何崩潰。
     *
     * @param buffer Buffer to flush.
     * @return error Error status of the call, which may be
     *     - `NONE` upon success.
     *     - `BAD_BUFFER` if the buffer is invalid or not locked.
     * @return releaseFence Handle containing a file descriptor referring to a
     *     sync fence object. The sync fence object will be signaled when the
     *     mapper has completed any pending work. @p releaseFence may be an
     *     empty fence.
     */
    flushLockedBuffer(pointer buffer) generates (Error error, handle releaseFence);

    /**
     * Rereads the contents of a locked buffer. 重新讀取鎖定緩衝區的內容
     *
     * This should fetch the most recent copy of the locked buffer. 這將獲取鎖定緩衝區的最新副本。
     *
     * It may reread locked copies of the buffer in other processes. 它可能會在其他進程中重新讀取緩衝區的鎖定副本
     *
     * The client is still responsible for calling unlock() when it is done
     * with all CPU accesses to the buffer.
     *
     * @param buffer Buffer to reread.
     * @return error Error status of the call, which may be
     *     - `NONE` upon success.
     *     - `BAD_BUFFER` if the buffer is invalid or not locked.
     *     - `NO_RESOURCES` if the buffer cannot be reread at this time. Note
     *       that rereading may succeed at a later time.
     */
    rereadLockedBuffer(pointer buffer) generates(Error error);

    /**
     * Test whether the given BufferDescriptorInfo is allocatable.
     *
     * 測試給定的BufferDescriptorInfo是否可分配。
     *
     * If this function returns true, it means that a buffer with the given
     * description can be allocated on this implementation, unless resource
     * exhaustion occurs. If this function returns false, it means that the
     * allocation of the given description will never succeed.
     *
     * @param description the description of the buffer
     * @return supported whether the description is supported
     */
    isSupported(BufferDescriptorInfo description)
            generates (Error error,
                       bool supported);


    /**
     * Description for get(...), set(...) and getFromBufferDescriptorInfo(...)
     *
     * ------------ Overview -----------------------------------
     * Gralloc 4 adds support for getting and setting buffer metadata on a buffer.
     *
     * To get buffer metadata, the client passes in a buffer handle and a token that
     * represents the type of buffer metadata they would like to get. IMapper returns
     * a byte stream that contains the buffer metadata. To set the buffer metadata, the
     * client passes in a buffer handle and a token that represents the type of buffer
     * metadata they would like to set and a byte stream that contains the buffer metadata
     * they are setting.
     *
     * Buffer metadata is global for a buffer. When the metadata is set on the buffer
     * in a process, the updated metadata should be available to all other processes.
     * Please see "Storing and Propagating Metadata" below for more details.
     *
     * The getter and setter functions have been optimized for easy vendor extension.
     * They do not require a formal HIDL extension to add support for getting and setting
     * vendor defined buffer metadata. In order to allow easy extension, the types used
     * here are not typical HIDL types. See "Buffer Metadata Token" and
     * "Buffer Metadata Stream" below for more details.
     *
     * ------------ Storing and Propagating Metadata -----------
     * Buffer metadata must be global. Any changes to the metadata must be propagated
     * to all other processes immediately. Vendors may chose how they would like support
     * this functionality.
     *
     * We recommend supporting this functionality by allocating an extra page of shared
     * memory and storing it in the buffer's native_handle_t. The buffer metadata can
     * be stored in the extra page of shared memory. Set operations are automatically
     * propagated to all other processes.
     *
     * ------------ Buffer Metadata Synchronization ------------
     * There are no explicit buffer metadata synchronization primitives. Many devices
     * before gralloc 4 already support getting and setting of global buffer metadata
     * with no explicit synchronization primitives. Adding synchronization primitives
     * would just add unnecessary complexity.
     *
     * The general rule is if a process has permission to write to a buffer, they
     * have permission to write to the buffer's metadata. If a process has permission
     * to read from a buffer, they have permission to read the buffer's metadata.
     *
     * There is one exception to this rule. Fences CANNOT be used to protect a buffer's
     * metadata. A process should finish writing to a buffer's metadata before
     * sending the buffer to another process that will read or write to the buffer.
     * This exception is needed because sometimes userspace needs to read the
     * buffer's metadata before the buffer's contents are ready.
     *
     * As a simple example: an app renders to a buffer and then displays the buffer.
     * In this example when the app renders to the buffer, both the buffer and its
     * metadata need to be updated. The app's process queues up its work on the GPU
     * and gets back an acquire fence. The app's process must update the buffer's
     * metadata before enqueuing the buffer to SurfaceFlinger. The app process CANNOT
     * update the buffer's metadata after enqueuing the buffer. When HardwareComposer
     * receives the buffer, it is immediately safe to read the buffer's metadata
     * and use it to program the display driver. To read the buffer's contents,
     * display driver must still wait on the acquire fence.
     *
     * ------------ Buffer Metadata Token ----------------------
     * In order to allow arbitrary vendor defined metadata, we could not use a
     * HIDL enum as the buffer metadata token. Extending a HIDL enum requires a full
     * HIDL extension. We also could not use a simple non-HIDL enum because vendor
     * defined enums from different vendors could collide. Instead we have defined
     * a struct that has a string representing the enum type and an int that
     * represents the enum value. The string protects different enum values from
     * colliding.
     *
     * The token struct (MetadataType) is defined as a HIDL struct since it
     * is passed into a HIDL function. The standard buffer metadata types are NOT
     * defined as a HIDL enum because it would have required a new IMapper version
     * just to add future standard buffer metadata types. By putting the enum in the
     * stable AIDL (hardware/interfaces/graphics/common/aidl/android/hardware/
     * graphics/common/StandardMetadataType.aidl), vendors will be able to optionally
     * choose to support future standard buffer metadata types without upgrading
     * HIDL versions. For more information see the description of "struct MetadataType".
     *
     * ------------ Buffer Metadata Stream ---------------------
     * The buffer metadata is get and set as a byte stream (vec<uint8_t>). By getting
     * and setting buffer metadata as a byte stream, vendors can use the standard
     * getters and setter functions defined here. Vendors do NOT need to add their own
     * getters and setter functions for each new type of buffer metadata.
     *
     * Converting buffer metadata into a byte stream can be non-trivial. For the standard
     * buffer metadata types defined in StandardMetadataType.aidl, there are also
     * support functions that will encode the buffer metadata into a byte stream
     * and decode the buffer metadata from a byte stream. We STRONGLY recommend using
     * these support functions. The framework will use them when getting and setting
     * metadata. The support functions are defined in
     * frameworks/native/libs/gralloc/types/include/gralloctypes/Gralloc4.h.
     */

    /**
     * MetadataType represents the different types of buffer metadata that could be
     * associated with a buffer. It is used by IMapper to help get and set buffer metadata
     * on the buffer's native handle.
     *
     * Standard buffer metadata will have the name field set to
     * "android.hardware.graphics.common.StandardMetadataType" and will contain values
     * from StandardMetadataType.aidl.
     *
     * This struct should be "extended" by devices that use a proprietary or non-standard
     * buffer metadata. To extend the struct, first create a custom @VendorStability vendor
     * AIDL interface that defines the new type(s) you would like to support. Set the
     * struct's name field to the custom aidl interface's name
     * (eg. "vendor.mycompanyname.graphics.common.MetadataType"). Set the struct's value
     * field to the custom @VendorStabilty vendor AIDL interface.
     *
     * Each company should create their own StandardMetadataType.aidl extension. The name
     * field prevents values from different companies from colliding.
     */
    struct MetadataType {
        string name;
        int64_t value;
    };

    /**
     * Gets the buffer metadata for a given MetadataType.
     *
     * Buffer metadata can be changed after allocation so clients should avoid "caching"
     * the buffer metadata. For example, if the video resolution changes and the buffers
     * are not reallocated, several buffer metadata values may change without warning.
     * Clients should not expect the values to be constant. They should requery them every
     * frame. The only exception is buffer metadata that is determined at allocation
     * time. For StandardMetadataType values, only BUFFER_ID, NAME, WIDTH,
     * HEIGHT, LAYER_COUNT, PIXEL_FORMAT_REQUESTED and USAGE are safe to cache because
     * they are determined at allocation time.
     *
     * @param buffer Buffer containing desired metadata
     * @param metadataType MetadataType for the metadata value being queried
     * @return error Error status of the call, which may be
     *     - `NONE` upon success.
     *     - `BAD_BUFFER` if the raw handle is invalid.
     *     - `NO_RESOURCES` if the get cannot be fullfilled due to unavailability of
     *        resources.
     *     - `UNSUPPORTED` when metadataType is unknown/unsupported.
     *        IMapper must support getting all StandardMetadataType.aidl values defined
     *        at the time the device first launches.
     * @return metadata Vector of bytes representing the buffer metadata associated with
     *  the MetadataType.
     */
    get(pointer buffer, MetadataType metadataType)
            generates (Error error,
                       vec<uint8_t> metadata);

    /**
     * Sets the global value for a given MetadataType.
     *
     * Metadata fields are not required to be settable. This function can
     * return Error::UNSUPPORTED whenever it doesn't support setting a
     * particular Metadata field.
     *
     * The framework may attempt to set the following StandardMetadataType
     * values: DATASPACE, SMPTE2086, CTA861_3, SMPTE2094_40 and BLEND_MODE.
     * We strongly encourage everyone to support setting as many of those fields as
     * possible. If a device's Composer implementation supports a field, it should be
     * supported here. Over time these metadata fields will be moved out of
     * Composer/BufferQueue/etc. and into the buffer's Metadata fields.
     * If a device's IMapper doesn't support setting those Metadata fields,
     * eventually the device may not longer be able to support these fields.
     *
     * @param buffer Buffer receiving desired metadata
     * @param metadataType MetadataType for the metadata value being set
     * @param metadata Vector of bytes representing the value associated with
     * @return error Error status of the call, which may be
     *     - `NONE` upon success.
     *     - `BAD_BUFFER` if the raw handle is invalid.
     *     - `BAD_VALUE` when the field is constant and can never be set (such as
     *       BUFFER_ID, NAME, WIDTH, HEIGHT, LAYER_COUNT, PIXEL_FORMAT_REQUESTED and
     *       USAGE)
     *     - `NO_RESOURCES` if the set cannot be fullfilled due to unavailability of
     *        resources.
     *     - `UNSUPPORTED` when metadataType is unknown/unsupported or setting
     *       it is unsupported. Unsupported should also be returned if the metadata
     *       is malformed.
     */
    set(pointer buffer, MetadataType metadataType, vec<uint8_t> metadata)
            generates (Error error);

    /**
     * Given a BufferDescriptorInfo, gets the starting value of a given
     * MetadataType. This can be used to query basic information about a buffer
     * before the buffer is allocated.
     *
     * @param description Attributes of the descriptor.
     * @param metadataType MetadataType for the metadata value being queried
     * @return error Error status of the call, which may be
     *     - `NONE` upon success.
     *     - `BAD_VALUE` if any of the specified BufferDescriptorInfo attributes
     *       are invalid.
     *     - `NO_RESOURCES` if the get cannot be fullfilled due to unavailability of
     *       resources.
     *     - `UNSUPPORTED` when any of the description attributes are unsupported or
     *       if the metadataType is unknown/unsupported. This should also be
     *       returned if the requested metadata is not defined until a buffer has been
     *       allocated.
     * @return metadata Vector of bytes representing the value associated with
     *  the MetadataType value.
     */
    getFromBufferDescriptorInfo(BufferDescriptorInfo description,
                                MetadataType metadataType)
            generates (Error error,
                       vec<uint8_t> metadata);

    struct MetadataTypeDescription {
        MetadataType metadataType;
        /**
         * description should contain a string representation of the MetadataType.
         *
         * For example: "MyExampleMetadataType is a 64-bit timestamp in nanoseconds
         * that indicates when a buffer is decoded. It is set by the media HAL after
         * a buffer is decoded. It is used by the display HAL for hardware
         * synchronization".
         *
         * This field is required for any non-StandardMetadataTypes.
         */
        string description;
        /**
         * isGettable represents if the MetadataType can be get.
         */
        bool isGettable;
        /**
         * isSettable represents if the MetadataType can be set.
         */
        bool isSettable;
    };

    /**
     * Lists all the MetadataTypes supported by IMapper as well as a description
     * of each supported MetadataType. For StandardMetadataTypes, the description
     * string can be left empty.
     *
     * @return error Error status of the call, which may be
     *     - `NONE` upon success.
     *     - `NO_RESOURCES` if the get cannot be fullfilled due to unavailability of
     *       resources.
     * @return descriptions Vector of MetadataTypeDescriptions that represent the
     *  MetadataTypes supported by the device.
     */
    listSupportedMetadataTypes()
            generates (Error error, vec<MetadataTypeDescription> descriptions);

    struct MetadataDump {
        /**
         * The type of metadata being dumped.
         */
        MetadataType metadataType;
        /**
         * The byte stream representation of the metadata. If the metadata is not
         * gettable, the vector must be empty.
         */
        vec<uint8_t> metadata; //位元組流
    };

    struct BufferDump {
        /**
         * A vector of all the metadata that is being dumped for a particular buffer.
         */
        vec<MetadataDump> metadataDump;
    };

    /**
     * Dumps a buffer's metadata. 列印buffer的metadata資訊
     *
     * @param buffer Buffer that is being dumped
     * @return error Error status of the call, which may be
     *     - `NONE` upon success.
     *     - `BAD_BUFFER` if the raw handle is invalid.
     *     - `NO_RESOURCES` if the get cannot be fullfilled due to unavailability of
     *       resources.
     * @return bufferDump Struct representing the metadata being dumped
     */
    dumpBuffer(pointer buffer)
            generates (Error error, BufferDump bufferDump);

    /**
     * Dumps the metadata for all the buffers in the current process.
     *
     * @return error Error status of the call, which may be
     *     - `NONE` upon success.
     *     - `NO_RESOURCES` if the get cannot be fullfilled due to unavailability of
     *       resources.
     * @return bufferDumps Vector of structs representing the buffers being dumped
     */
    dumpBuffers()
            generates (Error error, vec<BufferDump> bufferDumps);

    /**
     * Returns the region of shared memory associated with the buffer that is
     * reserved for client use.
     *
     * 返回與這個buffer相關的保留給client使用的共享記憶體區域
     *
     * The shared memory may be allocated from any shared memory allocator.
     * The shared memory must be CPU-accessible and virtually contiguous. The
     * starting address must be word-aligned.
     *
     * 共享記憶體可以從任何共享記憶體分配器分配。
     * 共享記憶體必須是CPU可訪問且虛擬地址連續。起始地址必須是字對齊的。
     *
     * This function may only be called after importBuffer() has been called by the
     * client. The reserved region must remain accessible until freeBuffer() has
     * been called. After freeBuffer() has been called, the client must not access
     * the reserved region.
     *
     * 這個函數只有在importBuffer()被調用後才可使用。
     * 保留的記憶體區域在freeBuffer()被調用前都是可訪問的。
     * freeBuffer()被調用後,client就無法再去訪問這塊記憶體區域了
     *
     * This reserved memory may be used in future versions of Android to
     * help clients implement backwards compatible features without requiring
     * IAllocator/IMapper updates.
     *
     * 這些保留記憶體可能會在未來版本的Android中使用,
     * 以幫助客戶端實現向後兼容的功能,而無需iLocator/IMapper更新。
     *
     * @param buffer Imported buffer handle.
     * @return error Error status of the call, which may be
     *     - `NONE` upon success.
     *     - `BAD_BUFFER` if the buffer is invalid.
     * @return reservedRegion CPU-accessible pointer to the reserved region
     * @return reservedSize the size of the reservedRegion that was requested
     *    in the BufferDescriptorInfo.
     */
    getReservedRegion(pointer buffer)
            generates (Error error,
                       pointer reservedRegion,
                       uint64_t reservedSize);
};