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