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