【Android GUI】FramebufferNativeWindow与Surface

文章目录

显示整体体系

native window为OpenGL与本地窗口系统之间搭建了桥梁。

这个窗口系统中,有两类本地窗口,nativewindow1是能直接显示在屏幕的,使用的是帧缓冲区;nativewindow2是从内存缓冲区分配的空间,通常需要通过其他方式(例如将其内容绘制到帧缓冲区)才能在屏幕上显示。

当系统中存在多个需要显示UI的应用程序时,一方面这种改进设计保证了它们都能获得一个"本地窗口";另一方面这些"本地窗口"也都可以被有序地显示到终端屏幕上,因为SurfaceFlinger会收集所有程序的显示需求,对它们进行统一的图像混合操作,然后输出到自己的NativeWindow-1上。

应用程序也可以使用Skia等第三方图形库,只要它们和SurfaceFlinger之间的"协议"不变即可。

FramebufferNativeWindow

EGL需要本地窗口为OpenGL创造环境:

cpp 复制代码
EGLSurface eglCreateWindowSurface(  EGLDisplay dpy, EGLConfig config,
NativeWindowTypewindow, const EGLint *attrib_list);

无论哪种本地窗口都需要和NativeWindowType保持一致,数据类型的定义:

cpp 复制代码
/*frameworks/native/opengl/include/egl/Eglplatform.h*/
typedef EGLNativeWindowType  NativeWindowType;//注意这两种数据类型其实是一样的
...
#if defined(_WIN32) || defined(__VC32__) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__)
 /* Win32 和 WinCE系统下的定义 */
...
typedef HWND    EGLNativeWindowType;
#elif defined(__WINSCW__) || defined(__SYMBIAN32__)  /* Symbian系统 */
...
typedef void *EGLNativeWindowType;
#elif defined(__ANDROID__) || defined(ANDROID)/* Android系统 */
struct ANativeWindow;
...
typedef struct ANativeWindow* EGLNativeWindowType;
...
#elif defined(__unix__)/* UNIX系统 */
...
typedef Window   EGLNativeWindowType;
#else
#error "Platform not recognized"
#endif

ANativeWindow定义:

cpp 复制代码
/*system/core/include/system/Window.h*/
struct ANativeWindow
{...
    const uint32_t flags; //与Surface或updater有关的属性
    const int   minSwapInterval;//所支持的最小交换间隔时间
    const int   maxSwapInterval;//所支持的最大交换间隔时间
    const float xdpi; //水平方向的密度,以dpi为单位
    const float ydpi;//垂直方向的密度,以dpi为单位
    intptr_t    oem[4];//为OEM定制驱动所保留的空间
    int (*setSwapInterval)(struct ANativeWindow* window, int interval);
    int (*dequeueBuffer)(struct ANativeWindow* window,
                struct ANativeWindowBuffer** buffer, int* fenceFd);
    int (*queueBuffer)(struct ANativeWindow* window,
                struct ANativeWindowBuffer* buffer, int fenceFd);
    int (*cancelBuffer)(struct ANativeWindow* window,
                struct ANativeWindowBuffer* buffer, int fenceFd);
    int (*query)(const struct ANativeWindow* window,int what, int* value);
    int (*perform)(struct ANativeWindow* window,int operation, ... );
    void* reserved_proc[2];
};

FramebufferNativeWindow构造函数

