java层面的Surface

   对于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的一个会话连接。

浅谈Android Surface机制_第1张图片

2 认识几个重要类

   在开始介绍cpp层面的Surface工作流程之前,我们先简要的介绍几个比较重要的类,因为Surface的机制抽象层级比较多,对基本类的功能有一个初步了解有助于我们更容易理解。

   首先,需要说明的是,java层的Surface与cpp层的Surface并不相同,他们之间存在着关系,但并不是同一个抽象. 而cpp层里Surface与ISurface又是不同的抽象,切忌混为一谈。

   我们知道,在android里大量的使用了CS模式,把一些功能做成服务Service,供各个客户端Client访问,而Client,Service都具有相同的接口,这样抽象掉了Client,Service之间的通信,让Client,Service各自独立,消除耦合。对于Surface部分来说,Android的framework里主要涉及到以下的几个接口:

浅谈Android Surface机制_第2张图片

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时需要用到它。

3 cpp层面的Surface

   从前面的图中可见,在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,这个类是非常重要的与服务端通讯的类,它的作用:

  • 通过在构造函数里使用ISurfaceComposer的createConnection接口,它获得ISurfaceComposerClient的本地代理
  • 通过得到的ISurfaceComposerClient创建或销毁ISurface
  • 通过它持有的Composer来记录Surface的状态,并在Composer里通过ISurfaceComposer接口更新状态。

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,SurfaceControl是对ISurface及Surface的一层封装,其需要注意的地方是:

  •  通过构造SurfaceControl时传入ISurface,其持有ISurface接口
  •  它的getSurface方法可以构造一个Surface对象,并通过mSurfaceData持有Surface对象
  •  它可以通过SurfaceComposerClient去更改Surface的状态

通过上面的分析我们得到了两个Surface,sp, sp,前者,我们知道是ISurface的本地代理,但是Surface是做什么的呢,我们下面将具体分析Surface。

Surface

     前面我们提到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);    }}
     可以看到,lockCanvas最终会调用到Surface的lock方法,而unlockCanvasAndPost最终调用到Surface的Surface的unlockAndPost,前面说到lockCanvas会返回一个Canvas供我们绘制使用,这个Canvas其实是利用lock得到的缓冲区来构建的。我们下面来分析。

首先,我们说Surface是一个ANativeWindow,它的继承关系如下:

浅谈Android Surface机制_第3张图片

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。

5 GraphicBuffer

      在具体分析之前,我们先来看一个ANativeWindow的dequeueBuffer以及queueBuffer原型:

int     (*dequeueBuffer)(struct ANativeWindow* window,                struct ANativeWindowBuffer** buffer);int     (*queueBuffer)(struct ANativeWindow* window,                struct ANativeWindowBuffer* buffer);
       GraphicBuffer是一个ANativeWindowBuffer,从前面我们看到,GraphicBuffer是需要通过ISurfaceTexture接口在客户端及服务端来传递的,所以其需要实现Flattenable接口。       GraphicBuffer实际的存储空间其实是在ashmem上的,具体是gralloc模块来完成分配的,然后映射到应用程序的进程地址空间。因为这部分涉及到底层设备部分,这里就不在分析。

6 总结

      Surface对应了一块屏幕缓冲区,每个window对应一个Surface,任何View都是画在Surface上的,传统的view共享一块屏幕缓冲区,所有的绘制必须在UI线程中进行。原链接要想深入理解系统机制《Android 4.0.3 显示系统深入理解Android中Surface和SurfaceView的一些理解和总结

更多相关文章

  1. Android实现全屏的方法
  2. [android]布局(容器)简介和使用方法
  3. android 动态控制状态栏显示和隐藏的方法实例
  4. Android文件系统的结构及目录用途、操作方法 整理
  5. Android:Error retrieving parent for item: No resource found
  6. Android 性能监控与分析方法
  7. Android 解决setRequestedOrientation之后手机屏幕的旋转不触发o
  8. 面试例题6:两种方法将图像显示在View上
  9. Android NDK报错(Eclipse)及解决方法

随机推荐

  1. Android(安卓)在应用中使用用户凭证(PIN码
  2. Android(安卓)原始资源文件的使用详解
  3. 7、从头学Android之TextView控件
  4. Android入门(1) 不一样的HelloWorld
  5. 面向 Android* Jelly Bean 4.2 的英特尔
  6. CMake学习
  7. Android(安卓)O/P/Q 版本如何预装 APK
  8. Android(安卓)电子书应用完全开源代码
  9. android的Handler
  10. MTP in Android