在Android中,BufferQueue是Surface实现本地窗口的关键,驻留在SurfaceFlinger进程中进行服务,下面从BufferQueue的结构开始分析。

1、BufferQueue模式

BufferQueue相关的源码在frameworks/native/libs/gui/,涉及以下几个重要的数据结构:

class BufferQueue;
class BufferQueueCore;
class BufferQueueProducer;
class BufferQueueConsumer;

BufferQueue属于典型的生产者-消费者模式,还有个表示buffer状态的BufferState,共五种状态,分别为FREE、DEQUEUED、QUEUED、ACQUIRED和SHARED。FREE表示buffer可以被Producer进行dequeue,此时buffer属于BufferQueue,当dequeue buffer时,状态变为DEQUEUED;DEQUEUED表示buffer已经被Producer dequeued,但还没有被queued和canceled,当收到相关的release fence通知时,Producer还可以修改buffer的数据,此时buffer属于Producer,当queue或attach buffer时,状态变为QUEUED,当cancel或detach buffer时,状态又变回FREE;QUEUED表示Producer填充了buffer且被Consumer queued,buffer数据仍有可能被修改,与fence信号相关,此时buffer属于BufferQueue,当acquire buffer时,状态变为ACQUIRED,当其它的异步buffer变为QUEUED时,这个buffer则变为FREE;ACQUIRED表示buffer被Consumer acquired,buffer数据仍有可能被修改,与fence信号相关,此时buffer属于Consumer,当release或detach buffer时,状态变为FREE,如果buffer datach后又进行了attach,其状态又会变为ACQUIRED;SHARED表示buffer为共享模式,同时可以是除FREE之外的其它任何状态,还可以被多次dequeud、queued和acquired。

在buffer的几个状态中,涉及Producer和Consumer,而它们的交互必须通过BufferQueue这个管理者或中介才能完成。Producer一般为应用程序,会不断地给buffer填充数据,不过首先要向BufferQueue进行dequeue以申请一块buffer,此时buffer为其所有,填充好数据之后再向BufferQueue进行queue,把控制权还给BufferQueue,这些操作都是由Producer主动发起的。而Consumer是被动的,当buffer数据准备好后才被通知进行消费,这个通知是被BufferQueue发起的,BufferQueue就是一个服务机构,其内部有个ProxyConsumerListener,当buffer数据就绪后就会通知Consumer进行消费。

2、BufferQueue缓冲分配过程

全局上下并无BufferQueue实例,只是声明了private BufferQueue构造函数而没有实现,其实也用不到,通过其static函数createBufferQueue实现,分别创建了BufferQueueCore、BufferQueueProducer和BufferQueueConsumer,其中BufferQueueCore作为参数传给了BufferQueueProducer和BufferQueueConsumer,如下所示:

void BufferQueue::createBufferQueue(sp<IGraphicBufferProducer>* outProducer,sp<IGraphicBufferConsumer>* outConsumer,const sp<IGraphicBufferAlloc>& allocator) {LOG_ALWAYS_FATAL_IF(outProducer == NULL,"BufferQueue: outProducer must not be NULL");LOG_ALWAYS_FATAL_IF(outConsumer == NULL,"BufferQueue: outConsumer must not be NULL");sp<BufferQueueCore> core(new BufferQueueCore(allocator));LOG_ALWAYS_FATAL_IF(core == NULL,"BufferQueue: failed to create BufferQueueCore");sp<IGraphicBufferProducer> producer(new BufferQueueProducer(core));LOG_ALWAYS_FATAL_IF(producer == NULL,"BufferQueue: failed to create BufferQueueProducer");sp<IGraphicBufferConsumer> consumer(new BufferQueueConsumer(core));LOG_ALWAYS_FATAL_IF(consumer == NULL,"BufferQueue: failed to create BufferQueueConsumer");*outProducer = producer;*outConsumer = consumer;
}

BufferQueueCore是管理BufferQueue的核心类,有如下两个重要的成员变量,mAllocator与SurfaceFlinger关联,用来创建GraphicBuffer,mSlots用于存储buffer数据,支持64个buffer,其中的BufferSlot存储了GraphicBuffer和BufferState。