cpp 复制代码
/*frameworks/native/libs/ui/FramebufferNativeWindow.cpp*/
FramebufferNativeWindow::FramebufferNativeWindow() 
    : BASE(), fbDev(0), grDev(0), mUpdateOnDemand(false)
{
    hw_module_t const* module;
    if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module) == 0) {...//加载模块
        int stride;
        int err;
        int i;
        err = framebuffer_open(module, &fbDev);
        err = gralloc_open(module, &grDev);//分别打开fb和gralloc
        ...
        if(fbDev->numFramebuffers >= MIN_NUM_FRAME_BUFFERS &&
           fbDev->numFramebuffers <= MAX_NUM_FRAME_BUFFERS){//根据fb设备属性获得buffer数
            mNumBuffers = fbDev->numFramebuffers;
        } else {
            mNumBuffers = MIN_NUM_FRAME_BUFFERS;//否则就采用最少的buffer数值,即2
        }
        mNumFreeBuffers = mNumBuffers;//可用的buffer个数,初始时是所有buffer可用
        mBufferHead = mNumBuffers-1;
        ...
        for (i = 0; i < mNumBuffers; i++) //给每个buffer初始化
        {
            buffers[i] = new NativeBuffer(fbDev->width, fbDev->height, fbDev->format,
                                  GRALLOC_USAGE _HW_FB);
        }//NativeBuffer是什么?

        for (i = 0; i < mNumBuffers; i++) //给每个buffer分配空间
        {
            err = grDev->alloc(grDev, fbDev->width, fbDev->height, fbDev->format,
                       GRALLOC_USAGE_HW_FB, &buffers[i]->handle, &buffers[i]->stride);
            ...
        }
             /*为本地窗口赋属性值*/
        const_cast<uint32_t&>(ANativeWindow::flags) = fbDev->flags; 
        const_cast<float&>(ANativeWindow::xdpi) = fbDev->xdpi;
        const_cast<float&>(ANativeWindow::ydpi) = fbDev->ydpi;
        const_cast<int&>(ANativeWindow::minSwapInterval) =fbDev->minSwapInterval;
        const_cast<int&>(ANativeWindow::maxSwapInterval) = fbDev->maxSwapInterval;
    } else {
        ALOGE("Couldn't get gralloc module");
    }
    /*以下代码段开始履行窗口"协议"*/
    ANativeWindow::setSwapInterval = setSwapInterval;
    ANativeWindow::dequeueBuffer = dequeueBuffer;
    ANativeWindow::queueBuffer = queueBuffer;
    ANativeWindow::query = query;
    ANativeWindow::perform = perform;
    /*下面这几个接口已经被废弃了,不过为了保持兼容性,暂时还是保留的*/
    ANativeWindow::dequeueBuffer_DEPRECATED = dequeueBuffer_DEPRECATED;
    ANativeWindow::lockBuffer_DEPRECATED = lockBuffer_DEPRECATED;
    ANativeWindow::queueBuffer_DEPRECATED = queueBuffer_DEPRECATED; 
}

重点关注的是FramebufferNativeWindow是如何分配buffer的。

成员变量mNumBuffers代表了FramebufferNativeWindow所管理的buffer总数。它取决于两个方面:首先从fb设备中取值,即numFramebuffers;否则就默认定义为MIN_NUM_FRAME_BUFFERS:

cpp 复制代码
#define MIN_NUM_FRAME_BUFFERS  2
#define MAX_NUM_FRAME_BUFFERS  3

这代表双缓冲或者三缓冲机制。

FramebufferNativeWindow构造函数中的第一个for循环里先给各buffer创建相应的实例(new NativeBuffer),其中的属性值都来源于fbDev,如宽、高、格式等。紧随其后的就是调用Gralloc设备的alloc()方法:

cpp 复制代码
err = grDev->alloc(grDev, fbDev->width, fbDev->height, fbDev->format,
GRALLOC_USAGE_HW_FB, &buffers[i]->handle, &buffers[i]->stride);

所有申请到的缓冲区都需要由FramebufferNativeWindow中的全局变量buffers[MAX_NUM_FRAME_BUFFERS]来记录,每个数据元素是一个NativeBuffer:

