• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #define LOG_TAG "BufferPoolClient"
18 //#define LOG_NDEBUG 0
19 
20 #include <thread>
21 #include <utils/Log.h>
22 #include "BufferPoolClient.h"
23 #include "Connection.h"
24 
25 namespace android {
26 namespace hardware {
27 namespace media {
28 namespace bufferpool {
29 namespace V1_0 {
30 namespace implementation {
31 
32 static constexpr int64_t kReceiveTimeoutUs = 1000000; // 100ms
33 static constexpr int kPostMaxRetry = 3;
34 static constexpr int kCacheTtlUs = 1000000; // TODO: tune
35 
36 class BufferPoolClient::Impl
37         : public std::enable_shared_from_this<BufferPoolClient::Impl> {
38 public:
39     explicit Impl(const sp<Accessor> &accessor);
40 
41     explicit Impl(const sp<IAccessor> &accessor);
42 
isValid()43     bool isValid() {
44         return mValid;
45     }
46 
isLocal()47     bool isLocal() {
48         return mValid && mLocal;
49     }
50 
getConnectionId()51     ConnectionId getConnectionId() {
52         return mConnectionId;
53     }
54 
getAccessor()55     sp<IAccessor> &getAccessor() {
56         return mAccessor;
57     }
58 
59     bool isActive(int64_t *lastTransactionUs, bool clearCache);
60 
61     ResultStatus allocate(const std::vector<uint8_t> &params,
62                           native_handle_t **handle,
63                           std::shared_ptr<BufferPoolData> *buffer);
64 
65     ResultStatus receive(
66             TransactionId transactionId, BufferId bufferId,
67             int64_t timestampUs,
68             native_handle_t **handle, std::shared_ptr<BufferPoolData> *buffer);
69 
70     void postBufferRelease(BufferId bufferId);
71 
72     bool postSend(
73             BufferId bufferId, ConnectionId receiver,
74             TransactionId *transactionId, int64_t *timestampUs);
75 private:
76 
77     bool postReceive(
78             BufferId bufferId, TransactionId transactionId,
79             int64_t timestampUs);
80 
81     bool postReceiveResult(
82             BufferId bufferId, TransactionId transactionId, bool result);
83 
84     bool syncReleased();
85 
86     void evictCaches(bool clearCache = false);
87 
88     ResultStatus allocateBufferHandle(
89             const std::vector<uint8_t>& params, BufferId *bufferId,
90             native_handle_t **handle);
91 
92     ResultStatus fetchBufferHandle(
93             TransactionId transactionId, BufferId bufferId,
94             native_handle_t **handle);
95 
96 
97     struct BlockPoolDataDtor;
98     struct ClientBuffer;
99 
100     bool mLocal;
101     bool mValid;
102     sp<IAccessor> mAccessor;
103     sp<Connection> mLocalConnection;
104     sp<IConnection> mRemoteConnection;
105     uint32_t mSeqId;
106     ConnectionId mConnectionId;
107     int64_t mLastEvictCacheUs;
108 
109     // CachedBuffers
110     struct BufferCache {
111         std::mutex mLock;
112         bool mCreating;
113         std::condition_variable mCreateCv;
114         std::map<BufferId, std::unique_ptr<ClientBuffer>> mBuffers;
115         int mActive;
116         int64_t mLastChangeUs;
117 
BufferCacheandroid::hardware::media::bufferpool::V1_0::implementation::BufferPoolClient::Impl::BufferCache118         BufferCache() : mCreating(false), mActive(0), mLastChangeUs(getTimestampNow()) {}
119 
incActive_landroid::hardware::media::bufferpool::V1_0::implementation::BufferPoolClient::Impl::BufferCache120         void incActive_l() {
121             ++mActive;
122             mLastChangeUs = getTimestampNow();
123         }
124 
decActive_landroid::hardware::media::bufferpool::V1_0::implementation::BufferPoolClient::Impl::BufferCache125         void decActive_l() {
126             --mActive;
127             mLastChangeUs = getTimestampNow();
128         }
129     } mCache;
130 
131     // FMQ - release notifier
132     struct {
133         std::mutex mLock;
134         // TODO: use only one list?(using one list may dealy sending messages?)
135         std::list<BufferId> mReleasingIds;
136         std::list<BufferId> mReleasedIds;
137         std::unique_ptr<BufferStatusChannel> mStatusChannel;
138     } mReleasing;
139 };
140 
141 struct BufferPoolClient::Impl::BlockPoolDataDtor {
BlockPoolDataDtorandroid::hardware::media::bufferpool::V1_0::implementation::BufferPoolClient::Impl::BlockPoolDataDtor142     BlockPoolDataDtor(const std::shared_ptr<BufferPoolClient::Impl> &impl)
143             : mImpl(impl) {}
144 
operator ()android::hardware::media::bufferpool::V1_0::implementation::BufferPoolClient::Impl::BlockPoolDataDtor145     void operator()(BufferPoolData *buffer) {
146         BufferId id = buffer->mId;
147         delete buffer;
148 
149         auto impl = mImpl.lock();
150         if (impl && impl->isValid()) {
151             impl->postBufferRelease(id);
152         }
153     }
154     const std::weak_ptr<BufferPoolClient::Impl> mImpl;
155 };
156 
157 struct BufferPoolClient::Impl::ClientBuffer {
158 private:
159     bool mInvalidated; // TODO: implement
160     int64_t mExpireUs;
161     bool mHasCache;
162     ConnectionId mConnectionId;
163     BufferId mId;
164     native_handle_t *mHandle;
165     std::weak_ptr<BufferPoolData> mCache;
166 
updateExpireandroid::hardware::media::bufferpool::V1_0::implementation::BufferPoolClient::Impl::ClientBuffer167     void updateExpire() {
168         mExpireUs = getTimestampNow() + kCacheTtlUs;
169     }
170 
171 public:
ClientBufferandroid::hardware::media::bufferpool::V1_0::implementation::BufferPoolClient::Impl::ClientBuffer172     ClientBuffer(
173             ConnectionId connectionId, BufferId id, native_handle_t *handle)
174             : mInvalidated(false), mHasCache(false),
175               mConnectionId(connectionId), mId(id), mHandle(handle) {
176         (void)mInvalidated;
177         mExpireUs = getTimestampNow() + kCacheTtlUs;
178     }
179 
~ClientBufferandroid::hardware::media::bufferpool::V1_0::implementation::BufferPoolClient::Impl::ClientBuffer180     ~ClientBuffer() {
181         if (mHandle) {
182             native_handle_close(mHandle);
183             native_handle_delete(mHandle);
184         }
185     }
186 
expireandroid::hardware::media::bufferpool::V1_0::implementation::BufferPoolClient::Impl::ClientBuffer187     bool expire() const {
188         int64_t now = getTimestampNow();
189         return now >= mExpireUs;
190     }
191 
hasCacheandroid::hardware::media::bufferpool::V1_0::implementation::BufferPoolClient::Impl::ClientBuffer192     bool hasCache() const {
193         return mHasCache;
194     }
195 
fetchCacheandroid::hardware::media::bufferpool::V1_0::implementation::BufferPoolClient::Impl::ClientBuffer196     std::shared_ptr<BufferPoolData> fetchCache(native_handle_t **pHandle) {
197         if (mHasCache) {
198             std::shared_ptr<BufferPoolData> cache = mCache.lock();
199             if (cache) {
200                 *pHandle = mHandle;
201             }
202             return cache;
203         }
204         return nullptr;
205     }
206 
createCacheandroid::hardware::media::bufferpool::V1_0::implementation::BufferPoolClient::Impl::ClientBuffer207     std::shared_ptr<BufferPoolData> createCache(
208             const std::shared_ptr<BufferPoolClient::Impl> &impl,
209             native_handle_t **pHandle) {
210         if (!mHasCache) {
211             // Allocates a raw ptr in order to avoid sending #postBufferRelease
212             // from deleter, in case of native_handle_clone failure.
213             BufferPoolData *ptr = new BufferPoolData(mConnectionId, mId);
214             if (ptr) {
215                 std::shared_ptr<BufferPoolData> cache(ptr, BlockPoolDataDtor(impl));
216                 if (cache) {
217                     mCache = cache;
218                     mHasCache = true;
219                     *pHandle = mHandle;
220                     return cache;
221                 }
222             }
223             if (ptr) {
224                 delete ptr;
225             }
226         }
227         return nullptr;
228     }
229 
onCacheReleaseandroid::hardware::media::bufferpool::V1_0::implementation::BufferPoolClient::Impl::ClientBuffer230     bool onCacheRelease() {
231         if (mHasCache) {
232             // TODO: verify mCache is not valid;
233             updateExpire();
234             mHasCache = false;
235             return true;
236         }
237         return false;
238     }
239 };
240 
Impl(const sp<Accessor> & accessor)241 BufferPoolClient::Impl::Impl(const sp<Accessor> &accessor)
242     : mLocal(true), mValid(false), mAccessor(accessor), mSeqId(0),
243       mLastEvictCacheUs(getTimestampNow()) {
244     const QueueDescriptor *fmqDesc;
245     ResultStatus status = accessor->connect(
246             &mLocalConnection, &mConnectionId, &fmqDesc, true);
247     if (status == ResultStatus::OK) {
248         mReleasing.mStatusChannel =
249                 std::make_unique<BufferStatusChannel>(*fmqDesc);
250         mValid = mReleasing.mStatusChannel &&
251                 mReleasing.mStatusChannel->isValid();
252     }
253 }
254 
Impl(const sp<IAccessor> & accessor)255 BufferPoolClient::Impl::Impl(const sp<IAccessor> &accessor)
256     : mLocal(false), mValid(false), mAccessor(accessor), mSeqId(0),
257       mLastEvictCacheUs(getTimestampNow()) {
258     bool valid = false;
259     sp<IConnection>& outConnection = mRemoteConnection;
260     ConnectionId& id = mConnectionId;
261     std::unique_ptr<BufferStatusChannel>& outChannel =
262             mReleasing.mStatusChannel;
263     Return<void> transResult = accessor->connect(
264             [&valid, &outConnection, &id, &outChannel]
265             (ResultStatus status, sp<IConnection> connection,
266              ConnectionId connectionId, const QueueDescriptor& desc) {
267                 if (status == ResultStatus::OK) {
268                     outConnection = connection;
269                     id = connectionId;
270                     outChannel = std::make_unique<BufferStatusChannel>(desc);
271                     if (outChannel && outChannel->isValid()) {
272                         valid = true;
273                     }
274                 }
275             });
276     mValid = transResult.isOk() && valid;
277 }
278 
isActive(int64_t * lastTransactionUs,bool clearCache)279 bool BufferPoolClient::Impl::isActive(int64_t *lastTransactionUs, bool clearCache) {
280     {
281         std::lock_guard<std::mutex> lock(mCache.mLock);
282         syncReleased();
283         evictCaches(clearCache);
284         *lastTransactionUs = mCache.mLastChangeUs;
285     }
286     if (mValid && mLocal && mLocalConnection) {
287         mLocalConnection->cleanUp(clearCache);
288         return true;
289     }
290     return mCache.mActive > 0;
291 }
292 
allocate(const std::vector<uint8_t> & params,native_handle_t ** pHandle,std::shared_ptr<BufferPoolData> * buffer)293 ResultStatus BufferPoolClient::Impl::allocate(
294         const std::vector<uint8_t> &params,
295         native_handle_t **pHandle,
296         std::shared_ptr<BufferPoolData> *buffer) {
297     if (!mLocal || !mLocalConnection || !mValid) {
298         return ResultStatus::CRITICAL_ERROR;
299     }
300     BufferId bufferId;
301     native_handle_t *handle = NULL;
302     buffer->reset();
303     ResultStatus status = allocateBufferHandle(params, &bufferId, &handle);
304     if (status == ResultStatus::OK) {
305         if (handle) {
306             std::unique_lock<std::mutex> lock(mCache.mLock);
307             syncReleased();
308             evictCaches();
309             auto cacheIt = mCache.mBuffers.find(bufferId);
310             if (cacheIt != mCache.mBuffers.end()) {
311                 // TODO: verify it is recycled. (not having active ref)
312                 mCache.mBuffers.erase(cacheIt);
313             }
314             auto clientBuffer = std::make_unique<ClientBuffer>(
315                     mConnectionId, bufferId, handle);
316             if (clientBuffer) {
317                 auto result = mCache.mBuffers.insert(std::make_pair(
318                         bufferId, std::move(clientBuffer)));
319                 if (result.second) {
320                     *buffer = result.first->second->createCache(
321                             shared_from_this(), pHandle);
322                     if (*buffer) {
323                         mCache.incActive_l();
324                     }
325                 }
326             }
327         }
328         if (!*buffer) {
329             ALOGV("client cache creation failure %d: %lld",
330                   handle != NULL, (long long)mConnectionId);
331             status = ResultStatus::NO_MEMORY;
332             postBufferRelease(bufferId);
333         }
334     }
335     return status;
336 }
337 
receive(TransactionId transactionId,BufferId bufferId,int64_t timestampUs,native_handle_t ** pHandle,std::shared_ptr<BufferPoolData> * buffer)338 ResultStatus BufferPoolClient::Impl::receive(
339         TransactionId transactionId, BufferId bufferId, int64_t timestampUs,
340         native_handle_t **pHandle,
341         std::shared_ptr<BufferPoolData> *buffer) {
342     if (!mValid) {
343         return ResultStatus::CRITICAL_ERROR;
344     }
345     if (timestampUs != 0) {
346         timestampUs += kReceiveTimeoutUs;
347     }
348     if (!postReceive(bufferId, transactionId, timestampUs)) {
349         return ResultStatus::CRITICAL_ERROR;
350     }
351     ResultStatus status = ResultStatus::CRITICAL_ERROR;
352     buffer->reset();
353     while(1) {
354         std::unique_lock<std::mutex> lock(mCache.mLock);
355         syncReleased();
356         evictCaches();
357         auto cacheIt = mCache.mBuffers.find(bufferId);
358         if (cacheIt != mCache.mBuffers.end()) {
359             if (cacheIt->second->hasCache()) {
360                 *buffer = cacheIt->second->fetchCache(pHandle);
361                 if (!*buffer) {
362                     // check transfer time_out
363                     lock.unlock();
364                     std::this_thread::yield();
365                     continue;
366                 }
367                 ALOGV("client receive from reference %lld", (long long)mConnectionId);
368                 break;
369             } else {
370                 *buffer = cacheIt->second->createCache(shared_from_this(), pHandle);
371                 if (*buffer) {
372                     mCache.incActive_l();
373                 }
374                 ALOGV("client receive from cache %lld", (long long)mConnectionId);
375                 break;
376             }
377         } else {
378             if (!mCache.mCreating) {
379                 mCache.mCreating = true;
380                 lock.unlock();
381                 native_handle_t* handle = NULL;
382                 status = fetchBufferHandle(transactionId, bufferId, &handle);
383                 lock.lock();
384                 if (status == ResultStatus::OK) {
385                     if (handle) {
386                         auto clientBuffer = std::make_unique<ClientBuffer>(
387                                 mConnectionId, bufferId, handle);
388                         if (clientBuffer) {
389                             auto result = mCache.mBuffers.insert(
390                                     std::make_pair(bufferId, std::move(
391                                             clientBuffer)));
392                             if (result.second) {
393                                 *buffer = result.first->second->createCache(
394                                         shared_from_this(), pHandle);
395                                 if (*buffer) {
396                                     mCache.incActive_l();
397                                 }
398                             }
399                         }
400                     }
401                     if (!*buffer) {
402                         status = ResultStatus::NO_MEMORY;
403                     }
404                 }
405                 mCache.mCreating = false;
406                 lock.unlock();
407                 mCache.mCreateCv.notify_all();
408                 break;
409             }
410             mCache.mCreateCv.wait(lock);
411         }
412     }
413     bool posted = postReceiveResult(bufferId, transactionId,
414                                       *buffer ? true : false);
415     ALOGV("client receive %lld - %u : %s (%d)", (long long)mConnectionId, bufferId,
416           *buffer ? "ok" : "fail", posted);
417     if (mValid && mLocal && mLocalConnection) {
418         mLocalConnection->cleanUp(false);
419     }
420     if (*buffer) {
421         if (!posted) {
422             buffer->reset();
423             return ResultStatus::CRITICAL_ERROR;
424         }
425         return ResultStatus::OK;
426     }
427     return status;
428 }
429 
430 
postBufferRelease(BufferId bufferId)431 void BufferPoolClient::Impl::postBufferRelease(BufferId bufferId) {
432     std::lock_guard<std::mutex> lock(mReleasing.mLock);
433     mReleasing.mReleasingIds.push_back(bufferId);
434     mReleasing.mStatusChannel->postBufferRelease(
435             mConnectionId, mReleasing.mReleasingIds, mReleasing.mReleasedIds);
436 }
437 
438 // TODO: revise ad-hoc posting data structure
postSend(BufferId bufferId,ConnectionId receiver,TransactionId * transactionId,int64_t * timestampUs)439 bool BufferPoolClient::Impl::postSend(
440         BufferId bufferId, ConnectionId receiver,
441         TransactionId *transactionId, int64_t *timestampUs) {
442     bool ret = false;
443     {
444         std::lock_guard<std::mutex> lock(mReleasing.mLock);
445         *timestampUs = getTimestampNow();
446         *transactionId = (mConnectionId << 32) | mSeqId++;
447         // TODO: retry, add timeout, target?
448         ret =  mReleasing.mStatusChannel->postBufferStatusMessage(
449                 *transactionId, bufferId, BufferStatus::TRANSFER_TO, mConnectionId,
450                 receiver, mReleasing.mReleasingIds, mReleasing.mReleasedIds);
451     }
452     if (mValid && mLocal && mLocalConnection) {
453         mLocalConnection->cleanUp(false);
454     }
455     return ret;
456 }
457 
postReceive(BufferId bufferId,TransactionId transactionId,int64_t timestampUs)458 bool BufferPoolClient::Impl::postReceive(
459         BufferId bufferId, TransactionId transactionId, int64_t timestampUs) {
460     for (int i = 0; i < kPostMaxRetry; ++i) {
461         std::unique_lock<std::mutex> lock(mReleasing.mLock);
462         int64_t now = getTimestampNow();
463         if (timestampUs == 0 || now < timestampUs) {
464             bool result = mReleasing.mStatusChannel->postBufferStatusMessage(
465                     transactionId, bufferId, BufferStatus::TRANSFER_FROM,
466                     mConnectionId, -1, mReleasing.mReleasingIds,
467                     mReleasing.mReleasedIds);
468             if (result) {
469                 return true;
470             }
471             lock.unlock();
472             std::this_thread::yield();
473         } else {
474             mReleasing.mStatusChannel->postBufferStatusMessage(
475                     transactionId, bufferId, BufferStatus::TRANSFER_TIMEOUT,
476                     mConnectionId, -1, mReleasing.mReleasingIds,
477                     mReleasing.mReleasedIds);
478             return false;
479         }
480     }
481     return false;
482 }
483 
postReceiveResult(BufferId bufferId,TransactionId transactionId,bool result)484 bool BufferPoolClient::Impl::postReceiveResult(
485         BufferId bufferId, TransactionId transactionId, bool result) {
486     std::lock_guard<std::mutex> lock(mReleasing.mLock);
487     // TODO: retry, add timeout
488     return mReleasing.mStatusChannel->postBufferStatusMessage(
489             transactionId, bufferId,
490             result ? BufferStatus::TRANSFER_OK : BufferStatus::TRANSFER_ERROR,
491             mConnectionId, -1, mReleasing.mReleasingIds,
492             mReleasing.mReleasedIds);
493 }
494 
495 // should have mCache.mLock
syncReleased()496 bool BufferPoolClient::Impl::syncReleased() {
497     std::lock_guard<std::mutex> lock(mReleasing.mLock);
498     if (mReleasing.mReleasingIds.size() > 0) {
499         mReleasing.mStatusChannel->postBufferRelease(
500                 mConnectionId, mReleasing.mReleasingIds,
501                 mReleasing.mReleasedIds);
502     }
503     if (mReleasing.mReleasedIds.size() > 0) {
504         for (BufferId& id: mReleasing.mReleasedIds) {
505             ALOGV("client release buffer %lld - %u", (long long)mConnectionId, id);
506             auto found = mCache.mBuffers.find(id);
507             if (found != mCache.mBuffers.end()) {
508                 if (found->second->onCacheRelease()) {
509                     mCache.decActive_l();
510                 } else {
511                     // should not happen!
512                     ALOGW("client %lld cache release status inconsitent!",
513                           (long long)mConnectionId);
514                 }
515             } else {
516                 // should not happen!
517                 ALOGW("client %lld cache status inconsitent!", (long long)mConnectionId);
518             }
519         }
520         mReleasing.mReleasedIds.clear();
521         return true;
522     }
523     return false;
524 }
525 
526 // should have mCache.mLock
evictCaches(bool clearCache)527 void BufferPoolClient::Impl::evictCaches(bool clearCache) {
528     int64_t now = getTimestampNow();
529     if (now >= mLastEvictCacheUs + kCacheTtlUs || clearCache) {
530         size_t evicted = 0;
531         for (auto it = mCache.mBuffers.begin(); it != mCache.mBuffers.end();) {
532             if (!it->second->hasCache() && (it->second->expire() || clearCache)) {
533                 it = mCache.mBuffers.erase(it);
534                 ++evicted;
535             } else {
536                 ++it;
537             }
538         }
539         ALOGV("cache count %lld : total %zu, active %d, evicted %zu",
540               (long long)mConnectionId, mCache.mBuffers.size(), mCache.mActive, evicted);
541         mLastEvictCacheUs = now;
542     }
543 }
544 
allocateBufferHandle(const std::vector<uint8_t> & params,BufferId * bufferId,native_handle_t ** handle)545 ResultStatus BufferPoolClient::Impl::allocateBufferHandle(
546         const std::vector<uint8_t>& params, BufferId *bufferId,
547         native_handle_t** handle) {
548     if (mLocalConnection) {
549         const native_handle_t* allocHandle = NULL;
550         ResultStatus status = mLocalConnection->allocate(
551                 params, bufferId, &allocHandle);
552         if (status == ResultStatus::OK) {
553             *handle = native_handle_clone(allocHandle);
554         }
555         ALOGV("client allocate result %lld %d : %u clone %p",
556               (long long)mConnectionId, status == ResultStatus::OK,
557               *handle ? *bufferId : 0 , *handle);
558         return status;
559     }
560     return ResultStatus::CRITICAL_ERROR;
561 }
562 
fetchBufferHandle(TransactionId transactionId,BufferId bufferId,native_handle_t ** handle)563 ResultStatus BufferPoolClient::Impl::fetchBufferHandle(
564         TransactionId transactionId, BufferId bufferId,
565         native_handle_t **handle) {
566     sp<IConnection> connection;
567     if (mLocal) {
568         connection = mLocalConnection;
569     } else {
570         connection = mRemoteConnection;
571     }
572     ResultStatus status;
573     Return<void> transResult = connection->fetch(
574             transactionId, bufferId,
575             [&status, &handle]
576             (ResultStatus outStatus, Buffer outBuffer) {
577                 status = outStatus;
578                 if (status == ResultStatus::OK) {
579                     *handle = native_handle_clone(
580                             outBuffer.buffer.getNativeHandle());
581                 }
582             });
583     return transResult.isOk() ? status : ResultStatus::CRITICAL_ERROR;
584 }
585 
586 
BufferPoolClient(const sp<Accessor> & accessor)587 BufferPoolClient::BufferPoolClient(const sp<Accessor> &accessor) {
588     mImpl = std::make_shared<Impl>(accessor);
589 }
590 
BufferPoolClient(const sp<IAccessor> & accessor)591 BufferPoolClient::BufferPoolClient(const sp<IAccessor> &accessor) {
592     mImpl = std::make_shared<Impl>(accessor);
593 }
594 
~BufferPoolClient()595 BufferPoolClient::~BufferPoolClient() {
596     // TODO: how to handle orphaned buffers?
597 }
598 
isValid()599 bool BufferPoolClient::isValid() {
600     return mImpl && mImpl->isValid();
601 }
602 
isLocal()603 bool BufferPoolClient::isLocal() {
604     return mImpl && mImpl->isLocal();
605 }
606 
isActive(int64_t * lastTransactionUs,bool clearCache)607 bool BufferPoolClient::isActive(int64_t *lastTransactionUs, bool clearCache) {
608     if (!isValid()) {
609         *lastTransactionUs = 0;
610         return false;
611     }
612     return mImpl->isActive(lastTransactionUs, clearCache);
613 }
614 
getConnectionId()615 ConnectionId BufferPoolClient::getConnectionId() {
616     if (isValid()) {
617         return mImpl->getConnectionId();
618     }
619     return -1;
620 }
621 
getAccessor(sp<IAccessor> * accessor)622 ResultStatus BufferPoolClient::getAccessor(sp<IAccessor> *accessor) {
623     if (isValid()) {
624         *accessor = mImpl->getAccessor();
625         return ResultStatus::OK;
626     }
627     return ResultStatus::CRITICAL_ERROR;
628 }
629 
allocate(const std::vector<uint8_t> & params,native_handle_t ** handle,std::shared_ptr<BufferPoolData> * buffer)630 ResultStatus BufferPoolClient::allocate(
631         const std::vector<uint8_t> &params,
632         native_handle_t **handle,
633         std::shared_ptr<BufferPoolData> *buffer) {
634     if (isValid()) {
635         return mImpl->allocate(params, handle, buffer);
636     }
637     return ResultStatus::CRITICAL_ERROR;
638 }
639 
receive(TransactionId transactionId,BufferId bufferId,int64_t timestampUs,native_handle_t ** handle,std::shared_ptr<BufferPoolData> * buffer)640 ResultStatus BufferPoolClient::receive(
641         TransactionId transactionId, BufferId bufferId, int64_t timestampUs,
642         native_handle_t **handle, std::shared_ptr<BufferPoolData> *buffer) {
643     if (isValid()) {
644         return mImpl->receive(transactionId, bufferId, timestampUs, handle, buffer);
645     }
646     return ResultStatus::CRITICAL_ERROR;
647 }
648 
postSend(ConnectionId receiverId,const std::shared_ptr<BufferPoolData> & buffer,TransactionId * transactionId,int64_t * timestampUs)649 ResultStatus BufferPoolClient::postSend(
650         ConnectionId receiverId,
651         const std::shared_ptr<BufferPoolData> &buffer,
652         TransactionId *transactionId,
653         int64_t *timestampUs) {
654     if (isValid()) {
655         bool result = mImpl->postSend(
656                 buffer->mId, receiverId, transactionId, timestampUs);
657         return result ? ResultStatus::OK : ResultStatus::CRITICAL_ERROR;
658     }
659     return ResultStatus::CRITICAL_ERROR;
660 }
661 
662 }  // namespace implementation
663 }  // namespace V1_0
664 }  // namespace bufferpool
665 }  // namespace media
666 }  // namespace hardware
667 }  // namespace android
668