sp<IGraphicBufferAlloc> mAllocator;
BufferQueueDefs::SlotsType mSlots;
namespace BufferQueueDefs {enum { NUM_BUFFER_SLOTS = 64 };typedef BufferSlot SlotsType[NUM_BUFFER_SLOTS];
}
struct BufferSlot {BufferSlot(): mGraphicBuffer(nullptr),mEglDisplay(EGL_NO_DISPLAY),mBufferState(),mRequestBufferCalled(false),mFrameNumber(0),mEglFence(EGL_NO_SYNC_KHR),mFence(Fence::NO_FENCE),mAcquireCalled(false),mNeedsReallocation(false) {}sp<GraphicBuffer> mGraphicBuffer;EGLDisplay mEglDisplay;BufferState mBufferState;bool mRequestBufferCalled;uint64_t mFrameNumber;EGLSyncKHR mEglFence;sp<Fence> mFence;bool mAcquireCalled;bool mNeedsReallocation;
};

上面提到了buffer分配由生产者发起,即BufferQueueProducer的deququeBuffer操作,函数原型如下:

status_t BufferQueueProducer::dequeueBuffer(int *outSlot,sp<android::Fence> *outFence, uint32_t width, uint32_t height,PixelFormat format, uint32_t usage) {ATRACE_CALL();{ // Autolock scopeMutex::Autolock lock(mCore->mMutex);mConsumerName = mCore->mConsumerName;if (mCore->mIsAbandoned) {BQ_LOGE("dequeueBuffer: BufferQueue has been abandoned");return NO_INIT;}if (mCore->mConnectedApi == BufferQueueCore::NO_CONNECTED_API) {BQ_LOGE("dequeueBuffer: BufferQueue has no connected producer");return NO_INIT;}} // Autolock scopeBQ_LOGV("dequeueBuffer: w=%u h=%u format=%#x, usage=%#x", width, height,format, usage);if ((width && !height) || (!width && height)) {BQ_LOGE("dequeueBuffer: invalid size: w=%u h=%u", width, height);return BAD_VALUE;}status_t returnFlags = NO_ERROR;EGLDisplay eglDisplay = EGL_NO_DISPLAY;EGLSyncKHR eglFence = EGL_NO_SYNC_KHR;bool attachedByConsumer = false;{ // Autolock scopeMutex::Autolock lock(mCore->mMutex);mCore->waitWhileAllocatingLocked();if (format == 0) {format = mCore->mDefaultBufferFormat;}// Enable the usage bits the consumer requestedusage |= mCore->mConsumerUsageBits;const bool useDefaultSize = !width && !height;if (useDefaultSize) {width = mCore->mDefaultWidth;height = mCore->mDefaultHeight;}int found = BufferItem::INVALID_BUFFER_SLOT;while (found == BufferItem::INVALID_BUFFER_SLOT) {status_t status = waitForFreeSlotThenRelock(FreeSlotCaller::Dequeue,&found);if (status != NO_ERROR) {return status;}// This should not happenif (found == BufferQueueCore::INVALID_BUFFER_SLOT) {BQ_LOGE("dequeueBuffer: no available buffer slots");return -EBUSY;}const sp<GraphicBuffer>& buffer(mSlots[found].mGraphicBuffer);// If we are not allowed to allocate new buffers,// waitForFreeSlotThenRelock must have returned a slot containing a// buffer. If this buffer would require reallocation to meet the// requested attributes, we free it and attempt to get another one.if (!mCore->mAllowAllocation) {if (buffer->needsReallocation(width, height, format, usage)) {if (mCore->mSharedBufferSlot == found) {BQ_LOGE("dequeueBuffer: cannot re-allocate a shared""buffer");return BAD_VALUE;}mCore->mFreeSlots.insert(found);mCore->clearBufferSlotLocked(found);found = BufferItem::INVALID_BUFFER_SLOT;continue;}}}const sp<GraphicBuffer>& buffer(mSlots[found].mGraphicBuffer);if (mCore->mSharedBufferSlot == found &&buffer->needsReallocation(width,  height, format, usage)) {BQ_LOGE("dequeueBuffer: cannot re-allocate a shared""buffer");return BAD_VALUE;}if (mCore->mSharedBufferSlot != found) {mCore->mActiveBuffers.insert(found);}*outSlot = found;ATRACE_BUFFER_INDEX(found);attachedByConsumer = mSlots[found].mNeedsReallocation;mSlots[found].mNeedsReallocation = false;mSlots[found].mBufferState.dequeue();if ((buffer == NULL) ||buffer->needsReallocation(width, height, format, usage)){mSlots[found].mAcquireCalled = false;mSlots[found].mGraphicBuffer = NULL;mSlots[found].mRequestBufferCalled = false;mSlots[found].mEglDisplay = EGL_NO_DISPLAY;mSlots[found].mEglFence = EGL_NO_SYNC_KHR;mSlots[found].mFence = Fence::NO_FENCE;mCore->mBufferAge = 0;mCore->mIsAllocating = true;returnFlags |= BUFFER_NEEDS_REALLOCATION;} else {// We add 1 because that will be the frame number when this buffer// is queuedmCore->mBufferAge =mCore->mFrameCounter + 1 - mSlots[found].mFrameNumber;}BQ_LOGV("dequeueBuffer: setting buffer age to %" PRIu64,mCore->mBufferAge);if (CC_UNLIKELY(mSlots[found].mFence == NULL)) {BQ_LOGE("dequeueBuffer: about to return a NULL fence - ""slot=%d w=%d h=%d format=%u",found, buffer->width, buffer->height, buffer->format);}eglDisplay = mSlots[found].mEglDisplay;eglFence = mSlots[found].mEglFence;// Don't return a fence in shared buffer mode, except for the first// frame.*outFence = (mCore->mSharedBufferMode &&mCore->mSharedBufferSlot == found) ?Fence::NO_FENCE : mSlots[found].mFence;mSlots[found].mEglFence = EGL_NO_SYNC_KHR;mSlots[found].mFence = Fence::NO_FENCE;// If shared buffer mode has just been enabled, cache the slot of the// first buffer that is dequeued and mark it as the shared buffer.if (mCore->mSharedBufferMode && mCore->mSharedBufferSlot ==BufferQueueCore::INVALID_BUFFER_SLOT) {mCore->mSharedBufferSlot = found;mSlots[found].mBufferState.mShared = true;}} // Autolock scopeif (returnFlags & BUFFER_NEEDS_REALLOCATION) {status_t error;BQ_LOGV("dequeueBuffer: allocating a new buffer for slot %d", *outSlot);sp<GraphicBuffer> graphicBuffer(mCore->mAllocator->createGraphicBuffer(width, height, format, usage,{mConsumerName.string(), mConsumerName.size()}, &error));{ // Autolock scopeMutex::Autolock lock(mCore->mMutex);if (graphicBuffer != NULL && !mCore->mIsAbandoned) {graphicBuffer->setGenerationNumber(mCore->mGenerationNumber);mSlots[*outSlot].mGraphicBuffer = graphicBuffer;}mCore->mIsAllocating = false;mCore->mIsAllocatingCondition.broadcast();if (graphicBuffer == NULL) {mCore->mFreeSlots.insert(*outSlot);mCore->clearBufferSlotLocked(*outSlot);BQ_LOGE("dequeueBuffer: createGraphicBuffer failed");return error;}if (mCore->mIsAbandoned) {mCore->mFreeSlots.insert(*outSlot);mCore->clearBufferSlotLocked(*outSlot);BQ_LOGE("dequeueBuffer: BufferQueue has been abandoned");return NO_INIT;}VALIDATE_CONSISTENCY();} // Autolock scope}if (attachedByConsumer) {returnFlags |= BUFFER_NEEDS_REALLOCATION;}if (eglFence != EGL_NO_SYNC_KHR) {EGLint result = eglClientWaitSyncKHR(eglDisplay, eglFence, 0,1000000000);// If something goes wrong, log the error, but return the buffer without// synchronizing access to it. It's too late at this point to abort the// dequeue operation.if (result == EGL_FALSE) {BQ_LOGE("dequeueBuffer: error %#x waiting for fence",eglGetError());} else if (result == EGL_TIMEOUT_EXPIRED_KHR) {BQ_LOGE("dequeueBuffer: timeout waiting for fence");}eglDestroySyncKHR(eglDisplay, eglFence);}BQ_LOGV("dequeueBuffer: returning slot=%d/%" PRIu64 " buf=%p flags=%#x",*outSlot,mSlots[*outSlot].mFrameNumber,mSlots[*outSlot].mGraphicBuffer->handle, returnFlags);return returnFlags;
}

deququeBuffer的目的就是给Producer申请一个可用的buffer,最终获取的是buffer slots数组索引,通过outSlot参数返回,outFence是一种同步形式,当使用Fence时,必须等待Fence信号才能修改buffer,width和height参数有一定的限制,最大值不能超过GL_MAX_VIEWPORT_DIMS和GL_MAX_TEXTURE_SIZE的最小值,这个值可通过glGetIntegerv获取,与updateTexImage有关,width和height都为0时就使用默认值1,如果其中一个为0将出错,format和usage用来指定buffer的格式和用途,format为0时使用默认的mDefaultBufferFormat,即PIXEL_FORMAT_RGBA_8888。

在deququeBuffer函数中,首先会检查BufferQueue是否可用,BufferQueue是否连接了Producer,width和height参数是否合法,失败时出错返回。然后进入while循环查找可用的buffer slot,不过在此之前还要处理一下width、height、format和usage变量,如果有其它的buffer分配操作还要等待其结束,使用的是pthread条件变量。在while循环中查找可用的buffer slot时,首先会进入waitForFreeSlotThenRelock,从名字就可以看出是用来获取FREE状态的buffer slot,同时还会统计buffer的DEQUEUEED和ACQUIRED状态的个数,不能超过限制的最大值,而且还不能频繁地disconect后马上connect,这可能会用尽内存,在等待buffer期间,是否阻塞、延时效果都将影响buffer查询结果。在获取buffer slot成功后,实际上是buffer slot的数组索引,这时还没有真正地分配内存,当我们没有权限分配新的buffer时,这一步通常会返回一个可用的buffer,但是需要注意的是,这个buffer有时候还不是最优的,还需要进行重分配,在这种清空下,这个buffer就会被free掉然后等待后面的重分配。while循环之后,若buffer需要重新分配,就通过createGraphicBuffer完成,至此,dequeueBuffer完成。

dequeueBuffer时获取到的是一个buffer slot索引,那么如何保证属于不同进程的服务端和客户端访问的是同一块内存呢,这就用到了Android中的Binder机制,涉及下面几个相关的类:

class BufferQueueProducer : public BnGraphicBufferProducer, private IBinder::DeathRecipient
class BnGraphicBufferProducer : public BnInterface<IGraphicBufferProducer>
class BpGraphicBufferProducer : public BpInterface<IGraphicBufferProducer>

下面是BpGraphicBufferProducer的dequeueBuffer实现,关键是通过remote调用transact,这时就会走到native的BnGraphicBufferProducer的onTransact。

virtual status_t dequeueBuffer(int *buf, sp<Fence>* fence, uint32_t width,uint32_t height, PixelFormat format, uint32_t usage) {Parcel data, reply;data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor());data.writeUint32(width);data.writeUint32(height);data.writeInt32(static_cast<int32_t>(format));data.writeUint32(usage);status_t result = remote()->transact(DEQUEUE_BUFFER, data, &reply);if (result != NO_ERROR) {return result;}*buf = reply.readInt32();bool nonNull = reply.readInt32();if (nonNull) {*fence = new Fence();result = reply.read(**fence);if (result != NO_ERROR) {fence->clear();return result;}}result = reply.readInt32();return result;}

