diff options
author | Andy McFadden <fadden@android.com> | 2013-10-18 15:50:24 -0700 |
---|---|---|
committer | The Android Automerger <android-build@google.com> | 2013-10-20 12:33:03 -0700 |
commit | c7852e74b946172fd9c645b73fa77e2797a52840 (patch) | |
tree | 35f0c64f7476f707770ffd3803e3438d97dfbcad | |
parent | 993da5c301ff3ac1de8f4b4425120d5183a776d9 (diff) | |
download | frameworks_native-android-4.4_r1.2.zip frameworks_native-android-4.4_r1.2.tar.gz frameworks_native-android-4.4_r1.2.tar.bz2 |
Wait for buffers to drainandroid-cts-4.4_r4android-4.4_r1.2.0.1android-4.4_r1.2android-4.4_r1.1.0.1android-4.4_r1.1android-4.4_r1.0.1android-4.4_r1android-4.4_r0.9
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
-rw-r--r-- | libs/gui/BufferQueue.cpp | 47 |
1 files changed, 30 insertions, 17 deletions
diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp index c165a68..2aecb67 100644 --- a/libs/gui/BufferQueue.cpp +++ b/libs/gui/BufferQueue.cpp @@ -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,29 +655,41 @@ 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()); - - // set-up a death notification so that we can disconnect - // automatically when/if the remote producer dies. - if (token != NULL && token->remoteBinder() != NULL) { - status_t err = token->linkToDeath(static_cast<IBinder::DeathRecipient*>(this)); - if (err == NO_ERROR) { - mConnectedProducerToken = token; - } else { - ALOGE("linkToDeath failed: %s (%d)", strerror(-err), err); - } + mConnectedApi = api; + output->inflate(mDefaultWidth, mDefaultHeight, mTransformHint, mQueue.size()); + + // set-up a death notification so that we can disconnect + // automatically when/if the remote producer dies. + if (token != NULL && token->remoteBinder() != NULL) { + status_t err = token->linkToDeath(static_cast<IBinder::DeathRecipient*>(this)); + if (err == NO_ERROR) { + mConnectedProducerToken = token; + } else { + ALOGE("linkToDeath failed: %s (%d)", strerror(-err), err); } } break; |