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