下面是BnGraphicBufferProducer的onTransact的部分代码,在DEQUEUE_BUFFER时,从data获取参数,然后调用buffer生产者的dequeueBuffer,随后把结果回传到reply参数。

status_t BnGraphicBufferProducer::onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{switch(code) {case DEQUEUE_BUFFER: {CHECK_INTERFACE(IGraphicBufferProducer, data, reply);uint32_t width = data.readUint32();uint32_t height = data.readUint32();PixelFormat format = static_cast<PixelFormat>(data.readInt32());uint32_t usage = data.readUint32();int buf = 0;sp<Fence> fence;int result = dequeueBuffer(&buf, &fence, width, height, format,usage);reply->writeInt32(buf);reply->writeInt32(fence != NULL);if (fence != NULL) {reply->write(*fence);}reply->writeInt32(result);return NO_ERROR;}}return BBinder::onTransact(code, data, reply, flags);
}

在IGraphicBufferProducer中,还有两个struct,QueueBufferInput和QueueBufferOutput如下所示,其中QueueBufferInput使用了Flattenable协议,用于对一个对象即buffer进形数字化。

struct QueueBufferInput : public Flattenable<QueueBufferInput>
struct QueueBufferOutput

3、应用程序与BufferQueue

前面介绍了BufferQueue的基本原理,那么它是如何与应用程序联系起来的呢?以frameworks/base/cmds/bootanimation/这个系统开机动画为例,bootanimation和SurfaceFlinger都是使用OpenGL ES来完成UI显示的,当一个Android设备上电后,可能会显示几个不同的开机画面,如BootLoader画面、Kernel画面、Android画面等,bootanim.rc启动脚本内容如下:

