学习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 scopeMutex::Autolock lock(mCore->mMutex);mConsumerName = mCore->mConsumerName;} // Autolock scopeBQ_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 scopeMutex::Autolock lock(mCore->mMutex);mCore->waitWhileAllocatingLocked();if (format == 0) {format = mCore->mDefaultBufferFormat;}// Enable the usage bits the consumer requestedusage |= mCore->mConsumerUsageBits;int found;status_t status = waitForFreeSlotThenRelock("dequeueBuffer", async,&found, &returnFlags);if (status != NO_ERROR) {return status;}// This should not happenif (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 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, &error));if (graphicBuffer == NULL) {BQ_LOGE("dequeueBuffer: createGraphicBuffer failed");return error;}{ // Autolock scopeMutex::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// repaintsignalRefresh();}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 fromfor (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();
}

//ConsumerBase.cpp

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//发现consumerDisconnectmConsumer->consumerDisconnect();mConsumer.clear();
}

通过以上分析我们现在知道E/BufferQueueProducer: queueBuffer: BufferQueue has been abandoned这个日志的触发条件是
1.app还在调用dequebuffer,即Mediaplayer还在作用。
2.surface的销毁,layer的移除。

那样解决方案很明了,在不使用视屏播放时必须把Mediaplayer和surface销毁,或者说surface销毁前Mediaplayer必须先销毁。

安卓框架,分析项目中surfaceFlinger出现的bug ---queueBuffer: BufferQueue has been abandoned相关推荐

  1. prism项目搭建 wpf_WPF Step By Step 系列-Prism框架在项目中使用

    Prism是一个强大的Mvvm框架,下面我们将重点讲解如何在项目使用Prism提供的基础功能,完成基于MVVM的WPF项目的框架设计和开发,包括应用程序的架构. 项目的解决方案结构,项目采用Prism ...

  2. Shiro框架在项目中的应用

    1.Shiro 框架简介 Shiro 概述 Shiro 是Apache公司推出一个权限管理框架,其内部封装了项目中认证,授权,加密,会话等逻辑操作,通过Shiro框架可以简化我们项目权限控制逻辑的代码 ...

  3. 如何在安卓(Android studio)项目中导入模块、jar包、和aar包

    安卓(Android studio)编程中,我们常需要引用"别人写的功能",以扩展app的功能,"别人写的功能"主要有模块.jar包.和aar包三种方式. 下面 ...

  4. 如何分析项目中的数据库

    开发工具与关键技术:SQL 数据库分析 作者:微凉之夏 撰写日期:2019年06月03日 我想当你们大家刚拿到项目时,所看到的都是一个文档类型的文件,里面只有图片和文字说明,我不知道大家刚拿到项目的想 ...

  5. ssm框架的项目中用户图片的上传功能

    后台管理的web项目中,需要完成图片的上传功能 工具准备:一.图片上传的必要JS文件:二:当前页面中JS重写提交图片的方法:三.后台接收和处理图片的方法 整体思路:一.HTML中添加文件上传按钮: 二 ...

  6. 2021年C++项目中的十大Bug:乍一看都正确的代码,实则暗藏玄机

    作者 | Vladislav Stolyarov 译者 | 弯月 出品 | CSDN(ID:CSDNnews) 在程序员的新年祝福中,大家或多或少会来一句,新年编码无Bug.Bug越写越少--对程序员 ...

  7. SLF4J日志框架在项目中使用

    介绍 SLF4J全称"Simple Logging Facade for Java",作为各种日志框架的简单门面.例如: java.util.logging.logback . r ...

  8. 安卓:Android项目中三种依赖的添加方式

    添加本地依赖 首先将所需的 jar 或者 aar 包放在libs文件夹下. 方式1(适合jar) 右击jar包,选择Add As Library,最后sync. 方式2 (适合jar 和 aar) 在 ...

  9. 前端项目中碰到的难题bug

    1.this.parent或者是this.parent或者是 this.parent或者是this.children 这种方式获取与传递数据十分不妥, 因为没有明确数据来源与使用者, 这样就会导致除了 ...

最新文章

  1. 祝大家春节快乐身体健康
  2. struts2漏洞监测_Apache Shiro身份验证绕过漏洞风险提示
  3. Redis的两种持久化机制RDB和AOF
  4. Git 分支管理策略
  5. api报错 javaee maven_JavaEE关于Maven的配置与学习
  6. vue 鼠标点击事件_VBA代码解决方案第115讲:点击鼠标实现精准控制触发事件的VBA代码第二方案...
  7. mysql 1607_Windows下Mysql启动“服务名无效”及“系统错误1607”解决办法
  8. LeetCode刷题(21)
  9. 玩Elastix遇到的几个问题和解决办法。
  10. 基于node搭建前端服务器,nodejs做微信小程序后端
  11. 小学英语语法口诀巧记大全,简单实用!
  12. 人在囧途之tar命令
  13. VO,DTO,PO 的个人见解
  14. 创建Chinaskills20为GPO管理员;加入到企业管理、域控管理员组;
  15. ARP代理(Proxy ARP)
  16. 计算方法(二):n次多项式插值
  17. Qt网络编程——get请求
  18. html5鼠标经过图片切换,JS实现鼠标移入移出控制图片的切换效果
  19. C/C++:写代码时将数组放在main函数里面还是外面的区别
  20. AUTOSAR-RS-BSWAndRTEFeatures(中文版)

热门文章

  1. 关于linux上运行ONS
  2. 来自Google持续更新中的TCP BBR v2.0最新进展
  3. rustup 慢_Rust真的比C慢吗?进一步分析queen微测评
  4. 姿态检测 树莓派_基于深度学习的树莓派老人摔倒检测系统的制作方法
  5. 解决AndroidStudio编译时报错:org.gradle.api.ProjectConfigurationException;编译报错Read Time out
  6. OIM Training Lab 1
  7. 计算机毕业设计java+ssm车辆租赁网站(源码+系统+mysql数据库+Lw文档)
  8. codeforces1437C. Chef Monocarp
  9. java请输入三个成绩 求平均分_Java编程,定义一个学生类,输入3个学生数据,输出平均分和总分...
  10. 我是这样理解HTTPS的