Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 85075869 authored by Andy McFadden's avatar Andy McFadden
Browse files

Wait for buffers to drain

When a BufferQueue producer disconnects and reconnects, we retain
the previously-queued buffers but empty the slots.  This allows
the number of queued buffers to grow without limit.  The low-memory
killer does not approve.

Bug 11069934

Change-Id: Ia2eaa954c7a3904b54209a3701dba01689e204d8
parent dacd4159
Loading
Loading
Loading
Loading
+30 −17
Original line number Diff line number Diff line
@@ -644,6 +644,7 @@ status_t BufferQueue::connect(const sp<IBinder>& token,
            producerControlledByApp ? "true" : "false");
    Mutex::Autolock lock(mMutex);

retry:
    if (mAbandoned) {
        ST_LOGE("connect: BufferQueue has been abandoned!");
        return NO_INIT;
@@ -654,17 +655,30 @@ status_t BufferQueue::connect(const sp<IBinder>& token,
        return NO_INIT;
    }

    if (mConnectedApi != NO_CONNECTED_API) {
        ST_LOGE("connect: already connected (cur=%d, req=%d)",
                mConnectedApi, api);
        return -EINVAL;
    }

    // If we disconnect and reconnect quickly, we can be in a state where our slots are
    // empty but we have many buffers in the queue.  This can cause us to run out of
    // memory if we outrun the consumer.  Wait here if it looks like we have too many
    // buffers queued up.
    int maxBufferCount = getMaxBufferCountLocked(false);    // worst-case, i.e. largest value
    if (mQueue.size() > (size_t) maxBufferCount) {
        // TODO: make this bound tighter?
        ST_LOGV("queue size is %d, waiting", mQueue.size());
        mDequeueCondition.wait(mMutex);
        goto retry;
    }

    int err = NO_ERROR;
    switch (api) {
        case NATIVE_WINDOW_API_EGL:
        case NATIVE_WINDOW_API_CPU:
        case NATIVE_WINDOW_API_MEDIA:
        case NATIVE_WINDOW_API_CAMERA:
            if (mConnectedApi != NO_CONNECTED_API) {
                ST_LOGE("connect: already connected (cur=%d, req=%d)",
                        mConnectedApi, api);
                err = -EINVAL;
            } else {
            mConnectedApi = api;
            output->inflate(mDefaultWidth, mDefaultHeight, mTransformHint, mQueue.size());

@@ -678,7 +692,6 @@ status_t BufferQueue::connect(const sp<IBinder>& token,
                    ALOGE("linkToDeath failed: %s (%d)", strerror(-err), err);
                }
            }
            }
            break;
        default:
            err = -EINVAL;