service bootanim /system/bin/bootanimationclass coreuser graphicsgroup graphics audiodisabledoneshotwritepid /dev/stune/top-app/tasks

bootanimation启动后,首先进入如下的main函数,通过属性debug.sf.nobootanimation判断有无启动动画,有动画时,启动一个线程池,然后创建一个BootAnimation对象并加入线程池。

int main()
{setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_DISPLAY);char value[PROPERTY_VALUE_MAX];property_get("debug.sf.nobootanimation", value, "0");int noBootAnimation = atoi(value);ALOGI_IF(noBootAnimation,  "boot animation disabled");if (!noBootAnimation) {sp<ProcessState> proc(ProcessState::self());ProcessState::self()->startThreadPool();// create the boot animation objectsp<BootAnimation> boot = new BootAnimation();IPCThreadState::self()->joinThreadPool();}return 0;
}

BootAnimation是启动动画的实现类,继承了Thread和Binder,在构造函数中创建了SurfaceComposerClient对象,即mSession,从而建立与SurfaceFlinger的连接通道,而前面提到的IGraphicBufferProducer则是应用程序与BufferQueue的传输通道,BufferQueue负责每个应用程序的绘画过程,SurfaceFlinger把所有应用程序的最终绘图结果混合后统一显示到物理屏幕上。

