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);
};