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

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/u013762045/article/details/82713744

学习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();
}

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

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

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

展开阅读全文

setCrop: SurfaceTexture has been abandoned!

04-03

04-03 11:57:39.649: WARN/InputManagerService(1806): Window already focused, ignoring focus gain of: com.android.internal.view.IInputMethodClient$Stub$Proxy@41485390rn04-03 11:57:39.669: ERROR/SurfaceTexture(1547): [SurfaceView] setCrop: SurfaceTexture has been abandoned!rn04-03 11:57:39.669: ERROR/SurfaceTextureClient(24579): ISurfaceTexture::setCrop(...) returned No such devicern04-03 11:57:39.669: ERROR/CameraHal(24579): ! setCrop error = -19 vendor/st-ericsson/hardware/libcamera/STENativeWindow.cpp:81rn04-03 11:57:39.669: ERROR/SurfaceTexture(1547): [SurfaceView] queueBuffer: SurfaceTexture has been abandoned!rn04-03 11:57:39.669: ERROR/SurfaceTextureClient(24579): queueBuffer: error queuing buffer to SurfaceTexture, -19rn04-03 11:57:39.669: ERROR/CameraHal(24579): ! enqueueBuffer error = -19 vendor/st-ericsson/hardware/libcamera/STENativeWindow.cpp:151rn04-03 11:57:39.669: ERROR/CameraHal(24579): IntIsp ! renderNativeBuffer STENativeWindow::enqueueBuffer() failed vendor/st-ericsson/hardware/libcamera/STECamera.cpp:5711rn04-03 11:57:39.669: ERROR/CameraHal(24579): IntIsp ! doPreviewProcessing renderNativebuffer failed - err = -1 vendor/st-ericsson/hardware/libcamera/STECamera.cpp:6111rn04-03 11:57:39.729: WARN/SurfaceTexture(1547): [SurfaceView] cancelBuffer: SurfaceTexture has been abandoned!rn04-03 11:57:39.729: WARN/SurfaceTexture(1547): [SurfaceView] cancelBuffer: SurfaceTexture has been abandoned!rn04-03 11:57:39.729: ERROR/SurfaceTexture(1547): [SurfaceView] setCrop: SurfaceTexture has been abandoned!rn04-03 11:57:39.729: ERROR/SurfaceTextureClient(24579): ISurfaceTexture::setCrop(...) returned No such devicern04-03 11:57:39.729: ERROR/CameraHal(24579): ! setCrop error = -19 vendor/st-ericsson/hardware/libcamera/STENativeWindow.cpp:81rn04-03 11:57:39.729: ERROR/CameraHal(24579): IntIsp ! doPreviewProcessing callback disable, err =0 vendor/st-ericsson/hardware/libcamera/STECamera.cpp:5820rn04-03 11:57:39.739: ERROR/CameraHal(24579): IntIsp ! ExifEventHandler Error detected by OMX event handler : -2147479524 (0x8000101c) - 0 (0x0) vendor/st-ericsson/hardware/libcamera/STECamera.cpp:1417rn04-03 11:57:39.860: ERROR/HtcCallback(24579): int android::HtcCallbackManager::stop(): HtcCbHandler->stop() Ern04-03 11:57:39.860: ERROR/HtcCallback(24579): int android::HtcCallbackManager::stop(): HtcCbHandler->stop() Xrnrnrn给点思路、= -、、不知道是什么引起的rnrn 论坛

没有更多推荐了,返回首页