Android 系统中AHardwareBuffer、ANativeWindowBuffer和GraphicBuffer的关系

Android Camera软件系统中,每路Stream的Buffer都是DMA-BUF,这种Buffer通常对外暴露的结构是ANativeWindowBuffer或GraphicBuffer(跨进程传递时用的native_handle_t),本文介绍Android系统中AHardwareBuffer、ANativeWindowBuffer和GraphicBuffer的关系。ANativeWindowBuffer、AHardwareBuffer都是GraphicBuffer通过类型转换而来,ANativeWindowBuffer对native_handle_t进行了封装。

ANativeWindowBuffer

ANativeWindowBuffer定义在nativebase.h头文件中。

复制代码
frameworks/native/libs/nativebase/include/nativebase/nativebase.h

定义如下:

复制代码
typedef struct ANativeWindowBuffer
{
#ifdef __cplusplus
    ANativeWindowBuffer() {
        common.magic = ANDROID_NATIVE_BUFFER_MAGIC;
        common.version = sizeof(ANativeWindowBuffer);
        memset(common.reserved, 0, sizeof(common.reserved));
    }

    // Implement the methods that sp<ANativeWindowBuffer> expects so that it
    // can be used to automatically refcount ANativeWindowBuffer's.
    void incStrong(const void* /*id*/) const {
        common.incRef(const_cast<android_native_base_t*>(&common));
    }
    void decStrong(const void* /*id*/) const {
        common.decRef(const_cast<android_native_base_t*>(&common));
    }
#endif

    struct android_native_base_t common;

    int width;
    int height;
    int stride;
    int format;
    int usage_deprecated;
    uintptr_t layerCount;

    void* reserved[1];

    const native_handle_t* handle;
    uint64_t usage;

    // we needed extra space for storing the 64-bits usage flags
    // the number of slots to use from reserved_proc depends on the
    // architecture.
    void* reserved_proc[8 - (sizeof(uint64_t) / sizeof(void*))];
} ANativeWindowBuffer_t;

typedef struct ANativeWindowBuffer ANativeWindowBuffer;

可以看到它是一个结构体,重要的成员有:

  • handle
  • width
  • height
  • stride
  • format
  • usage

ANativeWindowBuffer描述的是一块DMA Buffer,handle中包含了Buffer的FD,其他成员是该Buffer的一些描述/补充。

GraphicBuffer

GraphicBuffer的头文件分为

-- frameworks/native/libs/ui/include_vndk/ui/GraphicBuffer.h

-- frameworks/native/libs/ui/include/ui/GraphicBuffer.h

GraphicBuffer继承自ANativeWindowBuffer。

我们可以在Vendor/System分区使用GraphicBuffer,用到的库是libui.so(支持VNDK)。

AHardwareBuffer

AHardwareBuffer定义在

复制代码
frameworks/native/libs/nativewindow/include/android/hardware_buffer.h

定义如下:

复制代码
/**
 * Opaque handle for a native hardware buffer.
 */
typedef struct AHardwareBuffer AHardwareBuffer;

所以,AHardwareBuffer是一个抽象的概念,没有具体类型(类似void类型),主要用于在同一进程的不同模块间传递ANativeWindowBuffer。

GraphicBuffer 与 ANativeWindowBuffer相互转换

GraphicBuffer提供了接口来做转换,使用的static_cast

GraphicBuffer转成ANativeWindowBuffer:

复制代码
ANativeWindowBuffer* GraphicBuffer::getNativeBuffer() const
{
    return static_cast<ANativeWindowBuffer*>(
            const_cast<GraphicBuffer*>(this));
}

ANativeWindowBuffer转换成GraphicBuffer:

复制代码
sp<GraphicBuffer> GraphicBuffer::from(ANativeWindowBuffer* anwb) {
    return static_cast<GraphicBuffer *>(anwb);
}

AHardwareBuffer 与 GraphicBuffer 相互转换

GraphicBuffer提供了接口来做转换,使用的reinterpret_cast

AHardwareBuffer 转换成GraphicBuffer:

复制代码
GraphicBuffer* GraphicBuffer::fromAHardwareBuffer(AHardwareBuffer* buffer) {
    return reinterpret_cast<GraphicBuffer*>(buffer);
}

GraphicBuffer转换成AHardwareBuffer:

复制代码
AHardwareBuffer const* GraphicBuffer::toAHardwareBuffer() const {
    return reinterpret_cast<AHardwareBuffer const*>(this);
}

AHardwareBuffer 与 ANativeWindowBuffer相互转换

他们两不能直接转换,必须借助GraphicBuffer来作为中间桥梁。

AHardwareBuffer转换成ANativeWindowBuffer:

frameworks/native/libs/nativewindow/AHardwareBuffer.cpp定义了AHardwareBuffer_to_ANativeWindowBuffer方法完成该转换(注:无法在Vendor分区使用)

