Android显示系统分析

来源:互联网 发布:sql判断字段是否为空 编辑:程序博客网 时间:2024/05/16 08:54

1. Linux内核提供了统一的framebuffer显示驱动,设备节点/dev/graphics/fb*或者/dev/fb*,以fb0表示第一个显示屏,当前实现中只用到了一个显示屏。

2. Android的HAL层提供了Gralloc,分为fb和gralloc两个设备。设备fb负责打开内核中的framebuffer以及提供post、setSwapInterval等操作,设备gralloc则负责管理帧缓冲区的分配和释放。上层只能通过Gralloc访问帧缓冲区,这样一来就实现了有序的封装保护。

3. 由于OpenGL ES是一个通用的函数库,在不同的平台系统上需要被“本地化”——即把它与具体平台上的窗口系统建立起关联,这样才能保证它正常工作。从FramebufferNativeWindow就是将OpenGL ES在Android平台上本地化窗口。

4. OpenGL或者OpenGL ES 更多的只是一个接口协议,实现上既可以采用软件,也能依托于硬件。EGL通过读取egl.cfg配置文件,根据用户的设定来动态加载libagl(软件实现)或者libhgl(硬件实现)。然后上层才可以正常使用各种glXXX接口。

5. SurfaceFlinger中持有一个GraphicPlane成员变量mGraphicPlanes来描述“显示屏”;GraphicPlane类中又包含了一个DisplayHardware对象实例(mHw)。DisplayHardware在初始化时还将调用eglInitialize、eglCreateWindowSurface等接口,并利用EGL完成对OpenGLES环境的搭建。


本地窗口


Android提供了两种本地窗口:

1)         面向SurfaceFlinger的FramebufferNativeWindow;

2)         面向应用程序的SurfaceTextureClient;

 

使用OpenGL绘制图像前,需要通过EGL创建一个Surface画板:

frameworks\native\opengl\libagl\ Egl.cpp

EGLSurface eglCreateWindowSurface(  EGLDisplay dpy, EGLConfig config,                                    NativeWindowType window,                                    const EGLint *attrib_list){    return createWindowSurface(dpy, config, window, attrib_list);}

OpenGL是跨平台的图形库,不同平台上的NativeWindowType窗口类型有不同的定义:

frameworks\native\opengl\include\egl\ Eglplatform.h

typedef EGLNativeWindowType  NativeWindowType;#if defined(_WIN32) || defined(__VC32__) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__) /* Win32 and WinCE */#ifndef WIN32_LEAN_AND_MEAN#define WIN32_LEAN_AND_MEAN 1#endif#include <windows.h>typedef HDC     EGLNativeDisplayType;typedef HBITMAP EGLNativePixmapType;typedef HWND    EGLNativeWindowType;#elif defined(__WINSCW__) || defined(__SYMBIAN32__)  /* Symbian */typedef int   EGLNativeDisplayType;typedef void *EGLNativeWindowType;typedef void *EGLNativePixmapType;#elif defined(__ANDROID__) || defined(ANDROID)struct ANativeWindow;struct egl_native_pixmap_t;typedef struct ANativeWindow*           EGLNativeWindowType;typedef struct egl_native_pixmap_t*     EGLNativePixmapType;typedef void*                           EGLNativeDisplayType;#elif defined(__unix__)/* X11 (tentative)  */#include <X11/Xlib.h>#include <X11/Xutil.h>typedef Display *EGLNativeDisplayType;typedef Pixmap   EGLNativePixmapType;typedef Window   EGLNativeWindowType;#else#error "Platform not recognized"#endif

可以看出对于Android平台,NativeWindowType的类型为ANativeWindow

