对于Surface我们的认识主要是android的类Surface, android的文档描述Surface是“Handle onto a raw buffer that is being managed by the screen compositor”,这个描述透漏出两个信息:首先,Surface是一个raw buffer(屏幕缓冲区)的句柄,通过它去管理一个raw buffer,其次,Surface本身是由screen compositor来管理的。但是raw buffer具体是什么,screen compositor又是什么,Surface是如何管理一个raw buffer,而它又是怎样被compositor来管理,后续我们会具体来分析。
Surface的具体使用上,我们通常并不直接去手动创建一个Surface,尽管可以这么做,通常,我们是通过SurfaceView,GLSurfaceView间接地去创建Surface,当然,更多的时候我们在使用Surface而不自知,在Andorid的窗口实现里,每一个Window其实都会对应一个Surface,而每个Activity都会持有一个Window,所以,我们通常在Activity里设置的view(通过setContentView),从java抽象上看其最终的绘制目标就是在Surface上。(Window以及view本身的结构也比较复杂,我会在后面的文章里再讨论这个部分。)
下面我们来看看Surface的接口都有什么,除了重要的构造函数外,比较重要的两个接口,lockCanvas, unlockCanvasAndPost. lockCanvas会返回一个Canvas给我们,我们可以使用这个Canvas来改变Surface的内容, 但是这个改变不会立刻生效,只有在我们调用了unlockCanvasAndPost之后,改变才会生效。
上面说了,通常我们并不手动去创建Surface,帮我们创建Surface的是WindowManagerService,它在帮我们创建Surface时,会生成一个SurfaceSession,然后将这个SurfaceSession作为参数来构造Surface。SurfaceSession,其代表的是与前面说的compositor的一个会话连接。
在开始介绍cpp层面的Surface工作流程之前,我们先简要的介绍几个比较重要的类,因为Surface的机制抽象层级比较多,对基本类的功能有一个初步了解有助于我们更容易理解。
首先,需要说明的是,java层的Surface与cpp层的Surface并不相同,他们之间存在着关系,但并不是同一个抽象. 而cpp层里Surface与ISurface又是不同的抽象,切忌混为一谈。
我们知道,在android里大量的使用了CS模式,把一些功能做成服务Service,供各个客户端Client访问,而Client,Service都具有相同的接口,这样抽象掉了Client,Service之间的通信,让Client,Service各自独立,消除耦合。对于Surface部分来说,Android的framework里主要涉及到以下的几个接口:
SurfaceFinger:这个是Surface服务端的总管家,它具体是ISurfaceComposer接口的服务端实现。
ComposerService:这个是为客户端取得ISurfaceComposer代理而提供的方便类。
ISurfaceComposer:通过这个接口可以访问到SurfaceFlinger,可以通过它建立一个会话,即ISurfaceComposerClient,也可以通过它去更新Surface的相关信息,这个是通过setTransactionState接口完成的,代表一个到SurfaceFinger的会话连接。
SurfaceFlinger::Client: ISurfaceComposerClient的服务端实现。
SurfaceComposerClient: 持有ISurfaceComposerClient的客户端代理,在SurfaceComposerClient初次实例化时,通过ISurfaceComposer的createConnection()接口得到一个ISurfaceComposerClient的代理。同时,它也会管理Surface的状态,通过ISurfaceComposer更新Surface状态,状态的具体保存涉及到一个相关类Composer。可以说,它是Surface跟服务端打交道一个非常重要的接口。
SurfaceControl:从字面上看,其作用是控制Surface。其实际作用是持有ISurface的代理及SurfaceComposerClient
ISurfaceTexture:其对应具体的buffer管理
SurfaceTextureClient: 持有ISurfaceTexture的本地代理,通过它可以访问到ISurfaceTexture的实现。同时,特别注意的是,它继承了ANativeWindow,而Surface类会继承SurfaceTextureClient. ANativeWindow代表的是本地窗口,在创建EGL的eglSurface时需要用到它。
从前面的图中可见,在Surface及SurfaceSession的构造过程中,都会调用到各自的init方法,而init的具体实现是在cpp层,具体对framework/base/core/jni/android_view_Surface.java.
我们来看看这两个init的代码:
SurfaceSession#init:
static void SurfaceSession_init(JNIEnv* env, jobject clazz){ sp<SurfaceComposerClient> client = new SurfaceComposerClient; client->incStrong(clazz); env->SetIntField(clazz, sso.client, (int)client.get()); }
SurfaceSession的init方法SurfaceSession_init主要是获取到一个SurfaceComposerClient,这个类是非常重要的与服务端通讯的类,它的作用:
Surface#init:
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* client = (SurfaceComposerClient*)env->GetIntField(session, sso.client); 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; } setSurfaceControl(env, clazz, surface); } 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::surface_data_t data; sp<ISurface> surface = mClient->createSurface(&data, name, display, w, h, format, flags); if (surface != 0) { result = new SurfaceControl(this, surface, data); } } return result; } 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_init主要是通过SurfaceComposerClient获取了一个sp
通过上面的分析我们得到了两个Surface,sp
前面我们提到SurfaceControl的getSurface方法会构造一个Surface对象,事实上,Surface是我们Android GUI系统的核心部分,我们来看看代码:
Surface::Surface(const sp<SurfaceControl>& surface) : SurfaceTextureClient(), mSurface(surface->mSurface), mIdentity(surface->mIdentity) { sp<ISurfaceTexture> st; if (mSurface != NULL) { st = mSurface->getSurfaceTexture(); } init(st); } void Surface::init(const sp<ISurfaceTexture>& surfaceTexture) { if (mSurface != NULL || surfaceTexture != NULL) { LOGE_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; } }
可以看到,在构造函数里,通过ISurface接口的getSurfaceTexture,我们得到一个ISurfaceTexture的本地代理,在init里我们保存了该代理,即SurfaceTextureClient将持有ISurfaceTextureClient。我们第一节里说java层面的Surface有两个接口,lockCanvas,unlockCanvasAndPost,我们来看看其底层实现是怎样的:
const sp<Surface>& surface(getSurface(env, clazz)); ........................................ status_t err = surface->lock(&info, &dirtyRegion); static void Surface_unlockCanvasAndPost( JNIEnv* env, jobject clazz, jobject argCanvas) { jobject canvas = env->GetObjectField(clazz, so.canvas); if (env->IsSameObject(canvas, argCanvas) == JNI_FALSE) { doThrowIAE(env); return; } const sp<Surface>& surface(getSurface(env, clazz)); if (!Surface::isValid(surface)) return; // detach the canvas from the surface SkCanvas* nativeCanvas = (SkCanvas*)env->GetIntField(canvas, no.native_canvas); int saveCount = env->GetIntField(clazz, so.saveCount); nativeCanvas->restoreToCount(saveCount); nativeCanvas->setBitmapDevice(SkBitmap()); env->SetIntField(clazz, so.saveCount, 0); // unlock surface status_t err = surface->unlockAndPost(); if (err < 0) { doThrowIAE(env); } }
首先,我们说Surface是一个ANativeWindow,它的继承关系如下:
ANativeWindow是一个EGL可以操作的窗口,其具体定义在system/core/include/system/window.h里,它的主要接口有dequeueBuffer,queueBuffer,lockBuffer等。
好了,搞清楚Surface是个什么东西,下面来看其lock及unlockAndPost方法:
status_t Surface::lock(SurfaceInfo* other, Region* inOutDirtyRegion) { ANativeWindow_Buffer outBuffer; ARect temp; ARect* inOutDirtyBounds = NULL; if (inOutDirtyRegion) { temp = inOutDirtyRegion->getBounds(); inOutDirtyBounds = &temp; } status_t err = SurfaceTextureClient::lock(&outBuffer, inOutDirtyBounds); if (err == NO_ERROR) { other->w = uint32_t(outBuffer.width); other->h = uint32_t(outBuffer.height); other->s = uint32_t(outBuffer.stride); other->usage = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN; other->format = uint32_t(outBuffer.format); other->bits = outBuffer.bits; } if (inOutDirtyRegion) { inOutDirtyRegion->set( static_cast<Rect const&>(temp) ); } return err; } status_t Surface::unlockAndPost() { return SurfaceTextureClient::unlockAndPost(); }
这两个方法都会调用到SurfaceTextureClient里的相应方法,代码这里就不贴了,lock的实现主要是dequeueBuffer出一个GraphicBuffer,而unlockAndPost主要是将这个GraphicBuffer入队queueBuffer。我们来看看SurfaceTextureClient的dequeueBuffer及queueBuffer实现:
int SurfaceTextureClient::dequeueBuffer(android_native_buffer_t** buffer) { LOGV("SurfaceTextureClient::dequeueBuffer"); Mutex::Autolock lock(mMutex); int buf = -1; status_t result = mSurfaceTexture->dequeueBuffer(&buf, mReqWidth, mReqHeight, mReqFormat, mReqUsage); if (result < 0) { LOGV("dequeueBuffer: ISurfaceTexture::dequeueBuffer(%d, %d, %d, %d)" "failed: %d", mReqWidth, mReqHeight, mReqFormat, mReqUsage, result); return result; } sp<GraphicBuffer>& gbuf(mSlots[buf]); if (result & ISurfaceTexture::RELEASE_ALL_BUFFERS) { freeAllBuffers(); } if ((result & ISurfaceTexture::BUFFER_NEEDS_REALLOCATION) || gbuf == 0) { result = mSurfaceTexture->requestBuffer(buf, &gbuf); if (result != NO_ERROR) { LOGE("dequeueBuffer: ISurfaceTexture::requestBuffer failed: %d", result); return result; } } *buffer = gbuf.get(); return OK; } int SurfaceTextureClient::queueBuffer(android_native_buffer_t* buffer) { LOGV("SurfaceTextureClient::queueBuffer"); Mutex::Autolock lock(mMutex); int64_t timestamp; if (mTimestamp == NATIVE_WINDOW_TIMESTAMP_AUTO) { timestamp = systemTime(SYSTEM_TIME_MONOTONIC); LOGV("SurfaceTextureClient::queueBuffer making up timestamp: %.2f ms", timestamp / 1000000.f); } else { timestamp = mTimestamp; } int i = getSlotFromBufferLocked(buffer); if (i < 0) { return i; } status_t err = mSurfaceTexture->queueBuffer(i, timestamp, &mDefaultWidth, &mDefaultHeight, &mTransformHint); if (err != OK) { LOGE("queueBuffer: error queuing buffer to SurfaceTexture, %d", err); } return err; }
我们可以看到,SurfaceTexture会利用持有的ISurfaceTextureClient接口去得到或入队GraphicBuffer。我们前面也说过,Surface是一个ANativeWindow,而ANatvieWidnow是一个EGL可以操作的窗口,所以除了在java层显式调用lockCanvas方法可以操作Surface外,openGL ES通过EGL也能操作Surface。
在具体分析之前,我们先来看一个ANativeWindow的dequeueBuffer以及queueBuffer原型:
int (*dequeueBuffer)(struct ANativeWindow* window, struct ANativeWindowBuffer** buffer); int (*queueBuffer)(struct ANativeWindow* window, struct ANativeWindowBuffer* buffer);