class BootAnimation : public Thread, public IBinder::DeathRecipientBootAnimation::BootAnimation() : Thread(false), mClockEnabled(true), mTimeIsAccurate(false),mTimeCheckThread(NULL) {mSession = new SurfaceComposerClient();// If the system has already booted, the animation is not being used for a boot.mSystemBoot = !property_get_bool(BOOT_COMPLETED_PROP_NAME, 0);
}

BootAnimation继承子RefBase,当其指针被第一次引用时触发onFirstRef函数,与远程Binder服务建立连接后还要处理Binder服务挂掉的清空,通过重装binderDied函数完成,然后调用run启动BootAnimation线程。

void BootAnimation::onFirstRef() {status_t err = mSession->linkToComposerDeath(this);ALOGE_IF(err, "linkToComposerDeath failed (%s) ", strerror(-err));if (err == NO_ERROR) {run("BootAnimation", PRIORITY_DISPLAY);}
}void BootAnimation::binderDied(const wp<IBinder>&)
{// woah, surfaceflinger died!ALOGD("SurfaceFlinger died, exiting...");// calling requestExit() is not enough here because the Surface code// might be blocked on a condition variable that will never be updated.kill( getpid(), SIGKILL );requestExit();audioplay::destroy();
}

接下来便是readyToRun,关键两步是通过SurfaceComposerClient创建buffer和EGL配置,如下代码所示:

