1 /*
2  * Copyright (C) 2022 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 #define LOG_TAG "AidlBufferPoolMgr"
17 //#define LOG_NDEBUG 0
18 
19 #include <aidl/android/hardware/media/bufferpool2/ResultStatus.h>
20 #include <bufferpool2/ClientManager.h>
21 
22 #include <sys/types.h>
23 #include <utils/SystemClock.h>
24 #include <unistd.h>
25 #include <utils/Log.h>
26 
27 #include <chrono>
28 
29 #include "BufferPoolClient.h"
30 #include "Observer.h"
31 #include "Accessor.h"
32 
33 namespace aidl::android::hardware::media::bufferpool2::implementation {
34 
35 using namespace std::chrono_literals;
36 
37 using Registration = aidl::android::hardware::media::bufferpool2::IClientManager::Registration;
38 using aidl::android::hardware::media::bufferpool2::ResultStatus;
39 
40 static constexpr int64_t kRegisterTimeoutMs = 500; // 0.5 sec
41 static constexpr int64_t kCleanUpDurationMs = 1000; // TODO: 1 sec tune
42 static constexpr int64_t kClientTimeoutMs = 5000; // TODO: 5 secs tune
43 
44 class ClientManager::Impl {
45 public:
46     Impl();
47 
48     // BnRegisterSender
49     BufferPoolStatus registerSender(const std::shared_ptr<IAccessor> &accessor,
50                                 Registration *pRegistration);
51 
52     // BpRegisterSender
53     BufferPoolStatus registerSender(const std::shared_ptr<IClientManager> &receiver,
54                                 ConnectionId senderId,
55                                 ConnectionId *receiverId,
56                                 bool *isNew);
57 
58     BufferPoolStatus create(const std::shared_ptr<BufferPoolAllocator> &allocator,
59                         ConnectionId *pConnectionId);
60 
61     BufferPoolStatus close(ConnectionId connectionId);
62 
63     BufferPoolStatus flush(ConnectionId connectionId);
64 
65     BufferPoolStatus allocate(ConnectionId connectionId,
66                           const std::vector<uint8_t> &params,
67                           native_handle_t **handle,
68                           std::shared_ptr<BufferPoolData> *buffer);
69 
70     BufferPoolStatus receive(ConnectionId connectionId,
71                          TransactionId transactionId,
72                          BufferId bufferId,
73                          int64_t timestampMs,
74                          native_handle_t **handle,
75                          std::shared_ptr<BufferPoolData> *buffer);
76 
77     BufferPoolStatus postSend(ConnectionId receiverId,
78                           const std::shared_ptr<BufferPoolData> &buffer,
79                           TransactionId *transactionId,
80                           int64_t *timestampMs);
81 
82     BufferPoolStatus getAccessor(ConnectionId connectionId,
83                              std::shared_ptr<IAccessor> *accessor);
84 
85     void cleanUp(bool clearCache = false);
86 
87 private:
88     // In order to prevent deadlock between multiple locks,
89     // always lock ClientCache.lock before locking ActiveClients.lock.
90     struct ClientCache {
91         // This lock is held for brief duration.
92         // Blocking operation is not performed while holding the lock.
93         std::mutex mMutex;
94         std::list<std::pair<const std::weak_ptr<IAccessor>, const std::weak_ptr<BufferPoolClient>>>
95                 mClients;
96         std::condition_variable mConnectCv;
97         bool mConnecting;
98         int64_t mLastCleanUpMs;
99 
ClientCacheaidl::android::hardware::media::bufferpool2::implementation::ClientManager::Impl::ClientCache100         ClientCache() : mConnecting(false), mLastCleanUpMs(::android::elapsedRealtime()) {}
101     } mCache;
102 
103     // Active clients which can be retrieved via ConnectionId
104     struct ActiveClients {
105         // This lock is held for brief duration.
106         // Blocking operation is not performed holding the lock.
107         std::mutex mMutex;
108         std::map<ConnectionId, const std::shared_ptr<BufferPoolClient>>
109                 mClients;
110     } mActive;
111 
112     std::shared_ptr<Observer> mObserver;
113 };
114 
Impl()115 ClientManager::Impl::Impl()
116     : mObserver(::ndk::SharedRefBase::make<Observer>()) {}
117 
registerSender(const std::shared_ptr<IAccessor> & accessor,Registration * pRegistration)118 BufferPoolStatus ClientManager::Impl::registerSender(
119         const std::shared_ptr<IAccessor> &accessor, Registration *pRegistration) {
120     cleanUp();
121     int64_t timeoutMs = ::android::elapsedRealtime() + kRegisterTimeoutMs;
122     do {
123         std::unique_lock<std::mutex> lock(mCache.mMutex);
124         for (auto it = mCache.mClients.begin(); it != mCache.mClients.end(); ++it) {
125             std::shared_ptr<IAccessor> sAccessor = it->first.lock();
126             if (sAccessor && sAccessor.get() == accessor.get()) {
127                 const std::shared_ptr<BufferPoolClient> client = it->second.lock();
128                 if (client) {
129                     std::lock_guard<std::mutex> lock(mActive.mMutex);
130                     pRegistration->connectionId = client->getConnectionId();
131                     if (mActive.mClients.find(pRegistration->connectionId)
132                             != mActive.mClients.end()) {
133                         ALOGV("register existing connection %lld",
134                               (long long)pRegistration->connectionId);
135                         pRegistration->isNew = false;
136                         return ResultStatus::OK;
137                     }
138                 }
139                 mCache.mClients.erase(it);
140                 break;
141             }
142         }
143         if (!mCache.mConnecting) {
144             mCache.mConnecting = true;
145             lock.unlock();
146             BufferPoolStatus result = ResultStatus::OK;
147             const std::shared_ptr<BufferPoolClient> client =
148                     std::make_shared<BufferPoolClient>(accessor, mObserver);
149             lock.lock();
150             if (!client) {
151                 result = ResultStatus::NO_MEMORY;
152             } else if (!client->isValid()) {
153                 result = ResultStatus::CRITICAL_ERROR;
154             }
155             if (result == ResultStatus::OK) {
156                 // TODO: handle insert fail. (malloc fail)
157                 const std::weak_ptr<BufferPoolClient> wclient = client;
158                 mCache.mClients.push_back(std::make_pair(accessor, wclient));
159                 ConnectionId conId = client->getConnectionId();
160                 mObserver->addClient(conId, wclient);
161                 {
162                     std::lock_guard<std::mutex> lock(mActive.mMutex);
163                     mActive.mClients.insert(std::make_pair(conId, client));
164                 }
165                 pRegistration->connectionId = conId;
166                 pRegistration->isNew = true;
167                 ALOGV("register new connection %lld", (long long)conId);
168             }
169             mCache.mConnecting = false;
170             lock.unlock();
171             mCache.mConnectCv.notify_all();
172             return result;
173         }
174         mCache.mConnectCv.wait_for(lock, kRegisterTimeoutMs*1ms);
175     } while (::android::elapsedRealtime() < timeoutMs);
176     // TODO: return timeout error
177     return ResultStatus::CRITICAL_ERROR;
178 }
179 
registerSender(const std::shared_ptr<IClientManager> & receiver,ConnectionId senderId,ConnectionId * receiverId,bool * isNew)180 BufferPoolStatus ClientManager::Impl::registerSender(
181         const std::shared_ptr<IClientManager> &receiver,
182         ConnectionId senderId,
183         ConnectionId *receiverId,
184         bool *isNew) {
185     std::shared_ptr<IAccessor> accessor;
186     bool local = false;
187     {
188         std::lock_guard<std::mutex> lock(mActive.mMutex);
189         auto it = mActive.mClients.find(senderId);
190         if (it == mActive.mClients.end()) {
191             return ResultStatus::NOT_FOUND;
192         }
193         it->second->getAccessor(&accessor);
194         local = it->second->isLocal();
195     }
196     if (accessor) {
197         Registration registration;
198         ::ndk::ScopedAStatus status = receiver->registerSender(accessor, &registration);
199         if (!status.isOk()) {
200             return ResultStatus::CRITICAL_ERROR;
201         } else if (local) {
202             std::shared_ptr<ConnectionDeathRecipient> recipient =
203                     Accessor::getConnectionDeathRecipient();
204             if (recipient)  {
205                 ALOGV("client death recipient registered %lld", (long long)*receiverId);
206                 recipient->addCookieToConnection(receiver->asBinder().get(), *receiverId);
207                 AIBinder_linkToDeath(receiver->asBinder().get(), recipient->getRecipient(),
208                                      receiver->asBinder().get());
209             }
210         }
211         *receiverId = registration.connectionId;
212         *isNew = registration.isNew;
213         return ResultStatus::OK;
214     }
215     return ResultStatus::CRITICAL_ERROR;
216 }
217 
create(const std::shared_ptr<BufferPoolAllocator> & allocator,ConnectionId * pConnectionId)218 BufferPoolStatus ClientManager::Impl::create(
219         const std::shared_ptr<BufferPoolAllocator> &allocator,
220         ConnectionId *pConnectionId) {
221     std::shared_ptr<Accessor> accessor = ::ndk::SharedRefBase::make<Accessor>(allocator);
222     if (!accessor || !accessor->isValid()) {
223         return ResultStatus::CRITICAL_ERROR;
224     }
225     // TODO: observer is local. use direct call instead of hidl call.
226     std::shared_ptr<BufferPoolClient> client =
227             std::make_shared<BufferPoolClient>(accessor, mObserver);
228     if (!client || !client->isValid()) {
229         return ResultStatus::CRITICAL_ERROR;
230     }
231     // Since a new bufferpool is created, evict memories which are used by
232     // existing bufferpools and clients.
233     cleanUp(true);
234     {
235         // TODO: handle insert fail. (malloc fail)
236         std::lock_guard<std::mutex> lock(mCache.mMutex);
237         const std::weak_ptr<BufferPoolClient> wclient = client;
238         mCache.mClients.push_back(std::make_pair(accessor, wclient));
239         ConnectionId conId = client->getConnectionId();
240         mObserver->addClient(conId, wclient);
241         {
242             std::lock_guard<std::mutex> lock(mActive.mMutex);
243             mActive.mClients.insert(std::make_pair(conId, client));
244         }
245         *pConnectionId = conId;
246         ALOGV("create new connection %lld", (long long)*pConnectionId);
247     }
248     return ResultStatus::OK;
249 }
250 
close(ConnectionId connectionId)251 BufferPoolStatus ClientManager::Impl::close(ConnectionId connectionId) {
252     std::unique_lock<std::mutex> lock1(mCache.mMutex);
253     std::unique_lock<std::mutex> lock2(mActive.mMutex);
254     auto it = mActive.mClients.find(connectionId);
255     if (it != mActive.mClients.end()) {
256         std::shared_ptr<IAccessor> accessor;
257         it->second->getAccessor(&accessor);
258         std::shared_ptr<BufferPoolClient> closing = it->second;
259         mActive.mClients.erase(connectionId);
260         for (auto cit = mCache.mClients.begin(); cit != mCache.mClients.end();) {
261             // clean up dead client caches
262             std::shared_ptr<IAccessor> cAccessor = cit->first.lock();
263             if (!cAccessor || (accessor && cAccessor.get() ==  accessor.get())) {
264                 cit = mCache.mClients.erase(cit);
265             } else {
266                 cit++;
267             }
268         }
269         lock2.unlock();
270         lock1.unlock();
271         closing->flush();
272         return ResultStatus::OK;
273     }
274     return ResultStatus::NOT_FOUND;
275 }
276 
flush(ConnectionId connectionId)277 BufferPoolStatus ClientManager::Impl::flush(ConnectionId connectionId) {
278     std::shared_ptr<BufferPoolClient> client;
279     {
280         std::lock_guard<std::mutex> lock(mActive.mMutex);
281         auto it = mActive.mClients.find(connectionId);
282         if (it == mActive.mClients.end()) {
283             return ResultStatus::NOT_FOUND;
284         }
285         client = it->second;
286     }
287     return client->flush();
288 }
289 
allocate(ConnectionId connectionId,const std::vector<uint8_t> & params,native_handle_t ** handle,std::shared_ptr<BufferPoolData> * buffer)290 BufferPoolStatus ClientManager::Impl::allocate(
291         ConnectionId connectionId, const std::vector<uint8_t> &params,
292         native_handle_t **handle, std::shared_ptr<BufferPoolData> *buffer) {
293     std::shared_ptr<BufferPoolClient> client;
294     {
295         std::lock_guard<std::mutex> lock(mActive.mMutex);
296         auto it = mActive.mClients.find(connectionId);
297         if (it == mActive.mClients.end()) {
298             return ResultStatus::NOT_FOUND;
299         }
300         client = it->second;
301     }
302 #ifdef BUFFERPOOL_CLONE_HANDLES
303     native_handle_t *origHandle;
304     BufferPoolStatus res = client->allocate(params, &origHandle, buffer);
305     if (res != ResultStatus::OK) {
306         return res;
307     }
308     *handle = native_handle_clone(origHandle);
309     if (handle == NULL) {
310         buffer->reset();
311         return ResultStatus::NO_MEMORY;
312     }
313     return ResultStatus::OK;
314 #else
315     return client->allocate(params, handle, buffer);
316 #endif
317 }
318 
receive(ConnectionId connectionId,TransactionId transactionId,BufferId bufferId,int64_t timestampMs,native_handle_t ** handle,std::shared_ptr<BufferPoolData> * buffer)319 BufferPoolStatus ClientManager::Impl::receive(
320         ConnectionId connectionId, TransactionId transactionId,
321         BufferId bufferId, int64_t timestampMs,
322         native_handle_t **handle, std::shared_ptr<BufferPoolData> *buffer) {
323     std::shared_ptr<BufferPoolClient> client;
324     {
325         std::lock_guard<std::mutex> lock(mActive.mMutex);
326         auto it = mActive.mClients.find(connectionId);
327         if (it == mActive.mClients.end()) {
328             return ResultStatus::NOT_FOUND;
329         }
330         client = it->second;
331     }
332 #ifdef BUFFERPOOL_CLONE_HANDLES
333     native_handle_t *origHandle;
334     BufferPoolStatus res = client->receive(
335             transactionId, bufferId, timestampMs, &origHandle, buffer);
336     if (res != ResultStatus::OK) {
337         return res;
338     }
339     *handle = native_handle_clone(origHandle);
340     if (handle == NULL) {
341         buffer->reset();
342         return ResultStatus::NO_MEMORY;
343     }
344     return ResultStatus::OK;
345 #else
346     return client->receive(transactionId, bufferId, timestampMs, handle, buffer);
347 #endif
348 }
349 
postSend(ConnectionId receiverId,const std::shared_ptr<BufferPoolData> & buffer,TransactionId * transactionId,int64_t * timestampMs)350 BufferPoolStatus ClientManager::Impl::postSend(
351         ConnectionId receiverId, const std::shared_ptr<BufferPoolData> &buffer,
352         TransactionId *transactionId, int64_t *timestampMs) {
353     ConnectionId connectionId = buffer->mConnectionId;
354     std::shared_ptr<BufferPoolClient> client;
355     {
356         std::lock_guard<std::mutex> lock(mActive.mMutex);
357         auto it = mActive.mClients.find(connectionId);
358         if (it == mActive.mClients.end()) {
359             return ResultStatus::NOT_FOUND;
360         }
361         client = it->second;
362     }
363     return client->postSend(receiverId, buffer, transactionId, timestampMs);
364 }
365 
getAccessor(ConnectionId connectionId,std::shared_ptr<IAccessor> * accessor)366 BufferPoolStatus ClientManager::Impl::getAccessor(
367         ConnectionId connectionId, std::shared_ptr<IAccessor> *accessor) {
368     std::shared_ptr<BufferPoolClient> client;
369     {
370         std::lock_guard<std::mutex> lock(mActive.mMutex);
371         auto it = mActive.mClients.find(connectionId);
372         if (it == mActive.mClients.end()) {
373             return ResultStatus::NOT_FOUND;
374         }
375         client = it->second;
376     }
377     return client->getAccessor(accessor);
378 }
379 
cleanUp(bool clearCache)380 void ClientManager::Impl::cleanUp(bool clearCache) {
381     int64_t now = ::android::elapsedRealtime();
382     int64_t lastTransactionMs;
383     std::lock_guard<std::mutex> lock1(mCache.mMutex);
384     if (clearCache || mCache.mLastCleanUpMs + kCleanUpDurationMs < now) {
385         std::lock_guard<std::mutex> lock2(mActive.mMutex);
386         int cleaned = 0;
387         for (auto it = mActive.mClients.begin(); it != mActive.mClients.end();) {
388             if (!it->second->isActive(&lastTransactionMs, clearCache)) {
389                 if (lastTransactionMs + kClientTimeoutMs < now) {
390                   std::shared_ptr<IAccessor> accessor;
391                     it->second->getAccessor(&accessor);
392                     it = mActive.mClients.erase(it);
393                     ++cleaned;
394                     continue;
395                 }
396             }
397             ++it;
398         }
399         for (auto cit = mCache.mClients.begin(); cit != mCache.mClients.end();) {
400             // clean up dead client caches
401           std::shared_ptr<IAccessor> cAccessor = cit->first.lock();
402             if (!cAccessor) {
403                 cit = mCache.mClients.erase(cit);
404             } else {
405                 ++cit;
406             }
407         }
408         ALOGV("# of cleaned connections: %d", cleaned);
409         mCache.mLastCleanUpMs = now;
410     }
411 }
412 
registerSender(const std::shared_ptr<IAccessor> & in_bufferPool,Registration * _aidl_return)413 ::ndk::ScopedAStatus ClientManager::registerSender(
414         const std::shared_ptr<IAccessor>& in_bufferPool, Registration* _aidl_return) {
415     BufferPoolStatus status = ResultStatus::CRITICAL_ERROR;
416     if (mImpl) {
417         status = mImpl->registerSender(in_bufferPool, _aidl_return);
418     }
419     if (status != ResultStatus::OK) {
420         return ::ndk::ScopedAStatus::fromServiceSpecificError(status);
421     }
422     return ::ndk::ScopedAStatus::ok();
423 }
424 
registerPassiveSender(const std::shared_ptr<IAccessor> & in_bufferPool,Registration * _aidl_return)425 ::ndk::ScopedAStatus ClientManager::registerPassiveSender(
426         const std::shared_ptr<IAccessor>& in_bufferPool, Registration* _aidl_return) {
427     // TODO
428     (void) in_bufferPool;
429     (void) _aidl_return;
430     return ::ndk::ScopedAStatus::fromServiceSpecificError(ResultStatus::NOT_FOUND);
431 }
432 
433 // Methods for local use.
434 std::shared_ptr<ClientManager> ClientManager::sInstance;
435 std::mutex ClientManager::sInstanceLock;
436 
getInstance()437 std::shared_ptr<ClientManager> ClientManager::getInstance() {
438     std::lock_guard<std::mutex> lock(sInstanceLock);
439     if (!sInstance) {
440         sInstance = ::ndk::SharedRefBase::make<ClientManager>();
441         // TODO: configure thread count for threadpool properly
442         // after b/261652496 is resolved.
443     }
444     Accessor::createInvalidator();
445     Accessor::createEvictor();
446     return sInstance;
447 }
448 
ClientManager()449 ClientManager::ClientManager() : mImpl(new Impl()) {}
450 
~ClientManager()451 ClientManager::~ClientManager() {
452 }
453 
create(const std::shared_ptr<BufferPoolAllocator> & allocator,ConnectionId * pConnectionId)454 BufferPoolStatus ClientManager::create(
455         const std::shared_ptr<BufferPoolAllocator> &allocator,
456         ConnectionId *pConnectionId) {
457     if (mImpl) {
458         return mImpl->create(allocator, pConnectionId);
459     }
460     return ResultStatus::CRITICAL_ERROR;
461 }
462 
registerSender(const std::shared_ptr<IClientManager> & receiver,ConnectionId senderId,ConnectionId * receiverId,bool * isNew)463 BufferPoolStatus ClientManager::registerSender(
464         const std::shared_ptr<IClientManager> &receiver,
465         ConnectionId senderId,
466         ConnectionId *receiverId,
467         bool *isNew) {
468     if (mImpl) {
469         return mImpl->registerSender(receiver, senderId, receiverId, isNew);
470     }
471     return ResultStatus::CRITICAL_ERROR;
472 }
473 
close(ConnectionId connectionId)474 BufferPoolStatus ClientManager::close(ConnectionId connectionId) {
475     if (mImpl) {
476         return mImpl->close(connectionId);
477     }
478     return ResultStatus::CRITICAL_ERROR;
479 }
480 
flush(ConnectionId connectionId)481 BufferPoolStatus ClientManager::flush(ConnectionId connectionId) {
482     if (mImpl) {
483         return mImpl->flush(connectionId);
484     }
485     return ResultStatus::CRITICAL_ERROR;
486 }
487 
allocate(ConnectionId connectionId,const std::vector<uint8_t> & params,native_handle_t ** handle,std::shared_ptr<BufferPoolData> * buffer)488 BufferPoolStatus ClientManager::allocate(
489         ConnectionId connectionId, const std::vector<uint8_t> &params,
490         native_handle_t **handle, std::shared_ptr<BufferPoolData> *buffer) {
491     if (mImpl) {
492         return mImpl->allocate(connectionId, params, handle, buffer);
493     }
494     return ResultStatus::CRITICAL_ERROR;
495 }
496 
receive(ConnectionId connectionId,TransactionId transactionId,BufferId bufferId,int64_t timestampMs,native_handle_t ** handle,std::shared_ptr<BufferPoolData> * buffer)497 BufferPoolStatus ClientManager::receive(
498         ConnectionId connectionId, TransactionId transactionId,
499         BufferId bufferId, int64_t timestampMs,
500         native_handle_t **handle, std::shared_ptr<BufferPoolData> *buffer) {
501     if (mImpl) {
502         return mImpl->receive(connectionId, transactionId, bufferId,
503                               timestampMs, handle, buffer);
504     }
505     return ResultStatus::CRITICAL_ERROR;
506 }
507 
postSend(ConnectionId receiverId,const std::shared_ptr<BufferPoolData> & buffer,TransactionId * transactionId,int64_t * timestampMs)508 BufferPoolStatus ClientManager::postSend(
509         ConnectionId receiverId, const std::shared_ptr<BufferPoolData> &buffer,
510         TransactionId *transactionId, int64_t* timestampMs) {
511     if (mImpl && buffer) {
512         return mImpl->postSend(receiverId, buffer, transactionId, timestampMs);
513     }
514     return ResultStatus::CRITICAL_ERROR;
515 }
516 
cleanUp()517 void ClientManager::cleanUp() {
518     if (mImpl) {
519         mImpl->cleanUp(true);
520     }
521 }
522 
523 }  // namespace ::aidl::android::hardware::media::bufferpool2::implementation
524