学习android graphic很好的系列文章:https://blog.csdn.net/lewif/article/details/50526494
GlSurfaceview和egl的相关文章 https://blog.csdn.net/qq_32175491/article/details/80271016
https://blog.csdn.net/u012515661/article/details/55213460
https://blog.csdn.net/kerwin_ch/article/details/48441247
播放视频切换页面后返回发现surfaceview黑屏了,错误日志如下
E/BufferQueueProducer: queueBuffer: BufferQueue has been abandoned
看下日志来源
//BufferQueueProducer.cpp
status_t BufferQueueProducer::dequeueBuffer(int *outSlot,
sp<android::Fence> *outFence, bool async,
uint32_t width, uint32_t height, uint32_t format, uint32_t usage) {
ATRACE_CALL();
{ // Autolock scope
Mutex::Autolock lock(mCore->mMutex);
mConsumerName = mCore->mConsumerName;
} // Autolock scope
BQ_LOGV("dequeueBuffer: async=%s w=%u h=%u format=%#x, usage=%#x",
async ? "true" : "false", 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 scope
Mutex::Autolock lock(mCore->mMutex);
mCore->waitWhileAllocatingLocked();
if (format == 0) {
format = mCore->mDefaultBufferFormat;
}
// Enable the usage bits the consumer requested
usage |= mCore->mConsumerUsageBits;
int found;
status_t status = waitForFreeSlotThenRelock("dequeueBuffer", async,
&found, &returnFlags);
if (status != NO_ERROR) {
return status;
}
// This should not happen
if (found == BufferQueueCore::INVALID_BUFFER_SLOT) {
BQ_LOGE("dequeueBuffer: no available buffer slots");
return -EBUSY;
}
*outSlot = found;
ATRACE_BUFFER_INDEX(found);
attachedByConsumer = mSlots[found].mAttachedByConsumer;
const bool useDefaultSize = !width && !height;
if (useDefaultSize) {
width = mCore->mDefaultWidth;
height = mCore->mDefaultHeight;
}
mSlots[found].mBufferState = BufferSlot::DEQUEUED;
const sp<GraphicBuffer>& buffer(mSlots[found].mGraphicBuffer);
if ((buffer == NULL) ||
(static_cast<uint32_t>(buffer->width) != width) ||
(static_cast<uint32_t>(buffer->height) != height) ||
(static_cast<uint32_t>(buffer->format) != format) ||
((static_cast<uint32_t>(buffer->usage) & usage) != 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;
returnFlags |= BUFFER_NEEDS_REALLOCATION;
}
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;
*outFence = mSlots[found].mFence;
mSlots[found].mEglFence = EGL_NO_SYNC_KHR;
mSlots[found].mFence = Fence::NO_FENCE;
} // Autolock scope
if (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, &error));
if (graphicBuffer == NULL) {
BQ_LOGE("dequeueBuffer: createGraphicBuffer failed");
return error;
}
{ // Autolock scope
Mutex::Autolock lock(mCore->mMutex);
if (mCore->mIsAbandoned) {
BQ_LOGE("dequeueBuffer: BufferQueue has been abandoned");
return NO_INIT;
}
mSlots[*outSlot].mFrameNumber = UINT32_MAX;
mSlots[*outSlot].mGraphicBuffer = graphicBuffer;
} // Autolock scope
}
//dequeue
if (mCore->mIsAbandoned) {
BQ_LOGE("dequeueBuffer: BufferQueue has been abandoned");
return NO_INIT;
}
看看mCore->mIsAbandoned 是什么,机翻下
// mIsAbandoned indicates that the BufferQueue will no longer be used to
// consume image buffers pushed to it using the IGraphicBufferProducer
// interface. It is initialized to false, and set to true in the
// consumerDisconnect method. A BufferQueue that is abandoned will return
// the NO_INIT error from all IGraphicBufferProducer methods capable of
// returning an error.
mIsAbandoned 指示 BufferQueue 将不再用于
使用 IGraphicBufferProducerinterface将image buffers推送到BufferQueue
mIsAbandoned 被初始化为false,并在consumerDisconnect method中设置为真
被丢弃的BufferQueue 会返回 NO_INIT error,这个错误来自可以返回返回 error
的所有IGraphicBufferProducer methods
bool mIsAbandoned;
翻译不太了解,但是有关键的点 并在consumerDisconnect method中设置为真,就是说必须经过consumerDisconnect 才会设置为true。
看下consumerDisconnect
IGraphicBufferConsumer.h
// consumerDisconnect disconnects a consumer from the BufferQueue. All
// buffers will be freed and the BufferQueue is placed in the "abandoned"
// state, causing most interactions with the BufferQueue by the producer to
// fail.
//
// Return of a value other than NO_ERROR means an error has occurred:
// * BAD_VALUE - no consumer is currently connected
consumerDisconnect 将consumer 从缓冲队列中分离出来
所有BufferQueue 将被释放,BufferQueue 被放置在“abandoned”状态中。
导致生产者与BufferQueue 的大部分交互作用失败了。
除了NO_ERROR 以外的值的返回意味着发生了一个错误:
* BAD_VALUE - no消费者是当前连接
virtual status_t consumerDisconnect() = 0;
注意“所有BufferQueue 将被释放”,我们知道创建surface过程就涉及到buferr的创建,那么buffer被释放时也应当是surface被销毁了。
BufferQueueConsumer.h
virtual status_t consumerDisconnect() { return disconnect(); }
BufferQueueConsumer.cpp
status_t BufferQueueConsumer::disconnect() {
ATRACE_CALL();
BQ_LOGV("disconnect(C)");
Mutex::Autolock lock(mCore->mMutex);
if (mCore->mConsumerListener == NULL) {
BQ_LOGE("disconnect(C): no consumer is connected");
return BAD_VALUE;
}
//找到了mIsAbandoned
mCore->mIsAbandoned = true;
mCore->mConsumerListener = NULL;
mCore->mQueue.clear();
mCore->freeAllBuffersLocked();
mCore->mDequeueCondition.broadcast();
return NO_ERROR;
}
找到了mCore->mIsAbandoned = true 接下来分析consumerDisconnect是何时被调用,前面猜测是销毁surface(移除layer)的时候调用,接下来看下surfaceflinger移除layer流程
参考https://blog.csdn.net/woai110120130/article/details/79112528
void SurfaceFlinger::onMessageReceived(int32_t what) {
ATRACE_CALL();
switch (what) {
case MessageQueue::TRANSACTION: {
handleMessageTransaction();
break;
}
case MessageQueue::INVALIDATE: {
bool refreshNeeded = handleMessageTransaction();
refreshNeeded |= handleMessageInvalidate();
refreshNeeded |= mRepaintEverything;
if (refreshNeeded) {
// Signal a refresh if a transaction modified the window state,
// a new buffer was latched, or if HWC has requested a full
// repaint
signalRefresh();
}
break;
}
case MessageQueue::REFRESH: {
handleMessageRefresh();
break;
}
}
}
bool SurfaceFlinger::handleMessageTransaction() {
uint32_t transactionFlags = peekTransactionFlags(eTransactionMask);
if (transactionFlags) {
handleTransaction(transactionFlags);
return true;
}
return false;
}
void SurfaceFlinger::handleTransaction(uint32_t transactionFlags)
{
ATRACE_CALL();
// here we keep a copy of the drawing state (that is the state that's
// going to be overwritten by handleTransactionLocked()) outside of
// mStateLock so that the side-effects of the State assignment
// don't happen with mStateLock held (which can cause deadlocks).
State drawingState(mDrawingState);
Mutex::Autolock _l(mStateLock);
const nsecs_t now = systemTime();
mDebugInTransaction = now;
// Here we're guaranteed that some transaction flags are set
// so we can call handleTransactionLocked() unconditionally.
// We call getTransactionFlags(), which will also clear the flags,
// with mStateLock held to guarantee that mCurrentState won't change
// until the transaction is committed.
transactionFlags = getTransactionFlags(eTransactionMask);
handleTransactionLocked(transactionFlags);
mLastTransactionTime = systemTime() - now;
mDebugInTransaction = 0;
invalidateHwcGeometry();
// here the transaction has been committed
}
void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags)
{
//省略
commitTransaction();
updateCursorAsync();
}
void SurfaceFlinger::commitTransaction()
{
if (!mLayersPendingRemoval.isEmpty()) {
// Notify removed layers now that they can't be drawn from
for (size_t i = 0; i < mLayersPendingRemoval.size(); i++) {
mLayersPendingRemoval[i]->onRemoved();
}
mLayersPendingRemoval.clear();
}
// If this transaction is part of a window animation then the next frame
// we composite should be considered an animation as well.
mAnimCompositionPending = mAnimTransactionPending;
mDrawingState = mCurrentState;
mTransactionPending = false;
mAnimTransactionPending = false;
mTransactionCV.broadcast();
}
其实移除layer的点就在commitTransaction mLayersPendingRemoval[i]->onRemoved();调用Layer.cpp的OnRemoved
void Layer::onRemoved() {
mSurfaceFlingerConsumer->abandon();
}
void ConsumerBase::abandon() {
CB_LOGV("abandon");
Mutex::Autolock lock(mMutex);
if (!mAbandoned) {
abandonLocked();
mAbandoned = true;
}
}
void ConsumerBase::abandonLocked() {
CB_LOGV("abandonLocked");
for (int i =0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
freeBufferLocked(i);
}
// disconnect from the BufferQueue
//发现consumerDisconnect
mConsumer->consumerDisconnect();
mConsumer.clear();
}
通过以上分析我们现在知道E/BufferQueueProducer: queueBuffer: BufferQueue has been abandoned这个日志的触发条件是
1.app还在调用dequebuffer,即Mediaplayer还在作用。
2.surface的销毁,layer的移除。
那样解决方案很明了,在不使用视屏播放时必须把Mediaplayer和surface销毁,或者说surface销毁前Mediaplayer必须先销毁。