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.string(), 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.string(), 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.string(), 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.string(), 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.string(), 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 mSlots(),
100 mQueue(),
101 mFreeSlots(),
102 mFreeBuffers(),
103 mUnusedSlots(),
104 mActiveBuffers(),
105 mDequeueCondition(),
106 mDequeueBufferCannotBlock(false),
107 mQueueBufferCanDrop(false),
108 mLegacyBufferDrop(true),
109 mDefaultBufferFormat(PIXEL_FORMAT_RGBA_8888),
110 mDefaultWidth(1),
111 mDefaultHeight(1),
112 mDefaultBufferDataSpace(HAL_DATASPACE_UNKNOWN),
113 mMaxBufferCount(BufferQueueDefs::NUM_BUFFER_SLOTS),
114 mMaxAcquiredBufferCount(1),
115 mMaxDequeuedBufferCount(1),
116 mBufferHasBeenQueued(false),
117 mFrameCounter(0),
118 mTransformHint(0),
119 mIsAllocating(false),
120 mIsAllocatingCondition(),
121 mAllowAllocation(true),
122 mBufferAge(0),
123 mGenerationNumber(0),
124 mAsyncMode(false),
125 mSharedBufferMode(false),
126 mAutoRefresh(false),
127 mSharedBufferSlot(INVALID_BUFFER_SLOT),
128 mSharedBufferCache(Rect::INVALID_RECT, 0, NATIVE_WINDOW_SCALING_MODE_FREEZE,
129 HAL_DATASPACE_UNKNOWN),
130 mLastQueuedSlot(INVALID_BUFFER_SLOT),
131 mUniqueId(getUniqueId()),
132 mAutoPrerotation(false),
133 mTransformHintInUse(0) {
134 int numStartingBuffers = getMaxBufferCountLocked();
135 for (int s = 0; s < numStartingBuffers; s++) {
136 mFreeSlots.insert(s);
137 }
138 for (int s = numStartingBuffers; s < BufferQueueDefs::NUM_BUFFER_SLOTS;
139 s++) {
140 mUnusedSlots.push_front(s);
141 }
142 }
143
~BufferQueueCore()144 BufferQueueCore::~BufferQueueCore() {}
145
dumpState(const String8 & prefix,String8 * outResult) const146 void BufferQueueCore::dumpState(const String8& prefix, String8* outResult) const {
147 std::lock_guard<std::mutex> lock(mMutex);
148
149 outResult->appendFormat("%s- BufferQueue ", prefix.string());
150 outResult->appendFormat("mMaxAcquiredBufferCount=%d mMaxDequeuedBufferCount=%d\n",
151 mMaxAcquiredBufferCount, mMaxDequeuedBufferCount);
152 outResult->appendFormat("%s mDequeueBufferCannotBlock=%d mAsyncMode=%d\n", prefix.string(),
153 mDequeueBufferCannotBlock, mAsyncMode);
154 outResult->appendFormat("%s mQueueBufferCanDrop=%d mLegacyBufferDrop=%d\n", prefix.string(),
155 mQueueBufferCanDrop, mLegacyBufferDrop);
156 outResult->appendFormat("%s default-size=[%dx%d] default-format=%d ", prefix.string(),
157 mDefaultWidth, mDefaultHeight, mDefaultBufferFormat);
158 outResult->appendFormat("%s transform-hint=%02x frame-counter=%" PRIu64 "\n", prefix.string(),
159 mTransformHint, mFrameCounter);
160 outResult->appendFormat("%s mTransformHintInUse=%02x mAutoPrerotation=%d\n", prefix.string(),
161 mTransformHintInUse, mAutoPrerotation);
162
163 outResult->appendFormat("%sFIFO(%zu):\n", prefix.string(), mQueue.size());
164
165 outResult->appendFormat("%s(mConsumerName=%s, ", prefix.string(), mConsumerName.string());
166
167 outResult->appendFormat("mConnectedApi=%d, mConsumerUsageBits=%" PRIu64 ", ", mConnectedApi,
168 mConsumerUsageBits);
169
170 String8 producerProcName = String8("\?\?\?");
171 String8 consumerProcName = String8("\?\?\?");
172 int32_t pid = getpid();
173 getProcessName(mConnectedPid, producerProcName);
174 getProcessName(pid, consumerProcName);
175 outResult->appendFormat("mId=%" PRIx64 ", producer=[%d:%s], consumer=[%d:%s])\n", mUniqueId,
176 mConnectedPid, producerProcName.string(), pid,
177 consumerProcName.string());
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.string(), 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.string());
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.string(),
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.string(), 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.string(), 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.string(), 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
266 // Destroy fence as BufferQueue now takes ownership
267 if (mSlots[slot].mEglFence != EGL_NO_SYNC_KHR) {
268 eglDestroySyncKHR(mSlots[slot].mEglDisplay, mSlots[slot].mEglFence);
269 mSlots[slot].mEglFence = EGL_NO_SYNC_KHR;
270 }
271 mSlots[slot].mFence = Fence::NO_FENCE;
272 mSlots[slot].mEglDisplay = EGL_NO_DISPLAY;
273
274 if (mLastQueuedSlot == slot) {
275 mLastQueuedSlot = INVALID_BUFFER_SLOT;
276 }
277 }
278
freeAllBuffersLocked()279 void BufferQueueCore::freeAllBuffersLocked() {
280 for (int s : mFreeSlots) {
281 clearBufferSlotLocked(s);
282 }
283
284 for (int s : mFreeBuffers) {
285 mFreeSlots.insert(s);
286 clearBufferSlotLocked(s);
287 }
288 mFreeBuffers.clear();
289
290 for (int s : mActiveBuffers) {
291 mFreeSlots.insert(s);
292 clearBufferSlotLocked(s);
293 }
294 mActiveBuffers.clear();
295
296 for (auto& b : mQueue) {
297 b.mIsStale = true;
298
299 // We set this to false to force the BufferQueue to resend the buffer
300 // handle upon acquire, since if we're here due to a producer
301 // disconnect, the consumer will have been told to purge its cache of
302 // slot-to-buffer-handle mappings and will not be able to otherwise
303 // obtain a valid buffer handle.
304 b.mAcquireCalled = false;
305 }
306
307 VALIDATE_CONSISTENCY();
308 }
309
discardFreeBuffersLocked()310 void BufferQueueCore::discardFreeBuffersLocked() {
311 // Notify producer about the discarded buffers.
312 if (mConnectedProducerListener != nullptr && mFreeBuffers.size() > 0) {
313 std::vector<int32_t> freeBuffers(mFreeBuffers.begin(), mFreeBuffers.end());
314 mConnectedProducerListener->onBuffersDiscarded(freeBuffers);
315 }
316
317 for (int s : mFreeBuffers) {
318 mFreeSlots.insert(s);
319 clearBufferSlotLocked(s);
320 }
321 mFreeBuffers.clear();
322
323 VALIDATE_CONSISTENCY();
324 }
325
adjustAvailableSlotsLocked(int delta)326 bool BufferQueueCore::adjustAvailableSlotsLocked(int delta) {
327 if (delta >= 0) {
328 // If we're going to fail, do so before modifying anything
329 if (delta > static_cast<int>(mUnusedSlots.size())) {
330 return false;
331 }
332 while (delta > 0) {
333 if (mUnusedSlots.empty()) {
334 return false;
335 }
336 int slot = mUnusedSlots.back();
337 mUnusedSlots.pop_back();
338 mFreeSlots.insert(slot);
339 delta--;
340 }
341 } else {
342 // If we're going to fail, do so before modifying anything
343 if (-delta > static_cast<int>(mFreeSlots.size() +
344 mFreeBuffers.size())) {
345 return false;
346 }
347 while (delta < 0) {
348 if (!mFreeSlots.empty()) {
349 auto slot = mFreeSlots.begin();
350 clearBufferSlotLocked(*slot);
351 mUnusedSlots.push_back(*slot);
352 mFreeSlots.erase(slot);
353 } else if (!mFreeBuffers.empty()) {
354 int slot = mFreeBuffers.back();
355 clearBufferSlotLocked(slot);
356 mUnusedSlots.push_back(slot);
357 mFreeBuffers.pop_back();
358 } else {
359 return false;
360 }
361 delta++;
362 }
363 }
364 return true;
365 }
366
waitWhileAllocatingLocked(std::unique_lock<std::mutex> & lock) const367 void BufferQueueCore::waitWhileAllocatingLocked(std::unique_lock<std::mutex>& lock) const {
368 ATRACE_CALL();
369 while (mIsAllocating) {
370 mIsAllocatingCondition.wait(lock);
371 }
372 }
373
374 #if DEBUG_ONLY_CODE
validateConsistencyLocked() const375 void BufferQueueCore::validateConsistencyLocked() const {
376 static const useconds_t PAUSE_TIME = 0;
377 int allocatedSlots = 0;
378 for (int slot = 0; slot < BufferQueueDefs::NUM_BUFFER_SLOTS; ++slot) {
379 bool isInFreeSlots = mFreeSlots.count(slot) != 0;
380 bool isInFreeBuffers =
381 std::find(mFreeBuffers.cbegin(), mFreeBuffers.cend(), slot) !=
382 mFreeBuffers.cend();
383 bool isInActiveBuffers = mActiveBuffers.count(slot) != 0;
384 bool isInUnusedSlots =
385 std::find(mUnusedSlots.cbegin(), mUnusedSlots.cend(), slot) !=
386 mUnusedSlots.cend();
387
388 if (isInFreeSlots || isInFreeBuffers || isInActiveBuffers) {
389 allocatedSlots++;
390 }
391
392 if (isInUnusedSlots) {
393 if (isInFreeSlots) {
394 BQ_LOGE("Slot %d is in mUnusedSlots and in mFreeSlots", slot);
395 usleep(PAUSE_TIME);
396 }
397 if (isInFreeBuffers) {
398 BQ_LOGE("Slot %d is in mUnusedSlots and in mFreeBuffers", slot);
399 usleep(PAUSE_TIME);
400 }
401 if (isInActiveBuffers) {
402 BQ_LOGE("Slot %d is in mUnusedSlots and in mActiveBuffers",
403 slot);
404 usleep(PAUSE_TIME);
405 }
406 if (!mSlots[slot].mBufferState.isFree()) {
407 BQ_LOGE("Slot %d is in mUnusedSlots but is not FREE", slot);
408 usleep(PAUSE_TIME);
409 }
410 if (mSlots[slot].mGraphicBuffer != nullptr) {
411 BQ_LOGE("Slot %d is in mUnusedSluts but has an active buffer",
412 slot);
413 usleep(PAUSE_TIME);
414 }
415 } else if (isInFreeSlots) {
416 if (isInUnusedSlots) {
417 BQ_LOGE("Slot %d is in mFreeSlots and in mUnusedSlots", slot);
418 usleep(PAUSE_TIME);
419 }
420 if (isInFreeBuffers) {
421 BQ_LOGE("Slot %d is in mFreeSlots and in mFreeBuffers", slot);
422 usleep(PAUSE_TIME);
423 }
424 if (isInActiveBuffers) {
425 BQ_LOGE("Slot %d is in mFreeSlots and in mActiveBuffers", slot);
426 usleep(PAUSE_TIME);
427 }
428 if (!mSlots[slot].mBufferState.isFree()) {
429 BQ_LOGE("Slot %d is in mFreeSlots but is not FREE", slot);
430 usleep(PAUSE_TIME);
431 }
432 if (mSlots[slot].mGraphicBuffer != nullptr) {
433 BQ_LOGE("Slot %d is in mFreeSlots but has a buffer",
434 slot);
435 usleep(PAUSE_TIME);
436 }
437 } else if (isInFreeBuffers) {
438 if (isInUnusedSlots) {
439 BQ_LOGE("Slot %d is in mFreeBuffers and in mUnusedSlots", slot);
440 usleep(PAUSE_TIME);
441 }
442 if (isInFreeSlots) {
443 BQ_LOGE("Slot %d is in mFreeBuffers and in mFreeSlots", slot);
444 usleep(PAUSE_TIME);
445 }
446 if (isInActiveBuffers) {
447 BQ_LOGE("Slot %d is in mFreeBuffers and in mActiveBuffers",
448 slot);
449 usleep(PAUSE_TIME);
450 }
451 if (!mSlots[slot].mBufferState.isFree()) {
452 BQ_LOGE("Slot %d is in mFreeBuffers but is not FREE", slot);
453 usleep(PAUSE_TIME);
454 }
455 if (mSlots[slot].mGraphicBuffer == nullptr) {
456 BQ_LOGE("Slot %d is in mFreeBuffers but has no buffer", slot);
457 usleep(PAUSE_TIME);
458 }
459 } else if (isInActiveBuffers) {
460 if (isInUnusedSlots) {
461 BQ_LOGE("Slot %d is in mActiveBuffers and in mUnusedSlots",
462 slot);
463 usleep(PAUSE_TIME);
464 }
465 if (isInFreeSlots) {
466 BQ_LOGE("Slot %d is in mActiveBuffers and in mFreeSlots", slot);
467 usleep(PAUSE_TIME);
468 }
469 if (isInFreeBuffers) {
470 BQ_LOGE("Slot %d is in mActiveBuffers and in mFreeBuffers",
471 slot);
472 usleep(PAUSE_TIME);
473 }
474 if (mSlots[slot].mBufferState.isFree() &&
475 !mSlots[slot].mBufferState.isShared()) {
476 BQ_LOGE("Slot %d is in mActiveBuffers but is FREE", slot);
477 usleep(PAUSE_TIME);
478 }
479 if (mSlots[slot].mGraphicBuffer == nullptr && !mIsAllocating) {
480 BQ_LOGE("Slot %d is in mActiveBuffers but has no buffer", slot);
481 usleep(PAUSE_TIME);
482 }
483 } else {
484 BQ_LOGE("Slot %d isn't in any of mUnusedSlots, mFreeSlots, "
485 "mFreeBuffers, or mActiveBuffers", slot);
486 usleep(PAUSE_TIME);
487 }
488 }
489
490 if (allocatedSlots != getMaxBufferCountLocked()) {
491 BQ_LOGE("Number of allocated slots is incorrect. Allocated = %d, "
492 "Should be %d (%zu free slots, %zu free buffers, "
493 "%zu activeBuffers, %zu unusedSlots)", allocatedSlots,
494 getMaxBufferCountLocked(), mFreeSlots.size(),
495 mFreeBuffers.size(), mActiveBuffers.size(),
496 mUnusedSlots.size());
497 }
498 }
499 #endif
500
501 } // namespace android
502