status_t BootAnimation::readyToRun() {mAssets.addDefaultAssets();sp<IBinder> dtoken(SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));DisplayInfo dinfo;status_t status = SurfaceComposerClient::getDisplayInfo(dtoken, &dinfo);if (status)return -1;// create the native surfacesp<SurfaceControl> control = session()->createSurface(String8("BootAnimation"),dinfo.w, dinfo.h, PIXEL_FORMAT_RGB_565);SurfaceComposerClient::openGlobalTransaction();control->setLayer(0x40000000);SurfaceComposerClient::closeGlobalTransaction();sp<Surface> s = control->getSurface();// initialize opengl and eglconst EGLint attribs[] = {EGL_RED_SIZE,   8,EGL_GREEN_SIZE, 8,EGL_BLUE_SIZE,  8,EGL_DEPTH_SIZE, 0,EGL_NONE};EGLint w, h;EGLint numConfigs;EGLConfig config;EGLSurface surface;EGLContext context;EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);eglInitialize(display, 0, 0);eglChooseConfig(display, attribs, &config, 1, &numConfigs);surface = eglCreateWindowSurface(display, config, s.get(), NULL);context = eglCreateContext(display, config, NULL, NULL);eglQuerySurface(display, surface, EGL_WIDTH, &w);eglQuerySurface(display, surface, EGL_HEIGHT, &h);if (eglMakeCurrent(display, surface, surface, context) == EGL_FALSE)return NO_INIT;mDisplay = display;mContext = context;mSurface = surface;mWidth = w;mHeight = h;mFlingerSurfaceControl = control;mFlingerSurface = s;// If the device has encryption turned on or is in process// of being encrypted we show the encrypted boot animation.char decrypt[PROPERTY_VALUE_MAX];property_get("vold.decrypt", decrypt, "");bool encryptedAnimation = atoi(decrypt) != 0 || !strcmp("trigger_restart_min_framework", decrypt);if (encryptedAnimation && (access(SYSTEM_ENCRYPTED_BOOTANIMATION_FILE, R_OK) == 0)) {mZipFileName = SYSTEM_ENCRYPTED_BOOTANIMATION_FILE;}else if (access(OEM_BOOTANIMATION_FILE, R_OK) == 0) {mZipFileName = OEM_BOOTANIMATION_FILE;}else if (access(SYSTEM_BOOTANIMATION_FILE, R_OK) == 0) {mZipFileName = SYSTEM_BOOTANIMATION_FILE;}return NO_ERROR;
}

SurfaceComposerClient的createSurface,在SurfaceFlinger端的实现便是Client中的createSurface,如下:

status_t Client::createSurface(const String8& name,uint32_t w, uint32_t h, PixelFormat format, uint32_t flags,sp<IBinder>* handle,sp<IGraphicBufferProducer>* gbp)
{/** createSurface must be called from the GL thread so that it can* have access to the GL context.*/class MessageCreateLayer : public MessageBase {SurfaceFlinger* flinger;Client* client;sp<IBinder>* handle;sp<IGraphicBufferProducer>* gbp;status_t result;const String8& name;uint32_t w, h;PixelFormat format;uint32_t flags;public:MessageCreateLayer(SurfaceFlinger* flinger,const String8& name, Client* client,uint32_t w, uint32_t h, PixelFormat format, uint32_t flags,sp<IBinder>* handle,sp<IGraphicBufferProducer>* gbp): flinger(flinger), client(client),handle(handle), gbp(gbp), result(NO_ERROR),name(name), w(w), h(h), format(format), flags(flags) {}status_t getResult() const { return result; }virtual bool handler() {result = flinger->createLayer(name, client, w, h, format, flags,handle, gbp);return true;}};sp<MessageBase> msg = new MessageCreateLayer(mFlinger.get(),name, this, w, h, format, flags, handle, gbp);mFlinger->postMessageSync(msg);return static_cast<MessageCreateLayer*>( msg.get() )->getResult();
}

