編輯:關於Android編程
Android應用程序在請求SurfaceFlinger服務渲染一個Surface之前,首先要將該Surface作為當前活動的繪圖上下文,以便可以使用OpengGL庫或者其它庫的API來在上面繪制UI,我們以Android系統的開機動畫應用程序bootanim為例,來說明這個問題。
從前面Android應用程序請求SurfaceFlinger服務創建Surface的過程分析一文可以知道,Android系統的開機動畫應用程序bootanim是在BootAnimation類的成員函數readyToRun中請求SurfaceFlinger服務創建Surface的。這個Surface創建完成之後,就會被設置為當前活動的繪圖上下文,如下所示:
[cpp]
status_t BootAnimation::readyToRun() {
......
// create the native surface
sp<SurfaceControl> control = session()->createSurface(
getpid(), 0, dinfo.w, dinfo.h, PIXEL_FORMAT_RGB_565);
......
sp<Surface> s = control->getSurface();
......
// initialize opengl and egl
const EGLint attribs[] = {
EGL_DEPTH_SIZE, 0,
EGL_NONE
};
......
EGLConfig config;
EGLSurface surface;
EGLContext context;
EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
eglInitialize(display, 0, 0);
EGLUtils::selectConfigForNativeWindow(display, attribs, s.get(), &config);
surface = eglCreateWindowSurface(display, config, s.get(), NULL);
context = eglCreateContext(display, config, NULL, NULL);
......
if (eglMakeCurrent(display, surface, surface, context) == EGL_FALSE)
return NO_INIT;
......
}
BootAnimation類的成員函數readyToRun首先調用eglGetDisplay和eglInitialize函數來獲得和初始化OpengGL庫的默認顯示屏,接著再調用EGLUtils::selectConfigForNativeWindow函數來獲得前面所創建的一個Surface(由sp<Surface>指針s來描述)的配置信息。有了這些信息之後,接下來就分別調用eglCreateWindowSurface和eglCreateContext函數來創建一個適用於OpenGL庫使用的繪圖表面surface以及繪圖上下文context,最後就可以調用eglMakeCurrent函數來將繪圖表面surface和繪圖上下文context設置為當前活動的繪圖表面和繪圖上下文,這就相當於是將前面請求SurfaceFlinger服務創建的一個Surface設置為當前活動的緩圖上下文了。
完成了上述操作之後,Android系統的開機動畫應用程序bootanim就可以繼續使用OpengGL庫的其它API來在當前活動的Surface上繪制UI了,不過,通過前面Android應用程序請求SurfaceFlinger服務創建Surface的過程分析一文的學習,我們知道,此時SurfaceFlinger服務為Android應用程序創建的Surface只有UI元數據緩沖區,而沒有UI數據緩沖區,即還沒有圖形緩沖區,換句來說,就是還沒有可以用來繪制UI的載體。那麼,這些用來繪制UI的圖形緩沖區是什麼時候創建的呢?
從前面Android應用程序與SurfaceFlinger服務的關系概述和學習計劃一文可以知道,每一個Surface都有一個對應的UI元數據緩沖區堆棧,這個UI元數據緩沖區堆棧是使用一個SharedBufferStack來描述的,
每一個UI元數據緩沖區都可能對應有一個UI數據緩沖區,這個UI數據緩沖區又可以稱為圖形緩沖區,它使用一個GraphicBuffer對象來描述。注意,一個UI元數據緩沖區只有第一次被使用時,Android應用程序才會為它創建一個圖形緩沖區,因此,我們才說每一個UI元數據緩沖區都可能對應有一個UI數據緩沖區。例如,在圖1中,目前只使到了編號為1和2的UI元數據緩沖區,因此,只有它們才有對應的圖形緩沖區,而編號為3、4和5的UI元數據緩沖區沒有。
Android應用程序渲染一個Surface的過程大致如下所示:
1. 從UI元數據緩沖區堆棧中得到一個空閒的UI元數據緩沖區;
2. 請求SurfaceFlinger服務為這個空閒的UI元數據緩沖區分配一個圖形緩沖區;
3. 在圖形緩沖區上面繪制好UI之後,即填充好UI數據之後,就將前面得到的空閒UI元數據緩沖區添加到UI元數據緩沖區堆棧中的待渲染隊列中去;
4. 請求SurfaceFlinger服務渲染前面已經准備好了圖形緩沖區的Surface;
5. SurfaceFlinger服務從即將要渲染的Surface的UI元數據緩沖區堆棧的待渲染隊列中找到待渲染的UI元數據緩沖區;
6. SurfaceFlinger服務得到了待渲染的UI元數據緩沖區之後,接著再找到在前面第2步為它所分配的圖形緩沖區,最後就可以將這個圖形緩沖區渲染到設備顯示屏上去。
這個過程的第1步、第3步和第5步涉到UI元數據緩沖區堆棧的一些出入棧操作,為了方便後面描述Android應用程序請求SurfaceFlinger服務渲染Surface的過程,我們首先介紹一下UI元數據緩沖區堆棧的一些出入棧操作。
在前面Android應用程序請求SurfaceFlinger服務創建Surface的過程分析一文中,我們分析了用來描述UI元數據緩沖區堆棧的SharedBufferServer和SharedBufferClient類的父類SharedBufferBase,它有一個成員函數waitForCondition,用來等待一個條件得到滿足,它定義在文件frameworks/base/include/private/surfaceflinger/SharedBufferStack.h中,如下所示:
[cpp]
class SharedBufferBase
{
......
protected:
......
struct ConditionBase {
SharedBufferStack& stack;
inline ConditionBase(SharedBufferBase* sbc)
: stack(*sbc->mSharedStack) { }
virtual ~ConditionBase() { };
virtual bool operator()() const = 0;
virtual const char* name() const = 0;
};
status_t waitForCondition(const ConditionBase& condition);
......
};
SharedBufferBase類的成員函數waitForCondition只有一個參數condition,它的類型為ConditionBase,用來描述一個需要等待滿足的條件。ConditionBase類是一個抽象類,我們需要以它來為父類,來實現一個自定義的條件,並且重寫操作符號()和成員函數name。接下來,我們分析SharedBufferBase類的成員函數waitForCondition的實現,接著再分析ConditionBase類的一個子類的實現。
SharedBufferBase類的成員函數waitForCondition實現在文件frameworks/base/libs/surfaceflinger_client/SharedBufferStack.cpp文件中,如下所示:
[cpp]
status_t SharedBufferBase::waitForCondition(const ConditionBase& condition)
{
const SharedBufferStack& stack( *mSharedStack );
SharedClient& client( *mSharedClient );
const nsecs_t TIMEOUT = s2ns(1);
const int identity = mIdentity;
Mutex::Autolock _l(client.lock);
while ((condition()==false) &&
(stack.identity == identity) &&
(stack.status == NO_ERROR))
{
status_t err = client.cv.waitRelative(client.lock, TIMEOUT);
// handle errors and timeouts
if (CC_UNLIKELY(err != NO_ERROR)) {
if (err == TIMED_OUT) {
if (condition()) {
LOGE("waitForCondition(%s) timed out (identity=%d), "
"but condition is true! We recovered but it "
"shouldn't happen." , condition.name(), stack.identity);
break;
} else {
LOGW("waitForCondition(%s) timed out "
"(identity=%d, status=%d). "
"CPU may be pegged. trying again.", condition.name(),
stack.identity, stack.status);
}
} else {
LOGE("waitForCondition(%s) error (%s) ",
condition.name(), strerror(-err));
return err;
}
}
}
return (stack.identity != mIdentity) ? status_t(BAD_INDEX) : stack.status;
}
SharedBufferBase類的成員變量mSharedStack指向了一個SharedBufferStack對象,即一個UI元數據緩沖區堆棧,另外一個成員變量mSharedClient指向了當前應用程序進程的一個SharedClient單例。
SharedClient類有一個類型為Condition的成員變量cv,用來描述一個條件變量,同時,SharedClient類還有一個類型為Mutex的成員變量lock,用來描述一個互斥鎖。通過調用一個Condition對象的成員函數waitRelative,就可以在指定的時間內等待一個互斥鎖變為可用。
SharedBufferBase類的成員函數waitForCondition中的while循環的作用是循環等待一個UI元數據緩沖區堆棧滿足某一個條件,這個條件是通過參數condition來描述的。當調用參數condition所描述的一個CondtitionBase對象的重載操作符號()的返回值等於true的時候,就表示所要等待的條件得到滿足了,這時候函數就會停止執行中間的while循環語句。另一方面,當調用參數condition所描述的一個CondtitionBase對象的重載操作符號()的返回值等於flase的時候,就表示所要等待的條件還沒有得到滿足,這時候函數就會繼續執中間的while循環,直到所要等待的條件得到滿足為止。等待的操作是通過調用下面這個語句來完成的:
[cpp]
status_t err = client.cv.waitRelative(client.lock, TIMEOUT);
即調用當前應用程序進程的SharedClient單例client的成員變量cv所描述的一個條件變量的成員函數waitRelative來完成,並且指定要等待的互斥鎖為當前應用程序進程的SharedClient單例client的成員變量lock所描述的一個互斥鎖,以及指定等待的時間為TIMEOUT,即1秒。如果在1秒內,當前應用程序進程的SharedClient單例client的成員變量lock所描述的一個互斥鎖還是不可用,那麼上述等待操作就會超時,然後導致重新執行外層的while循環,否則的話,等待操作就完成了。
在SharedBufferClient類中,定義了一個ConditionBase子類DequeueCondition,用來描述一個UI元數據緩沖區堆棧是否有空閒的緩沖區可以出棧,它定義在文件frameworks/base/include/private/surfaceflinger/SharedBufferStack.h中, [cpp]
class SharedBufferClient : public SharedBufferBase
{
......
private:
......
struct DequeueCondition : public ConditionBase {
inline DequeueCondition(SharedBufferClient* sbc);
inline bool operator()() const;
inline const char* name() const { return "DequeueCondition"; }
};
......
};
一個UI元數據緩沖區堆棧是否有空閒的緩沖區可以出棧是由DequeueCondition類的重載操作符號()來決定的,它實現在文件frameworks/base/libs/surfaceflinger_client/SharedBufferStack.cpp文件中,如下所示:
[cpp]
bool SharedBufferClient::DequeueCondition::operator()() const {
return stack.available > 0;
}
DequeueCondition類的成員變量stack是從父類ConditionBase繼承下來的,它指向了一個SharedBufferStack對象,即用來描述一個UI元數據緩沖區堆棧。從前面Android應用程序與SurfaceFlinger服務的關系概述和學習計劃一文可以知道,當一個SharedBufferStack對象的成員變量available的值大於0的時候,就說明它所描述的UI元數據緩沖區堆棧有空閒的緩沖區可以使用,因此,這時候DequeueCondition類的重載操作符號()的返回值就等於true,表示一個UI元數據緩沖區堆棧有空閒的緩沖區可以出棧。
SharedBufferBase類還有一個成員函數updateCondition,用來操作一個UI元數據緩沖區堆棧,例如,執行一個UI元數據緩沖區的出入棧操作。這個成員函數定義和實現在文件rameworks/base/include/private/surfaceflinger/SharedBufferStack.h中,如下所示:
[cpp]
class SharedBufferBase
{
......
protected:
......
struct UpdateBase {
SharedBufferStack& stack;
inline UpdateBase(SharedBufferBase* sbb)
: stack(*sbb->mSharedStack) { }
};
template <typename T>
status_t updateCondition(T update);
};
template <typename T>
status_t SharedBufferBase::updateCondition(T update) {
SharedClient& client( *mSharedClient );
Mutex::Autolock _l(client.lock);
ssize_t result = update();
client.cv.broadcast();
return result;
}
SharedBufferBase類的成員函數updateCondition是一個模板函數,它過調用參數T的重載操作符號()來實現一個具體的UI元數據緩沖區堆棧操作。這個參數T必須要從基類UpdateBase繼承下來,並且重載操作符號()。
SharedBufferBase類的成員函數updateCondition執行完成一個UI元數據緩沖區堆棧操作之後,還會調用當前應用進程的SharedClient單例client的成員變量cv所描述的一個條件變量的成員函數broadcast,用來喚醒那些在當前應用進程的SharedClient單例client的成員變量lock所描述的一個互斥鎖上等待的其它線程,以便它們可以繼續執行自己的操作,這樣,SharedBufferBase類的成員函數updateCondition就可以和前面介紹的成員函數waitCondition對應起來。
接下來,我們就分別分析UpdateBase的三個子類QueueUpdate、DequeueUpdate和RetireUpdate。QueueUpdate和DequeueUpdate兩個子類是Android應用程序這一側使用的,前者用來向一個UI元數據緩沖區堆棧的待渲染隊列增加一個緩沖區,而後者用來從一個UI元數據緩沖區堆棧出棧一個空閒的緩沖區。RetireUpdate類是在SurfaceFlinger服務這一側使用的,用來從一個UI元數據緩沖區堆棧的待渲染隊列出棧一個緩沖區,以便可以將與它所對應的圖形緩沖區渲染到設備顯示屏去。
QueueUpdate類定義在文件frameworks/base/include/private/surfaceflinger/SharedBufferStack.h中,如下所示:
[cpp]
class SharedBufferClient : public SharedBufferBase
{
......
private:
......
struct QueueUpdate : public UpdateBase {
inline QueueUpdate(SharedBufferBase* sbb);
inline ssize_t operator()();
};
......
};
它的重載操作符號()實現在文件frameworks/base/libs/surfaceflinger_client/SharedBufferStack.cpp文件中,如下所示:
[cpp]
ssize_t SharedBufferClient::QueueUpdate::operator()() {
android_atomic_inc(&stack.queued);
return NO_ERROR;
}
QueueUpdate類的成員變量stack是從父類UpdateBase繼承下來的,它指向了一個SharedBufferStack對象,用來描述當前要操作的UI元數據緩沖區堆棧。從前面的圖1可以知道,當我們將一個SharedBufferStack對象的成員變量queued的值增加1的時候,就表示這個SharedBufferStack對象所描述的UI元數據緩沖區堆棧的待渲染隊列的大小增加了1。不過,在執行這個操作之前,我們還需要將用來這個待渲染隊列頭queue_head往前移動一個位置。後面在分析Surface的渲染過程時,我們再詳細分析。
DequeueUpdate類定義在文件frameworks/base/include/private/surfaceflinger/SharedBufferStack.h中,如下所示:
[cpp]
class SharedBufferClient : public SharedBufferBase
{
......
private:
......
struct DequeueUpdate : public UpdateBase {
inline DequeueUpdate(SharedBufferBase* sbb);
inline ssize_t operator()();
};
......
};
它的重載操作符號()實現在文件frameworks/base/libs/surfaceflinger_client/SharedBufferStack.cpp文件中,如下所示:
[cpp]
ssize_t SharedBufferClient::DequeueUpdate::operator()() {
if (android_atomic_dec(&stack.available) == 0) {
LOGW("dequeue probably called from multiple threads!");
}
return NO_ERROR;
}
DequeueUpdate類的成員變量stack是從父類UpdateBase繼承下來的,它指向了一個SharedBufferStack對象,用來描述當前要操作的UI元數據緩沖區堆棧。從前面的圖1可以知道,當我們將一個SharedBufferStack對象的成員變量available的值減少1的時候,就表示這個SharedBufferStack對象所描述的UI元數據緩沖區堆棧的空閒緩沖區的大小就減少了1。不過,在執行這個操作之前,我們還需要將用來這個UI元數據緩沖區堆棧尾tail往前移動一個位置。後面在分析Surface的渲染過程時,我們再詳細分析。
RetireUpdate類定義在文件frameworks/base/include/private/surfaceflinger/SharedBufferStack.h中,如下所示:
[cpp]
class SharedBufferServer
: public SharedBufferBase,
public LightRefBase<SharedBufferServer>
{
......
private:
......
struct RetireUpdate : public UpdateBase {
const int numBuffers;
inline RetireUpdate(SharedBufferBase* sbb, int numBuffers);
inline ssize_t operator()();
};
......
};
RetireUpdate類的成員變量numBuffers用來描述一個UI元數據緩沖區堆棧的大小,它的重載操作符號()實現在文件frameworks/base/libs/surfaceflinger_client/SharedBufferStack.cpp文件中,如下所示:
[cpp]
ssize_t SharedBufferServer::RetireUpdate::operator()() {
int32_t head = stack.head;
if (uint32_t(head) >= SharedBufferStack::NUM_BUFFER_MAX)
return BAD_VALUE;
// Decrement the number of queued buffers
int32_t queued;
do {
queued = stack.queued;
if (queued == 0) {
return NOT_ENOUGH_DATA;
}
} while (android_atomic_cmpxchg(queued, queued-1, &stack.queued));
// lock the buffer before advancing head, which automatically unlocks
// the buffer we preventively locked upon entering this function
head = (head + 1) % numBuffers;
const int8_t headBuf = stack.index[head];
stack.headBuf = headBuf;
// head is only modified here, so we don't need to use cmpxchg
android_atomic_write(head, &stack.head);
// now that head has moved, we can increment the number of available buffers
android_atomic_inc(&stack.available);
return head;
}
在前面Android應用程序與SurfaceFlinger服務的關系概述和學習計劃一文中提到,在圖1所描述的UI元數據緩沖區堆棧中,位於(head, queue_head]裡面的緩沖區組成了一個待渲染隊列,而SurfaceFlinger服務就是按照head到queue_head的順序來渲染這個隊列中的緩沖區的。理解了這一點之後,RetireUpdate類的重載操作符號()的實現就好理解了。
首先,函數使用一個do...while循環來將queued的值減少1,即將待渲染隊列的大小減少1。當然,如果這個待渲染隊列的大小本來就等於0,那麼函數就什麼也不做就返回了。接著,函數將待渲染隊列的頭部head向前移一個位置。移動後的得到的位置所對應的緩沖區就是接下來要渲染的,因此,函數最後要將它返回給調用者。函數在將要渲染的緩沖區的位置返回給調用者之前,還會將當前正在操作的UI元數據緩沖區的空閒緩沖區的個數available增加1。
至此,DequeueCondition、QueueUpdate、DequeueUpdate和RetireUpdate這四個輔助類就介紹完成了,接下來,我們就可以繼續分析Android應用程序請求SurfaceFlinger服務渲染Surface的過程了。在分析的過程中,我們還會繼續看到這四個輔助類的使用方法。
在前面Android應用程序請求SurfaceFlinger服務創建Surface的過程分析一文的Step 16中,我們將在Android應用程序這一側所創建的一個Surface的父類ANativeWindow的OpenGL回調函數dequeueBuffer和queueBuffer分別設置為Surface類的靜態成員函數dequeueBuffer和queueBuffer。OpenGL在繪圖之前,就首先會調用Surface類的靜態成員函數dequeueBuffer來獲得一個空閒的UI元數據緩沖區,接著請求SurfaceFlinger服務為這個UI元數據緩沖區分配一個圖形緩沖區。有了圖形緩沖區之後,OpengGL庫就可以往裡面填入UI數據。在往圖形緩沖區填入UI數據的同時,OpenGL庫也會往前面獲得的UI元數據緩沖區填入當前正在操作的Surface的裁剪區域、紋理坐標和旋轉方向等信息。再接下來,OpenGL庫就會調用Surface類的靜態成員函數queueBuffer來將前面已經填好了數據的UI元數據緩沖區添加到當前正在操作的Surface的UI元數緩沖區堆棧的待渲染隊列中。最後,Android應用程序就會請求SurfaceFlinger服務將當前正在操作的Surface的UI數據渲染到設備顯示屏去。
接下來,我們就首先分析Surface類的靜態成員函數dequeueBuffer的實現,接著再分析Surface類的靜態成員函數queueBuffer的實現,最後分析SurfaceFlinger服務渲染Surface的圖形緩沖區的過程。
Surface類的靜態成員函數dequeueBuffer獲得空閒UI元數據緩沖區,以及請求SurfaceFlinger服務為這個空閒UI元數據緩沖區分配圖形緩沖區的過程如圖2所示:
圖2 分配空閒UI元數據緩沖區及其圖形緩沖區的過程
這個過程一共分為12個步驟,接下來我們就詳細分析每一個步驟。
Step 1. Surface.dequeueBuffer
[cpp]
int Surface::dequeueBuffer(ANativeWindow* window,
android_native_buffer_t** buffer) {
Surface* self = getSelf(window);
return self->dequeueBuffer(buffer);
}
這個函數定義在文件frameworks/base/libs/surfaceflinger_client/Surface.cpp中。
參數window雖然是一個ANativeWindow指針,但是它實際上指向的是一個Surface對象,因此,函數首先調用另外一個靜態成員函數getSelf來將它轉換為一個Surface對象self,接著再調用這個Surface對象self的成員函數dequeueBuffer來分配一個空閒UI元數據緩沖區和一個圖形緩沖區,其中,分配的圖形緩沖區就保存在輸出參數buffer中。
Surface類的非靜態成員函數dequeueBuffer的實現如下所示:
[cpp]
int Surface::dequeueBuffer(android_native_buffer_t** buffer)
{
status_t err = validate();
if (err != NO_ERROR)
return err;
......
ssize_t bufIdx = mSharedBufferClient->dequeue();
......
if (bufIdx < 0) {
......
return bufIdx;
}
// grow the buffer array if needed
const size_t size = mBuffers.size();
const size_t needed = bufIdx+1;
if (size < needed) {
mBuffers.insertAt(size, needed-size);
}
uint32_t w, h, format, usage;
if (needNewBuffer(bufIdx, &w, &h, &format, &usage)) {
err = getBufferLocked(bufIdx, w, h, format, usage);
......
if (err == NO_ERROR) {
// reset the width/height with the what we get from the buffer
const sp<GraphicBuffer>& backBuffer(mBuffers[bufIdx]);
mWidth = uint32_t(backBuffer->width);
mHeight = uint32_t(backBuffer->height);
}
}
// if we still don't have a buffer here, we probably ran out of memory
const sp<GraphicBuffer>& backBuffer(mBuffers[bufIdx]);
if (!err && backBuffer==0) {
err = NO_MEMORY;
}
if (err == NO_ERROR) {
mDirtyRegion.set(backBuffer->width, backBuffer->height);
*buffer = backBuffer.get();
} else {
mSharedBufferClient->undoDequeue(bufIdx);
}
return err;
}
這個函數定義在文件frameworks/base/libs/surfaceflinger_client/Surface.cpp中。
函數首先調用Surface類的成員變量mSharedBufferClient所指向的一個SharedBufferClient對象的成員函數dequeue來從UI元數據緩沖區堆棧中獲得一個空閒的緩沖區。獲得的空閒緩沖區使用一個編號來描述,這個編號保存在變量bufIdx中。後面我們再分析SharedBufferClient類的成員函數dequeue的實現。
獲最一個空閒UI元數據緩沖區之後,函數接下來判斷該緩沖區的編號是否大於Surface類的成員變量mBuffers所描述的一個GraphicBuffer向量的大小。如果大於,那麼就需要擴充這個向量的大小,以便後面可以用來保存與該緩沖區對應的一個GraphicBuffer,即一個圖形緩沖區。
函數再接下來調用Surface類的另外一個成員函數needNewBuffer來判斷之前是否已經為編號為bufIdx的UI元數據緩沖區分配過圖形緩沖區了,它的實現如下所示:
[cpp]
bool Surface::needNewBuffer(int bufIdx,
uint32_t *pWidth, uint32_t *pHeight,
uint32_t *pFormat, uint32_t *pUsage) const
{
Mutex::Autolock _l(mSurfaceLock);
// Always call needNewBuffer(), since it clears the needed buffers flags
bool needNewBuffer = mSharedBufferClient->needNewBuffer(bufIdx);
bool validBuffer = mBufferInfo.validateBuffer(mBuffers[bufIdx]);
bool newNeewBuffer = needNewBuffer || !validBuffer;
if (newNeewBuffer) {
mBufferInfo.get(pWidth, pHeight, pFormat, pUsage);
}
return newNeewBuffer;
}
這個函數定義在文件frameworks/base/libs/surfaceflinger_client/Surface.cpp中。
由於UI元數據緩沖區堆棧中的緩沖區是循環使用的。當一個UI元數據緩沖區第一次被使用的時候,應用程序就會請求SurfaceFlinger服務為它分配一個圖形緩沖區。這個圖形緩沖區使用完成之後,就會被應用程序緩存起來,以便後面可以繼續使用。但是這個圖形緩沖區可能會被得無效,例如,與它對應的Surface的大小和用途等信息發生改變之後,該圖形緩沖區就會變得無效了,因為它在分配的時候,是按照既定的大小和用途來分配的。
這個函數首先調用Surface類的成員變量mSharedBufferClient所指向的一個SharedBufferClient對象的成員函數needBuffer來驗證編號為bufIdx的UI元數據緩沖區所對應的圖形緩沖區信息是否發生了變化。如果發生了變化,那麼變量needNewBuffer的值就會等於true,表示要重新為編號為bufIdx的UI元數據緩沖區分配新的圖形緩沖區。
SharedBufferClient類的成員函數needBuffer的實現如下所示:
[cpp]
bool SharedBufferClient::needNewBuffer(int buf) const
{
SharedBufferStack& stack( *mSharedStack );
const uint32_t mask = 1<<(31-buf);
return (android_atomic_and(~mask, &stack.reallocMask) & mask) != 0;
}
這個函數定義在文件frameworks/base/libs/surfaceflinger_client/SharedBufferStack.cpp中。
SharedBufferClient類的成員變量mSharedStack的類型為SharedBufferStack,它是從父類SharedBufferBase繼承下來的,用來描述一個UI元數據緩沖區堆棧。SharedBufferStack類的成員變量reallocMask是一個掩碼,如果它的某一位的值等於1,那麼這一位所描述的一個UI元數據緩沖區所對應的圖形緩沖區就是無效的。這一般是由SurfaceFlinger服務來設備的。當SurfaceFlinger服務發現一個Surface的元信息發生變化時,就會通過一個SharedBufferServer對象來設置這個Surface的UI元數據緩沖區堆棧的成員變量reallocMask的相應位等於1,以便應用程序在使用到該位所描述的UI元數據緩沖區時,請求分配一個新的圖形緩沖區。例如,假設SharedBufferStack類的成員變量reallocMask的值等於01000000 00000000 00000000 00000000,那麼就表示編號為1的UI元數據緩沖區對應的圖形緩沖區需要重新分配。
回到Surface類的成員函數needNewBuffer中,接下來該函數繼續驗證編號為bufIdx對應的UI元數據緩沖區在成員變量mBuffers中所對應的圖形緩沖區是否還有效,即圖形緩沖區mBuffers[bufIdx]是否還有效,這是通過調用Surface類的成員變量mBufferInfo所描述的一個BufferInfo對象的成員函數validateBuffer來驗證的。如果沒有效,那麼變量validBuffer的值就會等於false,表示要重新為編號為bufIdx的UI元數據緩沖區分配新的圖形緩沖區。
BufferInfo類的成員函數validateBuffer的實現如下所示:
[cpp]
bool Surface::BufferInfo::validateBuffer(const sp<GraphicBuffer>& buffer) const {
// make sure we AT LEAST have the usage flags we want
if (mDirty || buffer==0 ||
((buffer->usage & mUsage) != mUsage)) {
mDirty = 0;
return false;
}
return true;
}
這個函數定義在文件frameworks/base/libs/surfaceflinger_client/Surface.cpp中。
BufferInfo類的成員變量mDirty用來描述一個Surface的元數據是否發了變化,例如,它的大小、像素格式等是發生了變化。如果發生了變化,那麼它的值就會不等於0。
參數buffer是一個類型為GraphicBuffer的強指針,如果它的值等於null,那麼就說明它所描述的圖形緩沖是無效的。
如果參數buffer所指向的圖形緩沖區是有效的,但是它的用途發生了變化,即它的用途與它所對應的Surface的用途已經不一致了。
上述三種情況都說明需要為編號為bufIdx的UI元數據緩沖分配新的圖形緩沖區,因此,這個函數的返回值就會等於false。
回到Surface類的成員函數needNewBuffer中,接下來該函數通過變量needNewBuffer和變量validBuffer的值就可以知道是否需要為編號為bufIdx的UI元數據緩沖分配新的圖形緩沖區了。假設應用程序是第一次使用編號為bufIdx的UI元數據緩沖,那麼變量validBuffer的值就一定會等於false,因此,Surface類的成員函數needNewBuffer的返回值就會等於true,表示要為編號為bufIdx的UI元數據緩沖分配新的圖形緩沖區。該函數在返回之前,還會通過Surface類的成員變量mBufferInfo所描述的一個BufferInfo對象來得到當前正在繪制的Surface的寬度、高度、像素格式以及用途,分別保存在輸出參數pWidth、pHeight、pFormat和pUsage,以便應用程序接下來可以使用這些信息來請求SurfaceFlinger服務分配一個新的圖形緩沖區。
回到Surface類的非靜態成員函數dequeueBuffer中,該函數接下來就會調用Surface類的另外一個成員函數getBufferLocked來請求SurfaceFlinger服務為編號為bufIdx的UI元數據緩沖區分配一個圖形緩沖區。分配完成之後,這個圖形緩沖區就會保存在mBuffers[bufIdx]中。後面我們就詳細分析Surface類的成員函數getBufferLocked的實現。
Surface類的非靜態成員函數dequeueBuffer獲得了編號為bufIdx的圖形緩沖區之後,接下來就會得到這個圖形緩沖區的寬度和高度,並且保存Surface類的成員變量mWidth和mHeight中,以便可以表示當前下在繪制的Surface的寬度和高度。同時,這個圖形緩沖區的寬度和高度還會被更新到用來描述當前正在繪制的Surface的裁剪區域去,因為SurfaceFlinger服務在渲染該Surface時,需要用到這個信息。當前正在繪制的Surface的裁剪區域是由Surface類的成員變量mDirtyRegion來描述的,只要調用它的成員函數set,就可以重新設置它的寬度和高度。
最後,Surface類的非靜態成員函數dequeueBuffer就將得到的圖形緩沖區的地址保存輸出參數buffer中,以便OpenGL庫可以在上面填入UI數據。另一方面,如果分配圖形緩沖區失敗,那麼Surface類的非靜態成員函數dequeueBuffer會將前面得到的一個UI元數據緩沖區返回給成員變量mSharedBufferClient所描述的一個UI元數據緩沖區堆棧去,這是通過調用成員變量mSharedBufferClient的成員函數undoDequeue來實現的。
接下來,我們就繼續分析SharedBufferClient類的成員函數dequeue的實現,以便了解它是如何從UI元數據緩沖區堆棧中獲得一個空閒的緩沖區的。
Step 2. SharedBufferClient.dequeue
[cpp]
ssize_t SharedBufferClient::dequeue()
{
SharedBufferStack& stack( *mSharedStack );
if (stack.head == tail && stack.available == mNumBuffers) {
LOGW("dequeue: tail=%d, head=%d, avail=%d, queued=%d",
tail, stack.head, stack.available, stack.queued);
}
RWLock::AutoRLock _rd(mLock);
const nsecs_t dequeueTime = systemTime(SYSTEM_TIME_THREAD);
//LOGD("[%d] about to dequeue a buffer",
// mSharedStack->identity);
DequeueCondition condition(this);
status_t err = waitForCondition(condition);
if (err != NO_ERROR)
return ssize_t(err);
DequeueUpdate update(this);
updateCondition( update );
int dequeued = stack.index[tail];
tail = ((tail+1 >= mNumBuffers) ? 0 : tail+1);
LOGD_IF(DEBUG_ATOMICS, "dequeued=%d, tail++=%d, %s",
dequeued, tail, dump("").string());
mDequeueTime[dequeued] = dequeueTime;
return dequeued;
}
這個函數定義在文件frameworks/base/libs/surfaceflinger_client/SharedBufferStack.cpp中。
從前面Android應用程序與SurfaceFlinger服務的關系概述和學習計劃一文可以知道,SharedBufferClient類的成員變量tail指向了一個UI元數據緩沖區堆棧的空閒緩沖區列表的尾部。當這個UI元數據緩沖區堆棧的可用空閒緩沖區的數量available的值大於0的時候,應用程序就可以從它的空閒緩沖區列表的尾部分配一個繪沖區出來使用。
函數首先創建了一個DequeueCondition對象condition,然後再調用SharedBufferClient從SharedBufferBase類繼承下來的成員函數waitForCondition來判斷當前正在使用的UI元數據緩沖區堆棧是否有空閒的緩沖區可以分配。如果沒有,那麼當前線程就會一直等待,直到可以得到一個空閒緩沖區為止。
函數接著創建了一個DequeueUpdate對象update,然後再調用SharedBufferClient從SharedBufferBase類繼承下來的成員函數updateCondition來減少當前正在使用的UI元數據緩沖區堆棧的空閒緩沖區的數量,因為接下來要將空閒緩沖區列表尾部的緩沖區分配出來使用。
函數最後就通過SharedBufferClient類的成員變量tail來獲得了一個編號為dequeued的空閒UI元數據緩沖區,並且將這個編號返回給調用者。不過,在返回之前,函數還會將SharedBufferClient類的成員變量tail向前移一個位置,以便它可以指向下一個可以用來分配的空閒UI元數據緩沖區。由於UI元數據緩沖區堆棧是循環使用的,因此,當SharedBufferClient類的成員變量tail向前移一個位置,即加1之後,它的值大於等於UI元數據緩沖區堆棧的大小mNumBuffers時,就需要繞回到堆棧的開頭去。
這一步執行完成之後,就返回到Step 1中,即Surface類的成員函數dequeueBuffer中,這時候應用程序就為當前正在繪制的Surface獲得了一個空閒UI元數據緩沖區,接下來就會繼續調用Surface類的成員函數getBufferLocked來為該空閒UI元數據緩沖區分配圖形緩沖區。
Step 3. Surface.getBufferLocked
[cpp]
status_t Surface::getBufferLocked(int index,
uint32_t w, uint32_t h, uint32_t format, uint32_t usage)
{
sp<ISurface> s(mSurface);
if (s == 0) return NO_INIT;
status_t err = NO_MEMORY;
// free the current buffer
sp<GraphicBuffer>& currentBuffer(mBuffers.editItemAt(index));
if (currentBuffer != 0) {
getBufferMapper().unregisterBuffer(currentBuffer->handle);
currentBuffer.clear();
}
sp<GraphicBuffer> buffer = s->requestBuffer(index, w, h, format, usage);
......
if (buffer != 0) { // this should never happen by construction
......
err = mSharedBufferClient->getStatus();
......
if (!err && buffer->handle != NULL) {
err = getBufferMapper().registerBuffer(buffer->handle);
......
if (err == NO_ERROR) {
currentBuffer = buffer;
currentBuffer->setIndex(index);
}
} else {
err = err<0 ? err : status_t(NO_MEMORY);
}
}
return err;
}
這個函數定義在文件frameworks/base/libs/surfaceflinger_client/Surface.cpp中。
從前面Android應用程序請求SurfaceFlinger服務創建Surface的過程分析一文可以知道, Surface類的成員變量mSurface指向了一個類型為BpSurface的Binder代理對象,這個Binder代理對象引用了運行在SurfaceFlinger服務一側的一個類型為SurfaceLayer的Binder本地對象。函數首先將這個成員變量保存在變量s中,後面會通過它來向SurfaceFlinger服務為編號為index的空閒UI元數據緩沖區分配一個圖形緩沖區。
在請求SurfaceFlinger服務為編號為index的空閒UI元數據緩沖區分配圖形緩沖區之前,函數還會檢查在Surface類的成員變量mBuffers中是否存在一個與編號為index的空閒UI元數據緩沖區對應的圖形緩沖區。如果存在的話,就需要將這個圖形緩沖區從應用程序進程的地址空間注銷掉,因為這個圖形緩沖區已經變成無效了。Surface類的成員函數getBufferMapper的返回值是一個GraphicBufferMapper對象,通過調用這個GraphicBufferMapper對象的成員函數unregisterBuffer就可以注銷一個指定的圖形緩沖區。GraphicBufferMapper類的成員函數unregisterBuffer最終也是通過HAL層中的Gralloc模塊提供的接口gralloc_unregister_buffer來注銷一個指定的圖形緩沖區,這一點可以參考前面Android幀緩沖區(Frame Buffer)硬件抽象層(HAL)模塊Gralloc的實現原理分析一文。
函數接下來就請求變量s所指向的一個BpSurface對象的成員函數requestBuffer請求SurfaceFlinger服務為編號為index的空閒UI元數據緩沖區分配一個圖形緩沖區,這個緩沖區保存在變量buffer中。應用程序得到圖形緩沖區buffer之後,還需要將它注冊到本進程的地址空間之後,才能使用,這是通過調用GraphicBufferMapper類的成員函數registerBuffer來實現的,後面我們再詳細分析這個注冊的過程。
接下來,函數就將圖形緩沖區buffer保存在一個GraphicBuffer引用currentBuffer中。由於currentBuffer引用的是Surface類的成員變量mBuffers的第index個圖形緩沖區,因此,前面相當於將圖形緩沖區buffer保存在Surface類的成員變量mBuffers的第index個位置中,以便以後可以重復利用。最後,函數還調用GraphicBuffer引用currentBuffer的成員函數setIndex來將前面分配到的圖形緩沖區的編號設置為index,這樣就可以將它與編號為index的UI元數據緩沖區關聯起來。
由於變量s引用的是一個類型為SurfaceLayer的Binder本地對象,因此,接下來我們就繼續分析SurfaceLayer類的成員函數requestBuffer的實現,以便可以了解SurfaceFlinger服務是如何為應用程序的一個Surface分配一個圖形緩沖區的。
Step 4. SurfaceLayer.requestBuffer
[cpp]
sp<GraphicBuffer> Layer::SurfaceLayer::requestBuffer(int index,
uint32_t w, uint32_t h, uint32_t format, uint32_t usage)
{
sp<GraphicBuffer> buffer;
sp<Layer> owner(getOwner());
if (owner != 0) {
/*
* requestBuffer() cannot be called from the main thread
* as it could cause a dead-lock, since it may have to wait
* on conditions updated my the main thread.
*/
buffer = owner->requestBuffer(index, w, h, format, usage);
}
return buffer;
}
這個函數定義在文件frameworks/base/services/surfaceflinger/Layer.cpp中。
函數首先調用SurfaceLayer類的成員函數getOwner來獲得當前正在處理的一個SurfaceLayer對象的宿主Layer對象,接著再調用這個Layer對象的成員函數requestBuffer來執行分配圖形緩沖區的操作。從前面Android應用程序請求SurfaceFlinger服務創建Surface的過程分析一文可以知道,SurfaceFlinger服務在為Android應用程序創建一個Surface的時候,會相應地創建一個Layer對象和一個SurfaceLayer對象來描述這個Surface。
接下來,我們就繼續分析Layer類的成員函數requestBuffer的實現。
Step 5. Layer.requestBuffer
這個函數定義在frameworks/base/services/surfaceflinger/Layer.cpp文件中,我們分段來閱讀:
[cpp]
sp<GraphicBuffer> Layer::requestBuffer(int index,
uint32_t reqWidth, uint32_t reqHeight, uint32_t reqFormat,
uint32_t usage)
{
sp<GraphicBuffer> buffer;
if (int32_t(reqWidth | reqHeight | reqFormat) < 0)
return buffer;
if ((!reqWidth && reqHeight) || (reqWidth && !reqHeight))
return buffer;
// this ensures our client doesn't go away while we're accessing
// the shared area.
ClientRef::Access sharedClient(mUserClientRef);
SharedBufferServer* lcblk(sharedClient.get());
if (!lcblk) {
// oops, the client is already gone
return buffer;
}
我們首先明確一下各個函數參數的含義。參數index用來描述一個UI元數據緩沖區的編號,參數reqWidth、reqHeight、reqFormat和usage分別表示要分配的圖形緩沖區的寬度、高度、像素格式和用途。函數首先檢查各個參數的合法性,即參數reqWidth、reqHeight和reqFormat不能為負數,並且參數reqWidth和reqHeight不能同時等於0。
從前面Android應用程序請求SurfaceFlinger服務創建Surface的過程分析一文可以知道,Layer類的成員變量mUserClientRef指向了一個ClientRef對象,通過這個ClientRef對象可以獲得一個SharedBufferServer對象lcblk。得到的SharedBufferServer對象lcblk就是用來描述正在請求SurfaceFlinger服務分配圖形緩沖區的Surface的UI元數據緩沖區堆棧的,接下來我們就會看到它的用法。
我們繼續往下看:
[cpp]
/*
* This is called from the client's Surface::dequeue(). This can happen
* at any time, especially while we're in the middle of using the
* buffer 'index' as our front buffer.
*/
uint32_t w, h, f, bypass;
{ // scope for the lock
Mutex::Autolock _l(mLock);
bypass = mBypassState;
// zero means default
mFixedSize = reqWidth && reqHeight;
if (!reqFormat) reqFormat = mFormat;
if (!reqWidth) reqWidth = mWidth;
if (!reqHeight) reqHeight = mHeight;
w = reqWidth;
h = reqHeight;
f = reqFormat;
if ((reqWidth != mReqWidth) || (reqHeight != mReqHeight) ||
(reqFormat != mReqFormat)) {
mReqWidth = reqWidth;
mReqHeight = reqHeight;
mReqFormat = reqFormat;
mNeedsScaling = mWidth != mReqWidth || mHeight != mReqHeight;
lcblk->reallocateAllExcept(index);
}
}
這一段代碼主要就是用來判斷要分配圖形緩沖區的Surface的寬度、高度和像素格式是否發生變化。當請求分配的圖形緩沖區的寬度、高度和像素格式與這個圖形緩沖區所描述的Surface原來的寬度、高度和像素格式不一樣時,SurfaceFlinger服務就會認為這個Surface的元信息發生了變化,這時候函數就會將請求分配的圖形緩沖區的寬度、高度和像素格式設置為當前Surface的寬度、高度和像素格式,並且調用前面所獲得的一個SharedBufferServer對象lcblk的成員函數reallocateAllExcept來將之前已經分配給當前Surface的圖形緩沖區設置為無效,因為之前已經分配給當前Surface的圖形緩沖區已經不適合於當前Surface使用了。
在這一段代碼中,還有一個需要注意的地方,即Layer類的成員變量mBypassState。這個成員變量表示當前正在處理的一個Layer對象所描述的一個Surface在SurfaceFlinger服務渲染UI時,是否需要參與合成。當它的值等於true的時候,就表示不需要參與合成,否則就要參考合成。一般當一個Layer對象所描述的Surface的圖形緩沖區是直接在硬件幀緩沖區fb上分配時,對應的Surface就不需要參與SurfaceFlinger服務的合成操作。
我們繼續向下看:
[cpp]
// here we have to reallocate a new buffer because the buffer could be
// used as the front buffer, or by a client in our process
// (eg: status bar), and we can't release the handle under its feet.
uint32_t effectiveUsage = getEffectiveUsage(usage);
status_t err = NO_MEMORY;
ef USE_COMPOSITION_BYPASS
if (!mSecure && bypass && (effectiveUsage & GRALLOC_USAGE_HW_RENDER)) {
// always allocate a buffer matching the screen size. the size
// may be different from (w,h) if the buffer is rotated.
const DisplayHardware& hw(graphicPlane(0).displayHardware());
int32_t w = hw.getWidth();
int32_t h = hw.getHeight();
int32_t f = hw.getFormat();
buffer = new GraphicBuffer(w, h, f, effectiveUsage | GRALLOC_USAGE_HW_FB);
err = buffer->initCheck();
buffer->transform = uint8_t(getOrientation());
if (err != NO_ERROR) {
// allocation didn't succeed, probably because an older bypass
// window hasn't released all its resources yet.
ClientRef::Access sharedClient(mUserClientRef);
SharedBufferServer* lcblk(sharedClient.get());
if (lcblk) {
// all buffers need reallocation
lcblk->reallocateAll();
}
}
}
if
這段代碼用來判斷是否需要直接在硬件幀緩沖區fb上分配一個圖形緩沖區。
當滿足以下四個條件時,一個圖形緩沖區就可以在硬件幀緩沖區fb分配:
1. SurfaceFlinger服務在編譯時,定義了USE_COMPOSITION_BYPASS宏;
2. 當前正在處理的Layer對象的成員變量mSecure的值等於false,即這個Layer對象的所描述的一個Surface是非進程間傳輸安全的,這種類型的Surface一般用來保存屏幕UI數據或者用來傳輸遠程桌面UI數據;
3. 當前正在處理的Layer對象的成員變量mBypassState的值等於true,即這個Layer對象的所描述的一個Surface是不需要參與到SurfaceFlinger服務渲染合成操作的;
4. 請求分配的圖形緩沖區的有效用途effectiveUsage的第GRALLOC_USAGE_HW_RENDER位等於1,即請求分配的圖形緩沖區要在直接在硬件幀緩沖區上渲染。
當滿足上述四個條件,函數就會創建一個類型為GRALLOC_USAGE_HW_FB的圖形緩沖區buffer,並且將它返回給應用程序。如果創建失敗,函數會調用前面所獲得的一個SharedBufferServer對象lcblk的成員函數reallocateAll來將之前已經分配給當前Surface的圖形緩沖區都設置為無效,因為這些圖形緩沖區有可能不是在硬件幀緩沖區fb上分配的。
請求分配的圖形緩沖區的有效用途effectiveUsage是通過調用Surface類的成員函數getEffectiveUsage來獲得的,如下所示:
[cpp]
uint32_t Layer::getEffectiveUsage(uint32_t usage) const
{
/*
* buffers used for software rendering, but h/w composition
* are allocated with SW_READ_OFTEN | SW_WRITE_OFTEN | HW_TEXTURE
*
* buffers used for h/w rendering and h/w composition
* are allocated with HW_RENDER | HW_TEXTURE
*
* buffers used with h/w rendering and either NPOT or no egl_image_ext
* are allocated with SW_READ_RARELY | HW_RENDER
*
*/
if (mSecure) {
// secure buffer, don't store it into the GPU
usage = GraphicBuffer::USAGE_SW_READ_OFTEN |
GraphicBuffer::USAGE_SW_WRITE_OFTEN;
} else {
// it's allowed to modify the usage flags here, but generally
// the requested flags should be honored.
// request EGLImage for all buffers
usage |= GraphicBuffer::USAGE_HW_TEXTURE;
}
return usage;
}
參數usage用來描述請求分配的圖形緩沖區的原始用途。
如果當前正在處理的Layer對象所描述的一個Surface是可以在進程間安全傳輸的,那麼函數就會將參數usage的值修改為(GraphicBuffer::USAGE_SW_READ_OFTEN | GraphicBuffer::USAGE_SW_WRITE_OFTEN),目的是防止該Surface的圖形緩沖區直接在硬件幀緩沖區上分配。
如果當前正在處理的Layer對象所描述的一個Surface是不可以在進程間安全傳輸的,那麼函數除了會保留參數usage的原值之外,還會將它的第GraphicBuffer::USAGE_HW_TEXTURE位設置為1,用來表示分配的圖形緩沖區可以用來作為OpenGL庫的紋理緩沖區。
最後,函數就將修改後的參數usage的值返回給調用者。
回到Layer類的成員函數requestBuffer中。對於一般應用程序創建的Surface來說,它們都是不可以在進程間安全傳輸的,即與它對應的Layer對象的成員變量mSecure的值等於false,因此,這時候Layer類的成員函數requestBuffer得到即將要分配的圖形緩沖區的有效用途effectiveUsage的GraphicBuffer::USAGE_HW_TEXTURE位就被設置為1。我們記住這個值,以便接下來可以了解圖形緩沖區的分配過程。
我們假設SurfaceFlinger服務在編譯時,沒有定義USE_COMPOSITION_BYPASS宏,或者當前正在處理的Layer對象所描述的一個Surface是需要由SurfaceFlinger服務執行渲染合成操作的,即前面第1個或者第3個條件不滿足,於是,我們就繼續向下分析Layer類的成員函數requestBuffer的實現:
[cpp
if (err != NO_ERROR) {
buffer = new GraphicBuffer(w, h, f, effectiveUsage);
err = buffer->initCheck();
}
.....
if (err == NO_ERROR && buffer->handle != 0) {
Mutex::Autolock _l(mLock);
mBufferManager.attachBuffer(index, buffer);
}
return buffer;
}
這段代碼首先使用參數w、h、f和effectiveUsage來創建了一個GraphicBuffer對象buffer,用來描述即將要分配的圖形緩沖區,接著再調用Layer類的成員變量mBufferManager所描述的一個BufferManager對象的成員函數attachBuffer來將GraphicBuffer對象buffer的編號設置為index,以便可以表示這個GraphicBuffer對象buffer是為編號為index的UI元數據緩沖區創建的。
最後,Layer類的成員函數requestBuffer就將分配好的圖形緩沖區,即GraphicBuffer對象buffer返回給應用程序。
接下來,我們首先分析一個GraphicBuffer對象的創建過程,即GraphicBuffer類的構造函數的實現,以便可以了解它所描述的圖形緩沖區是如何分配的,接著再分析BufferManager類的成員函數attachBuffer的實現,以便可以了解SurfaceFlinger服務是如何將一個UI元數據緩沖區與一個圖形緩沖區關聯起來的。
Step 6. new GraphicBuffer
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 =
transform = 0;
handle = NULL;
mInitCheck = initSize(w, h, reqFormat, reqUsage);
}
這個函數定義在文件frameworks/base/libs/ui/GraphicBuffer.cpp文件中。
GraphicBuffer類的構造函數最重要的是調用另外一個成員函數initSize來初始化即將要分配的圖形緩沖區。
Step 7. GraphicBuffer.initSize
[cpp]
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;
}
這個函數定義在文件frameworks/base/libs/ui/GraphicBuffer.cpp文件中。
函數首先獲得一個GraphicBufferAllocator對象,然後再調用這個GraphicBufferAllocator對象的成員函數alloc來分配一塊指定大小、像素格式以及用用途的圖形緩沖區。分配好的圖形緩沖的句柄值最終就保存在GraphicBuffer類的成員變量handle中。
GraphicBufferAllocator類是用來分配圖形緩沖區的,接下來我們就繼續分析它的成員函數alloc的實現。
Step 8. GraphicBufferAllocator.alloc
[cpp]
status_t GraphicBufferAllocator::alloc(uint32_t w, uint32_t h, PixelFormat format,
int usage, buffer_handle_t* handle, int32_t* stride)
{
// make sure to not allocate a N x 0 or 0 x N buffer, since this is
// allowed from an API stand-point allocate a 1x1 buffer instead.
if (!w || !h)
w = h = 1;
// we have a h/w allocator and h/w buffer is requested
status_t err;
if (usage & GRALLOC_USAGE_HW_MASK) {
err = mAllocDev->alloc(mAllocDev, w, h, format, usage, handle, stride);
} else {
err = sw_gralloc_handle_t::alloc(w, h, format, usage, handle, stride);
}
......
return err;
}
這個函數定義在文件frameworks/base/libs/ui/GraphicBufferAllocator.cpp中。
參數usage是從前面的Step 5中傳進來的,前面我們假設它的第GraphicBuffer::USAGE_HW_TEXTURE位的值等於1。
GraphicBuffer::USAGE_HW_TEXTURE是一個枚舉值,定義在文件frameworks/base/include/ui/GraphicBuffer.h中,如下所示:
[cpp]
class GraphicBuffer
: public EGLNativeBase<
android_native_buffer_t,
GraphicBuffer,
LightRefBase<GraphicBuffer> >, public Flattenable
{
public:
enum {
......
USAGE_HW_TEXTURE = GRALLOC_USAGE_HW_TEXTURE,
......
};
......
};
它的值等於GRALLOC_USAGE_HW_TEXTURE。
GRALLOC_USAGE_HW_TEXTURE和GRALLOC_USAGE_HW_MASK也是兩個枚舉值,它們定義在文件hardware/libhardware/include/hardware/gralloc.h中,如下所示:
[cpp]
enum {
......
/* buffer will be used as an OpenGL ES texture */
GRALLOC_USAGE_HW_TEXTURE = 0x00000100,
......
/* mask for the software usage bit-mask */
GRALLOC_USAGE_HW_MASK = 0x00001F00,
......
};
從GRALLOC_USAGE_HW_TEXTURE和GRALLOC_USAGE_HW_MASK這兩個枚舉值的定義可以知道,GraphicBufferAllocator類的成員函數alloc最終會調用其成員變量mAllocDev的成員函數alloc來分配一個圖形緩沖區。
GraphicBufferAllocator類的成員變量mAllocDev指向了一個alloc_device_t結構體,用來描述HAL層的Gralloc模塊中的一個gralloc設備,這個gralloc設備是在GraphicBufferAllocator類的構造函數中創建的,如下所示:
[cpp]
GraphicBufferAllocator::GraphicBufferAllocator()
: mAllocDev(0)
{
hw_module_t const* module;
int err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module);
LOGE_IF(err, "FATAL: can't find the %s module", GRALLOC_HARDWARE_MODULE_ID);
if (err == 0) {
gralloc_open(module, &mAllocDev);
}
}
GraphicBufferAllocator類的構造函數首先調用函數hw_get_module來加載ID值等於GRALLOC_HARDWARE_MODULE_ID的HAL模塊,即加載HAL層中的Gralloc模塊,目的是為了接下來調用函數gralloc_open來打開裡面的gralloc設備,並且將這個打開的gralloc設備保存在GraphicBufferAllocator類的成員變量mAllocDev中,這一點可以參考前面Android幀緩沖區(Frame Buffer)硬件抽象層(HAL)模塊Gralloc的實現原理分析一文。
接下來,我們就繼續分析alloc_device_t結構體的成員函數alloc的實現。
Step 9. alloc_device_t.alloc
從前面Android幀緩沖區(Frame Buffer)硬件抽象層(HAL)模塊Gralloc的實現原理分析一文可以知道,Gralloc模塊中的gralloc設備的成員函數alloc被設置為Gralloc模塊中的函數gralloc_alloc。
Gralloc模塊模塊中的函數gralloc_alloc有一個參數usage,當它的GRALLOC_USAGE_HW_FB位等於1的時候,函數gralloc_alloc就會直接在硬件幀緩沖區上分配一個圖形緩沖區,否則的話,就會在匿名共享內存中分配一個圖形緩沖區。從前面的調用過程可以知道,這個參數的值最開始是從前面的Step 1傳過來的,即是從應用程序進程這一側傳遞過來的。
由於整個系統在硬件上就只有一個幀緩沖區,它是由SurfaceFlinger服務來統一管理的,即只有SurfaceFlinger服務使用的圖形緩沖區才可以在上面分配,否則的話,隨便一個應用程序進程都可以在上面分配圖形緩沖區來使用,這個幀緩沖區的管理就亂套了。應用程序進程使用的圖形緩沖區一般都是在匿名共享內存裡面分配的,這個圖形緩區填好數據之後,就會再交給SurfaceFlinger服務來合成到硬件幀緩沖區上去渲染。因此,從前面Step 1傳過來給函數gralloc_alloc的參數usage的GRALLOC_USAGE_HW_FB位會被設置為0,以便可以在匿名共享內存中分配一個圖形緩沖區。這個分配的過程可以參考前面Android幀緩沖區(Frame Buffer)硬件抽象層(HAL)模塊Gralloc的實現原理分析一文,這裡就不再復述了。
這一步執行完成之後,應用程序所請求的圖形緩沖區就分配完成了,回到前面的Step 5中,即Layer類的成員函數requestBuffer中,接下來就會調用BufferManager類的成員函數attachBuffer來設置這個圖形緩沖區的編號,以便它可以與一個UI元數據緩沖區關聯起來的。關聯好之後,應用程序在請求SurfaceFlinger服務渲染一個Surface時,只需要指定一個UI元數據緩沖區的編號,SurfaceFlinger服務就可以根據這個編號來找到對應的圖形緩沖區,進而把這個圖形緩沖區的內容渲染到硬件幀緩沖區上去,即渲染到設備顯示屏上去。
接下來,我們就繼續分BufferManager類的成員函數attachBuffer的實現。
Step 10. BufferManager.attachBuffer
[cpp]
status_t Layer::BufferManager::attachBuffer(size_t index,
const sp<GraphicBuffer>& buffer)
{
BufferData* const buffers = mBufferData;
Mutex::Autolock _l(mLock);
buffers[index].buffer = buffer;
buffers[index].texture.dirty = true;
return NO_ERROR;
}
這個函數定義在frameworks/base/services/surfaceflinger/Layer.cpp文件中。
從前面的調用過程可以知道,參數index用來描述一個UI元數據緩沖區的編號,而參數buffer用來描述一個圖形緩沖區。
BufferManager類的成員變量mBufferData是一個類型為BufferData的數組,這個數組就是用來關聯當前正在處理的一個Layer對象所描述的一個Surface的UI元數據緩沖區和圖形緩沖區的。例如,編號為i的UI元數據緩沖區在數組mBufferData的第i個位置有一個對應的BufferData結構體,而這個BufferData結構體的成員變量buffer就指向為編號為i的UI元數據緩沖區所分配的一個圖形緩沖區。
理解了這一點之後,我們就不難理解BufferManager類的成員函數attachBuffer的實現了,它就是將編號為index的UI元數據緩沖區與參數buffer所描述的圖形緩沖區關聯起來。
這一步執行完成之後,回到前面的Step 5中,即Layer類的成員函數requestBuffer中,接下來就會將分配好的圖形緩沖區返回給應用程序,即返回到前面的Step 3中去,這時候應用程序就繼續調用GraphicBufferMapper類的成員函數registerBuffer來將獲得的圖形緩沖區注冊到當前進程的地址空間去。
Step 11. GraphicBufferMapper.registerBuffer
[cpp]
status_t GraphicBufferMapper::registerBuffer(buffer_handle_t handle)
{
status_t err;
if (sw_gralloc_handle_t::validate(handle) < 0) {
err = mAllocMod->registerBuffer(mAllocMod, handle);
} else {
err = sw_gralloc_handle_t::registerBuffer((sw_gralloc_handle_t*)handle);
}
LOGW_IF(err, "registerBuffer(%p) failed %d (%s)",
handle, err, strerror(-err));
return err;
}
這個函數定義在文件frameworks/base/libs/ui/GraphicBufferMapper.cpp中。
參數handle的類型為buffer_handle_t,它描述的便是前面在匿名共享內存中分配的一個圖形緩沖區。
從前面的Step 8可以知道,當GraphicBufferAllocator類的成員函數alloc的參數usage的第GraphicBuffer::USAGE_HW_TEXTURE位的值等於1的時候,SurfaceFlinger服務就會通過HAL層的Gralloc模塊來分配一個圖形緩沖區,否則的話,就會在sw_gralloc_handle_t模塊中分配一個圖形緩沖區。sw_gralloc_handle_t模塊中分配的圖形緩沖區是使用一個sw_gralloc_handle_t對象來描述的,而從前面Android幀緩沖區(Frame Buffer)硬件抽象層(HAL)模塊Gralloc的實現原理分析一文可以知道,Gralloc模塊分配的圖形緩沖區是使用一個private_handle_t對象來描述的。
sw_gralloc_handle_t類的靜態成員函數validate就是用來驗證參數handle所描述的一個圖形緩沖區是否是在sw_gralloc_handle_t模塊中分配的。如果是的話,那麼它的返回值就會等於0,否則的話,就會小於0。
由於參數handle所描述的一個圖形緩沖區是在Gralloc模塊中分配的,因此,這個函數接下來就會調用GraphicBufferAllocator類的成員變量mAllocMod的成員函數registerBuffer來執行注冊圖形緩沖區的操作。
GraphicBufferAllocator類的成員變量mAllocMod指向了HAL層中的Gralloc模塊,它是在GraphicBufferAllocator類的構造函數中初始化的,如下所示:
[cpp]
GraphicBufferMapper::GraphicBufferMapper()
: mAllocMod(0)
{
hw_module_t const* module;
int err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module);
LOGE_IF(err, "FATAL: can't find the %s module", GRALLOC_HARDWARE_MODULE_ID);
if (err == 0) {
mAllocMod = (gralloc_module_t const *)module;
}
}
GraphicBufferAllocator類的構造函數首先調用函數hw_get_module來加載ID值等於GRALLOC_HARDWARE_MODULE_ID的模塊,就可以將Gralloc模塊加載到應用程序進程中來。從前面Android幀緩沖區(Frame Buffer)硬件抽象層(HAL)模塊Gralloc的實現原理分析一文可以知道,Gralloc模塊是使用一個gralloc_module_t結構體來描述的,因此,GraphicBufferAllocator類的構造函數最終就可以將加載得到的模塊module轉換為一個gralloc_module_t結構體,並且保存在GraphicBufferAllocator類的成員變量mAllocMod中。
接下來,我們就繼續分析gralloc_module_t結構體的成員函數registerBuffer的實現。
Step 12. gralloc_module_t.registerBuffer
從前面Android幀緩沖區(Frame Buffer)硬件抽象層(HAL)模塊Gralloc的實現原理分析一文可以知道,Gralloc模塊的成員函數registerBuffer被設置為Gralloc模塊中的函數gralloc_register_buffer。Gralloc模塊模塊中的函數gralloc_register_buffer主要就是將一塊指定的圖形緩沖區映射到當前進程的地址空間來。在我們這個情景中,就是映射到應用程序進程的地址空間來。
這一步執行完成之後,應用程序請求SurfaceFlinger服務為一個空閒的UI元數據緩沖區分配一個圖形緩沖區的過程就分析完成了。從分析的過程可以知道,這個圖形緩沖區指向的是一塊匿名共享內存,最初是在SurfaceFlinger服務這一側分配的,然後再返回給應用程序進程這一側,並且會被映射到應用程序進程的地址空間來。這樣,SurfaceFlinger服務和應用程序就可以在各自的地址空間中訪問這個圖形緩沖區,其中,應用程序訪問這個圖形緩沖區的目的是往裡面寫入UI數據,而SurfaceFlinger服務訪問這個圖形緩沖區的目的是將裡面的UI數據讀取出來渲染。
接下來,我們繼續再分析Surface類的靜態成員函數queueBuffer的實現,以便可以了解應用程序是如何將一塊已經填好了數據的UI元數據緩沖區添加到當前正在繪制的Surface的UI元數緩沖區堆棧的待渲染隊列中去,這個過程如圖3所示:
圖3 准備就緒的UI元數據緩沖區進入待渲染隊列的過程
這個過程一共分為4個步驟,接下來我們就詳細分析每一個步驟。
Step 1. Surface.queueBuffer
[cpp]
int Surface::queueBuffer(ANativeWindow* window,
android_native_buffer_t* buffer) {
Surface* self = getSelf(window);
return self->queueBuffer(buffer);
}
這個函數定義文件frameworks/base/libs/surfaceflinger_client/Surface.cpp中。
參數window雖然是一個ANativeWindow指針,但是它實際上指向的是一個Surface對象,因此,函數首先調用另外一個靜態成員函數getSelf來將它轉換為一個Surface對象self,接著再調用這個Surface對象self的成員函數queueBuffer將一個UI元數據緩沖區加入到待渲染隊列中去,其中,要加入到待渲染隊列中去的UI元數據緩沖區就是使用參數buffer來描述的。
Surface類的非靜態成員函數queueBuffer的實現如下所示:
[cpp]
int Surface::queueBuffer(android_native_buffer_t* buffer)
{
status_t err = validate();
if (err != NO_ERROR)
return err;
if (mSwapRectangle.isValid()) {
mDirtyRegion.set(mSwapRectangle);
}
int32_t bufIdx = getBufferIndex(GraphicBuffer::getSelf(buffer));
GraphicLog::getInstance().log(GraphicLog::SF_APP_QUEUE, mIdentity, bufIdx);
mSharedBufferClient->setTransform(bufIdx, mNextBufferTransform);
mSharedBufferClient->setCrop(bufIdx, mNextBufferCrop);
mSharedBufferClient->setDirtyRegion(bufIdx, mDirtyRegion);
err = mSharedBufferClient->queue(bufIdx);
LOGE_IF(err, "error queuing buffer %d (%s)", bufIdx, strerror(-err));
if (err == NO_ERROR) {
// TODO: can we avoid this IPC if we know there is one pending?
mClient.signalServer();
}
return err;
}
這個函數定義文件frameworks/base/libs/surfaceflinger_client/Surface.cpp中。
Surface類的成員變量mSwapRectangle用來指定要繪制的Surface的區域。如果它的值是正確的,那麼函數就會將它的值設置到Surface類的另外一個成員變量mDirtyRegion中去,以便接下來可以用來作為裁剪區域傳遞給SurfaceFlinger服務。
如前所述,參數buffer描述的是一個圖形緩沖區,它的實際類型為GraphicBuffer,因此,函數就可以調用GraphicBuffer的靜態成員函數getSelf來將它轉換為一個GraphicBuffer對象,接著函數還調用Sufrace類的成員函數getBufferIndex來獲得參數buffer所描述的一個圖形緩沖區的編號bufIdx。這個編號是用來關聯一個UI元數據緩沖區。在前面分析空閒UI元數據緩沖區及其圖形緩沖區的分配過程的Step 3中提到,應用程序請求SurfaceFlinger服務為一個UI元數據緩沖區分配了一個圖形緩沖區時,就會將這個UI元數據緩沖區的編號設置到這個圖形緩沖區裡面去。
Surface類的成員變量mSharedBufferClient指向了一個SharedBufferClient對象,用來描述當前正在繪制的Surface的UI元數據緩沖區堆棧,接下來函數就會調用它的成員函數queue來將前面獲得的一個編號為bufIdx的UI元數據緩沖區加入到它的待渲染隊列中去。不過,在加入這個編號為bufIdx的UI元數據緩沖區之前,函數還會分別調用成員變量mSharedBufferClient的成員函數setTransform、setCrop和setDirtyRegion來設置它的旋轉方向、紋理坐標和裁剪區域等信息。這些信息分別保存在Surface類的成員變量mNextBufferTransform、mNextBufferCrop和mDirtyRegion中。注意,Surface類的成員變量mNextBufferTransform和mNextBufferCrop是由OpenGL庫通過調用Surface類的成員函數perform來設置。從前面Android應用程序請求SurfaceFlinger服務創建Surface的過程分析一文可以知道,應用程序在請求SurfaceFlinger服務創建一個繪圖表面的時候,會將用來描述這個繪圖表面的一個Surface對象的成員函數perform設置為OpenGL庫在畫圖的過程需要調用到的一個回調接口peform,這樣做的目的就是為了可以設置繪圖表面的元信息。
將編號為bufIdx的UI元數據緩沖區加入到正在繪制的Surface的UI元數據緩沖區堆棧的待渲染隊列之後,函數最後就會調用Surface類的成員變量mClient所描述的一個SurfaceClient對象的成員函數signalServer來通知SurfaceFlinger服務來相應的圖形緩沖區渲染到設備顯示屏上去。
接下來,我們首先分析SharedBufferClient類的成員函數queue的實現,以便可以了解一個UI元數緩沖區是如何進入到一個UI元數據緩沖區堆棧的待渲染隊列中去的,接著分析SurfaceClient類的成員函數signalServer的實現,以便可以了解應用程序是如何請求SurfaceFlinger服務渲染一個Surface的圖形緩沖區的。
Step 2. SharedBufferClient.queue
[cpp]
status_t SharedBufferClient::queue(int buf)
{
RWLock::AutoRLock _rd(mLock);
SharedBufferStack& stack( *mSharedStack );
queued_head = (queued_head + 1) % mNumBuffers;
stack.index[queued_head] = buf;
QueueUpdate update(this);
status_t err = updateCondition( update );
LOGD_IF(DEBUG_ATOMICS, "queued=%d, %s", buf, dump("").string());
const nsecs_t now = systemTime(SYSTEM_TIME_THREAD);
stack.stats.totalTime = ns2us(now - mDequeueTime[buf]);
return err;
}
這個函數定義在文件frameworks/base/libs/surfaceflinger_client/SharedBufferStack.cpp中。
SharedBufferClient類的成員變量mSharedStack是從父類SharedBufferBase繼承下來的,它的成員變量index是一個類型為int8_t的數組,而這個數組就是用來描述一個UI元數據緩沖區堆棧的,這一點可以參考前面Android應用程序與SurfaceFlinger服務之間的共享UI元數據(SharedClient)的創建過程分析一文。
從前面Android應用程序與SurfaceFlinger服務的關系概述和學習計劃一文可以知道,SharedBufferClient類的成員變量queue_head指向了一個UI元數據緩沖區堆棧的待渲染隊列的尾部,所有需要加入到這個待渲染隊列的UI元數據緩沖都保存在queue_head的下一個位置上。
參數buf描述的是要加入到當前正在繪制的Surface的UI元數據緩沖區堆棧的待渲染隊列的緩沖區的編號,在將這個緩沖區加入到待渲染隊列之後,還需要將這個待渲染隊列的大小增加1,以便SurfaceFlinger服務可以知道一個Surface當前有多少個圖形緩沖區是正在等待被渲染的。從前面Android應用程序與SurfaceFlinger服務的關系概述和學習計劃一文可以知道,一個UI元數據緩沖區堆棧的待渲染隊列的大小保存在一個SharedBufferStack對象的成員變量queued中,而將這個待渲染隊列的大小增加1的操作是通過調用用SharedBufferClient類從SharedBufferBase類繼承下來的成員函數updateCondition來實現的。
函數首先創建了一個QueueUpdate對象update,然後再以這個QueueUpdate對象update為參數,來調用SharedBufferClient從SharedBufferBase類繼承下來的成員函數updateCondition,就可以將當前正在處理的一個UI元數據緩沖區堆棧的待渲染隊列的大小增加1了。
這一步執行完成之後,就返回到Step 1中,即Surface類的成員函數queueBuffer中,這時候與需要渲染的圖形緩沖區所對應的UI元數據緩沖區就加入到當前正在繪制的Surface的UI元數據緩沖區的待渲染隊列中去了,接下來,應用程序就會調用SurfaceClient類的成員函數signalServer來請求SurfaceFlinger服務渲染這個Surface。
Step 3. SurfaceClient.signalServer
[cpp]
class SurfaceClient : public Singleton<SurfaceClient>
{
// all these attributes are constants
sp<ISurfaceComposer> mComposerService;
......
public:
......
void signalServer() const {
mComposerService->signal();
}
};
這個函數定義在文件frameworks/base/libs/surfaceflinger_client/Surface.cpp中。
從前面Android應用程序與SurfaceFlinger服務之間的共享UI元數據(SharedClient)的創建過程分析一文可以知道,SurfaceClient類的成員變量mComposerService指向了一個實現了ISurfaceComposer接口的Binder代理對象,而這個Binder代理對象引用了系統中的SurfaceFlinger服務,因此,SurfaceClient類的成員函數signalServer實際上就是通過成員變量mComposerService的成員函數signal來通知SurfaceFlinger服務執行渲染Surface的操作。
這一步執行完成之後,就會導致SurfaceFlinger類的成員函數signal被調用,接下來我們繼續分析這個成員函數的實現。
Step 4. SurfaceFlinger.signal
[cpp]
void SurfaceFlinger::signal() const {
// this is the IPC call
const_cast<SurfaceFlinger*>(this)->signalEvent();
}
這個函數定義在文件frameworks/base/services/surfaceflinger/SurfaceFlinger.cpp文件中。
SurfaceFlinger服務是運行在System進程中的一個單獨的線程中的。當SurfaceFlinger服務什麼也不需要做的時候,它就會在這個線程中睡眠。由於現在有應用程序請求SurfaceFlinger服務執行渲染Surface的操作了,因此,就需要將這個線程喚醒起來了。
喚醒SurfaceFlinger服務所運行在的線程的操作是通過調用SurfaceFlinger類的成員函數signalEvent來實現的。當這個線程被喚醒之後,它就會繼續執行SurfaceFlinger類的成員函數threadLoop來執行渲染Surface的操作。在後面的文章中,我們再詳細分析SurfaceFlinger服務的實現,到時候就可以知道SurfaceFlinger服務的運行原理了。
接下來,我們就從SurfaceFlinger類的成員函數threadLoop開始,分析SurfaceFlinger服務渲染Surface的圖形緩沖區的過程。這裡我們並不打算詳細分析這個過程,而是粗略地分析,目的是為了理清一下思路,為後面從正面分析SurfaceFlinger服務的實現打下基礎。這個過程如圖4所示。
圖 4 SurfaceFlinger服務渲染Surface的過程
這個過程一共分為6個步驟,接下來我們就詳細分析每一個步驟。
Step 1. SurfaceFlinger.threadLoop
[cpp]
bool SurfaceFlinger::threadLoop()
{
waitForEvent();
......
// post surfaces (if needed)
handlePageFlip();
const DisplayHardware& hw(graphicPlane(0).displayHardware());
if (LIKELY(hw.canDraw() && !isFrozen())) {
......
// repaint the framebuffer (if needed)
const int index = hw.getCurrentBufferIndex();
GraphicLog& logger(GraphicLog::getInstance());
logger.log(GraphicLog::SF_REPAINT, index);
handleRepaint();
// inform the h/w that we're done compositing
logger.log(GraphicLog::SF_COMPOSITION_COMPLETE, index);
hw.compositionComplete();
logger.log(GraphicLog::SF_SWAP_BUFFERS, index);
postFramebuffer();
logger.log(GraphicLog::SF_REPAINT_DONE, index);
} else {
// pretend we did the post
hw.compositionComplete();
usleep(16667); // 60 fps period
}
return true;
}
這個函數定義在文件frameworks/base/services/surfaceflinger/SurfaceFlinger.cpp文件中。
在SurfaceFlinger服務中,每一個Surface,或者說每一個Layer,都有自己的一系列圖形緩沖區。而對於每一個Surface來說,它們各自需要渲染的圖形緩沖區都保存在內部的一個UI元數據緩沖區堆棧的待渲染隊列中。當SurfaceFlinger服務需要渲染系統的UI時,首先就會將各個Surface的UI元數據緩沖區堆棧的待渲染隊列的緩沖區逐個取出來,並且找到對應的圖形緩沖區,接著再將這些圖形緩沖區合成在一起渲染到硬件幀緩沖區fb上,最後我們就可以在設備顯示屏上看到系統的UI了。
了解了這個背景知識之後,接下來我們就簡要描述SurfaceFlinger類的成員函數threadLoop的工作過程:
1. 在SurfaceFlinger類的成員函數waitForEvent中等待。一旦SurfaceFlinger類的成員函數signalEvent被調用,那麼SurfaceFlinger服務所運行的線程就會被喚醒。
2. 調用SurfaceFlinger類的成員函數handlePageFlip將各個Surface的UI元數據緩沖區堆棧的待渲染隊列頭部的緩沖區取出來,並且找到對應的圖形緩沖區。這些圖緩沖區就是接下來要被合成和渲染的。
3. 調用SurfaceFlinger類的成員函數handleRepaint來合成第2步得到的圖形緩沖區。
4. SurfaceFlinger服務使用一個DisplayHardware對象hw來描述系統當前所使用的顯示屏,這個DisplayHardware對象hw實際就是用來封裝對硬件幀緩沖區fb的訪問的,第3步就是將各個圖形緩沖區的內容合成到這個DisplayHardware對象hw中去。合成完成之後,就會調用這個DisplayHardware對象hw的成員函數compositionComplete來通知HAL層Gralloc模塊中的fb設備。這一步是可選的,即HAL層Gralloc模塊中的fb設備可以忽略掉這個合成完成通知。
5. 調用SurfaceFlinger類的成員函數postFramebuffer來將產須合成好的圖形緩沖區渲染到硬件幀緩沖區fb上去。
這裡我們只關注第2步的實現,以後分析SurfaceFlinger服務的實現時,再分析其它步驟的實現。
Step 2. SurfaceFlinger.handlePageFlip
[cpp]
void SurfaceFlinger::handlePageFlip()
{
bool visibleRegions = mVisibleRegionsDirty;
LayerVector& currentLayers = const_cast<LayerVector&>(
mDrawingState.layersSortedByZ);
visibleRegions |= lockPageFlip(currentLayers);
const DisplayHardware& hw = graphicPlane(0).displayHardware();
const Region screenRegion(hw.bounds());
if (visibleRegions) {
Region opaqueRegion;
computeVisibleRegions(currentLayers, mDirtyRegion, opaqueRegion);
/*
* rebuild the visible layer list
*/
mVisibleLayersSortedByZ.clear();
const LayerVector& currentLayers(mDrawingState.layersSortedByZ);
size_t count = currentLayers.size();
mVisibleLayersSortedByZ.setCapacity(count);
for (size_t i=0 ; i<count ; i++) {
if (!currentLayers[i]->visibleRegionScreen.isEmpty())
mVisibleLayersSortedByZ.add(currentLayers[i]);
}
......
mWormholeRegion = screenRegion.subtract(opaqueRegion);
mVisibleRegionsDirty = false;
}
unlockPageFlip(currentLayers);
mDirtyRegion.andSelf(screenRegion);
}
這個函數定義在文件frameworks/base/services/surfaceflinger/SurfaceFlinger.cpp文件中。
SurfaceFlinger服務將系統中的各個Surface按照其Z軸大小排列在SurfaceFlinger類的成員變量mDrawingState內部的一個layersSortedByZ列表中。函數首先將這個Surface列表layersSortedByZ取出來,並且調用SurfaceFlinger類的另外一個成員函數lockPageFlip來將各個Surface當前需要渲染的圖形緩沖區取出來。
如果SurfaceFlinger服務確實需要執行渲染圖形緩沖區的操作,那麼SurfaceFlinger類的成員函數lockPageFlip的返回值就會等於true。在這種情況下,函數接下來主要就是調用SurfaceFlinger類的成員函數computeVisibleRegions來計算需要渲染的各個Surface的可見區域,以便後面可以正確地將它們的UI繪制出來。
接下來,我們只關注SurfaceFlinger類的成員函數lockPageFlip的實現,以便可以了解SurfaceFlinger服務是如何將各個Surface當前需要渲染的圖形緩沖區取出來的。
Step 3. SurfaceFlinger.lockPageFlip
[cpp]
bool SurfaceFlinger::lockPageFlip(const LayerVector& currentLayers)
{
bool recomputeVisibleRegions = false;
size_t count = currentLayers.size();
sp<LayerBase> const* layers = currentLayers.array();
for (size_t i=0 ; i<count ; i++) {
const sp<LayerBase>& layer(layers[i]);
layer->lockPageFlip(recomputeVisibleRegions);
}
return recomputeVisibleRegions;
}
這個函數定義在文件frameworks/base/services/surfaceflinger/SurfaceFlinger.cpp文件中。
保存在Surface列表currentLayers中的Surface有可能是一個Layer對象,也有可能一個是LayerBlur對象或者一個LayerDim對象等。這裡我們只關心類型為Layer的Surface的圖形緩沖區是如何取出來渲染的,這是通過調用Layer類的成員函數lockPageFlip來實現的。
Step 4. Layer.lockPageFlip
[cpp]
void Layer::lockPageFlip(bool& recomputeVisibleRegions)
{
ClientRef::Access sharedClient(mUserClientRef);
SharedBufferServer* lcblk(sharedClient.get());
......
ssize_t buf = lcblk->retireAndLock();
......
// we retired a buffer, which becomes the new front buffer
if (mBufferManager.setActiveBufferIndex(buf) < NO_ERROR) {
......
return;
}
sp<GraphicBuffer> newFrontBuffer(getBuffer(buf));
if (newFrontBuffer != NULL) {
// get the dirty region
// compute the posted region
const Region dirty(lcblk->getDirtyRegion(buf));
mPostedDirtyRegion = dirty.intersect( newFrontBuffer->getBounds() );
......
// get the crop region
setBufferCrop( lcblk->getCrop(buf) );
// get the transformation
setBufferTransform( lcblk->getTransform(buf) );
}
......
if (lcblk->getQueuedCount()) {
// signal an event if we have more buffers waiting
mFlinger->signalEvent();
}
......
}
這個函數定義在文件frameworks/base/services/surfaceflinger/Layer.cpp中。
從前面Android應用程序請求SurfaceFlinger服務創建Surface的過程分析一文可以知道,Layer類的成員變量mUserClientRef指向了一個ClientRef對象,通過這個ClientRef對象可以獲得一個SharedBufferServer對象lcblk。有了SharedBufferServer對象lcblk之後,函數就可以調用它的成員函數retireAndLock來從它所描述的UI元數據緩沖區堆棧的待渲染隊列中取出一個緩沖區來,以便接下來可以找到對應的圖形緩沖區來渲染。
注意,調用SharedBufferServer對象lcblk的成員函數retireAndLock得到的是一個UI元數據緩沖區的編號,這個編號保存在變量buf中。函數接下來就會調用Layer類的成員變量mBufferManager所描述的一個BufferManager對象的成員函數setActiveBufferIndex來將這個編號為buf的圖形緩沖區設置當前激活的圖形緩沖區,即接下來要被SurfaceFlinger服務渲染的圖形緩沖區。前面在分析空閒UI元數據緩沖區及其圖形緩沖區的分配過程的Step 10時提到,每一個分配的圖形緩沖區都關聯有一個編號,而這個編號正好就是一個對應的UI元數據緩沖區的編號。因此,知道了一個UI元數據緩沖區的編號之後,就可以找到對應的圖形緩沖區。
函數接下來還會通過SharedBufferServer對象lcblk的成員函數getDirtyRegion、getCrop和getTransform來獲得當前激活的圖形緩沖區的元信息,即裁剪區域、紋理坐標和旋轉方向。這些元信息是在前面分析UI元數據緩沖區進入待渲染隊列的過程的Step 1中提供的,因此,這裡就可以將它們獲取回來。後面在渲染當前激活的圖形緩沖區時,就需要使用到這些元信息。
最後,函數調用SharedBufferServer對象lcblk的成員函數getQueueCount來檢查待渲染待隊列中的緩沖區的個數是否大於0。如果大於0,那麼就說明還有圖形緩沖區在等待被渲染。在這種情況下,函數就就會繼續調用Layer類的成員變量mFlinger的成員函數signalEvent來通知SurfaceFlinger服務在執行完成當前這次的Surface渲染操作之後,接著要馬上進行下一次的Surface渲染操作。
接下來,我們首先分析SharedBufferServer類的成員函數retireAndLock的實現,以便可以了解SurfaceFlinger服務是如何從一個Surface的UI元數據緩沖區堆棧的待渲染隊列中取出一個緩沖區編號的,接著再分析BufferManager類的成員函數setActiveBufferIndex的實現,以便可以了解一個圖形緩沖區是如何被設置為一個Surface的當前激活的圖形緩沖區的。
Step 5. SharedBufferServer.retireAndLock
[cpp]
ssize_t SharedBufferServer::retireAndLock()
{
RWLock::AutoRLock _l(mLock);
RetireUpdate update(this, mNumBuffers);
ssize_t buf = updateCondition( update );
if (buf >= 0) {
if (uint32_t(buf) >= SharedBufferStack::NUM_BUFFER_MAX)
return BAD_VALUE;
SharedBufferStack& stack( *mSharedStack );
buf = stack.index[buf];
LOGD_IF(DEBUG_ATOMICS && buf>=0, "retire=%d, %s",
int(buf), dump("").string());
}
return buf;
}
這個函數定義在文件frameworks/base/libs/surfaceflinger_client/SharedBufferStack.cpp中。
函數首先創建了一個RetireUpdate對象update,然後再調用SharedBufferServer從SharedBufferBase類繼承下來的成員函數updateCondition來獲得當前正在使用的UI元數據緩沖區堆棧的待渲染隊列頭部的緩沖區在堆棧中的位置值buf。有了這個位置值buf之後,函數再接下來就可以從用來描述當前正在使用的UI元數據緩沖區堆棧的一個index數組中獲得一個對應的緩沖區的編號。這個編號即為待渲染隊列頭部的UI元數據緩沖區的編號,因此,函數最後就可以將它返回給調用者。
這一步執行完成之後,就返回到Step 4中,即Layer類的成員函數lockPageFlip中,這時候SurfaceFlinger服務就可以就為當前正在處理的Surface設置當前激活的圖形緩沖區了,這是通過調用BufferManager類的成員函數setActiveBufferIndex來實現的。
Step 6. BufferManager.setActiveBufferIndex
[cpp]
status_t Layer::BufferManager::setActiveBufferIndex(size_t index) {
mActiveBuffer = index;
return NO_ERROR;
}
這個函數定義在文件frameworks/base/services/surfaceflinger/Layer.cpp中。
BufferManager類的成員變量mActiveBuffer用來描述一個Surface的當前激活的圖形緩沖區的編號。由於參數index正好就是描述一個Surface的當前激活的圖形緩沖區的編號,因此,函數就可以將它保存在BufferManager類的成員變量mActiveBuffer中。
前面在分析空閒UI元數據緩沖區及其圖形緩沖區的分配過程的Step 10時提到,BufferManager類有一個類型BufferData數組的成員變量mBufferData,它裡面保存了SurfaceFlinger服務為一個Surface所分配的圖形緩沖區,這樣,後面SurfaceFlinger服務在渲染一個Surface時,就可以通過與它所關聯的一個BufferManager對象的成員變量mActiveBuffer來在另外一個成員變量mBufferData中找到當前激活的圖形緩沖區。
這一步執行完成之後,SurfaceFlinger服務渲染Surface的圖形緩沖區的過程就分析完成了。這個過程雖然只是一個粗略的過程,但是已經足夠我們理解Android應用程序請求SurfaceFlinger服務渲染Surface的過程了,同時也為後面我們從正面分析SurfaceFlinger服務的實現原理理清了思路,以及打下了良好的基礎。
至此,Android應用程序和SurfaceFlinger服務的關系我們就學習完成了。要重新學習,請參考前面Android應用程序與SurfaceFlinger服務的關系概述和學習計劃一文。接下來,我們還會繼續分析SurfaceFlinger服務的實現原理,敬請關注!
Android TextView 改變字體主要有兩種方法: 1、Html.fromHtml 獲取一個用html格式表示的Spanned。 2、另一種方式
通過前面幾篇博客,我們能夠自定義出一些比較簡單的自定義控件,但是這在實際應用中是遠遠不夠的,為了實現一些比較牛X的效果,比如側滑菜單、滑動卡片等等,我們還需要了解自定義V
廢話不多說了,直接給大家貼代碼了。具體代碼如下所示:<?xml version=1.0 encoding=utf-8?><Relativ
Socket是基於Tcp的鏈接,適用於長鏈接Socke通訊需要客戶端和服務器,客戶端我們在android上編寫,而服務器則選擇在eclipse上編寫上效果圖;eclips