cpp 复制代码
class NativeBuffer : public ANativeObjectBase<ANativeWindowBuffer, 
       NativeBuffer,LightRefBase<NativeBuffer>>
{...

NativeBuffer 继承自ANativeWindowBuffer:

cpp 复制代码
typedef struct ANativeWindowBuffer
{...
    int width; //宽
    int height;//高
    ...
    buffer_handle_t handle;/*代表内存块的句柄,比如ashmem机制。*/
    ...
} ANativeWindowBuffer_t;

一个本地窗口包含了很多属性值,如各种标志(flags)、横纵坐标的密度值等。这些数值都可以从fb设备中查询到,我们需要将它们赋予刚生成的FramebufferNativeWindow实例的属性。

FramebufferNativeWindow会将其对应的成员函数逐个填充到ANativeWindow的函数指针中:

cpp 复制代码
ANativeWindow::setSwapInterval = setSwapInterval;
ANativeWindow::dequeueBuffer = dequeueBuffer;

这样的话OpenGL ES就通过ANativeWindow与本地窗口建立了联系。

dequeueBuffer

OpenGL ES就是通过这个方法来分配用于渲染的缓冲区的:

cpp 复制代码
int FramebufferNativeWindow::dequeueBuffer(ANativeWindow* window, ANativeWindowBuffer** buffer, int* fenceFd)
{
    FramebufferNativeWindow* self = getSelf(window); /*Step1*/
    Mutex::Autolock _l(self->mutex);/*Step2*/
    ...
    /*Step3. 计算mBufferHead */
    int index = self->mBufferHead++;
    if (self->mBufferHead >= self->mNumBuffers)
        self->mBufferHead = 0;//循环

    /*Step4. 如果当前没有可用缓冲区*/
    while (!self->mNumFreeBuffers) {
        self->mCondition.wait(self->mutex);
    }
    /*Step5. 如果有人释放了缓冲区*/
    self->mNumFreeBuffers--;
    self->mCurrentBufferIndex = index;
    *buffer = self->buffers[index].get();
    *fenceFd = -1;
    return 0;
}

Surface

应用程序端的本地窗口是Surface,和FramebufferNativeWindow一样,它必须继承AnativeWindow

cpp 复制代码
class Surface
    : public ANativeObjectBase<ANativeWindow, Surface, RefBase>
cpp 复制代码
/*frameworks/native/libs/gui/Surface.cpp*/
Surface::Surface(const sp<IGraphicBufferProducer>& bufferProducer): mGraphicBufferPro duc  er(bufferProducer)
{/*给ANativeWindow中的函数指针赋值*/
    ANativeWindow::setSwapInterval  = hook_setSwapInterval;
    ANativeWindow::dequeueBuffer    = hook_dequeueBuffer;
    ...
    /*为各内部变量赋值,因为此时用户还没有发起申请,所以大部分变量的初始值是0*/
    mReqWidth = 0;
    mReqHeight = 0;
    ...
    mDefaultWidth = 0;
    mDefaultHeight = 0;
    mUserWidth = 0;
    mUserHeight = 0;...
}

surface承担应用进程UI显示的责任。

Surface将通过mGraphicBufferProducer来获取buffer,而且这些缓冲区会被记录在mSlots数组中。

cpp 复制代码
int Surface::dequeueBuffer(android_native_buffer_t** buffer,int *fenceFd) {...
    Mutex::Autolock lock(mMutex);
    int buf = -1;
    /*Step1. 宽高计算*/
    int reqW = mReqWidth ? mReqWidth : mUserWidth;
    int reqH = mReqHeight ? mReqHeight : mUserHeight;
    /*Step2. dequeueBuffer得到一个缓冲区*/
    sp<Fence> fence;
    status_t result = mGraphicBufferProducer->dequeueBuffer(&buf, &fence,
                           reqW, reqH, mReqFormat, mReqUsage);/*生产者发挥作用了*/ 
    ...
sp<GraphicBuffer>&gbuf(mSlots[buf].buffer);/*注意buf是一个int值,
                                            代表的是mSlots数组序号*/
    ...
    if ((result & IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION) || gbuf == 0) {
        result = mGraphicBufferProducer->requestBuffer(buf, &gbuf);//申请空间
        ...
    }
    ...
    *buffer = gbuf.get();
}

摘自原书:

大致流程是:ViewRootImpl持有一个Java层的Surface对象(即mSurface),初始时是空的。后续ViewRootImpl将向WindowManagerService发起relayout请求,此时mSurface才被赋予真正有效的值。WindowManagerService会先让WindowStateAnimator生成一个SurfaceControl,然后通过Surface.copyFrom()函数将其复制到mSurface中。这个复制函数会通过native接口nativeCreateFrom SurfaceControl来生成本地Surface(C++)对象,具体是在android_view_Surface.cpp文件中。JNI函数nativeCreateFromSurfaceControl将从SurfaceControl中提取出Surface(C++),最终记录到Surface(Java)的成员变量中。这样,后期我们就可以从此变量中还原出底层的Surface对象了。

Surface由SurfaceControl管理,而后者又由SurfaceComposerClient创建。

cpp 复制代码
/*frameworks/native/libs/gui/SurfaceComposerClient.cpp*/
sp<SurfaceControl> SurfaceComposerClient::createSurface(const String8& name,uint32_t w,
                                       uint32_t h,PixelFormat format,uint32_t flags)
{
    sp<SurfaceControl> sur;
    if (mStatus == NO_ERROR) {
        sp<IBinder> handle;
        sp<IGraphicBufferProducer> gbp;
        status_t err = mClient->createSurface(name, w, h, format, flags, &handle, &gbp);  
        //生成一个Surface
        ...
        if (err == NO_ERROR) {
            sur = new SurfaceControl(this, handle, gbp);//SurfaceControl是"本地"的对象
        }
    }
    return sur;
}

mClient是一个ISurfaceComposerClient的sp指针,通过它创建一个surface。

SurfaceControl对象并不是由ISurfaceComposerClient的createSurface直接生成的,这个函数的参数中包括了gbp,即前面所说的"buffer生产者"。

真正与SurfaceFlinger间有联系的应该就是gbp。

来看下ISurfaceComposerClient的服务端:

cpp 复制代码
void SurfaceComposerClient::onFirstRef() {
    sp<ISurfaceComposer> sm(ComposerService::getComposerService());
    if (sm != 0) {
        sp<ISurfaceComposerClient> conn = sm->createConnection();
        if (conn != 0) {
            mClient = conn;
            mStatus = NO_ERROR;
        }
    }
}

这里面与三个匿名Binder相关联,它们是由surfaceflinger提供的。surface flinger是注册在server manager上面的。

总结

FramebufferNativeWindow是为surfaceflinger服务的,由Gralloc提供。

surface虽然为应用程序服务的,但是本质上还是由surface flinger服务统一管理的。

参考

《深入理解Android内核设计思想》

相关推荐
雨白14 小时前
Android 快捷方式实战指南:静态、动态与固定快捷方式详解
android
hqk14 小时前
鸿蒙项目实战:手把手带你实现 WanAndroid 布局与交互
android·前端·harmonyos
LING14 小时前
RN容器启动优化实践
android·react native
恋猫de小郭17 小时前
Flutter 发布官方 Skills ,Flutter 在 AI 领域再添一助力
android·前端·flutter
Kapaseker1 天前
一杯美式搞懂 Any、Unit、Nothing
android·kotlin
黄林晴1 天前
你的 Android App 还没接 AI?Gemini API 接入全攻略
android
恋猫de小郭1 天前
2026 Flutter VS React Native ,同时在 AI 时代 VS Native 开发,你没见过的版本
android·前端·flutter
冬奇Lab1 天前
PowerManagerService(上):电源状态与WakeLock管理
android·源码阅读
BoomHe2 天前
Now in Android 架构模式全面分析
android·android jetpack
二流小码农2 天前
鸿蒙开发:上传一张参考图片便可实现页面功能
android·ios·harmonyos