Home | History | Annotate | Download | only in 1.0
      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 
     43     bool isValid() {
     44         return mValid;
     45     }
     46 
     47     bool isLocal() {
     48         return mValid && mLocal;
     49     }
     50 
     51     ConnectionId getConnectionId() {
     52         return mConnectionId;
     53     }
     54 
     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, bool *needsSync);
     83 
     84     void trySyncFromRemote();
     85 
     86     bool syncReleased();
     87 
     88     void evictCaches(bool clearCache = false);
     89 
     90     ResultStatus allocateBufferHandle(
     91             const std::vector<uint8_t>& params, BufferId *bufferId,
     92             native_handle_t **handle);
     93 
     94     ResultStatus fetchBufferHandle(
     95             TransactionId transactionId, BufferId bufferId,
     96             native_handle_t **handle);
     97 
     98     struct BlockPoolDataDtor;
     99     struct ClientBuffer;
    100 
    101     bool mLocal;
    102     bool mValid;
    103     sp<IAccessor> mAccessor;
    104     sp<Connection> mLocalConnection;
    105     sp<IConnection> mRemoteConnection;
    106     uint32_t mSeqId;
    107     ConnectionId mConnectionId;
    108     int64_t mLastEvictCacheUs;
    109 
    110     // CachedBuffers
    111     struct BufferCache {
    112         std::mutex mLock;
    113         bool mCreating;
    114         std::condition_variable mCreateCv;
    115         std::map<BufferId, std::unique_ptr<ClientBuffer>> mBuffers;
    116         int mActive;
    117         int64_t mLastChangeUs;
    118 
    119         BufferCache() : mCreating(false), mActive(0), mLastChangeUs(getTimestampNow()) {}
    120 
    121         void incActive_l() {
    122             ++mActive;
    123             mLastChangeUs = getTimestampNow();
    124         }
    125 
    126         void decActive_l() {
    127             --mActive;
    128             mLastChangeUs = getTimestampNow();
    129         }
    130     } mCache;
    131 
    132     // FMQ - release notifier
    133     struct {
    134         std::mutex mLock;
    135         // TODO: use only one list?(using one list may dealy sending messages?)
    136         std::list<BufferId> mReleasingIds;
    137         std::list<BufferId> mReleasedIds;
    138         std::unique_ptr<BufferStatusChannel> mStatusChannel;
    139     } mReleasing;
    140 
    141     // This lock is held during synchronization from remote side.
    142     // In order to minimize remote calls and locking durtaion, this lock is held
    143     // by best effort approach using try_lock().
    144     std::mutex mRemoteSyncLock;
    145 };
    146 
    147 struct BufferPoolClient::Impl::BlockPoolDataDtor {
    148     BlockPoolDataDtor(const std::shared_ptr<BufferPoolClient::Impl> &impl)
    149             : mImpl(impl) {}
    150 
    151     void operator()(BufferPoolData *buffer) {
    152         BufferId id = buffer->mId;
    153         delete buffer;
    154 
    155         auto impl = mImpl.lock();
    156         if (impl && impl->isValid()) {
    157             impl->postBufferRelease(id);
    158         }
    159     }
    160     const std::weak_ptr<BufferPoolClient::Impl> mImpl;
    161 };
    162 
    163 struct BufferPoolClient::Impl::ClientBuffer {
    164 private:
    165     bool mInvalidated; // TODO: implement
    166     int64_t mExpireUs;
    167     bool mHasCache;
    168     ConnectionId mConnectionId;
    169     BufferId mId;
    170     native_handle_t *mHandle;
    171     std::weak_ptr<BufferPoolData> mCache;
    172 
    173     void updateExpire() {
    174         mExpireUs = getTimestampNow() + kCacheTtlUs;
    175     }
    176 
    177 public:
    178     ClientBuffer(
    179             ConnectionId connectionId, BufferId id, native_handle_t *handle)
    180             : mInvalidated(false), mHasCache(false),
    181               mConnectionId(connectionId), mId(id), mHandle(handle) {
    182         (void)mInvalidated;
    183         mExpireUs = getTimestampNow() + kCacheTtlUs;
    184     }
    185 
    186     ~ClientBuffer() {
    187         if (mHandle) {
    188             native_handle_close(mHandle);
    189             native_handle_delete(mHandle);
    190         }
    191     }
    192 
    193     bool expire() const {
    194         int64_t now = getTimestampNow();
    195         return now >= mExpireUs;
    196     }
    197 
    198     bool hasCache() const {
    199         return mHasCache;
    200     }
    201 
    202     std::shared_ptr<BufferPoolData> fetchCache(native_handle_t **pHandle) {
    203         if (mHasCache) {
    204             std::shared_ptr<BufferPoolData> cache = mCache.lock();
    205             if (cache) {
    206                 *pHandle = mHandle;
    207             }
    208             return cache;
    209         }
    210         return nullptr;
    211     }
    212 
    213     std::shared_ptr<BufferPoolData> createCache(
    214             const std::shared_ptr<BufferPoolClient::Impl> &impl,
    215             native_handle_t **pHandle) {
    216         if (!mHasCache) {
    217             // Allocates a raw ptr in order to avoid sending #postBufferRelease
    218             // from deleter, in case of native_handle_clone failure.
    219             BufferPoolData *ptr = new BufferPoolData(mConnectionId, mId);
    220             if (ptr) {
    221                 std::shared_ptr<BufferPoolData> cache(ptr, BlockPoolDataDtor(impl));
    222                 if (cache) {
    223                     mCache = cache;
    224                     mHasCache = true;
    225                     *pHandle = mHandle;
    226                     return cache;
    227                 }
    228             }
    229             if (ptr) {
    230                 delete ptr;
    231             }
    232         }
    233         return nullptr;
    234     }
    235 
    236     bool onCacheRelease() {
    237         if (mHasCache) {
    238             // TODO: verify mCache is not valid;
    239             updateExpire();
    240             mHasCache = false;
    241             return true;
    242         }
    243         return false;
    244     }
    245 };
    246 
    247 BufferPoolClient::Impl::Impl(const sp<Accessor> &accessor)
    248     : mLocal(true), mValid(false), mAccessor(accessor), mSeqId(0),
    249       mLastEvictCacheUs(getTimestampNow()) {
    250     const QueueDescriptor *fmqDesc;
    251     ResultStatus status = accessor->connect(
    252             &mLocalConnection, &mConnectionId, &fmqDesc, true);
    253     if (status == ResultStatus::OK) {
    254         mReleasing.mStatusChannel =
    255                 std::make_unique<BufferStatusChannel>(*fmqDesc);
    256         mValid = mReleasing.mStatusChannel &&
    257                 mReleasing.mStatusChannel->isValid();
    258     }
    259 }
    260 
    261 BufferPoolClient::Impl::Impl(const sp<IAccessor> &accessor)
    262     : mLocal(false), mValid(false), mAccessor(accessor), mSeqId(0),
    263       mLastEvictCacheUs(getTimestampNow()) {
    264     bool valid = false;
    265     sp<IConnection>& outConnection = mRemoteConnection;
    266     ConnectionId& id = mConnectionId;
    267     std::unique_ptr<BufferStatusChannel>& outChannel =
    268             mReleasing.mStatusChannel;
    269     Return<void> transResult = accessor->connect(
    270             [&valid, &outConnection, &id, &outChannel]
    271             (ResultStatus status, sp<IConnection> connection,
    272              ConnectionId connectionId, const QueueDescriptor& desc) {
    273                 if (status == ResultStatus::OK) {
    274                     outConnection = connection;
    275                     id = connectionId;
    276                     outChannel = std::make_unique<BufferStatusChannel>(desc);
    277                     if (outChannel && outChannel->isValid()) {
    278                         valid = true;
    279                     }
    280                 }
    281             });
    282     mValid = transResult.isOk() && valid;
    283 }
    284 
    285 bool BufferPoolClient::Impl::isActive(int64_t *lastTransactionUs, bool clearCache) {
    286     bool active = false;
    287     {
    288         std::lock_guard<std::mutex> lock(mCache.mLock);
    289         syncReleased();
    290         evictCaches(clearCache);
    291         *lastTransactionUs = mCache.mLastChangeUs;
    292         active = mCache.mActive > 0;
    293     }
    294     if (mValid && mLocal && mLocalConnection) {
    295         mLocalConnection->cleanUp(clearCache);
    296         return true;
    297     }
    298     return active;
    299 }
    300 
    301 ResultStatus BufferPoolClient::Impl::allocate(
    302         const std::vector<uint8_t> &params,
    303         native_handle_t **pHandle,
    304         std::shared_ptr<BufferPoolData> *buffer) {
    305     if (!mLocal || !mLocalConnection || !mValid) {
    306         return ResultStatus::CRITICAL_ERROR;
    307     }
    308     BufferId bufferId;
    309     native_handle_t *handle = nullptr;
    310     buffer->reset();
    311     ResultStatus status = allocateBufferHandle(params, &bufferId, &handle);
    312     if (status == ResultStatus::OK) {
    313         if (handle) {
    314             std::unique_lock<std::mutex> lock(mCache.mLock);
    315             syncReleased();
    316             evictCaches();
    317             auto cacheIt = mCache.mBuffers.find(bufferId);
    318             if (cacheIt != mCache.mBuffers.end()) {
    319                 // TODO: verify it is recycled. (not having active ref)
    320                 mCache.mBuffers.erase(cacheIt);
    321             }
    322             auto clientBuffer = std::make_unique<ClientBuffer>(
    323                     mConnectionId, bufferId, handle);
    324             if (clientBuffer) {
    325                 auto result = mCache.mBuffers.insert(std::make_pair(
    326                         bufferId, std::move(clientBuffer)));
    327                 if (result.second) {
    328                     *buffer = result.first->second->createCache(
    329                             shared_from_this(), pHandle);
    330                     if (*buffer) {
    331                         mCache.incActive_l();
    332                     }
    333                 }
    334             }
    335         }
    336         if (!*buffer) {
    337             ALOGV("client cache creation failure %d: %lld",
    338                   handle != nullptr, (long long)mConnectionId);
    339             status = ResultStatus::NO_MEMORY;
    340             postBufferRelease(bufferId);
    341         }
    342     }
    343     return status;
    344 }
    345 
    346 ResultStatus BufferPoolClient::Impl::receive(
    347         TransactionId transactionId, BufferId bufferId, int64_t timestampUs,
    348         native_handle_t **pHandle,
    349         std::shared_ptr<BufferPoolData> *buffer) {
    350     if (!mValid) {
    351         return ResultStatus::CRITICAL_ERROR;
    352     }
    353     if (timestampUs != 0) {
    354         timestampUs += kReceiveTimeoutUs;
    355     }
    356     if (!postReceive(bufferId, transactionId, timestampUs)) {
    357         return ResultStatus::CRITICAL_ERROR;
    358     }
    359     ResultStatus status = ResultStatus::CRITICAL_ERROR;
    360     buffer->reset();
    361     while(1) {
    362         std::unique_lock<std::mutex> lock(mCache.mLock);
    363         syncReleased();
    364         evictCaches();
    365         auto cacheIt = mCache.mBuffers.find(bufferId);
    366         if (cacheIt != mCache.mBuffers.end()) {
    367             if (cacheIt->second->hasCache()) {
    368                 *buffer = cacheIt->second->fetchCache(pHandle);
    369                 if (!*buffer) {
    370                     // check transfer time_out
    371                     lock.unlock();
    372                     std::this_thread::yield();
    373                     continue;
    374                 }
    375                 ALOGV("client receive from reference %lld", (long long)mConnectionId);
    376                 break;
    377             } else {
    378                 *buffer = cacheIt->second->createCache(shared_from_this(), pHandle);
    379                 if (*buffer) {
    380                     mCache.incActive_l();
    381                 }
    382                 ALOGV("client receive from cache %lld", (long long)mConnectionId);
    383                 break;
    384             }
    385         } else {
    386             if (!mCache.mCreating) {
    387                 mCache.mCreating = true;
    388                 lock.unlock();
    389                 native_handle_t* handle = nullptr;
    390                 status = fetchBufferHandle(transactionId, bufferId, &handle);
    391                 lock.lock();
    392                 if (status == ResultStatus::OK) {
    393                     if (handle) {
    394                         auto clientBuffer = std::make_unique<ClientBuffer>(
    395                                 mConnectionId, bufferId, handle);
    396                         if (clientBuffer) {
    397                             auto result = mCache.mBuffers.insert(
    398                                     std::make_pair(bufferId, std::move(
    399                                             clientBuffer)));
    400                             if (result.second) {
    401                                 *buffer = result.first->second->createCache(
    402                                         shared_from_this(), pHandle);
    403                                 if (*buffer) {
    404                                     mCache.incActive_l();
    405                                 }
    406                             }
    407                         }
    408                     }
    409                     if (!*buffer) {
    410                         status = ResultStatus::NO_MEMORY;
    411                     }
    412                 }
    413                 mCache.mCreating = false;
    414                 lock.unlock();
    415                 mCache.mCreateCv.notify_all();
    416                 break;
    417             }
    418             mCache.mCreateCv.wait(lock);
    419         }
    420     }
    421     bool needsSync = false;
    422     bool posted = postReceiveResult(bufferId, transactionId,
    423                                       *buffer ? true : false, &needsSync);
    424     ALOGV("client receive %lld - %u : %s (%d)", (long long)mConnectionId, bufferId,
    425           *buffer ? "ok" : "fail", posted);
    426     if (mValid && mLocal && mLocalConnection) {
    427         mLocalConnection->cleanUp(false);
    428     }
    429     if (needsSync && mRemoteConnection) {
    430         trySyncFromRemote();
    431     }
    432     if (*buffer) {
    433         if (!posted) {
    434             buffer->reset();
    435             return ResultStatus::CRITICAL_ERROR;
    436         }
    437         return ResultStatus::OK;
    438     }
    439     return status;
    440 }
    441 
    442 
    443 void BufferPoolClient::Impl::postBufferRelease(BufferId bufferId) {
    444     std::lock_guard<std::mutex> lock(mReleasing.mLock);
    445     mReleasing.mReleasingIds.push_back(bufferId);
    446     mReleasing.mStatusChannel->postBufferRelease(
    447             mConnectionId, mReleasing.mReleasingIds, mReleasing.mReleasedIds);
    448 }
    449 
    450 // TODO: revise ad-hoc posting data structure
    451 bool BufferPoolClient::Impl::postSend(
    452         BufferId bufferId, ConnectionId receiver,
    453         TransactionId *transactionId, int64_t *timestampUs) {
    454     bool ret = false;
    455     bool needsSync = false;
    456     {
    457         std::lock_guard<std::mutex> lock(mReleasing.mLock);
    458         *timestampUs = getTimestampNow();
    459         *transactionId = (mConnectionId << 32) | mSeqId++;
    460         // TODO: retry, add timeout, target?
    461         ret =  mReleasing.mStatusChannel->postBufferStatusMessage(
    462                 *transactionId, bufferId, BufferStatus::TRANSFER_TO, mConnectionId,
    463                 receiver, mReleasing.mReleasingIds, mReleasing.mReleasedIds);
    464         needsSync = !mLocal && mReleasing.mStatusChannel->needsSync();
    465     }
    466     if (mValid && mLocal && mLocalConnection) {
    467         mLocalConnection->cleanUp(false);
    468     }
    469     if (needsSync && mRemoteConnection) {
    470         trySyncFromRemote();
    471     }
    472     return ret;
    473 }
    474 
    475 bool BufferPoolClient::Impl::postReceive(
    476         BufferId bufferId, TransactionId transactionId, int64_t timestampUs) {
    477     for (int i = 0; i < kPostMaxRetry; ++i) {
    478         std::unique_lock<std::mutex> lock(mReleasing.mLock);
    479         int64_t now = getTimestampNow();
    480         if (timestampUs == 0 || now < timestampUs) {
    481             bool result = mReleasing.mStatusChannel->postBufferStatusMessage(
    482                     transactionId, bufferId, BufferStatus::TRANSFER_FROM,
    483                     mConnectionId, -1, mReleasing.mReleasingIds,
    484                     mReleasing.mReleasedIds);
    485             if (result) {
    486                 return true;
    487             }
    488             lock.unlock();
    489             std::this_thread::yield();
    490         } else {
    491             mReleasing.mStatusChannel->postBufferStatusMessage(
    492                     transactionId, bufferId, BufferStatus::TRANSFER_TIMEOUT,
    493                     mConnectionId, -1, mReleasing.mReleasingIds,
    494                     mReleasing.mReleasedIds);
    495             return false;
    496         }
    497     }
    498     return false;
    499 }
    500 
    501 bool BufferPoolClient::Impl::postReceiveResult(
    502         BufferId bufferId, TransactionId transactionId, bool result, bool *needsSync) {
    503     std::lock_guard<std::mutex> lock(mReleasing.mLock);
    504     // TODO: retry, add timeout
    505     bool ret = mReleasing.mStatusChannel->postBufferStatusMessage(
    506             transactionId, bufferId,
    507             result ? BufferStatus::TRANSFER_OK : BufferStatus::TRANSFER_ERROR,
    508             mConnectionId, -1, mReleasing.mReleasingIds,
    509             mReleasing.mReleasedIds);
    510     *needsSync = !mLocal && mReleasing.mStatusChannel->needsSync();
    511     return ret;
    512 }
    513 
    514 void BufferPoolClient::Impl::trySyncFromRemote() {
    515     if (mRemoteSyncLock.try_lock()) {
    516         bool needsSync = false;
    517         {
    518             std::lock_guard<std::mutex> lock(mReleasing.mLock);
    519             needsSync = mReleasing.mStatusChannel->needsSync();
    520         }
    521         if (needsSync) {
    522             TransactionId transactionId = (mConnectionId << 32);
    523             BufferId bufferId = Connection::SYNC_BUFFERID;
    524             Return<void> transResult = mRemoteConnection->fetch(
    525                     transactionId, bufferId,
    526                     []
    527                     (ResultStatus outStatus, Buffer outBuffer) {
    528                         (void) outStatus;
    529                         (void) outBuffer;
    530                     });
    531             if(!transResult.isOk()) {
    532                 ALOGD("sync from client %lld failed: bufferpool process died.",
    533                       (long long)mConnectionId);
    534             }
    535         }
    536         mRemoteSyncLock.unlock();
    537     }
    538 }
    539 
    540 // should have mCache.mLock
    541 bool BufferPoolClient::Impl::syncReleased() {
    542     std::lock_guard<std::mutex> lock(mReleasing.mLock);
    543     if (mReleasing.mReleasingIds.size() > 0) {
    544         mReleasing.mStatusChannel->postBufferRelease(
    545                 mConnectionId, mReleasing.mReleasingIds,
    546                 mReleasing.mReleasedIds);
    547     }
    548     if (mReleasing.mReleasedIds.size() > 0) {
    549         for (BufferId& id: mReleasing.mReleasedIds) {
    550             ALOGV("client release buffer %lld - %u", (long long)mConnectionId, id);
    551             auto found = mCache.mBuffers.find(id);
    552             if (found != mCache.mBuffers.end()) {
    553                 if (found->second->onCacheRelease()) {
    554                     mCache.decActive_l();
    555                 } else {
    556                     // should not happen!
    557                     ALOGW("client %lld cache release status inconsitent!",
    558                           (long long)mConnectionId);
    559                 }
    560             } else {
    561                 // should not happen!
    562                 ALOGW("client %lld cache status inconsitent!", (long long)mConnectionId);
    563             }
    564         }
    565         mReleasing.mReleasedIds.clear();
    566         return true;
    567     }
    568     return false;
    569 }
    570 
    571 // should have mCache.mLock
    572 void BufferPoolClient::Impl::evictCaches(bool clearCache) {
    573     int64_t now = getTimestampNow();
    574     if (now >= mLastEvictCacheUs + kCacheTtlUs || clearCache) {
    575         size_t evicted = 0;
    576         for (auto it = mCache.mBuffers.begin(); it != mCache.mBuffers.end();) {
    577             if (!it->second->hasCache() && (it->second->expire() || clearCache)) {
    578                 it = mCache.mBuffers.erase(it);
    579                 ++evicted;
    580             } else {
    581                 ++it;
    582             }
    583         }
    584         ALOGV("cache count %lld : total %zu, active %d, evicted %zu",
    585               (long long)mConnectionId, mCache.mBuffers.size(), mCache.mActive, evicted);
    586         mLastEvictCacheUs = now;
    587     }
    588 }
    589 
    590 ResultStatus BufferPoolClient::Impl::allocateBufferHandle(
    591         const std::vector<uint8_t>& params, BufferId *bufferId,
    592         native_handle_t** handle) {
    593     if (mLocalConnection) {
    594         const native_handle_t* allocHandle = nullptr;
    595         ResultStatus status = mLocalConnection->allocate(
    596                 params, bufferId, &allocHandle);
    597         if (status == ResultStatus::OK) {
    598             *handle = native_handle_clone(allocHandle);
    599         }
    600         ALOGV("client allocate result %lld %d : %u clone %p",
    601               (long long)mConnectionId, status == ResultStatus::OK,
    602               *handle ? *bufferId : 0 , *handle);
    603         return status;
    604     }
    605     return ResultStatus::CRITICAL_ERROR;
    606 }
    607 
    608 ResultStatus BufferPoolClient::Impl::fetchBufferHandle(
    609         TransactionId transactionId, BufferId bufferId,
    610         native_handle_t **handle) {
    611     sp<IConnection> connection;
    612     if (mLocal) {
    613         connection = mLocalConnection;
    614     } else {
    615         connection = mRemoteConnection;
    616     }
    617     ResultStatus status;
    618     Return<void> transResult = connection->fetch(
    619             transactionId, bufferId,
    620             [&status, &handle]
    621             (ResultStatus outStatus, Buffer outBuffer) {
    622                 status = outStatus;
    623                 if (status == ResultStatus::OK) {
    624                     *handle = native_handle_clone(
    625                             outBuffer.buffer.getNativeHandle());
    626                 }
    627             });
    628     return transResult.isOk() ? status : ResultStatus::CRITICAL_ERROR;
    629 }
    630 
    631 
    632 BufferPoolClient::BufferPoolClient(const sp<Accessor> &accessor) {
    633     mImpl = std::make_shared<Impl>(accessor);
    634 }
    635 
    636 BufferPoolClient::BufferPoolClient(const sp<IAccessor> &accessor) {
    637     mImpl = std::make_shared<Impl>(accessor);
    638 }
    639 
    640 BufferPoolClient::~BufferPoolClient() {
    641     // TODO: how to handle orphaned buffers?
    642 }
    643 
    644 bool BufferPoolClient::isValid() {
    645     return mImpl && mImpl->isValid();
    646 }
    647 
    648 bool BufferPoolClient::isLocal() {
    649     return mImpl && mImpl->isLocal();
    650 }
    651 
    652 bool BufferPoolClient::isActive(int64_t *lastTransactionUs, bool clearCache) {
    653     if (!isValid()) {
    654         *lastTransactionUs = 0;
    655         return false;
    656     }
    657     return mImpl->isActive(lastTransactionUs, clearCache);
    658 }
    659 
    660 ConnectionId BufferPoolClient::getConnectionId() {
    661     if (isValid()) {
    662         return mImpl->getConnectionId();
    663     }
    664     return -1;
    665 }
    666 
    667 ResultStatus BufferPoolClient::getAccessor(sp<IAccessor> *accessor) {
    668     if (isValid()) {
    669         *accessor = mImpl->getAccessor();
    670         return ResultStatus::OK;
    671     }
    672     return ResultStatus::CRITICAL_ERROR;
    673 }
    674 
    675 ResultStatus BufferPoolClient::allocate(
    676         const std::vector<uint8_t> &params,
    677         native_handle_t **handle,
    678         std::shared_ptr<BufferPoolData> *buffer) {
    679     if (isValid()) {
    680         return mImpl->allocate(params, handle, buffer);
    681     }
    682     return ResultStatus::CRITICAL_ERROR;
    683 }
    684 
    685 ResultStatus BufferPoolClient::receive(
    686         TransactionId transactionId, BufferId bufferId, int64_t timestampUs,
    687         native_handle_t **handle, std::shared_ptr<BufferPoolData> *buffer) {
    688     if (isValid()) {
    689         return mImpl->receive(transactionId, bufferId, timestampUs, handle, buffer);
    690     }
    691     return ResultStatus::CRITICAL_ERROR;
    692 }
    693 
    694 ResultStatus BufferPoolClient::postSend(
    695         ConnectionId receiverId,
    696         const std::shared_ptr<BufferPoolData> &buffer,
    697         TransactionId *transactionId,
    698         int64_t *timestampUs) {
    699     if (isValid()) {
    700         bool result = mImpl->postSend(
    701                 buffer->mId, receiverId, transactionId, timestampUs);
    702         return result ? ResultStatus::OK : ResultStatus::CRITICAL_ERROR;
    703     }
    704     return ResultStatus::CRITICAL_ERROR;
    705 }
    706 
    707 }  // namespace implementation
    708 }  // namespace V1_0
    709 }  // namespace bufferpool
    710 }  // namespace media
    711 }  // namespace hardware
    712 }  // namespace android
    713