1 /*
2  * Copyright (C) 2019 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 "StreamBufferCacheManager"
19 #define ATRACE_TAG ATRACE_TAG_CAMERA
20 
21 #include <cutils/native_handle.h>
22 #include <cutils/properties.h>
23 #include <log/log.h>
24 #include <sync/sync.h>
25 #include <sys/resource.h>
26 #include <utils/Trace.h>
27 
28 #include <chrono>
29 
30 #include "stream_buffer_cache_manager.h"
31 #include "utils.h"
32 
33 using namespace std::chrono_literals;
34 
35 namespace android {
36 namespace google_camera_hal {
37 
38 // setprop key for raising buffer allocation priority
39 inline constexpr char kRaiseBufAllocationPriority[] =
40     "persist.vendor.camera.raise_buf_allocation_priority";
41 
42 // For CTS testCameraDeviceCaptureFailure, it holds image buffers and hal hits
43 // refill buffer timeout. Large timeout time also results in close session time
44 // is larger than 5 second in this test case. Typical buffer request from
45 // provider(e.g. framework) usually takes 1~2 ms. Small timeout time here may
46 // cause more framedrop in certain cases. But large timeout time can lead to
47 // extra long delay of traffic(in both ways) between the framework and the layer
48 // below HWL.
49 static constexpr auto kBufferWaitingTimeOutSec = 400ms;
50 
StreamBufferCacheManager(const std::set<int32_t> & hal_buffer_managed_stream_ids)51 StreamBufferCacheManager::StreamBufferCacheManager(
52     const std::set<int32_t>& hal_buffer_managed_stream_ids)
53     : hal_buffer_managed_streams_(hal_buffer_managed_stream_ids) {
54   workload_thread_ = std::thread([this] { this->WorkloadThreadLoop(); });
55   if (utils::SupportRealtimeThread()) {
56     status_t res = utils::SetRealtimeThread(workload_thread_.native_handle());
57     if (res != OK) {
58       ALOGE("%s: SetRealtimeThread fail", __FUNCTION__);
59     } else {
60       ALOGI("%s: SetRealtimeThread OK", __FUNCTION__);
61     }
62   }
63 }
64 
~StreamBufferCacheManager()65 StreamBufferCacheManager::~StreamBufferCacheManager() {
66   ALOGI("%s: Destroying stream buffer cache manager.", __FUNCTION__);
67   {
68     std::lock_guard<std::mutex> lock(workload_mutex_);
69     workload_thread_exiting_ = true;
70   }
71   workload_cv_.notify_one();
72   workload_thread_.join();
73 }
74 
Create(const std::set<int32_t> & hal_buffer_managed_stream_ids)75 std::unique_ptr<StreamBufferCacheManager> StreamBufferCacheManager::Create(
76     const std::set<int32_t>& hal_buffer_managed_stream_ids) {
77   ATRACE_CALL();
78 
79   auto manager = std::unique_ptr<StreamBufferCacheManager>(
80       new StreamBufferCacheManager(hal_buffer_managed_stream_ids));
81   if (manager == nullptr) {
82     ALOGE("%s: Failed to create stream buffer cache manager.", __FUNCTION__);
83     return nullptr;
84   }
85 
86   manager->dummy_buffer_allocator_ = GrallocBufferAllocator::Create();
87   if (manager->dummy_buffer_allocator_ == nullptr) {
88     ALOGE("%s: Failed to create gralloc buffer allocator", __FUNCTION__);
89     return nullptr;
90   }
91 
92   ALOGI("%s: Created StreamBufferCacheManager.", __FUNCTION__);
93 
94   return manager;
95 }
96 
RegisterStream(const StreamBufferCacheRegInfo & reg_info)97 status_t StreamBufferCacheManager::RegisterStream(
98     const StreamBufferCacheRegInfo& reg_info) {
99   ATRACE_CALL();
100   if (reg_info.request_func == nullptr || reg_info.return_func == nullptr) {
101     ALOGE("%s: Can't register stream, request or return function is nullptr.",
102           __FUNCTION__);
103     return BAD_VALUE;
104   }
105 
106   if (hal_buffer_managed_streams_.find(reg_info.stream_id) ==
107       hal_buffer_managed_streams_.end()) {
108     ALOGE(
109         "%s: SBC only supports registering HAL buffer managed streams, "
110         "stream id %d not supported",
111         __FUNCTION__, reg_info.stream_id);
112     return BAD_VALUE;
113   }
114 
115   if (reg_info.num_buffers_to_cache != 1) {
116     ALOGE("%s: Only support caching one buffer.", __FUNCTION__);
117     return BAD_VALUE;
118   }
119 
120   std::lock_guard<std::mutex> lock(caches_map_mutex_);
121   if (stream_buffer_caches_.find(reg_info.stream_id) !=
122       stream_buffer_caches_.end()) {
123     ALOGE("%s: Stream %d has been registered.", __FUNCTION__,
124           reg_info.stream_id);
125     return INVALID_OPERATION;
126   }
127 
128   status_t res = AddStreamBufferCacheLocked(reg_info);
129   if (res != OK) {
130     ALOGE("%s: Failed to add stream buffer cache.", __FUNCTION__);
131     return UNKNOWN_ERROR;
132   }
133   return OK;
134 }
135 
GetStreamBuffer(int32_t stream_id,StreamBufferRequestResult * res)136 status_t StreamBufferCacheManager::GetStreamBuffer(
137     int32_t stream_id, StreamBufferRequestResult* res) {
138   ATRACE_CALL();
139   if (hal_buffer_managed_streams_.find(stream_id) ==
140       hal_buffer_managed_streams_.end()) {
141     ALOGE(
142         "%s: SBC only supports registering HAL buffer managed streams, "
143         "stream id %d not supported",
144         __FUNCTION__, stream_id);
145     return BAD_VALUE;
146   }
147   StreamBufferCache* stream_buffer_cache = nullptr;
148   status_t result = GetStreamBufferCache(stream_id, &stream_buffer_cache);
149   if (result != OK) {
150     ALOGE("%s: Querying stream buffer cache failed.", __FUNCTION__);
151     return result;
152   }
153 
154   result = stream_buffer_cache->GetBuffer(res);
155   if (result != OK) {
156     ALOGE("%s: Get buffer for stream %d failed.", __FUNCTION__, stream_id);
157     return UNKNOWN_ERROR;
158   }
159 
160   {
161     int fence_status = 0;
162     if (res->buffer.acquire_fence != nullptr) {
163       native_handle_t* fence_handle =
164           const_cast<native_handle_t*>(res->buffer.acquire_fence);
165       if (fence_handle->numFds == 1) {
166         fence_status = sync_wait(fence_handle->data[0], kSyncWaitTimeMs);
167       }
168       if (0 != fence_status) {
169         ALOGE("%s: Fence check failed.", __FUNCTION__);
170       }
171       native_handle_close(fence_handle);
172       native_handle_delete(fence_handle);
173       res->buffer.acquire_fence = nullptr;
174     }
175   }
176 
177   NotifyThreadWorkload();
178   return OK;
179 }
180 
NotifyProviderReadiness(int32_t stream_id)181 status_t StreamBufferCacheManager::NotifyProviderReadiness(int32_t stream_id) {
182   if (hal_buffer_managed_streams_.find(stream_id) ==
183       hal_buffer_managed_streams_.end()) {
184     ALOGE(
185         "%s: SBC only supports HAL buffer managed streams, "
186         "stream id %d not supported",
187         __FUNCTION__, stream_id);
188     return BAD_VALUE;
189   }
190   StreamBufferCache* stream_buffer_cache = nullptr;
191   status_t res = GetStreamBufferCache(stream_id, &stream_buffer_cache);
192   if (res != OK) {
193     ALOGE("%s: Querying stream buffer cache failed.", __FUNCTION__);
194     return res;
195   }
196 
197   stream_buffer_cache->SetManagerState(/*active=*/true);
198 
199   NotifyThreadWorkload();
200   return OK;
201 }
202 
NotifyFlushingAll()203 status_t StreamBufferCacheManager::NotifyFlushingAll() {
204   // Mark all StreamBufferCache as need to be flushed
205   std::vector<StreamBufferCache*> stream_buffer_caches;
206   {
207     std::lock_guard<std::mutex> map_lock(caches_map_mutex_);
208     for (auto& [stream_id, stream_buffer_cache] : stream_buffer_caches_) {
209       stream_buffer_caches.push_back(stream_buffer_cache.get());
210     }
211   }
212 
213   {
214     std::unique_lock<std::mutex> flush_lock(flush_mutex_);
215     for (auto& stream_buffer_cache : stream_buffer_caches) {
216       stream_buffer_cache->SetManagerState(/*active=*/false);
217     }
218   }
219 
220   NotifyThreadWorkload();
221   return OK;
222 }
223 
IsStreamActive(int32_t stream_id,bool * is_active)224 status_t StreamBufferCacheManager::IsStreamActive(int32_t stream_id,
225                                                   bool* is_active) {
226   if (hal_buffer_managed_streams_.find(stream_id) ==
227       hal_buffer_managed_streams_.end()) {
228     ALOGE(
229         "%s: SBC only supports HAL buffer managed streams, "
230         "stream id %d not supported",
231         __FUNCTION__, stream_id);
232     return BAD_VALUE;
233   }
234   StreamBufferCache* stream_buffer_cache = nullptr;
235   status_t res = GetStreamBufferCache(stream_id, &stream_buffer_cache);
236   if (res != OK) {
237     ALOGE("%s: Querying stream buffer cache failed.", __FUNCTION__);
238     return res;
239   }
240 
241   *is_active = !stream_buffer_cache->IsStreamDeactivated();
242   return OK;
243 }
244 
AddStreamBufferCacheLocked(const StreamBufferCacheRegInfo & reg_info)245 status_t StreamBufferCacheManager::AddStreamBufferCacheLocked(
246     const StreamBufferCacheRegInfo& reg_info) {
247   auto stream_buffer_cache = StreamBufferCacheManager::StreamBufferCache::Create(
248       reg_info, [this] { this->NotifyThreadWorkload(); },
249       dummy_buffer_allocator_.get());
250   if (stream_buffer_cache == nullptr) {
251     ALOGE("%s: Failed to create StreamBufferCache for stream %d", __FUNCTION__,
252           reg_info.stream_id);
253     return UNKNOWN_ERROR;
254   }
255 
256   stream_buffer_caches_[reg_info.stream_id] = std::move(stream_buffer_cache);
257   return OK;
258 }
259 
WorkloadThreadLoop()260 void StreamBufferCacheManager::WorkloadThreadLoop() {
261   if (property_get_bool(kRaiseBufAllocationPriority, true)) {
262     pid_t tid = gettid();
263     setpriority(PRIO_PROCESS, tid, -20);
264   }
265   // max thread name len = 16
266   pthread_setname_np(pthread_self(), "StreamBufMgr");
267   while (1) {
268     bool exiting = false;
269     {
270       std::unique_lock<std::mutex> thread_lock(workload_mutex_);
271       workload_cv_.wait(thread_lock, [this] {
272         return has_new_workload_ || workload_thread_exiting_;
273       });
274       has_new_workload_ = false;
275       exiting = workload_thread_exiting_;
276     }
277 
278     std::vector<StreamBufferCacheManager::StreamBufferCache*> stream_buffer_caches;
279     {
280       std::unique_lock<std::mutex> map_lock(caches_map_mutex_);
281       for (auto& [stream_id, cache] : stream_buffer_caches_) {
282         stream_buffer_caches.push_back(cache.get());
283       }
284     }
285 
286     {
287       std::unique_lock<std::mutex> flush_lock(flush_mutex_);
288       for (auto& stream_buffer_cache : stream_buffer_caches) {
289         status_t res = stream_buffer_cache->UpdateCache(exiting);
290         if (res != OK) {
291           ALOGE("%s: Updating(flush/refill) cache failed.", __FUNCTION__);
292         }
293       }
294     }
295 
296     if (exiting) {
297       ALOGI("%s: Exiting stream buffer cache manager workload thread.",
298             __FUNCTION__);
299       return;
300     }
301   }
302 }
303 
NotifyThreadWorkload()304 void StreamBufferCacheManager::NotifyThreadWorkload() {
305   {
306     std::lock_guard<std::mutex> lock(workload_mutex_);
307     has_new_workload_ = true;
308   }
309   workload_cv_.notify_one();
310 }
311 
312 std::unique_ptr<StreamBufferCacheManager::StreamBufferCache>
Create(const StreamBufferCacheRegInfo & reg_info,NotifyManagerThreadWorkloadFunc notify,IHalBufferAllocator * dummy_buffer_allocator)313 StreamBufferCacheManager::StreamBufferCache::Create(
314     const StreamBufferCacheRegInfo& reg_info,
315     NotifyManagerThreadWorkloadFunc notify,
316     IHalBufferAllocator* dummy_buffer_allocator) {
317   if (notify == nullptr || dummy_buffer_allocator == nullptr) {
318     ALOGE("%s: notify is nullptr or dummy_buffer_allocator is nullptr.",
319           __FUNCTION__);
320     return nullptr;
321   }
322 
323   auto cache = std::unique_ptr<StreamBufferCacheManager::StreamBufferCache>(
324       new StreamBufferCacheManager::StreamBufferCache(reg_info, notify,
325                                                       dummy_buffer_allocator));
326   if (cache == nullptr) {
327     ALOGE("%s: Failed to create stream buffer cache.", __FUNCTION__);
328     return nullptr;
329   }
330 
331   return cache;
332 }
333 
StreamBufferCache(const StreamBufferCacheRegInfo & reg_info,NotifyManagerThreadWorkloadFunc notify,IHalBufferAllocator * dummy_buffer_allocator)334 StreamBufferCacheManager::StreamBufferCache::StreamBufferCache(
335     const StreamBufferCacheRegInfo& reg_info,
336     NotifyManagerThreadWorkloadFunc notify,
337     IHalBufferAllocator* dummy_buffer_allocator)
338     : cache_info_(reg_info) {
339   std::lock_guard<std::mutex> lock(cache_access_mutex_);
340   notify_for_workload_ = notify;
341   dummy_buffer_allocator_ = dummy_buffer_allocator;
342 }
343 
UpdateCache(bool forced_flushing)344 status_t StreamBufferCacheManager::StreamBufferCache::UpdateCache(
345     bool forced_flushing) {
346   status_t res = OK;
347   std::unique_lock<std::mutex> cache_lock(cache_access_mutex_);
348   if (forced_flushing || !is_active_) {
349     res = FlushLocked(forced_flushing);
350     if (res != OK) {
351       ALOGE("%s: Failed to flush stream buffer cache for stream %d",
352             __FUNCTION__, cache_info_.stream_id);
353       return res;
354     }
355   } else if (RefillableLocked()) {
356     cache_lock.unlock();
357     res = Refill();
358     if (res != OK) {
359       ALOGE("%s: Failed to refill stream buffer cache for stream %d",
360             __FUNCTION__, cache_info_.stream_id);
361       return res;
362     }
363   }
364   return OK;
365 }
366 
GetBuffer(StreamBufferRequestResult * res)367 status_t StreamBufferCacheManager::StreamBufferCache::GetBuffer(
368     StreamBufferRequestResult* res) {
369   std::unique_lock<std::mutex> cache_lock(cache_access_mutex_);
370 
371   // 0. the buffer cache must be active
372   if (!is_active_) {
373     ALOGW("%s: The buffer cache for stream %d is not active.", __FUNCTION__,
374           cache_info_.stream_id);
375     return INVALID_OPERATION;
376   }
377 
378   // 1. check if the cache is deactived
379   if (stream_deactived_) {
380     res->is_dummy_buffer = true;
381     res->buffer = dummy_buffer_;
382     return OK;
383   }
384 
385   // 2. check if there is any buffer available in the cache. If not, try
386   // to wait for a short period and check again. In case of timeout, use the
387   // dummy buffer instead.
388   if (cached_buffers_.empty()) {
389     // In case the GetStreamBufer is called after NotifyFlushingAll, this will
390     // be the first event that should trigger the dedicated thread to restart
391     // and refill the caches. An extra notification of thread workload is
392     // harmless and will be bypassed very quickly.
393     cache_lock.unlock();
394     notify_for_workload_();
395     cache_lock.lock();
396     // Need to check this again since the state may change after the lock is
397     // acquired for the second time.
398     if (cached_buffers_.empty()) {
399       // Wait for a certain amount of time for the cache to be refilled
400       if (cache_access_cv_.wait_for(cache_lock, kBufferWaitingTimeOutSec) ==
401           std::cv_status::timeout) {
402         ALOGW("%s: StreamBufferCache for stream %d waiting for refill timeout.",
403               __FUNCTION__, cache_info_.stream_id);
404       }
405     }
406   }
407 
408   // 3. use dummy buffer if the cache is still empty
409   if (cached_buffers_.empty()) {
410     // Only allocate dummy buffer for the first time
411     if (dummy_buffer_.buffer == nullptr) {
412       status_t result = AllocateDummyBufferLocked();
413       if (result != OK) {
414         ALOGE("%s: Allocate dummy buffer failed.", __FUNCTION__);
415         return UNKNOWN_ERROR;
416       }
417     }
418     res->is_dummy_buffer = true;
419     res->buffer = dummy_buffer_;
420     return OK;
421   } else {
422     res->is_dummy_buffer = false;
423     res->buffer = cached_buffers_.back();
424     cached_buffers_.pop_back();
425   }
426 
427   return OK;
428 }
429 
IsStreamDeactivated()430 bool StreamBufferCacheManager::StreamBufferCache::IsStreamDeactivated() {
431   std::unique_lock<std::mutex> lock(cache_access_mutex_);
432   return stream_deactived_;
433 }
434 
SetManagerState(bool active)435 void StreamBufferCacheManager::StreamBufferCache::SetManagerState(bool active) {
436   std::unique_lock<std::mutex> lock(cache_access_mutex_);
437   is_active_ = active;
438 }
439 
FlushLocked(bool forced_flushing)440 status_t StreamBufferCacheManager::StreamBufferCache::FlushLocked(
441     bool forced_flushing) {
442   if (is_active_ && !forced_flushing) {
443     ALOGI("%s: Active stream buffer cache is not notified for forced flushing.",
444           __FUNCTION__);
445     return INVALID_OPERATION;
446   }
447 
448   if (cache_info_.return_func == nullptr) {
449     ALOGE("%s: return_func is nullptr.", __FUNCTION__);
450     return UNKNOWN_ERROR;
451   }
452 
453   if (cached_buffers_.empty()) {
454     ALOGV("%s: Stream buffer cache is already empty.", __FUNCTION__);
455     ReleaseDummyBufferLocked();
456     return OK;
457   }
458 
459   status_t res = cache_info_.return_func(cached_buffers_);
460   if (res != OK) {
461     ALOGE("%s: Failed to return buffers.", __FUNCTION__);
462     return res;
463   }
464 
465   cached_buffers_.clear();
466   ReleaseDummyBufferLocked();
467 
468   return OK;
469 }
470 
Refill()471 status_t StreamBufferCacheManager::StreamBufferCache::Refill() {
472   int32_t num_buffers_to_acquire = 0;
473   {
474     std::unique_lock<std::mutex> cache_lock(cache_access_mutex_);
475     if (cache_info_.request_func == nullptr) {
476       ALOGE("%s: request_func is nullptr.", __FUNCTION__);
477       return UNKNOWN_ERROR;
478     }
479 
480     if (!is_active_) {
481       ALOGI("%s: Buffer cache is not active.", __FUNCTION__);
482       return UNKNOWN_ERROR;
483     }
484 
485     if (stream_deactived_) {
486       ALOGI("%s: Stream already deactived.", __FUNCTION__);
487       return OK;
488     }
489 
490     if (cached_buffers_.size() >= cache_info_.num_buffers_to_cache) {
491       ALOGV("%s: Stream buffer cache is already full.", __FUNCTION__);
492       return INVALID_OPERATION;
493     }
494 
495     num_buffers_to_acquire =
496         cache_info_.num_buffers_to_cache - cached_buffers_.size();
497   }
498 
499   // Requesting buffer from the provider can take long(e.g. even > 1sec),
500   // consumer should not be blocked by this procedure and can get dummy buffer
501   // to unblock other pipelines. Thus, cache_access_mutex_ doesn't need to be
502   // locked here.
503   std::vector<StreamBuffer> buffers;
504   StreamBufferRequestError req_status = StreamBufferRequestError::kOk;
505   status_t res =
506       cache_info_.request_func(num_buffers_to_acquire, &buffers, &req_status);
507 
508   std::unique_lock<std::mutex> cache_lock(cache_access_mutex_);
509   if (res != OK) {
510     status_t result = AllocateDummyBufferLocked();
511     if (result != OK) {
512       ALOGE("%s: Allocate dummy buffer failed.", __FUNCTION__);
513       return UNKNOWN_ERROR;
514     }
515   }
516 
517   if (buffers.empty() || res != OK) {
518     ALOGW("%s: Failed to acquire buffer for stream %d, error %d", __FUNCTION__,
519           cache_info_.stream_id, req_status);
520     switch (req_status) {
521       case StreamBufferRequestError::kNoBufferAvailable:
522       case StreamBufferRequestError::kMaxBufferExceeded:
523         ALOGI(
524             "%s: No buffer available or max buffer exceeded for stream %d. "
525             "Will retry for next request or when refilling other streams.",
526             __FUNCTION__, cache_info_.stream_id);
527         break;
528       case StreamBufferRequestError::kStreamDisconnected:
529       case StreamBufferRequestError::kUnknownError:
530         ALOGW(
531             "%s: Stream %d is disconnected or unknown error observed."
532             "This stream is marked as inactive.",
533             __FUNCTION__, cache_info_.stream_id);
534         ALOGI("%s: Stream %d begin to use dummy buffer.", __FUNCTION__,
535               cache_info_.stream_id);
536         stream_deactived_ = true;
537         break;
538       default:
539         ALOGE("%s: Unknown error code: %d", __FUNCTION__, req_status);
540         break;
541     }
542   } else {
543     for (auto& buffer : buffers) {
544       cached_buffers_.push_back(buffer);
545     }
546   }
547 
548   cache_access_cv_.notify_one();
549 
550   return OK;
551 }
552 
RefillableLocked() const553 bool StreamBufferCacheManager::StreamBufferCache::RefillableLocked() const {
554   // No need to refill if the buffer cache is not active
555   if (!is_active_) {
556     return false;
557   }
558 
559   // Need to refill if the cache is not full
560   return cached_buffers_.size() < cache_info_.num_buffers_to_cache;
561 }
562 
AllocateDummyBufferLocked()563 status_t StreamBufferCacheManager::StreamBufferCache::AllocateDummyBufferLocked() {
564   if (dummy_buffer_.buffer != nullptr) {
565     ALOGW("%s: Dummy buffer has already been allocated.", __FUNCTION__);
566     return OK;
567   }
568 
569   HalBufferDescriptor hal_buffer_descriptor{
570       .stream_id = cache_info_.stream_id,
571       .width = cache_info_.width,
572       .height = cache_info_.height,
573       .format = cache_info_.format,
574       .producer_flags = cache_info_.producer_flags,
575       .consumer_flags = cache_info_.consumer_flags,
576       .immediate_num_buffers = 1,
577       .max_num_buffers = 1,
578   };
579   std::vector<buffer_handle_t> buffers;
580 
581   status_t res =
582       dummy_buffer_allocator_->AllocateBuffers(hal_buffer_descriptor, &buffers);
583   if (res != OK) {
584     ALOGE("%s: Dummy buffer allocator AllocateBuffers failed.", __FUNCTION__);
585     return res;
586   }
587 
588   if (buffers.size() != hal_buffer_descriptor.immediate_num_buffers) {
589     ALOGE("%s: Not enough buffers allocated.", __FUNCTION__);
590     return NO_MEMORY;
591   }
592   dummy_buffer_.stream_id = cache_info_.stream_id;
593   dummy_buffer_.buffer = buffers[0];
594   ALOGI("%s: [sbc] Dummy buffer allocated: strm %d buffer %p", __FUNCTION__,
595         dummy_buffer_.stream_id, dummy_buffer_.buffer);
596 
597   return OK;
598 }
599 
ReleaseDummyBufferLocked()600 void StreamBufferCacheManager::StreamBufferCache::ReleaseDummyBufferLocked() {
601   // Release dummy buffer if ever acquired from the dummy_buffer_allocator_.
602   if (dummy_buffer_.buffer != nullptr) {
603     std::vector<buffer_handle_t> buffers(1, dummy_buffer_.buffer);
604     dummy_buffer_allocator_->FreeBuffers(&buffers);
605     dummy_buffer_.buffer = nullptr;
606   }
607 }
608 
GetStreamBufferCache(int32_t stream_id,StreamBufferCache ** stream_buffer_cache)609 status_t StreamBufferCacheManager::GetStreamBufferCache(
610     int32_t stream_id, StreamBufferCache** stream_buffer_cache) {
611   std::unique_lock<std::mutex> map_lock(caches_map_mutex_);
612   if (hal_buffer_managed_streams_.find(stream_id) ==
613       hal_buffer_managed_streams_.end()) {
614     ALOGE(
615         "%s: SBC only supports HAL buffer managed streams, "
616         "stream id %d not supported",
617         __FUNCTION__, stream_id);
618     return BAD_VALUE;
619   }
620 
621   if (stream_buffer_caches_.find(stream_id) == stream_buffer_caches_.end()) {
622     ALOGE("%s: Stream %d can not be found.", __FUNCTION__, stream_id);
623     return BAD_VALUE;
624   }
625 
626   *stream_buffer_cache = stream_buffer_caches_[stream_id].get();
627   if (*stream_buffer_cache == nullptr) {
628     ALOGE("%s: Get null cache pointer.", __FUNCTION__);
629     return UNKNOWN_ERROR;
630   }
631   return OK;
632 }
633 
634 }  // namespace google_camera_hal
635 }  // namespace android
636