复制代码
ANativeWindowBuffer* AHardwareBuffer_to_ANativeWindowBuffer(AHardwareBuffer* buffer) {
    return AHardwareBuffer_to_GraphicBuffer(buffer)->getNativeBuffer();
}

先将AHardwareBuffer转换成GraphicBuffer,然后再调用GraphicBuffer的getNativeBuffer。

ANativeWindowBuffer转换成AHardwareBuffer:

先将ANativeWindowBuffer转换成GraphicBuffer,再调用toAHardwareBuffer获取到HardwareBuffer。

复制代码
sp<GraphicBuffer> GraphicBuffer::from(ANativeWindowBuffer* anwb) {
    return static_cast<GraphicBuffer *>(anwb);
}

AHardwareBuffer* GraphicBuffer::toAHardwareBuffer() {
    return reinterpret_cast<AHardwareBuffer*>(this);
}

如何创建ANativeWindowBuffer

为了让ANativeWindowBuffer有智能指针的作用,需要定义一个类继承自ANativeWindowBuffer和android::RefBase(如果不想要智能指针的作用则不用做这一步)。

举例:

复制代码
class NativeBuffer : public ANativeWindowBuffer, public android::RefBase
{
public:
    void incStrong(const void* id) const { RefBase::incStrong(id); }
    void decStrong(const void* id) const { RefBase::decStrong(id); }

    NativeBuffer(INT32 widthIn, INT32 heightIn, INT32 strideIn, INT32 formatIn,
        INT32 usageIn, native_handle_t *handleIn) :
        ANativeWindowBuffer(), RefBase()
    {
        width           = widthIn;
        height          = heightIn;
        stride          = strideIn;
        format          = formatIn;
        usage           = usageIn;
        handle          = handleIn;
        common.incRef   = incRef;
        common.decRef   = decRef;
    }

private:
    static void incRef(android_native_base_t* base)
    {
        NativeBuffer *self = static_cast<NativeBuffer*>(
            reinterpret_cast<ANativeWindowBuffer*>(base));
        self->incStrong(self);
    }

    static void decRef(android_native_base_t* base)
    {
        NativeBuffer *self = static_cast<NativeBuffer*>(
            reinterpret_cast<ANativeWindowBuffer*>(base));
        self->decStrong(self);
    }
};

这里面主要实现incRef和decRef,会尝试static_cast检查能否正常进行转换,然后调用RefBase相应的接口。

使用时,直接new NativeBuffer

复制代码
new NativeBuffer(width, height, stride, m_formatInput, m_usage, static_cast<native_handle_t*>(pImage->pNativeHandle));

reinterpret_cast与static_cast的作用和区别

reinterpret_cast用于执行低级别的类型转换,可以将一个指针或引用转换为另一种不同类型的指针或引用。它允许将任何指针类型转换为任何其他指针类型,即使它们之间没有任何关系。这种转换是非常危险的,潜在地导致未定义行为,因此应该谨慎使用。reinterpret_cast通常用于底层编程,例如将指针转换为整数类型或将数据强制转换为特定的内存布局。

static_cast是一种较为安全的类型转换操作符,它主要用于相关类型之间的转换,例如整数之间的转换、父类指针/引用到子类指针/引用的转换等。static_cast会在编译时进行类型检查,并检查是否存在可行的转换路径。如果存在转换,则进行转换,否则会产生编译错误。相对于reinterpret_cast,static_cast提供了更多的类型安全性,并且在一定程度上减少了潜在的错误。

总结一下:

  • reinterpret_cast执行低级别的类型转换,允许将任何指针类型转换为任何其他指针类型,但是风险较高,容易导致未定义行为。
  • static_cast用于相关类型之间的转换,提供了较为安全的类型转换,并在编译时进行类型检查,如果存在可行的转换路径,则进行转换,否则产生编译错误。
相关推荐
莞凰10 小时前
昇腾CANN的“灵脉根基“:Runtime仓库探秘
android·人工智能·transformer
NiceCloud喜云11 小时前
Claude Files API 深入:从上传、复用到配额管理的工程化指南
android·java·数据库·人工智能·python·json·飞书
ujainu11 小时前
CANN pto-isa:虚拟指令集如何连接编译与执行
android·ascend
赏金术士12 小时前
第六章:UI组件与Material3主题
android·ui·kotlin·compose
TechMerger13 小时前
Android 17 重磅重构!服役 20 年的 MessageQueue 迎来无锁改造,卡顿大幅优化!
android·性能优化
yuhuofei202116 小时前
【Python入门】Python中字符串相关拓展
android·java·python
dalancon16 小时前
Android Input Spy Window
android
dalancon17 小时前
InputDispatcher派发事件,查找目标窗口
android
我命由我1234517 小时前
Android Framework P3 - MediaServer 进程、认识 ServiceManager 进程
android·c语言·开发语言·c++·visualstudio·visual studio·android runtime
天才少年曾牛19 小时前
Android14 新增系统服务后,应用调用出现 “hidden api” 警告的原因与解决方案
android·frameworks