Client::createSurface中,以同步方式把消息post到SurfaceFlinger,期间还创建了Layer,如下的createNormalLayer:

status_t SurfaceFlinger::createLayer(const String8& name,const sp<Client>& client,uint32_t w, uint32_t h, PixelFormat format, uint32_t flags,sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp)
{//ALOGD("createLayer for (%d x %d), name=%s", w, h, name.string());if (int32_t(w|h) < 0) {ALOGE("createLayer() failed, w or h is negative (w=%d, h=%d)",int(w), int(h));return BAD_VALUE;}status_t result = NO_ERROR;sp<Layer> layer;switch (flags & ISurfaceComposerClient::eFXSurfaceMask) {case ISurfaceComposerClient::eFXSurfaceNormal:result = createNormalLayer(client,name, w, h, flags, format,handle, gbp, &layer);break;case ISurfaceComposerClient::eFXSurfaceDim:result = createDimLayer(client,name, w, h, flags,handle, gbp, &layer);break;default:result = BAD_VALUE;break;}if (result != NO_ERROR) {return result;}result = addClientLayer(client, *handle, *gbp, layer);if (result != NO_ERROR) {return result;}setTransactionFlags(eTransactionNeeded);return result;
}

从SurfaceFlinger::createNormalLayer可以看出,在这里真正的创建了一个Layer对象,同时创建了BufferQueue和SurfaceFlingerConsumer以及MonitorProducer,这样Buffer中介、生产者、消费者创建完成,Layer就像是许多画面中的一层,最后通过SurfaceFlinger进行处理以显示到屏幕上。

status_t SurfaceFlinger::createNormalLayer(const sp<Client>& client,const String8& name, uint32_t w, uint32_t h, uint32_t flags, PixelFormat& format,sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp, sp<Layer>* outLayer)
{// initialize the surfacesswitch (format) {case PIXEL_FORMAT_TRANSPARENT:case PIXEL_FORMAT_TRANSLUCENT:format = PIXEL_FORMAT_RGBA_8888;break;case PIXEL_FORMAT_OPAQUE:format = PIXEL_FORMAT_RGBX_8888;break;}*outLayer = new Layer(this, client, name, w, h, flags);status_t err = (*outLayer)->setBuffers(w, h, format, flags);if (err == NO_ERROR) {*handle = (*outLayer)->getHandle();*gbp = (*outLayer)->getProducer();}ALOGE_IF(err, "createNormalLayer() failed (%s)", strerror(-err));return err;
}

至此,buffer创建完成,EGL配置完成,然后进入threadLoop,接着可能为android或movie,里面全是一些OpenGL操作以显示动画,最后通过EGL释放资源,退出线程池。

bool BootAnimation::threadLoop()
{bool r;// We have no bootanimation file, so we use the stock android logo// animation.if (mZipFileName.isEmpty()) {r = android();} else {r = movie();}eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);eglDestroyContext(mDisplay, mContext);eglDestroySurface(mDisplay, mSurface);mFlingerSurface.clear();mFlingerSurfaceControl.clear();eglTerminate(mDisplay);eglReleaseThread();IPCThreadState::self()->stopProcess();return r;
}