struct ANativeWindow{#ifdef __cplusplus //C++定义    ANativeWindow(): flags(0), minSwapInterval(0), maxSwapInterval(0), xdpi(0), ydpi(0)    {        common.magic = ANDROID_NATIVE_WINDOW_MAGIC;        common.version = sizeof(ANativeWindow);        memset(common.reserved, 0, sizeof(common.reserved));    }    /* Implement the methods that sp<ANativeWindow> expects so that it       can be used to automatically refcount ANativeWindow'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;    /* flags describing some attributes of this surface or its updater */    const uint32_t flags;    /* min swap interval supported by this updated */    const int   minSwapInterval;    /* max swap interval supported by this updated */    const int   maxSwapInterval;    /* horizontal and vertical resolution in DPI */    const float xdpi;    const float ydpi;    /* Some storage reserved for the OEM's driver. */    intptr_t    oem[4];    /* Set the swap interval for this surface. */    int     (*setSwapInterval)(struct ANativeWindow* window,                int interval);    /*     * Hook called by EGL to acquire a buffer. After this call, the buffer     * is not locked, so its content cannot be modified. This call may block if     * no buffers are available.     */    int     (*dequeueBuffer)(struct ANativeWindow* window,                struct ANativeWindowBuffer** buffer);    /*     * hook called by EGL to lock a buffer. This MUST be called before modifying     * the content of a buffer. The buffer must have been acquired with     * dequeueBuffer first.     */    int     (*lockBuffer)(struct ANativeWindow* window,                struct ANativeWindowBuffer* buffer);    /*     * Hook called by EGL when modifications to the render buffer are done.     * This unlocks and post the buffer.     */    int     (*queueBuffer)(struct ANativeWindow* window,                struct ANativeWindowBuffer* buffer);    /*     * hook used to retrieve information about the native window.     */    int     (*query)(const struct ANativeWindow* window,                int what, int* value);    /*     * hook used to perform various operations on the surface.     * (*perform)() is a generic mechanism to add functionality to     * ANativeWindow while keeping backward binary compatibility.     * The valid operations are:     *     NATIVE_WINDOW_SET_USAGE     *     NATIVE_WINDOW_CONNECT               (deprecated)     *     NATIVE_WINDOW_DISCONNECT            (deprecated)     *     NATIVE_WINDOW_SET_CROP              (private)     *     NATIVE_WINDOW_SET_BUFFER_COUNT     *     NATIVE_WINDOW_SET_BUFFERS_GEOMETRY  (deprecated)     *     NATIVE_WINDOW_SET_BUFFERS_TRANSFORM     *     NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP     *     NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS     *     NATIVE_WINDOW_SET_BUFFERS_FORMAT     *     NATIVE_WINDOW_SET_SCALING_MODE       (private)     *     NATIVE_WINDOW_LOCK                   (private)     *     NATIVE_WINDOW_UNLOCK_AND_POST        (private)     *     NATIVE_WINDOW_API_CONNECT            (private)     *     NATIVE_WINDOW_API_DISCONNECT         (private)     *     NATIVE_WINDOW_SET_BUFFERS_USER_DIMENSIONS (private)     *     NATIVE_WINDOW_SET_POST_TRANSFORM_CROP (private)     *     */    int     (*perform)(struct ANativeWindow* window,                int operation, ... );    /*     * Hook used to cancel a buffer that has been dequeued.     * No synchronization is performed between dequeue() and cancel(), so     * either external synchronization is needed, or these functions must be     * called from the same thread.     */    int     (*cancelBuffer)(struct ANativeWindow* window,                struct ANativeWindowBuffer* buffer);    void* reserved_proc[2];};

无论是基于应用程序的本地窗口SurfaceTextureClient还是基于SurfaceFlinger的FramebufferNativeWindow本地窗口,都必须实现ANativeWindow定义的一套窗口协议,这样应用程序和SurfaceFlinger才能使用OpenGL。ANativeWindow就相当于Java中的接口类型,只是用于定义窗口的功能函数,并不去实现这些函数,而是由需要使用OpenGL的对象来实现。

应用程序本地窗口

应用程序端的SurfaceTextureClient实现了ANativeWindow类型中定义的函数,这样应用程序就可以使用OpenGL来绘制图形图像了,当然应用程序可以选择性地使用OpenGL或是Skia。

SurfaceFlinger本地窗口

由于SurfaceFlinger必须要使用OpenGL来混合图像,因此SurfaceFlinger端的FramebufferNativeWindow必须实现ANativeWindow类型。

Gralloc

通过加载gralloc抽象层,可以打开fb设备和gpu设备,fb设备用于操作framebuffergpu设备负责图形缓冲区的分配和释放。对于SurfaceFlinger服务端的本地窗口FramebufferNativeWindow将分别打开fb设备和gpu设备,FramebufferNativeWindow通过gpu设备从Framebuffer中分配图形缓冲区,通过fb设备来渲染经SurfaceFlinger混合后的图像。而对于应用程序端的SurfaceTextureClient本地窗口,其需要的图形缓冲区也是由SurfaceFlinger服务端来分配,应用程序进程只需要将服务端分配的图形缓冲区映射到应用程序的虚拟地址空间,图形缓冲区的映射过程也是由Gralloc模块完成。Android图形显示之硬件抽象层Gralloc对Gralloc模块进行了详细介绍,这里只简单带过。

gpu、fb和gralloc模块中定义的数据结构关系如下:

通过加载Gralloc动态库,可以分别打开fb设备和gpu设备。

gpu设备

Gpu打开过程就是创建并初始化一个gralloc_context_t对象,gpu负责图形buffer的分配和释放。

int gralloc_device_open(const hw_module_t* module, const char* name,        hw_device_t** device){    int status = -EINVAL;    if (!strcmp(name, GRALLOC_HARDWARE_GPU0)) {        gralloc_context_t *dev;        dev = (gralloc_context_t*)malloc(sizeof(*dev));        /* initialize our state here */        memset(dev, 0, sizeof(*dev));        /* initialize the procs */        dev->device.common.tag = HARDWARE_DEVICE_TAG;        dev->device.common.version = 0;        dev->device.common.module = const_cast<hw_module_t*>(module);        dev->device.common.close = gralloc_close;        dev->device.alloc   = gralloc_alloc;        dev->device.free    = gralloc_free;        *device = &dev->device.common;        status = 0;    return status;}

fb设备

Fb设备打开过程就是创建并初始化一个fb_context_t对象,关于屏幕大小、格式、刷新频率等信息都是通过Framebuffer驱动来获取,最后将Framebuffer映射到SurfaceFlinger进程地址空间,并将映射后的首地址保持到private_module_tframebuffer->base变量中。

int fb_device_open(hw_module_t const* module, const char* name,        hw_device_t** device){    int status = -EINVAL;    if (!strcmp(name, GRALLOC_HARDWARE_FB0)) {        alloc_device_t* gralloc_device;        status = gralloc_open(module, &gralloc_device);        if (status < 0)            return status;        /* initialize our state here */        fb_context_t *dev = (fb_context_t*)malloc(sizeof(*dev));        memset(dev, 0, sizeof(*dev));        /* initialize the procs */        dev->device.common.tag = HARDWARE_DEVICE_TAG;        dev->device.common.version = 0;        dev->device.common.module = const_cast<hw_module_t*>(module);        dev->device.common.close = fb_close;        dev->device.setSwapInterval = fb_setSwapInterval;        dev->device.post            = fb_post;        dev->device.setUpdateRect = 0;        private_module_t* m = (private_module_t*)module;        status = mapFrameBuffer(m);        if (status >= 0) {            int stride = m->finfo.line_length / (m->info.bits_per_pixel >> 3);            int format = (m->info.bits_per_pixel == 32)                         ? HAL_PIXEL_FORMAT_RGBX_8888                         : HAL_PIXEL_FORMAT_RGB_565;            const_cast<uint32_t&>(dev->device.flags) = 0;            const_cast<uint32_t&>(dev->device.width) = m->info.xres;            const_cast<uint32_t&>(dev->device.height) = m->info.yres;            const_cast<int&>(dev->device.stride) = stride;            const_cast<int&>(dev->device.format) = format;            const_cast<float&>(dev->device.xdpi) = m->xdpi;            const_cast<float&>(dev->device.ydpi) = m->ydpi;            const_cast<float&>(dev->device.fps) = m->fps;            const_cast<int&>(dev->device.minSwapInterval) = 1;            const_cast<int&>(dev->device.maxSwapInterval) = 1;            *device = &dev->device.common;        }    }    return status;}

为了方便应用程序及SurfaceFlinger使用Gralloc模块中的fb设备和gpu设备,Android对gpu设备进行了封装。我们知道,SurfaceFlinger不仅负责FramebufferNativeWindow本地窗口的图形buffer的分配,同时也负责应用程序本地窗口SurfaceTextureClient的图形buffer分配,应用程序只需将服务端分配的图形buffer映射到当前进程的虚拟地址空间即可,因此应用程序和SurfaceFlinger都将会使用到Gralloc模块。


SurfaceSession建立过程


SurfaceSession对象承担了应用程序与SurfaceFlinger之间的通信过程,每一个需要与SurfaceFlinger进程交互的应用程序端都需要创建一个SurfaceSession对象。

客户端请求

frameworks\base\core\java\android\view\SurfaceSession.java

public SurfaceSession() {init();}

Java层的SurfaceSession对象构造过程会通过JNI在native层创建一个SurfaceComposerClient对象。

frameworks\base\core\jni\android_view_Surface.cpp

static void SurfaceSession_init(JNIEnv* env, jobject clazz){    sp<SurfaceComposerClient> client = new SurfaceComposerClient;    client->incStrong(clazz);    env->SetIntField(clazz, sso.client, (int)client.get());}

Java层的SurfaceSession对象与C++层的SurfaceComposerClient对象之间是一对一关系。

frameworks\native\libs\gui\SurfaceComposerClient.cpp

SurfaceComposerClient::SurfaceComposerClient()    : mStatus(NO_INIT), mComposer(Composer::getInstance()){}

SurfaceComposerClient继承于RefBase类,当第一次被强引用时,onFirstRef函数被回调,在该函数中SurfaceComposerClient会请求SurfaceFlinger为当前应用程序创建一个Client对象,专门接收该应用程序的请求,在SurfaceFlinger端创建好Client本地Binder对象后,将该Binder代理对象返回给应用程序端,并保存在SurfaceComposerClient的成员变量mClient中。

void SurfaceComposerClient::onFirstRef() {//得到SurfaceFlinger的代理对象BpSurfaceComposer    sp<ISurfaceComposer> sm(getComposerService());    if (sm != 0) {        sp<ISurfaceComposerClient> conn = sm->createConnection();        if (conn != 0) {            mClient = conn;            mStatus = NO_ERROR;        }    }}

服务端处理

在SurfaceFlinger服务端为应用程序创建交互的Client对象

frameworks\native\services\surfaceflinger\SurfaceFlinger.cpp

sp<ISurfaceComposerClient> SurfaceFlinger::createConnection(){    sp<ISurfaceComposerClient> bclient;    sp<Client> client(new Client(this));    status_t err = client->initCheck();    if (err == NO_ERROR) {        bclient = client;    }    return bclient;}



关于SurfaceFlinger服务代理对象获取的详细过程请查看Android SurfaceFlinger服务代理对象获取过程源码分析

 

Surface创建过程

 

客户端请求

frameworks\base\core\java\android\view\Surface.java

public Surface(SurfaceSession s,int pid, String name, int display, int w, int h, int format, int flags)throws OutOfResourcesException {checkHeadless();if (DEBUG_RELEASE) {mCreationStack = new Exception();}mCanvas = new CompatibleCanvas();init(s,pid,name,display,w,h,format,flags);mName = name;}

frameworks\base\core\jni\android_view_Surface.cpp

static void Surface_init(JNIEnv* env, jobject clazz,jobject session,jint, jstring jname, jint dpy, jint w, jint h, jint format, jint flags){    if (session == NULL) {        doThrowNPE(env);        return;}//取得SurfaceComposerClient对象    SurfaceComposerClient* client =            (SurfaceComposerClient*)env->GetIntField(session, sso.client);//调用SurfaceComposerClient的createSurface函数在SurfaceFlinger服务端创建Layer对象,并返回ISurface    //代理对象,并通过ISurface代理对象在应用程序端创建一个SurfaceControl对象,用于控制Surface    sp<SurfaceControl> surface;    if (jname == NULL) {        surface = client->createSurface(dpy, w, h, format, flags);    } else {        const jchar* str = env->GetStringCritical(jname, 0);        const String8 name(str, env->GetStringLength(jname));        env->ReleaseStringCritical(jname, str);        surface = client->createSurface(name, dpy, w, h, format, flags);    }    if (surface == 0) {        jniThrowException(env, OutOfResourcesException, NULL);        return;}//将创建的SurfaceControl对象指针保存到Java层的Surface的成员变量mSurfaceControl中    setSurfaceControl(env, clazz, surface);}

该函数首先得到前面创建好的SurfaceComposerClient对象,通过该对象向SurfaceFlinger端的Client对象发送创建Surface的请求,最后得到一个SurfaceControl对象。

frameworks\native\libs\gui\SurfaceComposerClient.cpp

sp<SurfaceControl> SurfaceComposerClient::createSurface(        const String8& name,        DisplayID display,        uint32_t w,        uint32_t h,        PixelFormat format,        uint32_t flags){    sp<SurfaceControl> result;if (mStatus == NO_ERROR) {    //通过IsurfaceComposerClient的代理对象请求服务端的Client创建Surface        ISurfaceComposerClient::surface_data_t data;        sp<ISurface> surface = mClient->createSurface(&data, name,                display, w, h, format, flags);        //通过ISurface的代理对象创建SurfaceControl        if (surface != 0) {            result = new SurfaceControl(this, surface, data);        }    }    return result;}

SurfaceComposerClient将Surface创建请求转交给保存在其成员变量中的Bp SurfaceComposerClient对象来完成,在SurfaceFlinger端的Client本地对象会返回一个ISurface代理对象给应用程序,通过该代理对象为应用程序当前创建的Surface创建一个SurfaceControl对象。

frameworks\native\include\gui\ISurfaceComposerClient.h

virtual sp<ISurface> createSurface( surface_data_t* params,                                        const String8& name,                                        DisplayID display,                                        uint32_t w,                                        uint32_t h,                                        PixelFormat format,                                        uint32_t flags)    {        Parcel data, reply;        data.writeInterfaceToken(ISurfaceComposerClient::getInterfaceDescriptor());        data.writeString8(name);        data.writeInt32(display);        data.writeInt32(w);        data.writeInt32(h);        data.writeInt32(format);        data.writeInt32(flags);        remote()->transact(CREATE_SURFACE, data, &reply);        params->readFromParcel(reply);        return interface_cast<ISurface>(reply.readStrongBinder());    }

服务端处理

frameworks\native\include\gui\ISurfaceComposerClient.h

status_t BnSurfaceComposerClient::onTransact(    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags){     switch(code) {        case CREATE_SURFACE: {            CHECK_INTERFACE(ISurfaceComposerClient, data, reply);            surface_data_t params;            String8 name = data.readString8();            DisplayID display = data.readInt32();            uint32_t w = data.readInt32();            uint32_t h = data.readInt32();            PixelFormat format = data.readInt32();            uint32_t flags = data.readInt32();            //Client继承于BnSurfaceComposerClient,调用Client的createSurface函数处理            sp<ISurface> s = createSurface(¶ms, name, display, w, h,                    format, flags);            params.writeToParcel(reply);            reply->writeStrongBinder(s->asBinder());            return NO_ERROR;        } break;        default:            return BBinder::onTransact(code, data, reply, flags);    }}

frameworks\native\services\surfaceflinger\SurfaceFlinger.cpp$ Client

sp<ISurface> Client::createSurface(        ISurfaceComposerClient::surface_data_t* params,        const String8& name,        DisplayID display, uint32_t w, uint32_t h, PixelFormat format,        uint32_t flags){    sp<MessageBase> msg = new MessageCreateSurface(mFlinger.get(),            params, name, this, display, w, h, format, flags);    //将Surface创建请求转换为异步消息处理方式发送到SurfaceFlinger消息队列中,由SurfaceFlinger服务来完成    mFlinger->postMessageSync(msg);    return static_cast<MessageCreateSurface*>( msg.get() )->getResult();}

MessageCreateSurface消息是专门为应用程序请求创建Surface而定义的一种消息类型:

/* * createSurface must be called from the GL thread so that it can * have access to the GL context. */class MessageCreateSurface : public MessageBase {sp<ISurface> result;SurfaceFlinger* flinger;ISurfaceComposerClient::surface_data_t* params;Client* client;const String8& name;DisplayID display;uint32_t w, h;PixelFormat format;uint32_t flags;public:MessageCreateSurface(SurfaceFlinger* flinger,ISurfaceComposerClient::surface_data_t* params,const String8& name, Client* client,DisplayID display, uint32_t w, uint32_t h, PixelFormat format,uint32_t flags): flinger(flinger), params(params), client(client), name(name),display(display),w(w), h(h), format(format), flags(flags){}sp<ISurface> getResult() const { return result; }//MessageCreateSurface消息的处理过程virtual bool handler() {result = flinger->createSurface(params, name, client,display, w, h, format, flags);return true;}};

Client将应用程序创建Surface的请求转换为异步消息投递到SurfaceFlinger的消息队列中,将创建Surface的任务转交给SurfaceFlinger。

frameworks\native\services\surfaceflinger\SurfaceFlinger.cpp

sp<ISurface> SurfaceFlinger::createSurface(        ISurfaceComposerClient::surface_data_t* params,        const String8& name,        const sp<Client>& client,        DisplayID d, uint32_t w, uint32_t h, PixelFormat format,        uint32_t flags){    sp<LayerBaseClient> layer;    sp<ISurface> surfaceHandle;    if (int32_t(w|h) < 0) {        ALOGE("createSurface() failed, w or h is negative (w=%d, h=%d)",int(w), int(h));        return surfaceHandle;    }    //ALOGD("createSurface for (%d x %d), name=%s", w, h, name.string());    sp<Layer> normalLayer;//根据flags创建不同类型的Surface    switch (flags & eFXSurfaceMask) {        case eFXSurfaceNormal:            normalLayer = createNormalSurface(client, d, w, h, flags, format);            layer = normalLayer;            break;        case eFXSurfaceBlur:            // for now we treat Blur as Dim, until we can implement it            // efficiently.        case eFXSurfaceDim:            layer = createDimSurface(client, d, w, h, flags);            break;        case eFXSurfaceScreenshot:            layer = createScreenshotSurface(client, d, w, h, flags);            break;    }//为客户端的Surface创建好Layer对象    if (layer != 0) {        layer->initStates(w, h, flags);        layer->setName(name);//将创建好的Layer对象保存在Client中        ssize_t token = addClientLayer(client, layer);//创建BSurface本地Binder对象        surfaceHandle = layer->getSurface();        if (surfaceHandle != 0) {//token为当前Layer对象在Client中的id号            params->token = token;//Identity是每个Layer对象标号,SurfaceFlinger每创建一个Layer对象,自动加1            params->identity = layer->getIdentity();//将创建好的Layer对象保存在SurfaceFlinger中            if (normalLayer != 0) {                Mutex::Autolock _l(mStateLock);                mLayerMap.add(layer->getSurfaceBinder(), normalLayer);            }        }        setTransactionFlags(eTransactionNeeded);    }    return surfaceHandle;}

SurfaceFlinger根据标志位创建对应类型的Surface,当前系统定义了5种类型的Surface:


普遍Surface的创建过程:

sp<Layer> SurfaceFlinger::createNormalSurface(        const sp<Client>& client, DisplayID display,        uint32_t w, uint32_t h, uint32_t flags,        PixelFormat& format){    // initialize the surfaces    switch (format) { // TODO: take h/w into account    case PIXEL_FORMAT_TRANSPARENT:    case PIXEL_FORMAT_TRANSLUCENT:        format = PIXEL_FORMAT_RGBA_8888;        break;    case PIXEL_FORMAT_OPAQUE:#ifdef NO_RGBX_8888        format = PIXEL_FORMAT_RGB_565;#else        format = PIXEL_FORMAT_RGBX_8888;#endif        break;    }#ifdef NO_RGBX_8888    if (format == PIXEL_FORMAT_RGBX_8888)        format = PIXEL_FORMAT_RGBA_8888;#endif//在SurfaceFlinger端为应用程序的Surface创建对应的Layer对象    sp<Layer> layer = new Layer(this, display, client);    status_t err = layer->setBuffers(w, h, format, flags);    if (CC_LIKELY(err != NO_ERROR)) {        ALOGE("createNormalSurfaceLocked() failed (%s)", strerror(-err));        layer.clear();    }    return layer;}

在SurfaceFlinger服务端为应用程序创建的Surface创建对应的Layer对象。应用程序请求创建Surface过程如下:

 

Layer构造过程

frameworks\native\services\surfaceflinger\LayerBase.cpp

LayerBase::LayerBase(SurfaceFlinger* flinger, DisplayID display)    : dpy(display), contentDirty(false),      sequence(uint32_t(android_atomic_inc(&sSequence))),      mFlinger(flinger), mFiltering(false),      mNeedsFiltering(false),      mOrientation(0),      mPlaneOrientation(0),      mTransactionFlags(0),      mPremultipliedAlpha(true), mName("unnamed"), mDebug(false){    const DisplayHardware& hw(flinger->graphicPlane(0).displayHardware());    mFlags = hw.getFlags();}

 

LayerBaseClient::LayerBaseClient(SurfaceFlinger* flinger, DisplayID display,        const sp<Client>& client)    : LayerBase(flinger, display),      mHasSurface(false),      mClientRef(client),//为每个Layer对象分配一个唯一的标示号      mIdentity(uint32_t(android_atomic_inc(&sIdentity))){}

frameworks\native\services\surfaceflinger\Layer.cpp

Layer::Layer(SurfaceFlinger* flinger,        DisplayID display, const sp<Client>& client)    :   LayerBaseClient(flinger, display, client),        mTextureName(-1U),        mQueuedFrames(0),        mCurrentTransform(0),        mCurrentScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),        mCurrentOpacity(true),        mRefreshPending(false),        mFrameLatencyNeeded(false),        mFrameLatencyOffset(0),        mFormat(PIXEL_FORMAT_NONE),        mGLExtensions(GLExtensions::getInstance()),        mOpaqueLayer(true),        mNeedsDithering(false),        mSecure(false),        mProtectedByApp(false){    mCurrentCrop.makeInvalid();    glGenTextures(1, &mTextureName);}

第一次强引用Layer对象时,onFirstRef()函数被回调

void Layer::onFirstRef(){    LayerBaseClient::onFirstRef();    //创建BufferQueue对象sp<BufferQueue> bq = new SurfaceTextureLayer();    //创建SurfaceTexture对象    mSurfaceTexture = new SurfaceTexture(mTextureName, true,            GL_TEXTURE_EXTERNAL_OES, false, bq);    mSurfaceTexture->setConsumerUsageBits(getEffectiveUsage(0));    //设置buffer可用监听,生产者就是通过回调机制来通知消费者buffer数据已经填充好了    mSurfaceTexture->setFrameAvailableListener(new FrameQueuedListener(this));    //设置同步模式    mSurfaceTexture->setSynchronousMode(true);    //设置缓冲区个数#ifdef TARGET_DISABLE_TRIPLE_BUFFERING#warning "disabling triple buffering"    mSurfaceTexture->setBufferCountServer(2);#else    mSurfaceTexture->setBufferCountServer(3);#endif}

BufferQueue构造过程

frameworks\native\libs\gui\ SurfaceTexture.cpp

SurfaceTextureLayer::SurfaceTextureLayer()    : BufferQueue(true) {}

frameworks\native\libs\gui\BufferQueue.cpp

BufferQueue::BufferQueue(  bool allowSynchronousMode, int bufferCount ) :    mDefaultWidth(1),    mDefaultHeight(1),    mPixelFormat(PIXEL_FORMAT_RGBA_8888),    mMinUndequeuedBuffers(bufferCount),    mMinAsyncBufferSlots(bufferCount + 1),    mMinSyncBufferSlots(bufferCount),    mBufferCount(mMinAsyncBufferSlots),    mClientBufferCount(0),    mServerBufferCount(mMinAsyncBufferSlots),    mSynchronousMode(false),    mAllowSynchronousMode(allowSynchronousMode),    mConnectedApi(NO_CONNECTED_API),    mAbandoned(false),    mFrameCounter(0),    mBufferHasBeenQueued(false),    mDefaultBufferFormat(0),    mConsumerUsageBits(0),    mTransformHint(0){    // Choose a name using the PID and a process-unique ID.    mConsumerName = String8::format("unnamed-%d-%d", getpid(), createProcessUniqueId());    ST_LOGV("BufferQueue");    //由于BufferQueue与SurfaceFlinger处于同一进程中,因此这里获取到SurfaceFlinger的本地Binder对象    sp<ISurfaceComposer> composer(ComposerService::getComposerService());    //通过SurfaceFlinger来创建图形buffer分配器    mGraphicBufferAlloc = composer->createGraphicBufferAlloc();    if (mGraphicBufferAlloc == 0) {        ST_LOGE("createGraphicBufferAlloc() failed in BufferQueue()");    }}

GraphicBufferAlloc构造过程

frameworks\native\services\surfaceflinger\SurfaceFlinger.cpp

sp<IGraphicBufferAlloc> SurfaceFlinger::createGraphicBufferAlloc(){    sp<GraphicBufferAlloc> gba(new GraphicBufferAlloc());    return gba;}

SurfaceTexture构造过程

frameworks\native\libs\gui\ SurfaceTexture.cpp

SurfaceTexture::SurfaceTexture(GLuint tex, bool allowSynchronousMode,        GLenum texTarget, bool useFenceSync, const sp<BufferQueue> &bufferQueue) :    mCurrentTransform(0),    mCurrentTimestamp(0),    mFilteringEnabled(true),    mTexName(tex),#ifdef USE_FENCE_SYNC    mUseFenceSync(useFenceSync),#else    mUseFenceSync(false),#endif    mTexTarget(texTarget),    mEglDisplay(EGL_NO_DISPLAY),    mEglContext(EGL_NO_CONTEXT),    mAbandoned(false),    mCurrentTexture(BufferQueue::INVALID_BUFFER_SLOT),    mAttached(true){    // Choose a name using the PID and a process-unique ID.    mName = String8::format("unnamed-%d-%d", getpid(), createProcessUniqueId());    ST_LOGV("SurfaceTexture");    if (bufferQueue == 0) {        ST_LOGV("Creating a new BufferQueue");        mBufferQueue = new BufferQueue(allowSynchronousMode);    }    else {        mBufferQueue = bufferQueue;    }    memcpy(mCurrentTransformMatrix, mtxIdentity,            sizeof(mCurrentTransformMatrix));    // Note that we can't create an sp<...>(this) in a ctor that will not keep a    // reference once the ctor ends, as that would cause the refcount of 'this'    // dropping to 0 at the end of the ctor.  Since all we need is a wp<...>    // that's what we create.    wp<BufferQueue::ConsumerListener> listener;    sp<BufferQueue::ConsumerListener> proxy;//将当前SurfaceTexture对象保存到ProxyConsumerListener成员变量中,由ProxyConsumerListener//来代理接收FrameAvailable通知    listener = static_cast<BufferQueue::ConsumerListener*>(this);    proxy = new BufferQueue::ProxyConsumerListener(listener);//将ProxyConsumerListener对象设置到BufferQueue中,当buffer可被消费时,由BufferQueue//通知ProxyConsumerListener。BufferQueueProxyConsumerListenerSurfaceTexture    status_t err = mBufferQueue->consumerConnect(proxy);    if (err != NO_ERROR) {        ST_LOGE("SurfaceTexture: error connecting to BufferQueue: %s (%d)",                strerror(-err), err);    } else {        mBufferQueue->setConsumerName(mName);        mBufferQueue->setConsumerUsageBits(DEFAULT_USAGE_FLAGS);    }}

根据buffer可用监听器的注册过程,我们知道,当生产者也就是应用程序填充好图形buffer数据后,通过回调方式通知消费者的过程如下:


在服务端为Surface创建Layer过程中,分别创建了SurfaceTexture、BufferQueue和GraphicBufferAlloc对象,它们之间的关系如下:

ISurface本地对象创建过程

以上完成Layer对象创建后,通过layer->getSurface()来创建ISurface的Binder本地对象,并将其代理对象返回给应用程序。

frameworks\native\services\surfaceflinge\ Layer.cpp

sp<ISurface> Layer::createSurface(){    sp<ISurface> sur(new BSurface(mFlinger, this));    return sur;}

总结一下Surface创建过程,应用程序通过SurfaceComposerClient请求SurfaceFlinger创建一个Surface,在SurfaceFlinger服务端将会创建的对象有:

1.         一个Layer对象:

2.         一个SurfaceTexture对象

3.         一个BufferQueue对象:用于管理当前创建的Surface的图形buffer

4.         一个GraphicBufferAlloc对象:用于分配图形buffer

5.         一个BSurface本地Binder对象:用于获取BufferQueue的Binder代理对象

关于Surface创建过程的详细分析请参考Android应用程序创建Surface过程源码分析。Android在SurfaceFlinger进程为应用程序定义了4个Binder对象:

1.         SurfaceFlinger: 有名Binder对象,可通过服务查询方式获取;

2.         Client:                 无名Binder对象,只能由SurfaceFlinger服务创建;

3.         BSurface:           无名Binder对象,只能由Client服务创建;

4.         BufferQueue:      无名Binder对象,只能通过BSurface服务返回;

以上各个Binder对象提供的接口函数如下所示:


应用程序本地窗口Surface创建过程


从前面分析可知,SurfaceFlinger在处理应用程序请求创建Surface中,在SurfaceFlinger服务端仅仅创建了Layer对象,那么应用程序本地窗口Surface在什么时候、什么地方创建呢?

我们知道Surface继承于SurfaceTextureClient,而SurfaceTextureClient是面向应用程序的本地创建,因此它就应该是在应用程序进程中创建。在前面的分析中,我们也知道,SurfaceFlinger

为应用程序创建好了Layer对象并返回ISurface的代理对象给应用程序,应用程序通过该代理对象创建了一个SurfaceControl对象,Java层Surface需要通过android_view_Surface.cpp中的JNI函数来操作native层的Surface,在操作native层Surface前,首先需要获取到native的Surface,应用程序本地窗口Surface就是在这个时候创建的。

frameworks\base\core\jni\android_view_Surface.cpp

static sp<Surface> getSurface(JNIEnv* env, jobject clazz){    //从Java层的Surface对象中获取native的Surface对象指针    sp<Surface> result(Surface_getSurface(env, clazz));//native Surface还未创建    if (result == 0) {        /*         * if this method is called from the WindowManager's process, it means         * the client is is not remote, and therefore is allowed to have         * a Surface (data), so we create it here.         * If we don't have a SurfaceControl, it means we're in a different         * process.         */        SurfaceControl* const control =            (SurfaceControl*)env->GetIntField(clazz, so.surfaceControl);        if (control) {    //创建native Surface            result = control->getSurface();            if (result != 0) {                result->incStrong(clazz);                env->SetIntField(clazz, so.surface, (int)result.get());            }        }    }    return result;}

frameworks\native\libs\gui\Surface.cpp

sp<Surface> SurfaceControl::getSurface() const{    Mutex::Autolock _l(mLock);    if (mSurfaceData == 0) {        sp<SurfaceControl> surface_control(const_cast<SurfaceControl*>(this));//构造应用程序本地窗口        mSurfaceData = new Surface(surface_control);    }    return mSurfaceData;}

 

Surface::Surface(const sp<SurfaceControl>& surface)    : SurfaceTextureClient(),      mSurface(surface->mSurface),      mIdentity(surface->mIdentity){    sp<ISurfaceTexture> st;    if (mSurface != NULL) {        st = mSurface->getSurfaceTexture();    }    init(st);}

Surface继承于SurfaceTextureClient类,在构造Surface时,首先会调用SurfaceTextureClient的构造函数:

frameworks\native\libs\gui\SurfaceTextureClient.cpp

SurfaceTextureClient::SurfaceTextureClient() {    SurfaceTextureClient::init();}

 

void SurfaceTextureClient::init() {    // Initialize the ANativeWindow function pointers.    ANativeWindow::setSwapInterval  = hook_setSwapInterval;    ANativeWindow::dequeueBuffer    = hook_dequeueBuffer;    ANativeWindow::cancelBuffer     = hook_cancelBuffer;    ANativeWindow::lockBuffer       = hook_lockBuffer;    ANativeWindow::queueBuffer      = hook_queueBuffer;    ANativeWindow::query            = hook_query;    ANativeWindow::perform          = hook_perform;    const_cast<int&>(ANativeWindow::minSwapInterval) = 0;    const_cast<int&>(ANativeWindow::maxSwapInterval) = 1;    mReqWidth = 0;    mReqHeight = 0;    mReqFormat = 0;    mReqUsage = 0;    mTimestamp = NATIVE_WINDOW_TIMESTAMP_AUTO;    mCrop.clear();    mScalingMode = NATIVE_WINDOW_SCALING_MODE_FREEZE;    mTransform = 0;    mDefaultWidth = 0;    mDefaultHeight = 0;    mUserWidth = 0;    mUserHeight = 0;    mTransformHint = 0;    mConsumerRunningBehind = false;    mConnectedToCpu = false;}

父类SurfaceTextureClient构造完成后,通过ISurface的代理对象BpSurface请求BSurface获取BufferQueue的代理对象。

frameworks\native\services\surfaceflinge\ Layer.cpp

class BSurface : public BnSurface, public LayerCleaner {wp<const Layer> mOwner;virtual sp<ISurfaceTexture> getSurfaceTexture() const {sp<ISurfaceTexture> res;sp<const Layer> that( mOwner.promote() );if (that != NULL) {res = that->mSurfaceTexture->getBufferQueue();}return res;}public:BSurface(const sp<SurfaceFlinger>& flinger,const sp<Layer>& layer): LayerCleaner(flinger, layer), mOwner(layer) { }};

最后调用Surface的init函数进行初始化

frameworks\native\libs\gui\Surface.cpp

void Surface::init(const sp<ISurfaceTexture>& surfaceTexture){    if (mSurface != NULL || surfaceTexture != NULL) {        ALOGE_IF(surfaceTexture==0, "got a NULL ISurfaceTexture from ISurface");        if (surfaceTexture != NULL) {            setISurfaceTexture(surfaceTexture);            setUsage(GraphicBuffer::USAGE_HW_RENDER);        }        DisplayInfo dinfo;        SurfaceComposerClient::getDisplayInfo(0, &dinfo);        const_cast<float&>(ANativeWindow::xdpi) = dinfo.xdpi;        const_cast<float&>(ANativeWindow::ydpi) = dinfo.ydpi;        const_cast<uint32_t&>(ANativeWindow::flags) = 0;    }}

到此应用程序的本地窗口Surface就创建完成了,通过上面的分析,可以知道,应用程序本地窗口的创建会在应用程序进程和SurfaceFlinger进程分别创建不同的对象:

1. SurfaceFlinger进程:Layer、SurfaceTexture、BufferQueue等;

2. 应用程序进程:Surface、SurfaceControl、SurfaceComposerClient等;

ISurfaceTexture是应用程序与BufferQueue的传输通道。
ISurfaceComposerClient是应用程序与SurfaceFlinger间的桥梁,在应用进程中则被封装在SurfaceComposerClient这个类中。这是一个匿名binder server,由应用程序调用SurfaceFlinger这个实名binder的createConnection方法来获取到,服务端的实现是SurfaceFlinger::Client。任何有UI界面的程序都在SurfaceFlinger中有且仅有一个Client实例。
ISurface:由应用程序调用ISurfaceComposerClient::createSurface()得到,同时在SurfaceFlinger这一进程中将会有一个Layer被创建,代表了一个“画面”。ISurface就是控制这一画面的handle。
Surface:从逻辑关系上看,它是上述ISurface的使用者。从继承关系上看,它是一个SurfaceTextureClient,也就是本地窗口。SurfaceTextureClient内部持有ISurfaceTexture,即BufferQueue的实现接口。


以上Surface、Layer、SurfaceTexture、BufferQueue,应用程序和Client之间的关系如下图所示:



Surface的图形buffer申请过程


在创建完应用程序本地窗口Surface后,想要在该Surface上绘图,首先需要为该Surface分配图形buffer。我们前面介绍了Android应用程序图形缓冲区的分配都是由SurfaceFlinger服务进程来完成,在请求创建Surface时,在服务端创建了一个BufferQueue本地Binder对象,该对象负责管理应用程序一个本地窗口Surface的图形缓冲区。在BufferQueue中定义了图形buffer的四个状态:

enum BufferState {// FREE indicates that the buffer is not currently being used and// will not be used in the future until it gets dequeued and// subsequently queued by the client.// aka "owned by BufferQueue, ready to be dequeued"FREE = 0,// DEQUEUED indicates that the buffer has been dequeued by the// client, but has not yet been queued or canceled. The buffer is// considered 'owned' by the client, and the server should not use// it for anything.//// Note that when in synchronous-mode (mSynchronousMode == true),// the buffer that's currently attached to the texture may be// dequeued by the client.  That means that the current buffer can// be in either the DEQUEUED or QUEUED state.  In asynchronous mode,// however, the current buffer is always in the QUEUED state.// aka "owned by producer, ready to be queued"DEQUEUED = 1,// QUEUED indicates that the buffer has been queued by the client,// and has not since been made available for the client to dequeue.// Attaching the buffer to the texture does NOT transition the// buffer away from the QUEUED state. However, in Synchronous mode// the current buffer may be dequeued by the client under some// circumstances. See the note about the current buffer in the// documentation for DEQUEUED.// aka "owned by BufferQueue, ready to be acquired"QUEUED = 2,// aka "owned by consumer, ready to be released"ACQUIRED = 3};

BufferQueue对图形buffer的管理采用消费者-生产者模型,所有的buffer都由BufferQueue管理,当生产者也就是应用程序需要绘图时,必须向BufferQueue申请绘图缓冲区,并且将图形buffer设置为DEQUEUED出列状态,此时只有应用程序才能访问这块图形buffer。当应用程序完成绘图后,需要将图形缓冲区归还给BufferQueue管理,并设置当前buffer为QUEUED入列状态,同时通知消费者绘图完成。消费者又将向BufferQueue申请已完成的图形buffer,并将当前申请的图形buffer设置为ACQUIRED状态,此时的图形buffer只能被消费者处理。


客户端请求

frameworks\native\libs\gui\SurfaceTextureClient.cpp

int SurfaceTextureClient::dequeueBuffer(android_native_buffer_t** buffer) {    ATRACE_CALL();    ALOGV("SurfaceTextureClient::dequeueBuffer");    Mutex::Autolock lock(mMutex);//图形buffer的索引号    int buf = -1;    int reqW = mReqWidth ? mReqWidth : mUserWidth;    int reqH = mReqHeight ? mReqHeight : mUserHeight;//请求服务端的BufferQueue    status_t result = mSurfaceTexture->dequeueBuffer(&buf, reqW, reqH,            mReqFormat, mReqUsage);    if (result < 0) {        ALOGV("dequeueBuffer: ISurfaceTexture::dequeueBuffer(%d, %d, %d, %d)"             "failed: %d", mReqWidth, mReqHeight, mReqFormat, mReqUsage,             result);        return result;    }    sp<GraphicBuffer>& gbuf(mSlots[buf].buffer);//结果为RELEASE_ALL_BUFFERS,则释放所有的buffer    if (result & ISurfaceTexture::RELEASE_ALL_BUFFERS) {        freeAllBuffers();    }//结果为BUFFER_NEEDS_REALLOCATION,则请求重新分配图形buffer    if ((result & ISurfaceTexture::BUFFER_NEEDS_REALLOCATION) || gbuf == 0) {//请求服务端的BufferQueue        result = mSurfaceTexture->requestBuffer(buf, &gbuf);        if (result != NO_ERROR) {            ALOGE("dequeueBuffer: ISurfaceTexture::requestBuffer failed: %d",result);            return result;        }    }    *buffer = gbuf.get();    return OK;}

frameworks\native\libs\gui\ISurfaceTexture.cpp$ BpSurfaceTexture

virtual status_t dequeueBuffer(int *buf, uint32_t w, uint32_t h,uint32_t format, uint32_t usage) {Parcel data, reply;data.writeInterfaceToken(ISurfaceTexture::getInterfaceDescriptor());data.writeInt32(w);data.writeInt32(h);data.writeInt32(format);data.writeInt32(usage);status_t result = remote()->transact(DEQUEUE_BUFFER, data, &reply);if (result != NO_ERROR) {return result;}*buf = reply.readInt32();result = reply.readInt32();return result;}

服务端处理

frameworks\native\libs\gui\ISurfaceTexture.cpp$BnSurfaceTexture

status_t BnSurfaceTexture::onTransact(    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags){    switch(code) {        case DEQUEUE_BUFFER: {            CHECK_INTERFACE(ISurfaceTexture, data, reply);            uint32_t w      = data.readInt32();            uint32_t h      = data.readInt32();            uint32_t format = data.readInt32();            uint32_t usage  = data.readInt32();            int buf;            int result = dequeueBuffer(&buf, w, h, format, usage);            reply->writeInt32(buf);            reply->writeInt32(result);            return NO_ERROR;        } break;    }    return BBinder::onTransact(code, data, reply, flags);}

frameworks\native\libs\gui\BufferQueue.cpp

status_t BufferQueue::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h,        uint32_t format, uint32_t usage) {    ATRACE_CALL();    ST_LOGV("dequeueBuffer: w=%d h=%d fmt=%#x usage=%#x", w, h, format, usage);    if ((w && !h) || (!w && h)) {        ST_LOGE("dequeueBuffer: invalid size: w=%u, h=%u", w, h);        return BAD_VALUE;    }    status_t returnFlags(OK);    EGLDisplay dpy = EGL_NO_DISPLAY;    EGLSyncKHR fence = EGL_NO_SYNC_KHR;    { // Scope for the lock        Mutex::Autolock lock(mMutex);        if (format == 0) {            format = mDefaultBufferFormat;        }        // turn on usage bits the consumer requested        usage |= mConsumerUsageBits;        int found = -1;        int foundSync = -1;        int dequeuedCount = 0;        bool tryAgain = true;        while (tryAgain) {            if (mAbandoned) {                ST_LOGE("dequeueBuffer: SurfaceTexture has been abandoned!");                return NO_INIT;            }            const int minBufferCountNeeded = mSynchronousMode ? mMinSyncBufferSlots : mMinAsyncBufferSlots;            const bool numberOfBuffersNeedsToChange = !mClientBufferCount &&                    ((mServerBufferCount != mBufferCount) ||(mServerBufferCount < minBufferCountNeeded));if (!mQueue.isEmpty() && numberOfBuffersNeedsToChange) {                // wait for the FIFO to drain                mDequeueCondition.wait(mMutex);                // NOTE: we continue here because we need to reevaluate our                // whole state (eg: we could be abandoned or disconnected)                continue;            }            if (numberOfBuffersNeedsToChange) {                // here we're guaranteed that mQueue is empty                freeAllBuffersLocked();                mBufferCount = mServerBufferCount;                if (mBufferCount < minBufferCountNeeded)                    mBufferCount = minBufferCountNeeded;                mBufferHasBeenQueued = false;                returnFlags |= ISurfaceTexture::RELEASE_ALL_BUFFERS;            }            // look for a free buffer to give to the client            found = INVALID_BUFFER_SLOT;            foundSync = INVALID_BUFFER_SLOT;            dequeuedCount = 0;            for (int i = 0; i < mBufferCount; i++) {                const int state = mSlots[i].mBufferState;                if (state == BufferSlot::DEQUEUED) {                    dequeuedCount++;//统计已经被生产者出列的buffer个数                }if (state == BufferSlot::FREE) {/*  * mFrameNumber用于标示buffer入列序号,buffer入列时都会 * mFrameNumber自动加一,通过mFrameNumber可以判断buffer入列的先后顺序 */bool isOlder = mSlots[i].mFrameNumber < mSlots[found].mFrameNumber;if (found < 0 || isOlder) {foundSync = i;found = i;}}            }            // clients are not allowed to dequeue more than one buffer            // if they didn't set a buffer count.            if (!mClientBufferCount && dequeuedCount) {                ST_LOGE("dequeueBuffer: can't dequeue multiple buffers without "                        "setting the buffer count");                return -EINVAL;            }            // See whether a buffer has been queued since the last            // setBufferCount so we know whether to perform the            // mMinUndequeuedBuffers check below.            if (mBufferHasBeenQueued) {                // make sure the client is not trying to dequeue more buffers                // than allowed.                const int avail = mBufferCount - (dequeuedCount+1);                if (avail < (mMinUndequeuedBuffers-int(mSynchronousMode))) {                    ST_LOGE("dequeueBuffer: mMinUndequeuedBuffers=%d exceeded ""(dequeued=%d)",                            mMinUndequeuedBuffers-int(mSynchronousMode),                            dequeuedCount);                    return -EBUSY;                }            }            // if no buffer is found, wait for a buffer to be released            tryAgain = found == INVALID_BUFFER_SLOT;            if (tryAgain) {                mDequeueCondition.wait(mMutex);            }        }        if (found == INVALID_BUFFER_SLOT) {            // This should not happen.            ST_LOGE("dequeueBuffer: no available buffer slots");            return -EBUSY;        }//状态为FREE、合适的buffer索引号        const int buf = found;        *outBuf = found;        ATRACE_BUFFER_INDEX(buf);        const bool useDefaultSize = !w && !h;        if (useDefaultSize) {            // use the default size            w = mDefaultWidth;            h = mDefaultHeight;        }        const bool updateFormat = (format != 0);        if (!updateFormat) {            // keep the current (or default) format            format = mPixelFormat;        }        // buffer is now in DEQUEUED (but can also be current at the same time,        // if we're in synchronous mode)        mSlots[buf].mBufferState = BufferSlot::DEQUEUED;        const sp<GraphicBuffer>& buffer(mSlots[buf].mGraphicBuffer);//如果当前buffer不合适,则创建一个新的图形buffer        if ((buffer == NULL) ||            (uint32_t(buffer->width)  != w) ||            (uint32_t(buffer->height) != h) ||            (uint32_t(buffer->format) != format) ||            ((uint32_t(buffer->usage) & usage) != usage))        {            status_t error;//创建新的图形buffer            sp<GraphicBuffer> graphicBuffer(                    mGraphicBufferAlloc->createGraphicBuffer(w, h, format, usage, &error));            if (graphicBuffer == 0) {                ST_LOGE("dequeueBuffer: SurfaceComposer::createGraphicBuffer ""failed");                return error;            }            if (updateFormat) {                mPixelFormat = format;            }//根据buffer索引,初始化mSlots中对应的元素            mSlots[buf].mAcquireCalled = false;            mSlots[buf].mGraphicBuffer = graphicBuffer;            mSlots[buf].mRequestBufferCalled = false;            mSlots[buf].mFence = EGL_NO_SYNC_KHR;            mSlots[buf].mEglDisplay = EGL_NO_DISPLAY;//设置返回结果为BUFFER_NEEDS_REALLOCATION            returnFlags |= ISurfaceTexture::BUFFER_NEEDS_REALLOCATION;        }        dpy = mSlots[buf].mEglDisplay;        fence = mSlots[buf].mFence;        mSlots[buf].mFence = EGL_NO_SYNC_KHR;    }  // end lock scope    if (fence != EGL_NO_SYNC_KHR) {        EGLint result = eglClientWaitSyncKHR(dpy, fence, 0, 1000000000);        // If something goes wrong, log the error, but return the buffer without        // synchronizing access to it.  It's too late at this point to abort the        // dequeue operation.        if (result == EGL_FALSE) {            ST_LOGE("dequeueBuffer: error waiting for fence: %#x", eglGetError());        } else if (result == EGL_TIMEOUT_EXPIRED_KHR) {            ST_LOGE("dequeueBuffer: timeout waiting for fence");        }        eglDestroySyncKHR(dpy, fence);    }    ST_LOGV("dequeueBuffer: returning slot=%d buf=%p flags=%#x", *outBuf,            mSlots[*outBuf].mGraphicBuffer->handle, returnFlags);    return returnFlags;}

BufferQueue中有一个mSlots数组用于管理其内的各缓冲区,最大容量为32。mSlots在程序一开始就静态分配了32个BufferSlot大小的空间。但BufferSlot的内部变指针mGraphicBuffer所指向的图形buffer空间却是动态分配的。


图形缓冲区创建过程


如果从mSlots数组中找到了一个状态为FREE的图形buffer,但由于该图形buffer不合适,因此需要重新创建一个GraphicBuffer对象。


frameworks\native\services\surfaceflinger\SurfaceFlinger.cpp

sp<GraphicBuffer> GraphicBufferAlloc::createGraphicBuffer(uint32_t w, uint32_t h,        PixelFormat format, uint32_t usage, status_t* error) {//构造一个GraphicBuffer对象    sp<GraphicBuffer> graphicBuffer(new GraphicBuffer(w, h, format, usage));    status_t err = graphicBuffer->initCheck();    *error = err;    if (err != 0 || graphicBuffer->handle == 0) {        if (err == NO_MEMORY) {            GraphicBuffer::dumpAllocationsToSystemLog();        }        ALOGE("GraphicBufferAlloc::createGraphicBuffer(w=%d, h=%d) "             "failed (%s), handle=%p",                w, h, strerror(-err), graphicBuffer->handle);        return 0;    }    return graphicBuffer;}

frameworks\native\libs\ui\GraphicBuffer.cpp

GraphicBuffer::GraphicBuffer(uint32_t w, uint32_t h,         PixelFormat reqFormat, uint32_t reqUsage)    : BASE(), mOwner(ownData), mBufferMapper(GraphicBufferMapper::get()),      mInitCheck(NO_ERROR), mIndex(-1){    width  =     height =     stride =     format =     usage  = 0;    handle = NULL;//分配图形buffer存储空间    mInitCheck = initSize(w, h, reqFormat, reqUsage);}

根据图形buffer的宽高、格式等信息为图形缓冲区分配存储空间

status_t GraphicBuffer::initSize(uint32_t w, uint32_t h, PixelFormat format,        uint32_t reqUsage){    GraphicBufferAllocator& allocator = GraphicBufferAllocator::get();    status_t err = allocator.alloc(w, h, format, reqUsage, &handle, &stride);    if (err == NO_ERROR) {        this->width  = w;        this->height = h;        this->format = format;        this->usage  = reqUsage;    }    return err;}

使用GraphicBufferAllocator对象来为图形缓冲区分配内存空间,GraphicBufferAllocator是对Gralloc模块中的gpu设备的封装类。关于GraphicBufferAllocator内存分配过程请查看Android图形缓冲区分配过程源码分析,图形缓冲区分配完成后,还会映射到SurfaceFlinger服务进程的虚拟地址空间。


应用程序获取图形buffer首地址

我们知道,Surface为应用程序这边用于描述画板类,继承于SurfaceTextureClient类,是面向应用程序的本地窗口,实现了EGL窗口协议。在SurfaceTextureClient中定义了一个大小为32的mSlots数组,用于保存当前Surface申请的图形buffer。每个Surface在SurfaceFlinger服务端有一个layer对象与之对应,在前面也介绍了,每个Layer又拥有一个SurfaceTexture对象,每个SurfaceTexture对象又持有一个buffer队列BufferQue,BufferQue同样为每个Layer定义了一个大小为32的mSlots数组,同样用来保存每个Layer所使用的buffer。只不过应用程序端的mSlots数组元素和服务端的mSlots数组元素定义不同,应用程序在申请图形buffer时必须保存这两个队列数据中的buffer同步。

如果重新为图形buffer分配空间,那么BufferQueue的dequeueBuffer函数返回值中需要加上BUFFER_NEEDS_REALLOCATION标志。客户端在发现这个标志后,它还应调用requestBuffer()来取得最新的buffer地址。

客户端请求

frameworks\native\libs\gui\SurfaceTextureClient.cpp

int SurfaceTextureClient::dequeueBuffer(android_native_buffer_t** buffer) {...    if ((result & ISurfaceTexture::BUFFER_NEEDS_REALLOCATION) || gbuf == 0) {//获取图形buffer的首地址        result = mSurfaceTexture->requestBuffer(buf, &gbuf);        if (result != NO_ERROR) {            ALOGE("dequeueBuffer: ISurfaceTexture::requestBuffer failed: %d",                    result);            return result;        }    }    *buffer = gbuf.get();    return OK;}

frameworks\native\libs\gui\ISurfaceTexture.cpp$ BpSurfaceTexture

virtual status_t requestBuffer(int bufferIdx, sp<GraphicBuffer>* buf) {Parcel data, reply;data.writeInterfaceToken(ISurfaceTexture::getInterfaceDescriptor());data.writeInt32(bufferIdx);status_t result =remote()->transact(REQUEST_BUFFER, data, &reply);if (result != NO_ERROR) {return result;}bool nonNull = reply.readInt32();if (nonNull) {//在应用程序进程中创建一个GraphicBuffer对象sp<GraphicBuffer> p = new GraphicBuffer();result = reply.read(*p);if (result != NO_ERROR) {p = 0;return result;}*buf = p;}result = reply.readInt32();return result;}

frameworks\native\libs\ui\GraphicBuffer.cpp

GraphicBuffer::GraphicBuffer()    : BASE(), mOwner(ownData), mBufferMapper(GraphicBufferMapper::get()),      mInitCheck(NO_ERROR), mIndex(-1){    width  =     height =     stride =     format =     usage  = 0;    handle = NULL;}

服务端进程接收到应用程序进程requestBuffer请求后,将新创建的GraphicBuffer对象发送给应用程序。上面可以看到,应用程序进程这边也创建了一个GraphicBuffer对象,在SurfaceFlinger服务进程中也同样创建了一个GraphicBuffer对象,SurfaceFlinger服务进程只是将它进程中创建的GraphicBuffer对象传输给应用程序进程,我们知道,一个对象要在进程间传输必须继承于Flattenable类,并且实现flatten和unflatten方法,flatten方法用于序列化该对象,unflatten方法用于反序列化对象。

 

GraphicBuffer同样继承于Flattenable类并实现了flatten和unflatten方法,在应用程序读取来自服务进程的GraphicBuffer对象时,也就是result = reply.read(*p),会调用GraphicBuffer类的unflatten函数进行反序列化过程: 

status_t GraphicBuffer::unflatten(void const* buffer, size_t size,        int fds[], size_t count){    if (size < 8*sizeof(int)) return NO_MEMORY;    int const* buf = static_cast<int const*>(buffer);    if (buf[0] != 'GBFR') return BAD_TYPE;    const size_t numFds  = buf[6];    const size_t numInts = buf[7];    const size_t sizeNeeded = (8 + numInts) * sizeof(int);    if (size < sizeNeeded) return NO_MEMORY;    size_t fdCountNeeded = 0;    if (count < fdCountNeeded) return NO_MEMORY;    if (handle) {        // free previous handle if any        free_handle();    }    if (numFds || numInts) {        width  = buf[1];        height = buf[2];        stride = buf[3];        format = buf[4];        usage  = buf[5];//创建一个native_handle对象        native_handle* h = native_handle_create(numFds, numInts);        memcpy(h->data,          fds,     numFds*sizeof(int));        memcpy(h->data + numFds, &buf[8], numInts*sizeof(int));        handle = h;    } else {        width = height = stride = format = usage = 0;        handle = NULL;    }    mOwner = ownHandle;    if (handle != 0) {//使用GraphicBufferMapper将服务端创建的图形buffer映射到当前进程地址空间        status_t err = mBufferMapper.registerBuffer(handle);        if (err != NO_ERROR) {            native_handle_close(handle);            native_handle_delete(const_cast<native_handle*>(handle));            handle = NULL;            return err;        }    }    return NO_ERROR;}

应用程序进程得到服务端进程返回来的GraphicBuffer对象后,还需要将该图形buffer映射到应用程序进程地址空间,有关图形缓存区的映射详细过程请查看Android图形缓冲区映射过程源码分析。

服务端处理

frameworks\native\libs\gui\ISurfaceTexture.cpp$BnSurfaceTexture

status_t BnSurfaceTexture::onTransact(    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags){    switch(code) {        case REQUEST_BUFFER: {            CHECK_INTERFACE(ISurfaceTexture, data, reply);            int bufferIdx   = data.readInt32();            sp<GraphicBuffer> buffer;//通过BufferQueue的requestBuffer函数来获得重新分配的图形buffer            int result = requestBuffer(bufferIdx, &buffer);            reply->writeInt32(buffer != 0);//将GraphicBuffer对象写回到应用程序进程,因此GraphicBuffer必须是Flattenable的子类            if (buffer != 0) {                reply->write(*buffer);            }            reply->writeInt32(result);            return NO_ERROR;        } break;    }    return BBinder::onTransact(code, data, reply, flags);}

frameworks\native\libs\gui\BufferQueue.cpp

status_t BufferQueue::requestBuffer(int slot, sp<GraphicBuffer>* buf) {    ATRACE_CALL();    ST_LOGV("requestBuffer: slot=%d", slot);    Mutex::Autolock lock(mMutex);    if (mAbandoned) {        ST_LOGE("requestBuffer: SurfaceTexture has been abandoned!");        return NO_INIT;    }    if (slot < 0 || mBufferCount <= slot) {        ST_LOGE("requestBuffer: slot index out of range [0, %d]: %d",                mBufferCount, slot);        return BAD_VALUE;    }    mSlots[slot].mRequestBufferCalled = true;    *buf = mSlots[slot].mGraphicBuffer;    return NO_ERROR;}

由于GraphicBuffer继承于Flattenable类,在Android 数据Parcel序列化过程源码分析中介绍了,将一个对象写入到Parcel中,需要使用flatten函数序列化该对象:

frameworks\native\libs\ui\GraphicBuffer.cpp

status_t GraphicBuffer::flatten(void* buffer, size_t size,        int fds[], size_t count) const{    size_t sizeNeeded = GraphicBuffer::getFlattenedSize();    if (size < sizeNeeded) return NO_MEMORY;    size_t fdCountNeeded = GraphicBuffer::getFdCount();    if (count < fdCountNeeded) return NO_MEMORY;    int* buf = static_cast<int*>(buffer);    buf[0] = 'GBFR';    buf[1] = width;    buf[2] = height;    buf[3] = stride;    buf[4] = format;    buf[5] = usage;    buf[6] = 0;    buf[7] = 0;    if (handle) {        buf[6] = handle->numFds;        buf[7] = handle->numInts;        native_handle_t const* const h = handle;        memcpy(fds,     h->data,             h->numFds*sizeof(int));        memcpy(&buf[8], h->data + h->numFds, h->numInts*sizeof(int));    }    return NO_ERROR;}

到此我们就介绍完了应用程序请求BufferQueue出列一个可用图形buffer的完整过程,那么应用程序什么时候发出这个请求呢?我们知道,在使用Surface绘图前,需要调用SurfaceHolder的lockCanvas()函数来锁定画布,然后才可以在画布上作图,应用程序就是在这个时候向SurfaceFlinger服务进程中的BufferQueue申请图形缓存区的。



应用程序释放图形buffer过程



当应用程序完成绘图后,需要调用SurfaceHolder的unlockCanvasAndPost(canvas)函数来释放画布,并请求SurfaceFlinger服务进程混合并显示该图像。


从以上时序图可以看到,应用程序完成绘图后,首先对当前这块图形buffer进行解锁,然后调用queueBuffer()函数请求SurfaceFlinger服务进程中的BufferQueue将当前已绘制好图形的buffer入列,也就是将当前buffer交还给BufferQueue管理。应用程序这个生产者在这块buffer中生产出了图像产品后,就需要将buffer中的图像产品放到BufferQueue销售市场中交易,SurfaceFlinger这个消费者得知市场上有新的图像产品出现,就立刻请求VSync信号,在下一次VSync到来时,SurfaceFlinger混合当前市场上的所有图像产品,并显示到屏幕上,从而完成图像产品的消费过程。

客户端请求

frameworks\native\libs\gui\SurfaceTextureClient.cpp 
int SurfaceTextureClient::queueBuffer(android_native_buffer_t* buffer) {    ATRACE_CALL();    ALOGV("SurfaceTextureClient::queueBuffer");    Mutex::Autolock lock(mMutex);    int64_t timestamp;    if (mTimestamp == NATIVE_WINDOW_TIMESTAMP_AUTO) {        timestamp = systemTime(SYSTEM_TIME_MONOTONIC);        ALOGV("SurfaceTextureClient::queueBuffer making up timestamp: %.2f ms",             timestamp / 1000000.f);    } else {        timestamp = mTimestamp;    }    int i = getSlotFromBufferLocked(buffer);    if (i < 0) {        return i;    }    // Make sure the crop rectangle is entirely inside the buffer.    Rect crop;    mCrop.intersect(Rect(buffer->width, buffer->height), &crop);    ISurfaceTexture::QueueBufferOutput output;    ISurfaceTexture::QueueBufferInput input(timestamp, crop, mScalingMode,            mTransform);    status_t err = mSurfaceTexture->queueBuffer(i, input, &output);    if (err != OK)  {        ALOGE("queueBuffer: error queuing buffer to SurfaceTexture, %d", err);    }    uint32_t numPendingBuffers = 0;    output.deflate(&mDefaultWidth, &mDefaultHeight, &mTransformHint,&numPendingBuffers);    mConsumerRunningBehind = (numPendingBuffers >= 2);    return err;}
frameworks\native\libs\gui\ ISurfaceTexture.cpp $BpSurfaceTexture
virtual status_t queueBuffer(int buf,const QueueBufferInput& input, QueueBufferOutput* output) {Parcel data, reply;data.writeInterfaceToken(ISurfaceTexture::getInterfaceDescriptor());data.writeInt32(buf);memcpy(data.writeInplace(sizeof(input)), &input, sizeof(input));status_t result = remote()->transact(QUEUE_BUFFER, data, &reply);if (result != NO_ERROR) {return result;}memcpy(output, reply.readInplace(sizeof(*output)), sizeof(*output));result = reply.readInt32();return result;}

服务端处理

frameworks\native\libs\gui\ ISurfaceTexture.cpp $BnSurfaceTexture
status_t BnSurfaceTexture::onTransact(    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags){    switch(code) {        case QUEUE_BUFFER: {            CHECK_INTERFACE(ISurfaceTexture, data, reply);            int buf = data.readInt32();            QueueBufferInput const* const input =                    reinterpret_cast<QueueBufferInput const *>(                            data.readInplace(sizeof(QueueBufferInput)));            QueueBufferOutput* const output =                    reinterpret_cast<QueueBufferOutput *>(                            reply->writeInplace(sizeof(QueueBufferOutput)));            status_t result = queueBuffer(buf, *input, output);            reply->writeInt32(result);            return NO_ERROR;        } break;    }    return BBinder::onTransact(code, data, reply, flags);}
frameworks\native\libs\gui\ BufferQueue.cpp
status_t BufferQueue::queueBuffer(int buf,        const QueueBufferInput& input, QueueBufferOutput* output) {    ATRACE_CALL();    ATRACE_BUFFER_INDEX(buf);    Rect crop;    uint32_t transform;    int scalingMode;    int64_t timestamp;    input.deflate(×tamp, &crop, &scalingMode, &transform);    ST_LOGV("queueBuffer: slot=%d time=%#llx crop=[%d,%d,%d,%d] tr=%#x "            "scale=%s",            buf, timestamp, crop.left, crop.top, crop.right, crop.bottom,            transform, scalingModeName(scalingMode));    sp<ConsumerListener> listener;    { // scope for the lock        Mutex::Autolock lock(mMutex);        if (mAbandoned) {            ST_LOGE("queueBuffer: SurfaceTexture has been abandoned!");            return NO_INIT;        }        if (buf < 0 || buf >= mBufferCount) {            ST_LOGE("queueBuffer: slot index out of range [0, %d]: %d",                    mBufferCount, buf);            return -EINVAL;        } else if (mSlots[buf].mBufferState != BufferSlot::DEQUEUED) {            ST_LOGE("queueBuffer: slot %d is not owned by the client "                    "(state=%d)", buf, mSlots[buf].mBufferState);            return -EINVAL;        } else if (!mSlots[buf].mRequestBufferCalled) {            ST_LOGE("queueBuffer: slot %d was enqueued without requesting a "                    "buffer", buf);            return -EINVAL;        }        const sp<GraphicBuffer>& graphicBuffer(mSlots[buf].mGraphicBuffer);        Rect bufferRect(graphicBuffer->getWidth(), graphicBuffer->getHeight());        Rect croppedCrop;        crop.intersect(bufferRect, &croppedCrop);        if (croppedCrop != crop) {            ST_LOGE("queueBuffer: crop rect is not contained within the "                    "buffer in slot %d", buf);            return -EINVAL;        }        if (mSynchronousMode) {            // In synchronous mode we queue all buffers in a FIFO.            mQueue.push_back(buf);            // Synchronous mode always signals that an additional frame should            // be consumed.            listener = mConsumerListener;        } else {            // In asynchronous mode we only keep the most recent buffer.            if (mQueue.empty()) {                mQueue.push_back(buf);                // Asynchronous mode only signals that a frame should be                // consumed if no previous frame was pending. If a frame were                // pending then the consumer would have already been notified.                listener = mConsumerListener;            } else {                Fifo::iterator front(mQueue.begin());                // buffer currently queued is freed                mSlots[*front].mBufferState = BufferSlot::FREE;                // and we record the new buffer index in the queued list                *front = buf;            }        }        mSlots[buf].mTimestamp = timestamp;        mSlots[buf].mCrop = crop;        mSlots[buf].mTransform = transform;        switch (scalingMode) {            case NATIVE_WINDOW_SCALING_MODE_FREEZE:            case NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW:            case NATIVE_WINDOW_SCALING_MODE_SCALE_CROP:                break;            default:                ST_LOGE("unknown scaling mode: %d (ignoring)", scalingMode);                scalingMode = mSlots[buf].mScalingMode;                break;        }        mSlots[buf].mBufferState = BufferSlot::QUEUED;        mSlots[buf].mScalingMode = scalingMode;        mFrameCounter++;        mSlots[buf].mFrameNumber = mFrameCounter;        mBufferHasBeenQueued = true;//通知有buffer入列        mDequeueCondition.broadcast();        output->inflate(mDefaultWidth, mDefaultHeight, mTransformHint,                mQueue.size());        ATRACE_INT(mConsumerName.string(), mQueue.size());    } // scope for the lock    //通知消费者buffer已入列    if (listener != 0) {        listener->onFrameAvailable();    }    return OK;}
在前面构造SurfaceTexture对象时,通过mBufferQueue->consumerConnect(proxy)将ProxyConsumerListener监听器保存到了BufferQueue的成员变量mConsumerListener中,同时又将SurfaceTexture对象保存到ProxyConsumerListener的成员变量mConsumerListener中。

frameworks\native\libs\gui\SurfaceTexture.cpp

SurfaceTexture::SurfaceTexture(GLuint tex, bool allowSynchronousMode,        GLenum texTarget, bool useFenceSync, const sp<BufferQueue> &bufferQueue) {    ...    wp<BufferQueue::ConsumerListener> listener;    sp<BufferQueue::ConsumerListener> proxy;    listener = static_cast<BufferQueue::ConsumerListener*>(this);    proxy = new BufferQueue::ProxyConsumerListener(listener);    status_t err = mBufferQueue->consumerConnect(proxy);    ....}

因此BufferQueue通过回调ProxyConsumerListener的onFrameAvailable()函数来通知消费者图形buffer已经准备就绪。
frameworks\native\libs\gui\ BufferQueue.cpp 

void BufferQueue::ProxyConsumerListener::onFrameAvailable() {    sp<BufferQueue::ConsumerListener> listener(mConsumerListener.promote());    if (listener != NULL) {        listener->onFrameAvailable();    }}
ProxyConsumerListener又回调SurfaceTexture的onFrameAvailable()函数来处理。

frameworks\native\libs\gui\ SurfaceTexture.cpp

void SurfaceTexture::onFrameAvailable() {    ST_LOGV("onFrameAvailable");    sp<FrameAvailableListener> listener;    { // scope for the lock        Mutex::Autolock lock(mMutex);        listener = mFrameAvailableListener;    }    if (listener != NULL) {        ST_LOGV("actually calling onFrameAvailable");        listener->onFrameAvailable();    }}
在Layer对象的onFirstRef()函数中,通过调用SurfaceTexture的setFrameAvailableListener函数来为SurfaceTexture设置buffer可用监器为FrameQueuedListene,其实就是将FrameQueuedListener对象保存到SurfaceTexture的成员变量mFrameAvailableListener中:
frameworks\native\services\surfaceflinger\ Layer.cpp 
mSurfaceTexture->setFrameAvailableListener(new FrameQueuedListener(this));
因此buffer可用通知最终又交给FrameQueuedListener来处理:
struct FrameQueuedListener : public SurfaceTexture::FrameAvailableListener {        FrameQueuedListener(Layer* layer) : mLayer(layer) { }private:wp<Layer> mLayer;virtual void onFrameAvailable() {sp<Layer> that(mLayer.promote());if (that != 0) {that->onFrameQueued();}}};
FrameQueuedListener的onFrameAvailable()函数又调用Layer类的onFrameQueued()来处理
void Layer::onFrameQueued() {    android_atomic_inc(&mQueuedFrames);    mFlinger->signalLayerUpdate();}
接着又通知SurfaceFlinger来更新Layer层。
frameworks\native\services\surfaceflinger\ SurfaceFlinger.cpp 
void SurfaceFlinger::signalLayerUpdate() {    mEventQueue.invalidate();}
该函数就是向SurfaceFlinger的事件队列中发送一个Vsync信号请求
frameworks\native\services\surfaceflinger\ MessageQueue.cpp 
void MessageQueue::invalidate() {    mEvents->requestNextVsync();}
应用程序入列一个图形buffer的整个过程如下:
1 0
原创粉丝点击