1 /*
2  * Copyright (C) 2018 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_NDEBUG 0
18 #define LOG_TAG "C2BqBuffer"
19 #include <utils/Log.h>
20 
21 #include <ui/BufferQueueDefs.h>
22 #include <ui/GraphicBuffer.h>
23 #include <ui/Fence.h>
24 
25 #include <types.h>
26 
27 #include <hidl/HidlSupport.h>
28 
29 #include <C2AllocatorGralloc.h>
30 #include <C2BqBufferPriv.h>
31 #include <C2BlockInternal.h>
32 
33 #include <list>
34 #include <map>
35 #include <mutex>
36 
37 using ::android::BufferQueueDefs::NUM_BUFFER_SLOTS;
38 using ::android::C2AllocatorGralloc;
39 using ::android::C2AndroidMemoryUsage;
40 using ::android::Fence;
41 using ::android::GraphicBuffer;
42 using ::android::sp;
43 using ::android::status_t;
44 using ::android::wp;
45 using ::android::hardware::hidl_handle;
46 using ::android::hardware::Return;
47 
48 using HBuffer = ::android::hardware::graphics::common::V1_2::HardwareBuffer;
49 using HStatus = ::android::hardware::graphics::bufferqueue::V2_0::Status;
50 using ::android::hardware::graphics::bufferqueue::V2_0::utils::b2h;
51 using ::android::hardware::graphics::bufferqueue::V2_0::utils::h2b;
52 using ::android::hardware::graphics::bufferqueue::V2_0::utils::HFenceWrapper;
53 
54 using HGraphicBufferProducer = ::android::hardware::graphics::bufferqueue::V2_0
55         ::IGraphicBufferProducer;
56 
57 struct C2BufferQueueBlockPoolData : public _C2BlockPoolData {
58 
59     bool held;
60     bool local;
61     uint32_t generation;
62     uint64_t bqId;
63     int32_t bqSlot;
64     bool transfer; // local transfer to remote
65     bool attach; // attach on remote
66     bool display; // display on remote;
67     std::weak_ptr<int> owner;
68     sp<HGraphicBufferProducer> igbp;
69     std::shared_ptr<C2BufferQueueBlockPool::Impl> localPool;
70     mutable std::mutex lock;
71 
getTypeC2BufferQueueBlockPoolData72     virtual type_t getType() const override {
73         return TYPE_BUFFERQUEUE;
74     }
75 
76     // Create a remote BlockPoolData.
77     C2BufferQueueBlockPoolData(
78             uint32_t generation, uint64_t bqId, int32_t bqSlot,
79             const std::shared_ptr<int> &owner,
80             const sp<HGraphicBufferProducer>& producer);
81 
82     // Create a local BlockPoolData.
83     C2BufferQueueBlockPoolData(
84             uint32_t generation, uint64_t bqId, int32_t bqSlot,
85             const std::shared_ptr<C2BufferQueueBlockPool::Impl>& pool);
86 
87     virtual ~C2BufferQueueBlockPoolData() override;
88 
89     int migrate(const sp<HGraphicBufferProducer>& producer,
90                 uint32_t toGeneration, uint64_t toBqId,
91                 sp<GraphicBuffer> *buffers, uint32_t oldGeneration);
92 };
93 
GetBufferQueueData(const std::shared_ptr<const _C2BlockPoolData> & data,uint32_t * generation,uint64_t * bqId,int32_t * bqSlot)94 bool _C2BlockFactory::GetBufferQueueData(
95         const std::shared_ptr<const _C2BlockPoolData>& data,
96         uint32_t* generation, uint64_t* bqId, int32_t* bqSlot) {
97     if (data && data->getType() == _C2BlockPoolData::TYPE_BUFFERQUEUE) {
98         if (generation) {
99             const std::shared_ptr<const C2BufferQueueBlockPoolData> poolData =
100                     std::static_pointer_cast<const C2BufferQueueBlockPoolData>(data);
101             std::scoped_lock<std::mutex> lock(poolData->lock);
102             *generation = poolData->generation;
103             if (bqId) {
104                 *bqId = poolData->bqId;
105             }
106             if (bqSlot) {
107                 *bqSlot = poolData->bqSlot;
108             }
109         }
110         return true;
111     }
112     return false;
113 }
114 
HoldBlockFromBufferQueue(const std::shared_ptr<_C2BlockPoolData> & data,const std::shared_ptr<int> & owner,const sp<HGraphicBufferProducer> & igbp)115 bool _C2BlockFactory::HoldBlockFromBufferQueue(
116         const std::shared_ptr<_C2BlockPoolData>& data,
117         const std::shared_ptr<int>& owner,
118         const sp<HGraphicBufferProducer>& igbp) {
119     const std::shared_ptr<C2BufferQueueBlockPoolData> poolData =
120             std::static_pointer_cast<C2BufferQueueBlockPoolData>(data);
121     std::scoped_lock<std::mutex> lock(poolData->lock);
122     if (!poolData->local) {
123         poolData->owner = owner;
124         poolData->igbp = igbp;
125     }
126     if (poolData->held) {
127         poolData->held = true;
128         return false;
129     }
130     poolData->held = true;
131     return true;
132 }
133 
BeginTransferBlockToClient(const std::shared_ptr<_C2BlockPoolData> & data)134 bool _C2BlockFactory::BeginTransferBlockToClient(
135         const std::shared_ptr<_C2BlockPoolData>& data) {
136     const std::shared_ptr<C2BufferQueueBlockPoolData> poolData =
137             std::static_pointer_cast<C2BufferQueueBlockPoolData>(data);
138     std::scoped_lock<std::mutex> lock(poolData->lock);
139     poolData->transfer = true;
140     return true;
141 }
142 
EndTransferBlockToClient(const std::shared_ptr<_C2BlockPoolData> & data,bool transfer)143 bool _C2BlockFactory::EndTransferBlockToClient(
144         const std::shared_ptr<_C2BlockPoolData>& data,
145         bool transfer) {
146     const std::shared_ptr<C2BufferQueueBlockPoolData> poolData =
147             std::static_pointer_cast<C2BufferQueueBlockPoolData>(data);
148     std::scoped_lock<std::mutex> lock(poolData->lock);
149     poolData->transfer = false;
150     if (transfer) {
151         poolData->held = false;
152     }
153     return true;
154 }
155 
BeginAttachBlockToBufferQueue(const std::shared_ptr<_C2BlockPoolData> & data)156 bool _C2BlockFactory::BeginAttachBlockToBufferQueue(
157         const std::shared_ptr<_C2BlockPoolData>& data) {
158     const std::shared_ptr<C2BufferQueueBlockPoolData> poolData =
159             std::static_pointer_cast<C2BufferQueueBlockPoolData>(data);
160     std::scoped_lock<std::mutex> lock(poolData->lock);
161     if (poolData->local || poolData->display ||
162         poolData->attach || !poolData->held) {
163         return false;
164     }
165     if (poolData->bqId == 0) {
166         return false;
167     }
168     poolData->attach = true;
169     return true;
170 }
171 
172 // if display was tried during attach, buffer should be retired ASAP.
EndAttachBlockToBufferQueue(const std::shared_ptr<_C2BlockPoolData> & data,const std::shared_ptr<int> & owner,const sp<HGraphicBufferProducer> & igbp,uint32_t generation,uint64_t bqId,int32_t bqSlot)173 bool _C2BlockFactory::EndAttachBlockToBufferQueue(
174         const std::shared_ptr<_C2BlockPoolData>& data,
175         const std::shared_ptr<int>& owner,
176         const sp<HGraphicBufferProducer>& igbp,
177         uint32_t generation,
178         uint64_t bqId,
179         int32_t bqSlot) {
180     const std::shared_ptr<C2BufferQueueBlockPoolData> poolData =
181             std::static_pointer_cast<C2BufferQueueBlockPoolData>(data);
182     std::scoped_lock<std::mutex> lock(poolData->lock);
183     if (poolData->local || !poolData->attach ) {
184         return false;
185     }
186     if (poolData->display) {
187         poolData->attach = false;
188         poolData->held = false;
189         return false;
190     }
191     poolData->attach = false;
192     poolData->held = true;
193     poolData->owner = owner;
194     poolData->igbp = igbp;
195     poolData->generation = generation;
196     poolData->bqId = bqId;
197     poolData->bqSlot = bqSlot;
198     return true;
199 }
200 
DisplayBlockToBufferQueue(const std::shared_ptr<_C2BlockPoolData> & data)201 bool _C2BlockFactory::DisplayBlockToBufferQueue(
202         const std::shared_ptr<_C2BlockPoolData>& data) {
203     const std::shared_ptr<C2BufferQueueBlockPoolData> poolData =
204             std::static_pointer_cast<C2BufferQueueBlockPoolData>(data);
205     std::scoped_lock<std::mutex> lock(poolData->lock);
206     if (poolData->local || poolData->display || !poolData->held) {
207         return false;
208     }
209     if (poolData->bqId == 0) {
210         return false;
211     }
212     poolData->display = true;
213     if (poolData->attach) {
214         return false;
215     }
216     poolData->held = false;
217     return true;
218 }
219 
CreateGraphicBlock(const C2Handle * handle)220 std::shared_ptr<C2GraphicBlock> _C2BlockFactory::CreateGraphicBlock(
221         const C2Handle *handle) {
222     // TODO: get proper allocator? and mutex?
223     static std::unique_ptr<C2AllocatorGralloc> sAllocator = std::make_unique<C2AllocatorGralloc>(0);
224 
225     std::shared_ptr<C2GraphicAllocation> alloc;
226     if (C2AllocatorGralloc::isValid(handle)) {
227         uint32_t width;
228         uint32_t height;
229         uint32_t format;
230         uint64_t usage;
231         uint32_t stride;
232         uint32_t generation;
233         uint64_t bqId;
234         uint32_t bqSlot;
235         android::_UnwrapNativeCodec2GrallocMetadata(
236                 handle, &width, &height, &format, &usage, &stride, &generation, &bqId, &bqSlot);
237         c2_status_t err = sAllocator->priorGraphicAllocation(handle, &alloc);
238         if (err == C2_OK) {
239             std::shared_ptr<C2GraphicBlock> block;
240             if (bqId || bqSlot) {
241                 // BQBBP
242                 std::shared_ptr<C2BufferQueueBlockPoolData> poolData =
243                         std::make_shared<C2BufferQueueBlockPoolData>(generation,
244                                                                      bqId,
245                                                                      (int32_t)bqSlot,
246                                                                      nullptr,
247                                                                      nullptr);
248                 block = _C2BlockFactory::CreateGraphicBlock(alloc, poolData);
249             } else {
250                 block = _C2BlockFactory::CreateGraphicBlock(alloc);
251             }
252             return block;
253         }
254     }
255     return nullptr;
256 }
257 
258 namespace {
259 
getTimestampNow()260 int64_t getTimestampNow() {
261     int64_t stamp;
262     struct timespec ts;
263     // TODO: CLOCK_MONOTONIC_COARSE?
264     clock_gettime(CLOCK_MONOTONIC, &ts);
265     stamp = ts.tv_nsec / 1000;
266     stamp += (ts.tv_sec * 1000000LL);
267     return stamp;
268 }
269 
getGenerationNumber(const sp<HGraphicBufferProducer> & producer,uint32_t * generation)270 bool getGenerationNumber(const sp<HGraphicBufferProducer> &producer,
271                          uint32_t *generation) {
272     status_t status{};
273     int slot{};
274     bool bufferNeedsReallocation{};
275     sp<Fence> fence = new Fence();
276 
277     using Input = HGraphicBufferProducer::DequeueBufferInput;
278     using Output = HGraphicBufferProducer::DequeueBufferOutput;
279     Return<void> transResult = producer->dequeueBuffer(
280             Input{640, 480, HAL_PIXEL_FORMAT_YCBCR_420_888, 0},
281             [&status, &slot, &bufferNeedsReallocation, &fence]
282             (HStatus hStatus, int32_t hSlot, Output const& hOutput) {
283                 slot = static_cast<int>(hSlot);
284                 if (!h2b(hStatus, &status) || !h2b(hOutput.fence, &fence)) {
285                     status = ::android::BAD_VALUE;
286                 } else {
287                     bufferNeedsReallocation =
288                             hOutput.bufferNeedsReallocation;
289                 }
290             });
291     if (!transResult.isOk() || status != android::OK) {
292         return false;
293     }
294     HFenceWrapper hFenceWrapper{};
295     if (!b2h(fence, &hFenceWrapper)) {
296         (void)producer->detachBuffer(static_cast<int32_t>(slot)).isOk();
297         ALOGE("Invalid fence received from dequeueBuffer.");
298         return false;
299     }
300     sp<GraphicBuffer> slotBuffer = new GraphicBuffer();
301     // N.B. This assumes requestBuffer# returns an existing allocation
302     // instead of a new allocation.
303     transResult = producer->requestBuffer(
304             slot,
305             [&status, &slotBuffer, &generation](
306                     HStatus hStatus,
307                     HBuffer const& hBuffer,
308                     uint32_t generationNumber){
309                 if (h2b(hStatus, &status) &&
310                         h2b(hBuffer, &slotBuffer) &&
311                         slotBuffer) {
312                     *generation = generationNumber;
313                     slotBuffer->setGenerationNumber(generationNumber);
314                 } else {
315                     status = android::BAD_VALUE;
316                 }
317             });
318     if (!transResult.isOk()) {
319         return false;
320     } else if (status != android::NO_ERROR) {
321         (void)producer->detachBuffer(static_cast<int32_t>(slot)).isOk();
322         return false;
323     }
324     (void)producer->detachBuffer(static_cast<int32_t>(slot)).isOk();
325     return true;
326 }
327 
328 };
329 
330 class C2BufferQueueBlockPool::Impl
331         : public std::enable_shared_from_this<C2BufferQueueBlockPool::Impl> {
332 private:
fetchFromIgbp_l(uint32_t width,uint32_t height,uint32_t format,C2MemoryUsage usage,std::shared_ptr<C2GraphicBlock> * block)333     c2_status_t fetchFromIgbp_l(
334             uint32_t width,
335             uint32_t height,
336             uint32_t format,
337             C2MemoryUsage usage,
338             std::shared_ptr<C2GraphicBlock> *block /* nonnull */) {
339         // We have an IGBP now.
340         C2AndroidMemoryUsage androidUsage = usage;
341         status_t status{};
342         int slot{};
343         bool bufferNeedsReallocation{};
344         sp<Fence> fence = new Fence();
345         ALOGV("tries to dequeue buffer");
346 
347         { // Call dequeueBuffer().
348             using Input = HGraphicBufferProducer::DequeueBufferInput;
349             using Output = HGraphicBufferProducer::DequeueBufferOutput;
350             Return<void> transResult = mProducer->dequeueBuffer(
351                     Input{
352                         width,
353                         height,
354                         format,
355                         androidUsage.asGrallocUsage()},
356                     [&status, &slot, &bufferNeedsReallocation,
357                      &fence](HStatus hStatus,
358                              int32_t hSlot,
359                              Output const& hOutput) {
360                         slot = static_cast<int>(hSlot);
361                         if (!h2b(hStatus, &status) ||
362                                 !h2b(hOutput.fence, &fence)) {
363                             status = ::android::BAD_VALUE;
364                         } else {
365                             bufferNeedsReallocation =
366                                     hOutput.bufferNeedsReallocation;
367                         }
368                     });
369             if (!transResult.isOk() || status != android::OK) {
370                 if (transResult.isOk()) {
371                     ++mDqFailure;
372                     if (status == android::INVALID_OPERATION ||
373                         status == android::TIMED_OUT ||
374                         status == android::WOULD_BLOCK) {
375                         // Dequeue buffer is blocked temporarily. Retrying is
376                         // required.
377                         return C2_BLOCKING;
378                     }
379                 }
380                 ALOGD("cannot dequeue buffer %d", status);
381                 return C2_BAD_VALUE;
382             }
383             mDqFailure = 0;
384             mLastDqTs = getTimestampNow();
385         }
386         HFenceWrapper hFenceWrapper{};
387         if (!b2h(fence, &hFenceWrapper)) {
388             ALOGE("Invalid fence received from dequeueBuffer.");
389             return C2_BAD_VALUE;
390         }
391         ALOGV("dequeued a buffer successfully");
392         if (fence) {
393             static constexpr int kFenceWaitTimeMs = 10;
394 
395             status_t status = fence->wait(kFenceWaitTimeMs);
396             if (status == -ETIME) {
397                 // fence is not signalled yet.
398                 (void)mProducer->cancelBuffer(slot, hFenceWrapper.getHandle()).isOk();
399                 return C2_BLOCKING;
400             }
401             if (status != android::NO_ERROR) {
402                 ALOGD("buffer fence wait error %d", status);
403                 (void)mProducer->cancelBuffer(slot, hFenceWrapper.getHandle()).isOk();
404                 return C2_BAD_VALUE;
405             } else if (mRenderCallback) {
406                 nsecs_t signalTime = fence->getSignalTime();
407                 if (signalTime >= 0 && signalTime < INT64_MAX) {
408                     mRenderCallback(mProducerId, slot, signalTime);
409                 } else {
410                     ALOGV("got fence signal time of %lld", (long long)signalTime);
411                 }
412             }
413         }
414 
415         sp<GraphicBuffer> &slotBuffer = mBuffers[slot];
416         uint32_t outGeneration;
417         if (bufferNeedsReallocation || !slotBuffer) {
418             if (!slotBuffer) {
419                 slotBuffer = new GraphicBuffer();
420             }
421             // N.B. This assumes requestBuffer# returns an existing allocation
422             // instead of a new allocation.
423             Return<void> transResult = mProducer->requestBuffer(
424                     slot,
425                     [&status, &slotBuffer, &outGeneration](
426                             HStatus hStatus,
427                             HBuffer const& hBuffer,
428                             uint32_t generationNumber){
429                         if (h2b(hStatus, &status) &&
430                                 h2b(hBuffer, &slotBuffer) &&
431                                 slotBuffer) {
432                             slotBuffer->setGenerationNumber(generationNumber);
433                             outGeneration = generationNumber;
434                         } else {
435                             status = android::BAD_VALUE;
436                         }
437                     });
438             if (!transResult.isOk()) {
439                 slotBuffer.clear();
440                 return C2_BAD_VALUE;
441             } else if (status != android::NO_ERROR) {
442                 slotBuffer.clear();
443                 (void)mProducer->cancelBuffer(slot, hFenceWrapper.getHandle()).isOk();
444                 return C2_BAD_VALUE;
445             }
446             if (mGeneration == 0) {
447                 // getting generation # lazily due to dequeue failure.
448                 mGeneration = outGeneration;
449             }
450         }
451         if (slotBuffer) {
452             ALOGV("buffer wraps %llu %d", (unsigned long long)mProducerId, slot);
453             C2Handle *c2Handle = android::WrapNativeCodec2GrallocHandle(
454                     slotBuffer->handle,
455                     slotBuffer->width,
456                     slotBuffer->height,
457                     slotBuffer->format,
458                     slotBuffer->usage,
459                     slotBuffer->stride,
460                     slotBuffer->getGenerationNumber(),
461                     mProducerId, slot);
462             if (c2Handle) {
463                 std::shared_ptr<C2GraphicAllocation> alloc;
464                 c2_status_t err = mAllocator->priorGraphicAllocation(c2Handle, &alloc);
465                 if (err != C2_OK) {
466                     return err;
467                 }
468                 std::shared_ptr<C2BufferQueueBlockPoolData> poolData =
469                         std::make_shared<C2BufferQueueBlockPoolData>(
470                                 slotBuffer->getGenerationNumber(),
471                                 mProducerId, slot,
472                                 shared_from_this());
473                 mPoolDatas[slot] = poolData;
474                 *block = _C2BlockFactory::CreateGraphicBlock(alloc, poolData);
475                 return C2_OK;
476             }
477             // Block was not created. call requestBuffer# again next time.
478             slotBuffer.clear();
479             (void)mProducer->cancelBuffer(slot, hFenceWrapper.getHandle()).isOk();
480         }
481         return C2_BAD_VALUE;
482     }
483 
484 public:
Impl(const std::shared_ptr<C2Allocator> & allocator)485     Impl(const std::shared_ptr<C2Allocator> &allocator)
486         : mInit(C2_OK), mProducerId(0), mGeneration(0),
487           mDqFailure(0), mLastDqTs(0), mLastDqLogTs(0),
488           mAllocator(allocator) {
489     }
490 
~Impl()491     ~Impl() {
492         bool noInit = false;
493         for (int i = 0; i < NUM_BUFFER_SLOTS; ++i) {
494             if (!noInit && mProducer) {
495                 Return<HStatus> transResult =
496                         mProducer->detachBuffer(static_cast<int32_t>(i));
497                 noInit = !transResult.isOk() ||
498                          static_cast<HStatus>(transResult) == HStatus::NO_INIT;
499             }
500             mBuffers[i].clear();
501         }
502     }
503 
fetchGraphicBlock(uint32_t width,uint32_t height,uint32_t format,C2MemoryUsage usage,std::shared_ptr<C2GraphicBlock> * block)504     c2_status_t fetchGraphicBlock(
505             uint32_t width,
506             uint32_t height,
507             uint32_t format,
508             C2MemoryUsage usage,
509             std::shared_ptr<C2GraphicBlock> *block /* nonnull */) {
510         block->reset();
511         if (mInit != C2_OK) {
512             return mInit;
513         }
514 
515         static int kMaxIgbpRetryDelayUs = 10000;
516 
517         std::unique_lock<std::mutex> lock(mMutex);
518         if (mLastDqLogTs == 0) {
519             mLastDqLogTs = getTimestampNow();
520         } else {
521             int64_t now = getTimestampNow();
522             if (now >= mLastDqLogTs + 5000000) {
523                 if (now >= mLastDqTs + 1000000 || mDqFailure > 5) {
524                     ALOGW("last successful dequeue was %lld us ago, "
525                           "%zu consecutive failures",
526                           (long long)(now - mLastDqTs), mDqFailure);
527                 }
528                 mLastDqLogTs = now;
529             }
530         }
531         if (mProducerId == 0) {
532             std::shared_ptr<C2GraphicAllocation> alloc;
533             c2_status_t err = mAllocator->newGraphicAllocation(
534                     width, height, format, usage, &alloc);
535             if (err != C2_OK) {
536                 return err;
537             }
538             std::shared_ptr<C2BufferQueueBlockPoolData> poolData =
539                     std::make_shared<C2BufferQueueBlockPoolData>(
540                             0, (uint64_t)0, ~0, shared_from_this());
541             *block = _C2BlockFactory::CreateGraphicBlock(alloc, poolData);
542             ALOGV("allocated a buffer successfully");
543 
544             return C2_OK;
545         }
546         c2_status_t status = fetchFromIgbp_l(width, height, format, usage, block);
547         if (status == C2_BLOCKING) {
548             lock.unlock();
549             // in order not to drain cpu from component's spinning
550             ::usleep(kMaxIgbpRetryDelayUs);
551         }
552         return status;
553     }
554 
setRenderCallback(const OnRenderCallback & renderCallback)555     void setRenderCallback(const OnRenderCallback &renderCallback) {
556         std::scoped_lock<std::mutex> lock(mMutex);
557         mRenderCallback = renderCallback;
558     }
559 
configureProducer(const sp<HGraphicBufferProducer> & producer)560     void configureProducer(const sp<HGraphicBufferProducer> &producer) {
561         uint64_t producerId = 0;
562         uint32_t generation = 0;
563         bool haveGeneration = false;
564         if (producer) {
565             Return<uint64_t> transResult = producer->getUniqueId();
566             if (!transResult.isOk()) {
567                 ALOGD("configureProducer -- failed to connect to the producer");
568                 return;
569             }
570             producerId = static_cast<uint64_t>(transResult);
571             // TODO: provide gneration number from parameter.
572             haveGeneration = getGenerationNumber(producer, &generation);
573             if (!haveGeneration) {
574                 ALOGW("get generationNumber failed %llu",
575                       (unsigned long long)producerId);
576             }
577         }
578         int migrated = 0;
579         // poolDatas dtor should not be called during lock is held.
580         std::shared_ptr<C2BufferQueueBlockPoolData>
581                 poolDatas[NUM_BUFFER_SLOTS];
582         {
583             sp<GraphicBuffer> buffers[NUM_BUFFER_SLOTS];
584             std::scoped_lock<std::mutex> lock(mMutex);
585             bool noInit = false;
586             for (int i = 0; i < NUM_BUFFER_SLOTS; ++i) {
587                 if (!noInit && mProducer) {
588                     Return<HStatus> transResult =
589                             mProducer->detachBuffer(static_cast<int32_t>(i));
590                     noInit = !transResult.isOk() ||
591                              static_cast<HStatus>(transResult) == HStatus::NO_INIT;
592                 }
593             }
594             int32_t oldGeneration = mGeneration;
595             if (producer) {
596                 mProducer = producer;
597                 mProducerId = producerId;
598                 mGeneration = haveGeneration ? generation : 0;
599             } else {
600                 mProducer = nullptr;
601                 mProducerId = 0;
602                 mGeneration = 0;
603                 ALOGW("invalid producer producer(%d), generation(%d)",
604                       (bool)producer, haveGeneration);
605             }
606             if (mProducer && haveGeneration) { // migrate buffers
607                 for (int i = 0; i < NUM_BUFFER_SLOTS; ++i) {
608                     std::shared_ptr<C2BufferQueueBlockPoolData> data =
609                             mPoolDatas[i].lock();
610                     if (data) {
611                         int slot = data->migrate(
612                                 mProducer, generation,
613                                 producerId, mBuffers, oldGeneration);
614                         if (slot >= 0) {
615                             buffers[slot] = mBuffers[i];
616                             poolDatas[slot] = data;
617                             ++migrated;
618                         }
619                     }
620                 }
621             }
622             for (int i = 0; i < NUM_BUFFER_SLOTS; ++i) {
623                 mBuffers[i] = buffers[i];
624                 mPoolDatas[i] = poolDatas[i];
625             }
626         }
627         if (producer && haveGeneration) {
628             ALOGD("local generation change %u , "
629                   "bqId: %llu migrated buffers # %d",
630                   generation, (unsigned long long)producerId, migrated);
631         }
632     }
633 
634 private:
635     friend struct C2BufferQueueBlockPoolData;
636 
cancel(uint32_t generation,uint64_t igbp_id,int32_t igbp_slot)637     void cancel(uint32_t generation, uint64_t igbp_id, int32_t igbp_slot) {
638         bool cancelled = false;
639         {
640         std::scoped_lock<std::mutex> lock(mMutex);
641         if (generation == mGeneration && igbp_id == mProducerId && mProducer) {
642             (void)mProducer->cancelBuffer(igbp_slot, hidl_handle{}).isOk();
643             cancelled = true;
644         }
645         }
646     }
647 
648     c2_status_t mInit;
649     uint64_t mProducerId;
650     uint32_t mGeneration;
651     OnRenderCallback mRenderCallback;
652 
653     size_t mDqFailure;
654     int64_t mLastDqTs;
655     int64_t mLastDqLogTs;
656 
657     const std::shared_ptr<C2Allocator> mAllocator;
658 
659     std::mutex mMutex;
660     sp<HGraphicBufferProducer> mProducer;
661     sp<HGraphicBufferProducer> mSavedProducer;
662 
663     sp<GraphicBuffer> mBuffers[NUM_BUFFER_SLOTS];
664     std::weak_ptr<C2BufferQueueBlockPoolData> mPoolDatas[NUM_BUFFER_SLOTS];
665 };
666 
C2BufferQueueBlockPoolData(uint32_t generation,uint64_t bqId,int32_t bqSlot,const std::shared_ptr<int> & owner,const sp<HGraphicBufferProducer> & producer)667 C2BufferQueueBlockPoolData::C2BufferQueueBlockPoolData(
668         uint32_t generation, uint64_t bqId, int32_t bqSlot,
669         const std::shared_ptr<int>& owner,
670         const sp<HGraphicBufferProducer>& producer) :
671         held(producer && bqId != 0), local(false),
672         generation(generation), bqId(bqId), bqSlot(bqSlot),
673         transfer(false), attach(false), display(false),
674         owner(owner), igbp(producer),
675         localPool() {
676 }
677 
C2BufferQueueBlockPoolData(uint32_t generation,uint64_t bqId,int32_t bqSlot,const std::shared_ptr<C2BufferQueueBlockPool::Impl> & pool)678 C2BufferQueueBlockPoolData::C2BufferQueueBlockPoolData(
679         uint32_t generation, uint64_t bqId, int32_t bqSlot,
680         const std::shared_ptr<C2BufferQueueBlockPool::Impl>& pool) :
681         held(true), local(true),
682         generation(generation), bqId(bqId), bqSlot(bqSlot),
683         transfer(false), attach(false), display(false),
684         igbp(pool ? pool->mProducer : nullptr),
685         localPool(pool) {
686 }
687 
~C2BufferQueueBlockPoolData()688 C2BufferQueueBlockPoolData::~C2BufferQueueBlockPoolData() {
689     if (!held || bqId == 0) {
690         return;
691     }
692     if (local) {
693         if (localPool) {
694             localPool->cancel(generation, bqId, bqSlot);
695         }
696     } else if (igbp && !owner.expired()) {
697         igbp->cancelBuffer(bqSlot, hidl_handle{}).isOk();
698     }
699 }
migrate(const sp<HGraphicBufferProducer> & producer,uint32_t toGeneration,uint64_t toBqId,sp<GraphicBuffer> * buffers,uint32_t oldGeneration)700 int C2BufferQueueBlockPoolData::migrate(
701         const sp<HGraphicBufferProducer>& producer,
702         uint32_t toGeneration, uint64_t toBqId,
703         sp<GraphicBuffer> *buffers, uint32_t oldGeneration) {
704     std::scoped_lock<std::mutex> l(lock);
705     if (!held || bqId == 0) {
706         ALOGV("buffer is not owned");
707         return -1;
708     }
709     if (!local || !localPool) {
710         ALOGV("pool is not local");
711         return -1;
712     }
713     if (bqSlot < 0 || bqSlot >= NUM_BUFFER_SLOTS || !buffers[bqSlot]) {
714         ALOGV("slot is not in effect");
715         return -1;
716     }
717     if (toGeneration == generation && bqId == toBqId) {
718         ALOGV("cannot migrate to same bufferqueue");
719         return -1;
720     }
721     if (oldGeneration != generation) {
722         ALOGV("cannot migrate stale buffer");
723     }
724     if (transfer) {
725         // either transferred or detached.
726         ALOGV("buffer is in transfer");
727         return -1;
728     }
729     sp<GraphicBuffer> const& graphicBuffer = buffers[bqSlot];
730     graphicBuffer->setGenerationNumber(toGeneration);
731 
732     HBuffer hBuffer{};
733     uint32_t hGenerationNumber{};
734     if (!b2h(graphicBuffer, &hBuffer, &hGenerationNumber)) {
735         ALOGD("I to O conversion failed");
736         return -1;
737     }
738 
739     bool converted{};
740     status_t bStatus{};
741     int slot;
742     int *outSlot = &slot;
743     Return<void> transResult =
744             producer->attachBuffer(hBuffer, hGenerationNumber,
745                     [&converted, &bStatus, outSlot](
746                             HStatus hStatus, int32_t hSlot, bool releaseAll) {
747                         converted = h2b(hStatus, &bStatus);
748                         *outSlot = static_cast<int>(hSlot);
749                         if (converted && releaseAll && bStatus == android::OK) {
750                             bStatus = android::INVALID_OPERATION;
751                         }
752                     });
753     if (!transResult.isOk() || !converted || bStatus != android::OK) {
754         ALOGD("attach failed %d", static_cast<int>(bStatus));
755         return -1;
756     }
757     ALOGV("local migration from gen %u : %u slot %d : %d",
758           generation, toGeneration, bqSlot, slot);
759     generation = toGeneration;
760     bqId = toBqId;
761     bqSlot = slot;
762     return slot;
763 }
764 
C2BufferQueueBlockPool(const std::shared_ptr<C2Allocator> & allocator,const local_id_t localId)765 C2BufferQueueBlockPool::C2BufferQueueBlockPool(
766         const std::shared_ptr<C2Allocator> &allocator, const local_id_t localId)
767         : mAllocator(allocator), mLocalId(localId), mImpl(new Impl(allocator)) {}
768 
~C2BufferQueueBlockPool()769 C2BufferQueueBlockPool::~C2BufferQueueBlockPool() {}
770 
fetchGraphicBlock(uint32_t width,uint32_t height,uint32_t format,C2MemoryUsage usage,std::shared_ptr<C2GraphicBlock> * block)771 c2_status_t C2BufferQueueBlockPool::fetchGraphicBlock(
772         uint32_t width,
773         uint32_t height,
774         uint32_t format,
775         C2MemoryUsage usage,
776         std::shared_ptr<C2GraphicBlock> *block /* nonnull */) {
777     if (mImpl) {
778         return mImpl->fetchGraphicBlock(width, height, format, usage, block);
779     }
780     return C2_CORRUPTED;
781 }
782 
configureProducer(const sp<HGraphicBufferProducer> & producer)783 void C2BufferQueueBlockPool::configureProducer(const sp<HGraphicBufferProducer> &producer) {
784     if (mImpl) {
785         mImpl->configureProducer(producer);
786     }
787 }
788 
setRenderCallback(const OnRenderCallback & renderCallback)789 void C2BufferQueueBlockPool::setRenderCallback(const OnRenderCallback &renderCallback) {
790     if (mImpl) {
791         mImpl->setRenderCallback(renderCallback);
792     }
793 }
794