blob: 81e8eac21dccb3e0517192920e828abba39ddfef [file] [log] [blame]
Sungtak Lee97e1dfb2022-12-07 07:45:45 +00001/*
Sungtak Lee8878a132022-12-07 11:42:03 +00002 * Copyright (C) 2022 The Android Open Source Project
Sungtak Lee97e1dfb2022-12-07 07:45:45 +00003 *
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 */
Sungtak Lee8878a132022-12-07 11:42:03 +000016#define LOG_TAG "AidlBufferPoolAcc"
17//#define LOG_NDEBUG 0
18
Sungtak Lee5e104e42024-06-07 04:46:23 +000019#include <android-base/no_destructor.h>
20
Sungtak Lee8878a132022-12-07 11:42:03 +000021#include <sys/types.h>
22#include <stdint.h>
23#include <time.h>
24#include <unistd.h>
25#include <utils/Log.h>
26#include <thread>
Sungtak Lee97e1dfb2022-12-07 07:45:45 +000027
28#include "Accessor.h"
Sungtak Lee97e1dfb2022-12-07 07:45:45 +000029#include "Connection.h"
Sungtak Lee8878a132022-12-07 11:42:03 +000030#include "DataHelper.h"
Sungtak Lee97e1dfb2022-12-07 07:45:45 +000031
Sungtak Lee8878a132022-12-07 11:42:03 +000032namespace aidl::android::hardware::media::bufferpool2::implementation {
33
34namespace {
35 static constexpr nsecs_t kEvictGranularityNs = 1000000000; // 1 sec
36 static constexpr nsecs_t kEvictDurationNs = 5000000000; // 5 secs
37}
38
39#ifdef __ANDROID_VNDK__
40static constexpr uint32_t kSeqIdVndkBit = 1U << 31;
41#else
42static constexpr uint32_t kSeqIdVndkBit = 0;
43#endif
44
45static constexpr uint32_t kSeqIdMax = 0x7fffffff;
Sungtak Lee5e104e42024-06-07 04:46:23 +000046
47Accessor::ConnectionIdGenerator::ConnectionIdGenerator() {
48 mSeqId = static_cast<uint32_t>(time(nullptr) & kSeqIdMax);
49 mPid = static_cast<int32_t>(getpid());
50}
51
52ConnectionId Accessor::ConnectionIdGenerator::getConnectionId() {
53 uint32_t seq;
54 {
55 std::lock_guard<std::mutex> l(mLock);
56 seq = mSeqId;
57 if (mSeqId == kSeqIdMax) {
58 mSeqId = 0;
59 } else {
60 ++mSeqId;
61 }
62 }
63 return (int64_t)mPid << 32 | seq | kSeqIdVndkBit;
64}
Sungtak Lee8878a132022-12-07 11:42:03 +000065
66namespace {
67// anonymous namespace
68static std::shared_ptr<ConnectionDeathRecipient> sConnectionDeathRecipient =
69 std::make_shared<ConnectionDeathRecipient>();
70
71void serviceDied(void *cookie) {
72 if (sConnectionDeathRecipient) {
73 sConnectionDeathRecipient->onDead(cookie);
74 }
75}
76}
77
78std::shared_ptr<ConnectionDeathRecipient> Accessor::getConnectionDeathRecipient() {
79 return sConnectionDeathRecipient;
80}
81
82ConnectionDeathRecipient::ConnectionDeathRecipient() {
83 mDeathRecipient = ndk::ScopedAIBinder_DeathRecipient(
84 AIBinder_DeathRecipient_new(serviceDied));
85}
Sungtak Lee97e1dfb2022-12-07 07:45:45 +000086
87void ConnectionDeathRecipient::add(
88 int64_t connectionId,
Sungtak Lee8878a132022-12-07 11:42:03 +000089 const std::shared_ptr<Accessor> &accessor) {
Sungtak Lee97e1dfb2022-12-07 07:45:45 +000090 std::lock_guard<std::mutex> lock(mLock);
91 if (mAccessors.find(connectionId) == mAccessors.end()) {
92 mAccessors.insert(std::make_pair(connectionId, accessor));
93 }
94}
95
96void ConnectionDeathRecipient::remove(int64_t connectionId) {
97 std::lock_guard<std::mutex> lock(mLock);
98 mAccessors.erase(connectionId);
99 auto it = mConnectionToCookie.find(connectionId);
100 if (it != mConnectionToCookie.end()) {
Sungtak Lee8878a132022-12-07 11:42:03 +0000101 void * cookie = it->second;
Sungtak Lee97e1dfb2022-12-07 07:45:45 +0000102 mConnectionToCookie.erase(it);
103 auto cit = mCookieToConnections.find(cookie);
104 if (cit != mCookieToConnections.end()) {
105 cit->second.erase(connectionId);
106 if (cit->second.size() == 0) {
107 mCookieToConnections.erase(cit);
108 }
109 }
110 }
111}
112
113void ConnectionDeathRecipient::addCookieToConnection(
Sungtak Lee8878a132022-12-07 11:42:03 +0000114 void *cookie,
Sungtak Lee97e1dfb2022-12-07 07:45:45 +0000115 int64_t connectionId) {
116 std::lock_guard<std::mutex> lock(mLock);
117 if (mAccessors.find(connectionId) == mAccessors.end()) {
118 return;
119 }
120 mConnectionToCookie.insert(std::make_pair(connectionId, cookie));
121 auto it = mCookieToConnections.find(cookie);
122 if (it != mCookieToConnections.end()) {
123 it->second.insert(connectionId);
124 } else {
125 mCookieToConnections.insert(std::make_pair(
126 cookie, std::set<int64_t>{connectionId}));
127 }
128}
129
Sungtak Lee8878a132022-12-07 11:42:03 +0000130void ConnectionDeathRecipient::onDead(void *cookie) {
131 std::map<int64_t, const std::weak_ptr<Accessor>> connectionsToClose;
Sungtak Lee97e1dfb2022-12-07 07:45:45 +0000132 {
133 std::lock_guard<std::mutex> lock(mLock);
134
135 auto it = mCookieToConnections.find(cookie);
136 if (it != mCookieToConnections.end()) {
137 for (auto conIt = it->second.begin(); conIt != it->second.end(); ++conIt) {
138 auto accessorIt = mAccessors.find(*conIt);
139 if (accessorIt != mAccessors.end()) {
140 connectionsToClose.insert(std::make_pair(*conIt, accessorIt->second));
141 mAccessors.erase(accessorIt);
142 }
143 mConnectionToCookie.erase(*conIt);
144 }
145 mCookieToConnections.erase(it);
146 }
147 }
148
149 if (connectionsToClose.size() > 0) {
Sungtak Lee8878a132022-12-07 11:42:03 +0000150 std::shared_ptr<Accessor> accessor;
Sungtak Lee97e1dfb2022-12-07 07:45:45 +0000151 for (auto it = connectionsToClose.begin(); it != connectionsToClose.end(); ++it) {
Sungtak Lee8878a132022-12-07 11:42:03 +0000152 accessor = it->second.lock();
Sungtak Lee97e1dfb2022-12-07 07:45:45 +0000153
154 if (accessor) {
155 accessor->close(it->first);
156 ALOGD("connection %lld closed on death", (long long)it->first);
157 }
158 }
159 }
160}
161
Sungtak Lee8878a132022-12-07 11:42:03 +0000162AIBinder_DeathRecipient *ConnectionDeathRecipient::getRecipient() {
163 return mDeathRecipient.get();
Sungtak Lee97e1dfb2022-12-07 07:45:45 +0000164}
165
Sungtak Lee8878a132022-12-07 11:42:03 +0000166::ndk::ScopedAStatus Accessor::connect(const std::shared_ptr<::aidl::android::hardware::media::bufferpool2::IObserver>& in_observer, ::aidl::android::hardware::media::bufferpool2::IAccessor::ConnectionInfo* _aidl_return) {
167 std::shared_ptr<Connection> connection;
Sungtak Lee97e1dfb2022-12-07 07:45:45 +0000168 ConnectionId connectionId;
169 uint32_t msgId;
Sungtak Lee8878a132022-12-07 11:42:03 +0000170 StatusDescriptor statusDesc;
171 InvalidationDescriptor invDesc;
172 BufferPoolStatus status = connect(
173 in_observer, false, &connection, &connectionId, &msgId, &statusDesc, &invDesc);
Sungtak Lee97e1dfb2022-12-07 07:45:45 +0000174 if (status == ResultStatus::OK) {
Sungtak Lee8878a132022-12-07 11:42:03 +0000175 _aidl_return->connection = connection;
176 _aidl_return->connectionId = connectionId;
177 _aidl_return->msgId = msgId;
178 _aidl_return->toFmqDesc = std::move(statusDesc);
179 _aidl_return->fromFmqDesc = std::move(invDesc);
180 return ::ndk::ScopedAStatus::ok();
Sungtak Lee97e1dfb2022-12-07 07:45:45 +0000181 }
Sungtak Lee8878a132022-12-07 11:42:03 +0000182 return ::ndk::ScopedAStatus::fromServiceSpecificError(status);
Sungtak Lee97e1dfb2022-12-07 07:45:45 +0000183}
184
185Accessor::Accessor(const std::shared_ptr<BufferPoolAllocator> &allocator)
Sungtak Lee8878a132022-12-07 11:42:03 +0000186 : mAllocator(allocator), mScheduleEvictTs(0) {}
Sungtak Lee97e1dfb2022-12-07 07:45:45 +0000187
188Accessor::~Accessor() {
189}
190
191bool Accessor::isValid() {
Sungtak Lee8878a132022-12-07 11:42:03 +0000192 return mBufferPool.isValid();
Sungtak Lee97e1dfb2022-12-07 07:45:45 +0000193}
194
Sungtak Lee8878a132022-12-07 11:42:03 +0000195BufferPoolStatus Accessor::flush() {
196 std::lock_guard<std::mutex> lock(mBufferPool.mMutex);
197 mBufferPool.processStatusMessages();
198 mBufferPool.flush(ref<Accessor>());
199 return ResultStatus::OK;
Sungtak Lee97e1dfb2022-12-07 07:45:45 +0000200}
201
Sungtak Lee8878a132022-12-07 11:42:03 +0000202BufferPoolStatus Accessor::allocate(
Sungtak Lee97e1dfb2022-12-07 07:45:45 +0000203 ConnectionId connectionId,
204 const std::vector<uint8_t> &params,
205 BufferId *bufferId, const native_handle_t** handle) {
Sungtak Lee8878a132022-12-07 11:42:03 +0000206 std::unique_lock<std::mutex> lock(mBufferPool.mMutex);
207 mBufferPool.processStatusMessages();
208 BufferPoolStatus status = ResultStatus::OK;
209 if (!mBufferPool.getFreeBuffer(mAllocator, params, bufferId, handle)) {
210 lock.unlock();
211 std::shared_ptr<BufferPoolAllocation> alloc;
212 size_t allocSize;
213 status = mAllocator->allocate(params, &alloc, &allocSize);
214 lock.lock();
215 if (status == ResultStatus::OK) {
216 status = mBufferPool.addNewBuffer(alloc, allocSize, params, bufferId, handle);
217 }
218 ALOGV("create a buffer %d : %u %p",
219 status == ResultStatus::OK, *bufferId, *handle);
Sungtak Lee97e1dfb2022-12-07 07:45:45 +0000220 }
Sungtak Lee8878a132022-12-07 11:42:03 +0000221 if (status == ResultStatus::OK) {
222 // TODO: handle ownBuffer failure
223 mBufferPool.handleOwnBuffer(connectionId, *bufferId);
224 }
225 mBufferPool.cleanUp();
226 scheduleEvictIfNeeded();
227 return status;
Sungtak Lee97e1dfb2022-12-07 07:45:45 +0000228}
229
Sungtak Lee8878a132022-12-07 11:42:03 +0000230BufferPoolStatus Accessor::fetch(
Sungtak Lee97e1dfb2022-12-07 07:45:45 +0000231 ConnectionId connectionId, TransactionId transactionId,
232 BufferId bufferId, const native_handle_t** handle) {
Sungtak Lee8878a132022-12-07 11:42:03 +0000233 std::lock_guard<std::mutex> lock(mBufferPool.mMutex);
234 mBufferPool.processStatusMessages();
235 auto found = mBufferPool.mTransactions.find(transactionId);
236 if (found != mBufferPool.mTransactions.end() &&
237 contains(&mBufferPool.mPendingTransactions,
238 connectionId, transactionId)) {
239 if (found->second->mSenderValidated &&
240 found->second->mStatus == BufferStatus::TRANSFER_FROM &&
241 found->second->mBufferId == bufferId) {
242 found->second->mStatus = BufferStatus::TRANSFER_FETCH;
243 auto bufferIt = mBufferPool.mBuffers.find(bufferId);
244 if (bufferIt != mBufferPool.mBuffers.end()) {
245 mBufferPool.mStats.onBufferFetched();
246 *handle = bufferIt->second->handle();
247 return ResultStatus::OK;
248 }
Sungtak Lee97e1dfb2022-12-07 07:45:45 +0000249 }
Sungtak Lee97e1dfb2022-12-07 07:45:45 +0000250 }
Sungtak Lee8878a132022-12-07 11:42:03 +0000251 mBufferPool.cleanUp();
252 scheduleEvictIfNeeded();
Sungtak Lee97e1dfb2022-12-07 07:45:45 +0000253 return ResultStatus::CRITICAL_ERROR;
254}
255
Sungtak Lee8878a132022-12-07 11:42:03 +0000256BufferPoolStatus Accessor::connect(
257 const std::shared_ptr<IObserver> &observer, bool local,
258 std::shared_ptr<Connection> *connection, ConnectionId *pConnectionId,
259 uint32_t *pMsgId,
260 StatusDescriptor* statusDescPtr,
261 InvalidationDescriptor* invDescPtr) {
Sungtak Lee5e104e42024-06-07 04:46:23 +0000262 static ::android::base::NoDestructor<ConnectionIdGenerator> sConIdGenerator;
Sungtak Lee8878a132022-12-07 11:42:03 +0000263 std::shared_ptr<Connection> newConnection = ::ndk::SharedRefBase::make<Connection>();
264 BufferPoolStatus status = ResultStatus::CRITICAL_ERROR;
265 {
266 std::lock_guard<std::mutex> lock(mBufferPool.mMutex);
267 if (newConnection) {
268 int32_t pid = getpid();
Sungtak Lee5e104e42024-06-07 04:46:23 +0000269 ConnectionId id = sConIdGenerator->getConnectionId();
Sungtak Lee8878a132022-12-07 11:42:03 +0000270 status = mBufferPool.mObserver.open(id, statusDescPtr);
271 if (status == ResultStatus::OK) {
272 newConnection->initialize(ref<Accessor>(), id);
273 *connection = newConnection;
274 *pConnectionId = id;
275 *pMsgId = mBufferPool.mInvalidation.mInvalidationId;
276 mBufferPool.mConnectionIds.insert(id);
277 mBufferPool.mInvalidationChannel.getDesc(invDescPtr);
278 mBufferPool.mInvalidation.onConnect(id, observer);
Sungtak Lee8878a132022-12-07 11:42:03 +0000279 }
280
281 }
282 mBufferPool.processStatusMessages();
283 mBufferPool.cleanUp();
284 scheduleEvictIfNeeded();
Sungtak Lee97e1dfb2022-12-07 07:45:45 +0000285 }
Sungtak Lee8878a132022-12-07 11:42:03 +0000286 if (!local && status == ResultStatus::OK) {
287 std::shared_ptr<Accessor> accessor(ref<Accessor>());
288 sConnectionDeathRecipient->add(*pConnectionId, accessor);
289 }
290 return status;
291}
292
293BufferPoolStatus Accessor::close(ConnectionId connectionId) {
294 {
295 std::lock_guard<std::mutex> lock(mBufferPool.mMutex);
296 ALOGV("connection close %lld: %u", (long long)connectionId, mBufferPool.mInvalidation.mId);
297 mBufferPool.processStatusMessages();
298 mBufferPool.handleClose(connectionId);
299 mBufferPool.mObserver.close(connectionId);
300 mBufferPool.mInvalidation.onClose(connectionId);
301 // Since close# will be called after all works are finished, it is OK to
302 // evict unused buffers.
303 mBufferPool.cleanUp(true);
304 scheduleEvictIfNeeded();
305 }
306 sConnectionDeathRecipient->remove(connectionId);
307 return ResultStatus::OK;
Sungtak Lee97e1dfb2022-12-07 07:45:45 +0000308}
309
310void Accessor::cleanUp(bool clearCache) {
Sungtak Lee8878a132022-12-07 11:42:03 +0000311 // transaction timeout, buffer caching TTL handling
312 std::lock_guard<std::mutex> lock(mBufferPool.mMutex);
313 mBufferPool.processStatusMessages();
314 mBufferPool.cleanUp(clearCache);
315}
316
317void Accessor::handleInvalidateAck() {
318 std::map<ConnectionId, const std::shared_ptr<IObserver>> observers;
319 uint32_t invalidationId;
320 {
321 std::lock_guard<std::mutex> lock(mBufferPool.mMutex);
322 mBufferPool.processStatusMessages();
323 mBufferPool.mInvalidation.onHandleAck(&observers, &invalidationId);
324 }
325 // Do not hold lock for send invalidations
326 size_t deadClients = 0;
327 for (auto it = observers.begin(); it != observers.end(); ++it) {
328 const std::shared_ptr<IObserver> observer = it->second;
329 if (observer) {
330 ::ndk::ScopedAStatus status = observer->onMessage(it->first, invalidationId);
331 if (!status.isOk()) {
332 ++deadClients;
333 }
334 }
335 }
336 if (deadClients > 0) {
337 ALOGD("During invalidation found %zu dead clients", deadClients);
Sungtak Lee97e1dfb2022-12-07 07:45:45 +0000338 }
339}
340
Sungtak Lee8878a132022-12-07 11:42:03 +0000341void Accessor::invalidatorThread(
342 std::map<uint32_t, const std::weak_ptr<Accessor>> &accessors,
343 std::mutex &mutex,
344 std::condition_variable &cv,
345 bool &ready) {
346 constexpr uint32_t NUM_SPIN_TO_INCREASE_SLEEP = 1024;
347 constexpr uint32_t NUM_SPIN_TO_LOG = 1024*8;
348 constexpr useconds_t MAX_SLEEP_US = 10000;
349 uint32_t numSpin = 0;
350 useconds_t sleepUs = 1;
Sungtak Lee97e1dfb2022-12-07 07:45:45 +0000351
Sungtak Lee8878a132022-12-07 11:42:03 +0000352 while(true) {
353 std::map<uint32_t, const std::weak_ptr<Accessor>> copied;
354 {
355 std::unique_lock<std::mutex> lock(mutex);
356 while (!ready) {
357 numSpin = 0;
358 sleepUs = 1;
359 cv.wait(lock);
360 }
361 copied.insert(accessors.begin(), accessors.end());
362 }
363 std::list<ConnectionId> erased;
364 for (auto it = copied.begin(); it != copied.end(); ++it) {
365 const std::shared_ptr<Accessor> acc = it->second.lock();
366 if (!acc) {
367 erased.push_back(it->first);
368 } else {
369 acc->handleInvalidateAck();
370 }
371 }
372 {
373 std::unique_lock<std::mutex> lock(mutex);
374 for (auto it = erased.begin(); it != erased.end(); ++it) {
375 accessors.erase(*it);
376 }
377 if (accessors.size() == 0) {
378 ready = false;
379 } else {
380 // N.B. Since there is not a efficient way to wait over FMQ,
381 // polling over the FMQ is the current way to prevent draining
382 // CPU.
383 lock.unlock();
384 ++numSpin;
385 if (numSpin % NUM_SPIN_TO_INCREASE_SLEEP == 0 &&
386 sleepUs < MAX_SLEEP_US) {
387 sleepUs *= 10;
388 }
389 if (numSpin % NUM_SPIN_TO_LOG == 0) {
390 ALOGW("invalidator thread spinning");
391 }
392 ::usleep(sleepUs);
393 }
394 }
395 }
396}
397
398Accessor::AccessorInvalidator::AccessorInvalidator() : mReady(false) {
399 std::thread invalidator(
400 invalidatorThread,
401 std::ref(mAccessors),
402 std::ref(mMutex),
403 std::ref(mCv),
404 std::ref(mReady));
405 invalidator.detach();
406}
407
408void Accessor::AccessorInvalidator::addAccessor(
409 uint32_t accessorId, const std::weak_ptr<Accessor> &accessor) {
410 bool notify = false;
411 std::unique_lock<std::mutex> lock(mMutex);
412 if (mAccessors.find(accessorId) == mAccessors.end()) {
413 if (!mReady) {
414 mReady = true;
415 notify = true;
416 }
417 mAccessors.emplace(accessorId, accessor);
418 ALOGV("buffer invalidation added bp:%u %d", accessorId, notify);
419 }
420 lock.unlock();
421 if (notify) {
422 mCv.notify_one();
423 }
424}
425
426void Accessor::AccessorInvalidator::delAccessor(uint32_t accessorId) {
427 std::lock_guard<std::mutex> lock(mMutex);
428 mAccessors.erase(accessorId);
429 ALOGV("buffer invalidation deleted bp:%u", accessorId);
430 if (mAccessors.size() == 0) {
431 mReady = false;
432 }
433}
434
435std::unique_ptr<Accessor::AccessorInvalidator> Accessor::sInvalidator;
436
437void Accessor::createInvalidator() {
438 if (!sInvalidator) {
439 sInvalidator = std::make_unique<Accessor::AccessorInvalidator>();
440 }
441}
442
443void Accessor::evictorThread(
444 std::map<const std::weak_ptr<Accessor>, nsecs_t, std::owner_less<>> &accessors,
445 std::mutex &mutex,
446 std::condition_variable &cv) {
Ryan Prichard9f160cb2024-06-27 22:33:21 -0700447 std::list<std::weak_ptr<Accessor>> evictList;
Sungtak Lee8878a132022-12-07 11:42:03 +0000448 while (true) {
449 int expired = 0;
450 int evicted = 0;
451 {
452 nsecs_t now = systemTime();
453 std::unique_lock<std::mutex> lock(mutex);
454 while (accessors.size() == 0) {
455 cv.wait(lock);
456 }
457 auto it = accessors.begin();
458 while (it != accessors.end()) {
459 if (now > (it->second + kEvictDurationNs)) {
460 ++expired;
461 evictList.push_back(it->first);
462 it = accessors.erase(it);
463 } else {
464 ++it;
465 }
466 }
467 }
468 // evict idle accessors;
469 for (auto it = evictList.begin(); it != evictList.end(); ++it) {
470 const std::shared_ptr<Accessor> accessor = it->lock();
471 if (accessor) {
472 accessor->cleanUp(true);
473 ++evicted;
474 }
475 }
476 if (expired > 0) {
477 ALOGD("evictor expired: %d, evicted: %d", expired, evicted);
478 }
479 evictList.clear();
480 ::usleep(kEvictGranularityNs / 1000);
481 }
482}
483
484Accessor::AccessorEvictor::AccessorEvictor() {
485 std::thread evictor(
486 evictorThread,
487 std::ref(mAccessors),
488 std::ref(mMutex),
489 std::ref(mCv));
490 evictor.detach();
491}
492
493void Accessor::AccessorEvictor::addAccessor(
494 const std::weak_ptr<Accessor> &accessor, nsecs_t ts) {
495 std::lock_guard<std::mutex> lock(mMutex);
496 bool notify = mAccessors.empty();
497 auto it = mAccessors.find(accessor);
498 if (it == mAccessors.end()) {
499 mAccessors.emplace(accessor, ts);
500 } else {
501 it->second = ts;
502 }
503 if (notify) {
504 mCv.notify_one();
505 }
506}
507
508std::unique_ptr<Accessor::AccessorEvictor> Accessor::sEvictor;
509
510void Accessor::createEvictor() {
511 if (!sEvictor) {
512 sEvictor = std::make_unique<Accessor::AccessorEvictor>();
513 }
514}
515
516void Accessor::scheduleEvictIfNeeded() {
517 nsecs_t now = systemTime();
518
519 if (now > (mScheduleEvictTs + kEvictGranularityNs)) {
520 mScheduleEvictTs = now;
521 sEvictor->addAccessor(ref<Accessor>(), now);
522 }
523}
524
525} // namespace aidl::android::hardware::media::bufferpool2::implemntation {