1 /*
2 * Copyright 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #define LOG_TAG "BufferQueueCore"
18 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
19 //#define LOG_NDEBUG 0
20
21 #define EGL_EGLEXT_PROTOTYPES
22
23 #if DEBUG_ONLY_CODE
24 #define VALIDATE_CONSISTENCY() do { validateConsistencyLocked(); } while (0)
25 #else
26 #define VALIDATE_CONSISTENCY()
27 #endif
28
29 #include <inttypes.h>
30
31 #include <cutils/atomic.h>
32
33 #include <gui/BufferItem.h>
34 #include <gui/BufferQueueCore.h>
35 #include <gui/IConsumerListener.h>
36 #include <gui/IProducerListener.h>
37 #include <private/gui/ComposerService.h>
38
39 #include <system/window.h>
40
41 namespace android {
42
43 // Macros for include BufferQueueCore information in log messages
44 #define BQ_LOGV(x, ...) \
45 ALOGV("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.c_str(), mUniqueId, \
46 mConnectedApi, mConnectedPid, mUniqueId >> 32, ##__VA_ARGS__)
47 #define BQ_LOGD(x, ...) \
48 ALOGD("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.c_str(), mUniqueId, \
49 mConnectedApi, mConnectedPid, mUniqueId >> 32, ##__VA_ARGS__)
50 #define BQ_LOGI(x, ...) \
51 ALOGI("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.c_str(), mUniqueId, \
52 mConnectedApi, mConnectedPid, mUniqueId >> 32, ##__VA_ARGS__)
53 #define BQ_LOGW(x, ...) \
54 ALOGW("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.c_str(), mUniqueId, \
55 mConnectedApi, mConnectedPid, mUniqueId >> 32, ##__VA_ARGS__)
56 #define BQ_LOGE(x, ...) \
57 ALOGE("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.c_str(), mUniqueId, \
58 mConnectedApi, mConnectedPid, mUniqueId >> 32, ##__VA_ARGS__)
59
getUniqueName()60 static String8 getUniqueName() {
61 static volatile int32_t counter = 0;
62 return String8::format("unnamed-%d-%d", getpid(),
63 android_atomic_inc(&counter));
64 }
65
getUniqueId()66 static uint64_t getUniqueId() {
67 static std::atomic<uint32_t> counter{0};
68 static uint64_t id = static_cast<uint64_t>(getpid()) << 32;
69 return id | counter++;
70 }
71
getProcessName(int pid,String8 & name)72 static status_t getProcessName(int pid, String8& name) {
73 FILE* fp = fopen(String8::format("/proc/%d/cmdline", pid), "r");
74 if (NULL != fp) {
75 const size_t size = 64;
76 char proc_name[size];
77 char* result = fgets(proc_name, size, fp);
78 fclose(fp);
79 if (result != nullptr) {
80 name = proc_name;
81 return NO_ERROR;
82 }
83 }
84 return INVALID_OPERATION;
85 }
86
BufferQueueCore()87 BufferQueueCore::BufferQueueCore()
88 : mMutex(),
89 mIsAbandoned(false),
90 mConsumerControlledByApp(false),
91 mConsumerName(getUniqueName()),
92 mConsumerListener(),
93 mConsumerUsageBits(0),
94 mConsumerIsProtected(false),
95 mConnectedApi(NO_CONNECTED_API),
96 mLinkedToDeath(),
97 mConnectedProducerListener(),
98 mBufferReleasedCbEnabled(false),
99 mBufferAttachedCbEnabled(false),
100 mSlots(),
101 mQueue(),
102 mFreeSlots(),
103 mFreeBuffers(),
104 mUnusedSlots(),
105 mActiveBuffers(),
106 mDequeueCondition(),
107 mDequeueBufferCannotBlock(false),
108 mQueueBufferCanDrop(false),
109 mLegacyBufferDrop(true),
110 mDefaultBufferFormat(PIXEL_FORMAT_RGBA_8888),
111 mDefaultWidth(1),
112 mDefaultHeight(1),
113 mDefaultBufferDataSpace(HAL_DATASPACE_UNKNOWN),
114 mMaxBufferCount(BufferQueueDefs::NUM_BUFFER_SLOTS),
115 mMaxAcquiredBufferCount(1),
116 mMaxDequeuedBufferCount(1),
117 mBufferHasBeenQueued(false),
118 mFrameCounter(0),
119 mTransformHint(0),
120 mIsAllocating(false),
121 mIsAllocatingCondition(),
122 mAllowAllocation(true),
123 mBufferAge(0),
124 mGenerationNumber(0),
125 mAsyncMode(false),
126 mSharedBufferMode(false),
127 mAutoRefresh(false),
128 mSharedBufferSlot(INVALID_BUFFER_SLOT),
129 mSharedBufferCache(Rect::INVALID_RECT, 0, NATIVE_WINDOW_SCALING_MODE_FREEZE,
130 HAL_DATASPACE_UNKNOWN),
131 mLastQueuedSlot(INVALID_BUFFER_SLOT),
132 mUniqueId(getUniqueId()),
133 mAutoPrerotation(false),
134 mTransformHintInUse(0) {
135 int numStartingBuffers = getMaxBufferCountLocked();
136 for (int s = 0; s < numStartingBuffers; s++) {
137 mFreeSlots.insert(s);
138 }
139 for (int s = numStartingBuffers; s < BufferQueueDefs::NUM_BUFFER_SLOTS;
140 s++) {
141 mUnusedSlots.push_front(s);
142 }
143 }
144
~BufferQueueCore()145 BufferQueueCore::~BufferQueueCore() {}
146
dumpState(const String8 & prefix,String8 * outResult) const147 void BufferQueueCore::dumpState(const String8& prefix, String8* outResult) const {
148 std::lock_guard<std::mutex> lock(mMutex);
149
150 outResult->appendFormat("%s- BufferQueue ", prefix.c_str());
151 outResult->appendFormat("mMaxAcquiredBufferCount=%d mMaxDequeuedBufferCount=%d\n",
152 mMaxAcquiredBufferCount, mMaxDequeuedBufferCount);
153 outResult->appendFormat("%s mDequeueBufferCannotBlock=%d mAsyncMode=%d\n", prefix.c_str(),
154 mDequeueBufferCannotBlock, mAsyncMode);
155 outResult->appendFormat("%s mQueueBufferCanDrop=%d mLegacyBufferDrop=%d\n", prefix.c_str(),
156 mQueueBufferCanDrop, mLegacyBufferDrop);
157 outResult->appendFormat("%s default-size=[%dx%d] default-format=%d ", prefix.c_str(),
158 mDefaultWidth, mDefaultHeight, mDefaultBufferFormat);
159 outResult->appendFormat("%s transform-hint=%02x frame-counter=%" PRIu64 "\n", prefix.c_str(),
160 mTransformHint, mFrameCounter);
161 outResult->appendFormat("%s mTransformHintInUse=%02x mAutoPrerotation=%d\n", prefix.c_str(),
162 mTransformHintInUse, mAutoPrerotation);
163
164 outResult->appendFormat("%sFIFO(%zu):\n", prefix.c_str(), mQueue.size());
165
166 outResult->appendFormat("%s(mConsumerName=%s, ", prefix.c_str(), mConsumerName.c_str());
167
168 outResult->appendFormat("mConnectedApi=%d, mConsumerUsageBits=%" PRIu64 ", ", mConnectedApi,
169 mConsumerUsageBits);
170
171 String8 producerProcName = String8("\?\?\?");
172 String8 consumerProcName = String8("\?\?\?");
173 int32_t pid = getpid();
174 getProcessName(mConnectedPid, producerProcName);
175 getProcessName(pid, consumerProcName);
176 outResult->appendFormat("mId=%" PRIx64 ", producer=[%d:%s], consumer=[%d:%s])\n", mUniqueId,
177 mConnectedPid, producerProcName.c_str(), pid, consumerProcName.c_str());
178 Fifo::const_iterator current(mQueue.begin());
179 while (current != mQueue.end()) {
180 double timestamp = current->mTimestamp / 1e9;
181 outResult->appendFormat("%s %02d:%p ", prefix.c_str(), current->mSlot,
182 current->mGraphicBuffer.get());
183 outResult->appendFormat("crop=[%d,%d,%d,%d] ", current->mCrop.left, current->mCrop.top,
184 current->mCrop.right, current->mCrop.bottom);
185 outResult->appendFormat("xform=0x%02x time=%.4f scale=%s\n", current->mTransform, timestamp,
186 BufferItem::scalingModeName(current->mScalingMode));
187 ++current;
188 }
189
190 outResult->appendFormat("%sSlots:\n", prefix.c_str());
191 for (int s : mActiveBuffers) {
192 const sp<GraphicBuffer>& buffer(mSlots[s].mGraphicBuffer);
193 // A dequeued buffer might be null if it's still being allocated
194 if (buffer.get()) {
195 outResult->appendFormat("%s %s[%02d:%p] ", prefix.c_str(),
196 (mSlots[s].mBufferState.isAcquired()) ? ">" : " ", s,
197 buffer.get());
198 outResult->appendFormat("state=%-8s %p frame=%" PRIu64, mSlots[s].mBufferState.string(),
199 buffer->handle, mSlots[s].mFrameNumber);
200 outResult->appendFormat(" [%4ux%4u:%4u,%3X]\n", buffer->width, buffer->height,
201 buffer->stride, buffer->format);
202 } else {
203 outResult->appendFormat("%s [%02d:%p] ", prefix.c_str(), s, buffer.get());
204 outResult->appendFormat("state=%-8s frame=%" PRIu64 "\n",
205 mSlots[s].mBufferState.string(), mSlots[s].mFrameNumber);
206 }
207 }
208 for (int s : mFreeBuffers) {
209 const sp<GraphicBuffer>& buffer(mSlots[s].mGraphicBuffer);
210 outResult->appendFormat("%s [%02d:%p] ", prefix.c_str(), s, buffer.get());
211 outResult->appendFormat("state=%-8s %p frame=%" PRIu64, mSlots[s].mBufferState.string(),
212 buffer->handle, mSlots[s].mFrameNumber);
213 outResult->appendFormat(" [%4ux%4u:%4u,%3X]\n", buffer->width, buffer->height,
214 buffer->stride, buffer->format);
215 }
216
217 for (int s : mFreeSlots) {
218 const sp<GraphicBuffer>& buffer(mSlots[s].mGraphicBuffer);
219 outResult->appendFormat("%s [%02d:%p] state=%-8s\n", prefix.c_str(), s, buffer.get(),
220 mSlots[s].mBufferState.string());
221 }
222 }
223
getMinUndequeuedBufferCountLocked() const224 int BufferQueueCore::getMinUndequeuedBufferCountLocked() const {
225 // If dequeueBuffer is allowed to error out, we don't have to add an
226 // extra buffer.
227 if (mAsyncMode || mDequeueBufferCannotBlock) {
228 return mMaxAcquiredBufferCount + 1;
229 }
230
231 return mMaxAcquiredBufferCount;
232 }
233
getMinMaxBufferCountLocked() const234 int BufferQueueCore::getMinMaxBufferCountLocked() const {
235 return getMinUndequeuedBufferCountLocked() + 1;
236 }
237
getMaxBufferCountLocked(bool asyncMode,bool dequeueBufferCannotBlock,int maxBufferCount) const238 int BufferQueueCore::getMaxBufferCountLocked(bool asyncMode,
239 bool dequeueBufferCannotBlock, int maxBufferCount) const {
240 int maxCount = mMaxAcquiredBufferCount + mMaxDequeuedBufferCount +
241 ((asyncMode || dequeueBufferCannotBlock) ? 1 : 0);
242 maxCount = std::min(maxBufferCount, maxCount);
243 return maxCount;
244 }
245
getMaxBufferCountLocked() const246 int BufferQueueCore::getMaxBufferCountLocked() const {
247 int maxBufferCount = mMaxAcquiredBufferCount + mMaxDequeuedBufferCount +
248 ((mAsyncMode || mDequeueBufferCannotBlock) ? 1 : 0);
249
250 // limit maxBufferCount by mMaxBufferCount always
251 maxBufferCount = std::min(mMaxBufferCount, maxBufferCount);
252
253 return maxBufferCount;
254 }
255
clearBufferSlotLocked(int slot)256 void BufferQueueCore::clearBufferSlotLocked(int slot) {
257 BQ_LOGV("clearBufferSlotLocked: slot %d", slot);
258
259 mSlots[slot].mGraphicBuffer.clear();
260 mSlots[slot].mBufferState.reset();
261 mSlots[slot].mRequestBufferCalled = false;
262 mSlots[slot].mFrameNumber = 0;
263 mSlots[slot].mAcquireCalled = false;
264 mSlots[slot].mNeedsReallocation = true;
265 mSlots[slot].mFence = Fence::NO_FENCE;
266
267 #if !COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_GL_FENCE_CLEANUP)
268 // Destroy fence as BufferQueue now takes ownership
269 if (mSlots[slot].mEglFence != EGL_NO_SYNC_KHR) {
270 eglDestroySyncKHR(mSlots[slot].mEglDisplay, mSlots[slot].mEglFence);
271 mSlots[slot].mEglFence = EGL_NO_SYNC_KHR;
272 }
273 mSlots[slot].mEglDisplay = EGL_NO_DISPLAY;
274 #endif
275
276 if (mLastQueuedSlot == slot) {
277 mLastQueuedSlot = INVALID_BUFFER_SLOT;
278 }
279 }
280
freeAllBuffersLocked()281 void BufferQueueCore::freeAllBuffersLocked() {
282 for (int s : mFreeSlots) {
283 clearBufferSlotLocked(s);
284 }
285
286 for (int s : mFreeBuffers) {
287 mFreeSlots.insert(s);
288 clearBufferSlotLocked(s);
289 }
290 mFreeBuffers.clear();
291
292 for (int s : mActiveBuffers) {
293 mFreeSlots.insert(s);
294 clearBufferSlotLocked(s);
295 }
296 mActiveBuffers.clear();
297
298 for (auto& b : mQueue) {
299 b.mIsStale = true;
300
301 // We set this to false to force the BufferQueue to resend the buffer
302 // handle upon acquire, since if we're here due to a producer
303 // disconnect, the consumer will have been told to purge its cache of
304 // slot-to-buffer-handle mappings and will not be able to otherwise
305 // obtain a valid buffer handle.
306 b.mAcquireCalled = false;
307 }
308
309 VALIDATE_CONSISTENCY();
310 }
311
discardFreeBuffersLocked()312 void BufferQueueCore::discardFreeBuffersLocked() {
313 // Notify producer about the discarded buffers.
314 if (mConnectedProducerListener != nullptr && mFreeBuffers.size() > 0) {
315 std::vector<int32_t> freeBuffers(mFreeBuffers.begin(), mFreeBuffers.end());
316 mConnectedProducerListener->onBuffersDiscarded(freeBuffers);
317 }
318
319 for (int s : mFreeBuffers) {
320 mFreeSlots.insert(s);
321 clearBufferSlotLocked(s);
322 }
323 mFreeBuffers.clear();
324
325 VALIDATE_CONSISTENCY();
326 }
327
adjustAvailableSlotsLocked(int delta)328 bool BufferQueueCore::adjustAvailableSlotsLocked(int delta) {
329 if (delta >= 0) {
330 // If we're going to fail, do so before modifying anything
331 if (delta > static_cast<int>(mUnusedSlots.size())) {
332 return false;
333 }
334 while (delta > 0) {
335 if (mUnusedSlots.empty()) {
336 return false;
337 }
338 int slot = mUnusedSlots.back();
339 mUnusedSlots.pop_back();
340 mFreeSlots.insert(slot);
341 delta--;
342 }
343 } else {
344 // If we're going to fail, do so before modifying anything
345 if (-delta > static_cast<int>(mFreeSlots.size() +
346 mFreeBuffers.size())) {
347 return false;
348 }
349 while (delta < 0) {
350 if (!mFreeSlots.empty()) {
351 auto slot = mFreeSlots.begin();
352 clearBufferSlotLocked(*slot);
353 mUnusedSlots.push_back(*slot);
354 mFreeSlots.erase(slot);
355 } else if (!mFreeBuffers.empty()) {
356 int slot = mFreeBuffers.back();
357 clearBufferSlotLocked(slot);
358 mUnusedSlots.push_back(slot);
359 mFreeBuffers.pop_back();
360 } else {
361 return false;
362 }
363 delta++;
364 }
365 }
366 return true;
367 }
368
waitWhileAllocatingLocked(std::unique_lock<std::mutex> & lock) const369 void BufferQueueCore::waitWhileAllocatingLocked(std::unique_lock<std::mutex>& lock) const {
370 ATRACE_CALL();
371 while (mIsAllocating) {
372 mIsAllocatingCondition.wait(lock);
373 }
374 }
375
376 #if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL)
notifyBufferReleased() const377 void BufferQueueCore::notifyBufferReleased() const {
378 mDequeueCondition.notify_all();
379 }
380 #endif
381
382 #if DEBUG_ONLY_CODE
validateConsistencyLocked() const383 void BufferQueueCore::validateConsistencyLocked() const {
384 static const useconds_t PAUSE_TIME = 0;
385 int allocatedSlots = 0;
386 for (int slot = 0; slot < BufferQueueDefs::NUM_BUFFER_SLOTS; ++slot) {
387 bool isInFreeSlots = mFreeSlots.count(slot) != 0;
388 bool isInFreeBuffers =
389 std::find(mFreeBuffers.cbegin(), mFreeBuffers.cend(), slot) !=
390 mFreeBuffers.cend();
391 bool isInActiveBuffers = mActiveBuffers.count(slot) != 0;
392 bool isInUnusedSlots =
393 std::find(mUnusedSlots.cbegin(), mUnusedSlots.cend(), slot) !=
394 mUnusedSlots.cend();
395
396 if (isInFreeSlots || isInFreeBuffers || isInActiveBuffers) {
397 allocatedSlots++;
398 }
399
400 if (isInUnusedSlots) {
401 if (isInFreeSlots) {
402 BQ_LOGE("Slot %d is in mUnusedSlots and in mFreeSlots", slot);
403 usleep(PAUSE_TIME);
404 }
405 if (isInFreeBuffers) {
406 BQ_LOGE("Slot %d is in mUnusedSlots and in mFreeBuffers", slot);
407 usleep(PAUSE_TIME);
408 }
409 if (isInActiveBuffers) {
410 BQ_LOGE("Slot %d is in mUnusedSlots and in mActiveBuffers",
411 slot);
412 usleep(PAUSE_TIME);
413 }
414 if (!mSlots[slot].mBufferState.isFree()) {
415 BQ_LOGE("Slot %d is in mUnusedSlots but is not FREE", slot);
416 usleep(PAUSE_TIME);
417 }
418 if (mSlots[slot].mGraphicBuffer != nullptr) {
419 BQ_LOGE("Slot %d is in mUnusedSluts but has an active buffer",
420 slot);
421 usleep(PAUSE_TIME);
422 }
423 } else if (isInFreeSlots) {
424 if (isInUnusedSlots) {
425 BQ_LOGE("Slot %d is in mFreeSlots and in mUnusedSlots", slot);
426 usleep(PAUSE_TIME);
427 }
428 if (isInFreeBuffers) {
429 BQ_LOGE("Slot %d is in mFreeSlots and in mFreeBuffers", slot);
430 usleep(PAUSE_TIME);
431 }
432 if (isInActiveBuffers) {
433 BQ_LOGE("Slot %d is in mFreeSlots and in mActiveBuffers", slot);
434 usleep(PAUSE_TIME);
435 }
436 if (!mSlots[slot].mBufferState.isFree()) {
437 BQ_LOGE("Slot %d is in mFreeSlots but is not FREE", slot);
438 usleep(PAUSE_TIME);
439 }
440 if (mSlots[slot].mGraphicBuffer != nullptr) {
441 BQ_LOGE("Slot %d is in mFreeSlots but has a buffer",
442 slot);
443 usleep(PAUSE_TIME);
444 }
445 } else if (isInFreeBuffers) {
446 if (isInUnusedSlots) {
447 BQ_LOGE("Slot %d is in mFreeBuffers and in mUnusedSlots", slot);
448 usleep(PAUSE_TIME);
449 }
450 if (isInFreeSlots) {
451 BQ_LOGE("Slot %d is in mFreeBuffers and in mFreeSlots", slot);
452 usleep(PAUSE_TIME);
453 }
454 if (isInActiveBuffers) {
455 BQ_LOGE("Slot %d is in mFreeBuffers and in mActiveBuffers",
456 slot);
457 usleep(PAUSE_TIME);
458 }
459 if (!mSlots[slot].mBufferState.isFree()) {
460 BQ_LOGE("Slot %d is in mFreeBuffers but is not FREE", slot);
461 usleep(PAUSE_TIME);
462 }
463 if (mSlots[slot].mGraphicBuffer == nullptr) {
464 BQ_LOGE("Slot %d is in mFreeBuffers but has no buffer", slot);
465 usleep(PAUSE_TIME);
466 }
467 } else if (isInActiveBuffers) {
468 if (isInUnusedSlots) {
469 BQ_LOGE("Slot %d is in mActiveBuffers and in mUnusedSlots",
470 slot);
471 usleep(PAUSE_TIME);
472 }
473 if (isInFreeSlots) {
474 BQ_LOGE("Slot %d is in mActiveBuffers and in mFreeSlots", slot);
475 usleep(PAUSE_TIME);
476 }
477 if (isInFreeBuffers) {
478 BQ_LOGE("Slot %d is in mActiveBuffers and in mFreeBuffers",
479 slot);
480 usleep(PAUSE_TIME);
481 }
482 if (mSlots[slot].mBufferState.isFree() &&
483 !mSlots[slot].mBufferState.isShared()) {
484 BQ_LOGE("Slot %d is in mActiveBuffers but is FREE", slot);
485 usleep(PAUSE_TIME);
486 }
487 if (mSlots[slot].mGraphicBuffer == nullptr && !mIsAllocating) {
488 BQ_LOGE("Slot %d is in mActiveBuffers but has no buffer", slot);
489 usleep(PAUSE_TIME);
490 }
491 } else {
492 BQ_LOGE("Slot %d isn't in any of mUnusedSlots, mFreeSlots, "
493 "mFreeBuffers, or mActiveBuffers", slot);
494 usleep(PAUSE_TIME);
495 }
496 }
497
498 if (allocatedSlots != getMaxBufferCountLocked()) {
499 BQ_LOGE("Number of allocated slots is incorrect. Allocated = %d, "
500 "Should be %d (%zu free slots, %zu free buffers, "
501 "%zu activeBuffers, %zu unusedSlots)", allocatedSlots,
502 getMaxBufferCountLocked(), mFreeSlots.size(),
503 mFreeBuffers.size(), mActiveBuffers.size(),
504 mUnusedSlots.size());
505 }
506 }
507 #endif
508
509 } // namespace android
510