Android4.0 Surface機制分析


1. 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的一個會話連接。

image

      

2. 一些重要的類及關系介紹

   在開始介紹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接口完成的。

SurfaceFlinger::Client: ISurfaceComposerClient的服務端實現。

SurfaceComposerClient: 持有ISurfaceComposerClient的客戶端代理,在SurfaceComposerClient初次實例化時,通過ISurfaceComposer的createConnection()接口得到一個ISurfaceComposerClient的代理。同時,它也會管理Surface的狀態,通過ISurfaceComposer更新Surface狀態,狀態的具體保存涉及到一個相關類Composer。可以說,它是Surface跟服務端打交道一個非常重要的接口。

ISurfaceComposerClient:代表一個到SurfaceFinger的會話連接。

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的代碼:

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接口更新狀態。
    
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>,SurfaceControl是對ISurface及Surface的一層封裝,其需要注意的地方是:

  • 通過構造SurfaceControl時傳入ISurface,其持有ISurface接口
  • 它的getSurface方法可以構造一個Surface對象,並通過mSurfaceData持有Surface對象
  • 它可以通過SurfaceComposerClient去更改Surface的狀態

通過上面的分析我們得到了兩個Surface,sp<ISurface>, sp<Surface>,前者,我們知道是ISurface的本地代理,但是Surface是做什么的呢,我們下面將具體分析Surface。

4. 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,它的繼承關系如下:

image

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);
 
ANativeWindow我們前面說過了,ANativeWindowBuffer我們還沒有提及。我們本節講的GraphicBuffer正是一個ANativeWindowBuffer,從前面我們看到,GraphicBuffer是需要通過ISurfaceTexture接口在客戶端及服務端來傳遞的,所以其需要實現Flattenable接口。
GraphicBuffer實際的存儲空間其實是在ashmem上的,具體是gralloc模塊來完成分配的,然后映射到應用程序的進程地址空間。因為這部分涉及到底層設備部分,這里就不在分析。

 

參考文章:

http://www.linuxidc.com/Linux/2012-03/55898p7.htm


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM