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 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.c_str());
150 outResult->appendFormat("mMaxAcquiredBufferCount=%d mMaxDequeuedBufferCount=%d\n",
151 mMaxAcquiredBufferCount, mMaxDequeuedBufferCount);
152 outResult->appendFormat("%s mDequeueBufferCannotBlock=%d mAsyncMode=%d\n", prefix.c_str(),
153 mDequeueBufferCannotBlock, mAsyncMode);
154 outResult->appendFormat("%s mQueueBufferCanDrop=%d mLegacyBufferDrop=%d\n", prefix.c_str(),
155 mQueueBufferCanDrop, mLegacyBufferDrop);
156 outResult->appendFormat("%s default-size=[%dx%d] default-format=%d ", prefix.c_str(),
157 mDefaultWidth, mDefaultHeight, mDefaultBufferFormat);
158 outResult->appendFormat("%s transform-hint=%02x frame-counter=%" PRIu64 "\n", prefix.c_str(),
159 mTransformHint, mFrameCounter);
160 outResult->appendFormat("%s mTransformHintInUse=%02x mAutoPrerotation=%d\n", prefix.c_str(),
161 mTransformHintInUse, mAutoPrerotation);
162
163 outResult->appendFormat("%sFIFO(%zu):\n", prefix.c_str(), mQueue.size());
164
165 outResult->appendFormat("%s(mConsumerName=%s, ", prefix.c_str(), mConsumerName.c_str());
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.c_str(), pid, consumerProcName.c_str());
177 Fifo::const_iterator current(mQueue.begin());
178 while (current != mQueue.end()) {
179 double timestamp = current->mTimestamp / 1e9;
180 outResult->appendFormat("%s %02d:%p ", prefix.c_str(), current->mSlot,
181 current->mGraphicBuffer.get());
182 outResult->appendFormat("crop=[%d,%d,%d,%d] ", current->mCrop.left, current->mCrop.top,
183 current->mCrop.right, current->mCrop.bottom);
184 outResult->appendFormat("xform=0x%02x time=%.4f scale=%s\n", current->mTransform, timestamp,
185 BufferItem::scalingModeName(current->mScalingMode));
186 ++current;
187 }
188
189 outResult->appendFormat("%sSlots:\n", prefix.c_str());
190 for (int s : mActiveBuffers) {
191 const sp<GraphicBuffer>& buffer(mSlots[s].mGraphicBuffer);
192 // A dequeued buffer might be null if it's still being allocated
193 if (buffer.get()) {
194 outResult->appendFormat("%s %s[%02d:%p] ", prefix.c_str(),
195 (mSlots[s].mBufferState.isAcquired()) ? ">" : " ", s,
196 buffer.get());
197 outResult->appendFormat("state=%-8s %p frame=%" PRIu64, mSlots[s].mBufferState.string(),
198 buffer->handle, mSlots[s].mFrameNumber);
199 outResult->appendFormat(" [%4ux%4u:%4u,%3X]\n", buffer->width, buffer->height,
200 buffer->stride, buffer->format);
201 } else {
202 outResult->appendFormat("%s [%02d:%p] ", prefix.c_str(), s, buffer.get());
203 outResult->appendFormat("state=%-8s frame=%" PRIu64 "\n",
204 mSlots[s].mBufferState.string(), mSlots[s].mFrameNumber);
205 }
206 }
207 for (int s : mFreeBuffers) {
208 const sp<GraphicBuffer>& buffer(mSlots[s].mGraphicBuffer);
209 outResult->appendFormat("%s [%02d:%p] ", prefix.c_str(), s, buffer.get());
210 outResult->appendFormat("state=%-8s %p frame=%" PRIu64, mSlots[s].mBufferState.string(),
211 buffer->handle, mSlots[s].mFrameNumber);
212 outResult->appendFormat(" [%4ux%4u:%4u,%3X]\n", buffer->width, buffer->height,
213 buffer->stride, buffer->format);
214 }
215
216 for (int s : mFreeSlots) {
217 const sp<GraphicBuffer>& buffer(mSlots[s].mGraphicBuffer);
218 outResult->appendFormat("%s [%02d:%p] state=%-8s\n", prefix.c_str(), s, buffer.get(),
219 mSlots[s].mBufferState.string());
220 }
221 }
222
getMinUndequeuedBufferCountLocked() const223 int BufferQueueCore::getMinUndequeuedBufferCountLocked() const {
224 // If dequeueBuffer is allowed to error out, we don't have to add an
225 // extra buffer.
226 if (mAsyncMode || mDequeueBufferCannotBlock) {
227 return mMaxAcquiredBufferCount + 1;
228 }
229
230 return mMaxAcquiredBufferCount;
231 }
232
getMinMaxBufferCountLocked() const233 int BufferQueueCore::getMinMaxBufferCountLocked() const {
234 return getMinUndequeuedBufferCountLocked() + 1;
235 }
236
getMaxBufferCountLocked(bool asyncMode,bool dequeueBufferCannotBlock,int maxBufferCount) const237 int BufferQueueCore::getMaxBufferCountLocked(bool asyncMode,
238 bool dequeueBufferCannotBlock, int maxBufferCount) const {
239 int maxCount = mMaxAcquiredBufferCount + mMaxDequeuedBufferCount +
240 ((asyncMode || dequeueBufferCannotBlock) ? 1 : 0);
241 maxCount = std::min(maxBufferCount, maxCount);
242 return maxCount;
243 }
244
getMaxBufferCountLocked() const245 int BufferQueueCore::getMaxBufferCountLocked() const {
246 int maxBufferCount = mMaxAcquiredBufferCount + mMaxDequeuedBufferCount +
247 ((mAsyncMode || mDequeueBufferCannotBlock) ? 1 : 0);
248
249 // limit maxBufferCount by mMaxBufferCount always
250 maxBufferCount = std::min(mMaxBufferCount, maxBufferCount);
251
252 return maxBufferCount;
253 }
254
clearBufferSlotLocked(int slot)255 void BufferQueueCore::clearBufferSlotLocked(int slot) {
256 BQ_LOGV("clearBufferSlotLocked: slot %d", slot);
257
258 mSlots[slot].mGraphicBuffer.clear();
259 mSlots[slot].mBufferState.reset();
260 mSlots[slot].mRequestBufferCalled = false;
261 mSlots[slot].mFrameNumber = 0;
262 mSlots[slot].mAcquireCalled = false;
263 mSlots[slot].mNeedsReallocation = true;
264
265 // Destroy fence as BufferQueue now takes ownership
266 if (mSlots[slot].mEglFence != EGL_NO_SYNC_KHR) {
267 eglDestroySyncKHR(mSlots[slot].mEglDisplay, mSlots[slot].mEglFence);
268 mSlots[slot].mEglFence = EGL_NO_SYNC_KHR;
269 }
270 mSlots[slot].mFence = Fence::NO_FENCE;
271 mSlots[slot].mEglDisplay = EGL_NO_DISPLAY;
272
273 if (mLastQueuedSlot == slot) {
274 mLastQueuedSlot = INVALID_BUFFER_SLOT;
275 }
276 }
277
freeAllBuffersLocked()278 void BufferQueueCore::freeAllBuffersLocked() {
279 for (int s : mFreeSlots) {
280 clearBufferSlotLocked(s);
281 }
282
283 for (int s : mFreeBuffers) {
284 mFreeSlots.insert(s);
285 clearBufferSlotLocked(s);
286 }
287 mFreeBuffers.clear();
288
289 for (int s : mActiveBuffers) {
290 mFreeSlots.insert(s);
291 clearBufferSlotLocked(s);
292 }
293 mActiveBuffers.clear();
294
295 for (auto& b : mQueue) {
296 b.mIsStale = true;
297
298 // We set this to false to force the BufferQueue to resend the buffer
299 // handle upon acquire, since if we're here due to a producer
300 // disconnect, the consumer will have been told to purge its cache of
301 // slot-to-buffer-handle mappings and will not be able to otherwise
302 // obtain a valid buffer handle.
303 b.mAcquireCalled = false;
304 }
305
306 VALIDATE_CONSISTENCY();
307 }
308
discardFreeBuffersLocked()309 void BufferQueueCore::discardFreeBuffersLocked() {
310 // Notify producer about the discarded buffers.
311 if (mConnectedProducerListener != nullptr && mFreeBuffers.size() > 0) {
312 std::vector<int32_t> freeBuffers(mFreeBuffers.begin(), mFreeBuffers.end());
313 mConnectedProducerListener->onBuffersDiscarded(freeBuffers);
314 }
315
316 for (int s : mFreeBuffers) {
317 mFreeSlots.insert(s);
318 clearBufferSlotLocked(s);
319 }
320 mFreeBuffers.clear();
321
322 VALIDATE_CONSISTENCY();
323 }
324
adjustAvailableSlotsLocked(int delta)325 bool BufferQueueCore::adjustAvailableSlotsLocked(int delta) {
326 if (delta >= 0) {
327 // If we're going to fail, do so before modifying anything
328 if (delta > static_cast<int>(mUnusedSlots.size())) {
329 return false;
330 }
331 while (delta > 0) {
332 if (mUnusedSlots.empty()) {
333 return false;
334 }
335 int slot = mUnusedSlots.back();
336 mUnusedSlots.pop_back();
337 mFreeSlots.insert(slot);
338 delta--;
339 }
340 } else {
341 // If we're going to fail, do so before modifying anything
342 if (-delta > static_cast<int>(mFreeSlots.size() +
343 mFreeBuffers.size())) {
344 return false;
345 }
346 while (delta < 0) {
347 if (!mFreeSlots.empty()) {
348 auto slot = mFreeSlots.begin();
349 clearBufferSlotLocked(*slot);
350 mUnusedSlots.push_back(*slot);
351 mFreeSlots.erase(slot);
352 } else if (!mFreeBuffers.empty()) {
353 int slot = mFreeBuffers.back();
354 clearBufferSlotLocked(slot);
355 mUnusedSlots.push_back(slot);
356 mFreeBuffers.pop_back();
357 } else {
358 return false;
359 }
360 delta++;
361 }
362 }
363 return true;
364 }
365
waitWhileAllocatingLocked(std::unique_lock<std::mutex> & lock) const366 void BufferQueueCore::waitWhileAllocatingLocked(std::unique_lock<std::mutex>& lock) const {
367 ATRACE_CALL();
368 while (mIsAllocating) {
369 mIsAllocatingCondition.wait(lock);
370 }
371 }
372
373 #if DEBUG_ONLY_CODE
validateConsistencyLocked() const374 void BufferQueueCore::validateConsistencyLocked() const {
375 static const useconds_t PAUSE_TIME = 0;
376 int allocatedSlots = 0;
377 for (int slot = 0; slot < BufferQueueDefs::NUM_BUFFER_SLOTS; ++slot) {
378 bool isInFreeSlots = mFreeSlots.count(slot) != 0;
379 bool isInFreeBuffers =
380 std::find(mFreeBuffers.cbegin(), mFreeBuffers.cend(), slot) !=
381 mFreeBuffers.cend();
382 bool isInActiveBuffers = mActiveBuffers.count(slot) != 0;
383 bool isInUnusedSlots =
384 std::find(mUnusedSlots.cbegin(), mUnusedSlots.cend(), slot) !=
385 mUnusedSlots.cend();
386
387 if (isInFreeSlots || isInFreeBuffers || isInActiveBuffers) {
388 allocatedSlots++;
389 }
390
391 if (isInUnusedSlots) {
392 if (isInFreeSlots) {
393 BQ_LOGE("Slot %d is in mUnusedSlots and in mFreeSlots", slot);
394 usleep(PAUSE_TIME);
395 }
396 if (isInFreeBuffers) {
397 BQ_LOGE("Slot %d is in mUnusedSlots and in mFreeBuffers", slot);
398 usleep(PAUSE_TIME);
399 }
400 if (isInActiveBuffers) {
401 BQ_LOGE("Slot %d is in mUnusedSlots and in mActiveBuffers",
402 slot);
403 usleep(PAUSE_TIME);
404 }
405 if (!mSlots[slot].mBufferState.isFree()) {
406 BQ_LOGE("Slot %d is in mUnusedSlots but is not FREE", slot);
407 usleep(PAUSE_TIME);
408 }
409 if (mSlots[slot].mGraphicBuffer != nullptr) {
410 BQ_LOGE("Slot %d is in mUnusedSluts but has an active buffer",
411 slot);
412 usleep(PAUSE_TIME);
413 }
414 } else if (isInFreeSlots) {
415 if (isInUnusedSlots) {
416 BQ_LOGE("Slot %d is in mFreeSlots and in mUnusedSlots", slot);
417 usleep(PAUSE_TIME);
418 }
419 if (isInFreeBuffers) {
420 BQ_LOGE("Slot %d is in mFreeSlots and in mFreeBuffers", slot);
421 usleep(PAUSE_TIME);
422 }
423 if (isInActiveBuffers) {
424 BQ_LOGE("Slot %d is in mFreeSlots and in mActiveBuffers", slot);
425 usleep(PAUSE_TIME);
426 }
427 if (!mSlots[slot].mBufferState.isFree()) {
428 BQ_LOGE("Slot %d is in mFreeSlots but is not FREE", slot);
429 usleep(PAUSE_TIME);
430 }
431 if (mSlots[slot].mGraphicBuffer != nullptr) {
432 BQ_LOGE("Slot %d is in mFreeSlots but has a buffer",
433 slot);
434 usleep(PAUSE_TIME);
435 }
436 } else if (isInFreeBuffers) {
437 if (isInUnusedSlots) {
438 BQ_LOGE("Slot %d is in mFreeBuffers and in mUnusedSlots", slot);
439 usleep(PAUSE_TIME);
440 }
441 if (isInFreeSlots) {
442 BQ_LOGE("Slot %d is in mFreeBuffers and in mFreeSlots", slot);
443 usleep(PAUSE_TIME);
444 }
445 if (isInActiveBuffers) {
446 BQ_LOGE("Slot %d is in mFreeBuffers and in mActiveBuffers",
447 slot);
448 usleep(PAUSE_TIME);
449 }
450 if (!mSlots[slot].mBufferState.isFree()) {
451 BQ_LOGE("Slot %d is in mFreeBuffers but is not FREE", slot);
452 usleep(PAUSE_TIME);
453 }
454 if (mSlots[slot].mGraphicBuffer == nullptr) {
455 BQ_LOGE("Slot %d is in mFreeBuffers but has no buffer", slot);
456 usleep(PAUSE_TIME);
457 }
458 } else if (isInActiveBuffers) {
459 if (isInUnusedSlots) {
460 BQ_LOGE("Slot %d is in mActiveBuffers and in mUnusedSlots",
461 slot);
462 usleep(PAUSE_TIME);
463 }
464 if (isInFreeSlots) {
465 BQ_LOGE("Slot %d is in mActiveBuffers and in mFreeSlots", slot);
466 usleep(PAUSE_TIME);
467 }
468 if (isInFreeBuffers) {
469 BQ_LOGE("Slot %d is in mActiveBuffers and in mFreeBuffers",
470 slot);
471 usleep(PAUSE_TIME);
472 }
473 if (mSlots[slot].mBufferState.isFree() &&
474 !mSlots[slot].mBufferState.isShared()) {
475 BQ_LOGE("Slot %d is in mActiveBuffers but is FREE", slot);
476 usleep(PAUSE_TIME);
477 }
478 if (mSlots[slot].mGraphicBuffer == nullptr && !mIsAllocating) {
479 BQ_LOGE("Slot %d is in mActiveBuffers but has no buffer", slot);
480 usleep(PAUSE_TIME);
481 }
482 } else {
483 BQ_LOGE("Slot %d isn't in any of mUnusedSlots, mFreeSlots, "
484 "mFreeBuffers, or mActiveBuffers", slot);
485 usleep(PAUSE_TIME);
486 }
487 }
488
489 if (allocatedSlots != getMaxBufferCountLocked()) {
490 BQ_LOGE("Number of allocated slots is incorrect. Allocated = %d, "
491 "Should be %d (%zu free slots, %zu free buffers, "
492 "%zu activeBuffers, %zu unusedSlots)", allocatedSlots,
493 getMaxBufferCountLocked(), mFreeSlots.size(),
494 mFreeBuffers.size(), mActiveBuffers.size(),
495 mUnusedSlots.size());
496 }
497 }
498 #endif
499
500 } // namespace android
501