【Android】Android SurfaceFlinger之BufferQueue相关推荐

  1. c语言调用android surface,Android GUI SurfaceFlinger

    本文涉及的源代码基于 Android-7.1.1r. 一.Android GUI 框架 SurfaceFlinger 是 Android GUI 的核心,但是从 OpenGL_ES 的角度来看,它也只 ...

  2. 图解Android - Android GUI 系统 (2) - 窗口管理 (View, Canvas, Window Manager)

    Android 的窗口管理系统 (View, Canvas, WindowManager) 在图解Android - Zygote 和 System Server 启动分析一 文里,我们已经知道And ...

  3. 图解Android - Android GUI 系统 (1) - 概论

    http://www.cnblogs.com/samchen2009/p/3364327.html Android的GUI系统是Android最重要也最复杂的系统之一.它包括以下部分: 窗口和图形系统 ...

  4. Android - Android Studio 解决访问被墙的问题

    Android - Android Studio 解决访问被墙的问题 参考文章: (1)Android - Android Studio 解决访问被墙的问题 (2)https://www.cnblog ...

  5. OpenCV2.4.9 For Android + Android Studio (with gradle)配置教程

    OpenCV2.4.9 For Android + Android Studio (with gradle)配置教程 10 回复 / 9501 浏览 本页底部本帖地址 4king2 年前 - 2014 ...

  6. [Android]Android端ORM框架——RapidORM(v2.1)

    以下内容为原创,欢迎转载,转载请注明 来自天天博客:http://www.cnblogs.com/tiantianbyconan/p/6020412.html [Android]Android端ORM ...

  7. [Android] Android开发优化之——使用软引用和弱引用

    Java从JDK1.2版本开始,就把对象的引用分为四种级别,从而使程序能更加灵活的控制对象的生命周期.这四种级别由高到低依次为:强引用.软引用.弱引用和虚引用. 这里重点介绍一下软引用和弱引用. 如 ...

  8. android Android项目构建过程

    今天,简单讲讲android studio如何把写好的工程打包成apk的. 平时开发过程中我们通过android studio编写完成android项目之后直接点击 Run 'app'就可以在buil ...

  9. android抽屉屏幕右滑,android - Android - 使滑动抽屉从左向右滑动 - 堆栈内存溢出...

    我使用下面的XML布局在我的应用程序中实现了"Sliding Drawer":(我从androidpeople.com得到了这个例子) android:layout_width=& ...

  10. [Android]Android四大组件之Service总结

    一.Service介绍 Service是Android中实现程序后台运行的解决方案,它非常适合用于去执行那些不需要和用户交互而且还要长期运行的task.Service的运行不需要依赖于任何用户界面,即 ...

最新文章

  1. javascript编译与运行机理(1)--
  2. MySQL 笔记7 -- 权限操作与视图
  3. Linux下安装部署ElasticSearch教程【7.10.1】
  4. [CentOS Python系列] 三.阿里云MySQL数据库开启配置及SQL语句基础知识
  5. flyme禁止系统更新_魅族Flyme更新8.1.2.3A:重要系统更新!
  6. 特斯拉上海超级工厂汽车年产量已达到45万辆
  7. H3C iMC PLAT 安装部署相关问题及解决方法1
  8. Bailian3713 外星人翻译用数字转换模块【递归+映射】
  9. 【C++笔记】对象模型和this指针
  10. RPC框架的实现原理是什么?-开课吧
  11. 【电脑讲解】压缩包的使用技巧
  12. CFAR检测MATLAB仿真
  13. 微信上老师发的试卷怎样打印?
  14. 配置静态路由使用下一跳IP地址和使用出接口的区别
  15. html个人所得税计算器,上海个人所得税计算器_个税计算器_税后工资计算器
  16. 两种方法在Qt中使用OpenGL库加载stl三维模型
  17. 美国高防服务器:恒讯科技为您解答TCP/IP的攻击原理
  18. IT项目开发团队建设与管理总结
  19. JAVA 关于hasNext的白话理解
  20. 对于十进制转化为任意进制数的简单算法分析

热门文章

  1. Talk to AI,揭秘背后的语音识别数据
  2. 【APICloud系列|31】成功上架5个应用商店总结(腾讯应用宝、阿里应用分发平台、华为开发者联盟、小米开放平台、百度开放平台)
  3. Django—CRM项目练习
  4. 【获奖案例巡展】信创先锋之星——云上贵州信创工程中心大数据中台
  5. 使用c语言编程首先要新建,【C语言编程入门系列】—— 第三章,编写第一个C语言程序!...
  6. 制作的excel表格如何放到微信公众平台文章中?
  7. 不能撑开盒子css,CSS padding在什么情况下不撑开盒子
  8. LaTeX入门学习(2)(安装)
  9. Win10计算机窗口空白,windows10语言栏丢失怎么办?win10语言栏显示空白的解决办法...
  10. 数字图像处理:局部直方图处理(Local Histogram Processing)