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的一個會話連接。
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);
}
}
首先,我們說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。
5. GraphicBuffer
在具體分析之前,我們先來看一個ANativeWindow的dequeueBuffer以及queueBuffer原型:
int (*dequeueBuffer)(struct ANativeWindow* window,
struct ANativeWindowBuffer** buffer);
int (*queueBuffer)(struct ANativeWindow* window,
struct ANativeWindowBuffer* buffer);
參考文章: