blob: cb55b0781db565ac90351ef1ab39c100b822a254 [file] [log] [blame]
Sungtak Leebbe37b62018-08-29 15:15:48 -07001/*
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
Ray Essick3688d0a2019-10-09 15:31:58 -070017#define LOG_TAG "BufferPoolAccessor2.0"
Sungtak Leebbe37b62018-08-29 15:15:48 -070018//#define LOG_NDEBUG 0
19
20#include <sys/types.h>
Ray Essick3688d0a2019-10-09 15:31:58 -070021#include <stdint.h>
Sungtak Leebbe37b62018-08-29 15:15:48 -070022#include <time.h>
23#include <unistd.h>
24#include <utils/Log.h>
Sungtak Leec7f9e2c2018-09-14 16:23:40 -070025#include <thread>
Sungtak Leebbe37b62018-08-29 15:15:48 -070026#include "AccessorImpl.h"
27#include "Connection.h"
28
29namespace android {
30namespace hardware {
31namespace media {
32namespace bufferpool {
33namespace V2_0 {
34namespace implementation {
35
36namespace {
37 static constexpr int64_t kCleanUpDurationUs = 500000; // TODO tune 0.5 sec
38 static constexpr int64_t kLogDurationUs = 5000000; // 5 secs
39
40 static constexpr size_t kMinAllocBytesForEviction = 1024*1024*15;
Sungtak Lee30dbaa22019-10-03 14:38:01 -070041 static constexpr size_t kMinBufferCountForEviction = 25;
Sungtak Leebbe37b62018-08-29 15:15:48 -070042}
43
44// Buffer structure in bufferpool process
45struct InternalBuffer {
46 BufferId mId;
47 size_t mOwnerCount;
48 size_t mTransactionCount;
49 const std::shared_ptr<BufferPoolAllocation> mAllocation;
50 const size_t mAllocSize;
51 const std::vector<uint8_t> mConfig;
Sungtak Leec7f9e2c2018-09-14 16:23:40 -070052 bool mInvalidated;
Sungtak Leebbe37b62018-08-29 15:15:48 -070053
54 InternalBuffer(
55 BufferId id,
56 const std::shared_ptr<BufferPoolAllocation> &alloc,
57 const size_t allocSize,
58 const std::vector<uint8_t> &allocConfig)
59 : mId(id), mOwnerCount(0), mTransactionCount(0),
Sungtak Leec7f9e2c2018-09-14 16:23:40 -070060 mAllocation(alloc), mAllocSize(allocSize), mConfig(allocConfig),
61 mInvalidated(false) {}
Sungtak Leebbe37b62018-08-29 15:15:48 -070062
63 const native_handle_t *handle() {
64 return mAllocation->handle();
65 }
Sungtak Leec7f9e2c2018-09-14 16:23:40 -070066
67 void invalidate() {
68 mInvalidated = true;
69 }
Sungtak Leebbe37b62018-08-29 15:15:48 -070070};
71
72struct TransactionStatus {
73 TransactionId mId;
74 BufferId mBufferId;
75 ConnectionId mSender;
76 ConnectionId mReceiver;
77 BufferStatus mStatus;
78 int64_t mTimestampUs;
79 bool mSenderValidated;
80
81 TransactionStatus(const BufferStatusMessage &message, int64_t timestampUs) {
82 mId = message.transactionId;
83 mBufferId = message.bufferId;
84 mStatus = message.newStatus;
85 mTimestampUs = timestampUs;
86 if (mStatus == BufferStatus::TRANSFER_TO) {
87 mSender = message.connectionId;
88 mReceiver = message.targetConnectionId;
89 mSenderValidated = true;
90 } else {
91 mSender = -1LL;
92 mReceiver = message.connectionId;
93 mSenderValidated = false;
94 }
95 }
96};
97
98// Helper template methods for handling map of set.
99template<class T, class U>
100bool insert(std::map<T, std::set<U>> *mapOfSet, T key, U value) {
101 auto iter = mapOfSet->find(key);
102 if (iter == mapOfSet->end()) {
103 std::set<U> valueSet{value};
104 mapOfSet->insert(std::make_pair(key, valueSet));
105 return true;
106 } else if (iter->second.find(value) == iter->second.end()) {
107 iter->second.insert(value);
108 return true;
109 }
110 return false;
111}
112
113template<class T, class U>
114bool erase(std::map<T, std::set<U>> *mapOfSet, T key, U value) {
115 bool ret = false;
116 auto iter = mapOfSet->find(key);
117 if (iter != mapOfSet->end()) {
118 if (iter->second.erase(value) > 0) {
119 ret = true;
120 }
121 if (iter->second.size() == 0) {
122 mapOfSet->erase(iter);
123 }
124 }
125 return ret;
126}
127
128template<class T, class U>
129bool contains(std::map<T, std::set<U>> *mapOfSet, T key, U value) {
130 auto iter = mapOfSet->find(key);
131 if (iter != mapOfSet->end()) {
132 auto setIter = iter->second.find(value);
133 return setIter != iter->second.end();
134 }
135 return false;
136}
137
Pawin Vongmasa50d25732020-04-24 18:59:54 -0700138#ifdef __ANDROID_VNDK__
139static constexpr uint32_t kSeqIdVndkBit = 1 << 31;
140#else
141static constexpr uint32_t kSeqIdVndkBit = 0;
142#endif
143
144static constexpr uint32_t kSeqIdMax = 0x7fffffff;
145uint32_t Accessor::Impl::sSeqId = time(nullptr) & kSeqIdMax;
Sungtak Leebbe37b62018-08-29 15:15:48 -0700146
147Accessor::Impl::Impl(
148 const std::shared_ptr<BufferPoolAllocator> &allocator)
149 : mAllocator(allocator) {}
150
151Accessor::Impl::~Impl() {
152}
153
154ResultStatus Accessor::Impl::connect(
Sungtak Leec7f9e2c2018-09-14 16:23:40 -0700155 const sp<Accessor> &accessor, const sp<IObserver> &observer,
156 sp<Connection> *connection,
157 ConnectionId *pConnectionId,
158 uint32_t *pMsgId,
159 const StatusDescriptor** statusDescPtr,
160 const InvalidationDescriptor** invDescPtr) {
Sungtak Leebbe37b62018-08-29 15:15:48 -0700161 sp<Connection> newConnection = new Connection();
162 ResultStatus status = ResultStatus::CRITICAL_ERROR;
163 {
164 std::lock_guard<std::mutex> lock(mBufferPool.mMutex);
165 if (newConnection) {
Ray Essick3688d0a2019-10-09 15:31:58 -0700166 int32_t pid = getpid();
Pawin Vongmasa50d25732020-04-24 18:59:54 -0700167 ConnectionId id = (int64_t)pid << 32 | sSeqId | kSeqIdVndkBit;
Sungtak Leec7f9e2c2018-09-14 16:23:40 -0700168 status = mBufferPool.mObserver.open(id, statusDescPtr);
Sungtak Leebbe37b62018-08-29 15:15:48 -0700169 if (status == ResultStatus::OK) {
170 newConnection->initialize(accessor, id);
171 *connection = newConnection;
172 *pConnectionId = id;
Sungtak Leec7f9e2c2018-09-14 16:23:40 -0700173 *pMsgId = mBufferPool.mInvalidation.mInvalidationId;
Sungtak Leeccc32cb2019-08-20 18:07:54 -0700174 mBufferPool.mConnectionIds.insert(id);
Sungtak Leec7f9e2c2018-09-14 16:23:40 -0700175 mBufferPool.mInvalidationChannel.getDesc(invDescPtr);
176 mBufferPool.mInvalidation.onConnect(id, observer);
Pawin Vongmasa50d25732020-04-24 18:59:54 -0700177 if (sSeqId == kSeqIdMax) {
Ray Essick3688d0a2019-10-09 15:31:58 -0700178 sSeqId = 0;
179 } else {
180 ++sSeqId;
181 }
Sungtak Leebbe37b62018-08-29 15:15:48 -0700182 }
Sungtak Leec7f9e2c2018-09-14 16:23:40 -0700183
Sungtak Leebbe37b62018-08-29 15:15:48 -0700184 }
185 mBufferPool.processStatusMessages();
186 mBufferPool.cleanUp();
187 }
188 return status;
189}
190
191ResultStatus Accessor::Impl::close(ConnectionId connectionId) {
192 std::lock_guard<std::mutex> lock(mBufferPool.mMutex);
Sungtak Leed3128382018-11-07 17:30:37 -0800193 ALOGV("connection close %lld: %u", (long long)connectionId, mBufferPool.mInvalidation.mId);
Sungtak Leebbe37b62018-08-29 15:15:48 -0700194 mBufferPool.processStatusMessages();
195 mBufferPool.handleClose(connectionId);
196 mBufferPool.mObserver.close(connectionId);
Sungtak Leec7f9e2c2018-09-14 16:23:40 -0700197 mBufferPool.mInvalidation.onClose(connectionId);
Sungtak Leebbe37b62018-08-29 15:15:48 -0700198 // Since close# will be called after all works are finished, it is OK to
199 // evict unused buffers.
200 mBufferPool.cleanUp(true);
201 return ResultStatus::OK;
202}
203
204ResultStatus Accessor::Impl::allocate(
205 ConnectionId connectionId, const std::vector<uint8_t>& params,
206 BufferId *bufferId, const native_handle_t** handle) {
207 std::unique_lock<std::mutex> lock(mBufferPool.mMutex);
208 mBufferPool.processStatusMessages();
209 ResultStatus status = ResultStatus::OK;
210 if (!mBufferPool.getFreeBuffer(mAllocator, params, bufferId, handle)) {
211 lock.unlock();
212 std::shared_ptr<BufferPoolAllocation> alloc;
213 size_t allocSize;
214 status = mAllocator->allocate(params, &alloc, &allocSize);
215 lock.lock();
216 if (status == ResultStatus::OK) {
217 status = mBufferPool.addNewBuffer(alloc, allocSize, params, bufferId, handle);
218 }
219 ALOGV("create a buffer %d : %u %p",
220 status == ResultStatus::OK, *bufferId, *handle);
221 }
222 if (status == ResultStatus::OK) {
223 // TODO: handle ownBuffer failure
224 mBufferPool.handleOwnBuffer(connectionId, *bufferId);
225 }
226 mBufferPool.cleanUp();
227 return status;
228}
229
230ResultStatus Accessor::Impl::fetch(
231 ConnectionId connectionId, TransactionId transactionId,
232 BufferId bufferId, const native_handle_t** handle) {
233 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 }
249 }
250 }
251 mBufferPool.cleanUp();
252 return ResultStatus::CRITICAL_ERROR;
253}
254
255void Accessor::Impl::cleanUp(bool clearCache) {
256 // transaction timeout, buffer cacheing TTL handling
257 std::lock_guard<std::mutex> lock(mBufferPool.mMutex);
258 mBufferPool.processStatusMessages();
259 mBufferPool.cleanUp(clearCache);
260}
261
Sungtak Leec7f9e2c2018-09-14 16:23:40 -0700262void Accessor::Impl::flush() {
263 std::lock_guard<std::mutex> lock(mBufferPool.mMutex);
264 mBufferPool.processStatusMessages();
265 mBufferPool.flush(shared_from_this());
266}
267
268void Accessor::Impl::handleInvalidateAck() {
Sungtak Leebe6a1182018-12-17 19:00:40 -0800269 std::map<ConnectionId, const sp<IObserver>> observers;
270 uint32_t invalidationId;
271 {
272 std::lock_guard<std::mutex> lock(mBufferPool.mMutex);
273 mBufferPool.processStatusMessages();
274 mBufferPool.mInvalidation.onHandleAck(&observers, &invalidationId);
275 }
276 // Do not hold lock for send invalidations
Sungtak Lee603467b2019-05-16 16:48:00 -0700277 size_t deadClients = 0;
Sungtak Leebe6a1182018-12-17 19:00:40 -0800278 for (auto it = observers.begin(); it != observers.end(); ++it) {
279 const sp<IObserver> observer = it->second;
280 if (observer) {
281 Return<void> transResult = observer->onMessage(it->first, invalidationId);
Sungtak Lee603467b2019-05-16 16:48:00 -0700282 if (!transResult.isOk()) {
283 ++deadClients;
284 }
Sungtak Leebe6a1182018-12-17 19:00:40 -0800285 }
286 }
Sungtak Lee603467b2019-05-16 16:48:00 -0700287 if (deadClients > 0) {
288 ALOGD("During invalidation found %zu dead clients", deadClients);
289 }
Sungtak Leec7f9e2c2018-09-14 16:23:40 -0700290}
291
292bool Accessor::Impl::isValid() {
293 return mBufferPool.isValid();
294}
295
Sungtak Leebbe37b62018-08-29 15:15:48 -0700296Accessor::Impl::Impl::BufferPool::BufferPool()
297 : mTimestampUs(getTimestampNow()),
298 mLastCleanUpUs(mTimestampUs),
299 mLastLogUs(mTimestampUs),
Sungtak Leec7f9e2c2018-09-14 16:23:40 -0700300 mSeq(0),
301 mStartSeq(0) {
302 mValid = mInvalidationChannel.isValid();
303}
Sungtak Leebbe37b62018-08-29 15:15:48 -0700304
305
306// Statistics helper
307template<typename T, typename S>
308int percentage(T base, S total) {
309 return int(total ? 0.5 + 100. * static_cast<S>(base) / total : 0);
310}
311
Sungtak Leed3128382018-11-07 17:30:37 -0800312std::atomic<std::uint32_t> Accessor::Impl::BufferPool::Invalidation::sInvSeqId(0);
Sungtak Leec7f9e2c2018-09-14 16:23:40 -0700313
Sungtak Leebbe37b62018-08-29 15:15:48 -0700314Accessor::Impl::Impl::BufferPool::~BufferPool() {
315 std::lock_guard<std::mutex> lock(mMutex);
Sungtak Leed3318082018-09-07 15:52:43 -0700316 ALOGD("Destruction - bufferpool2 %p "
Sungtak Leebbe37b62018-08-29 15:15:48 -0700317 "cached: %zu/%zuM, %zu/%d%% in use; "
318 "allocs: %zu, %d%% recycled; "
Nicholas Reiterba056462019-07-30 16:10:18 -0700319 "transfers: %zu, %d%% unfetched",
Sungtak Leebbe37b62018-08-29 15:15:48 -0700320 this, mStats.mBuffersCached, mStats.mSizeCached >> 20,
321 mStats.mBuffersInUse, percentage(mStats.mBuffersInUse, mStats.mBuffersCached),
322 mStats.mTotalAllocations, percentage(mStats.mTotalRecycles, mStats.mTotalAllocations),
323 mStats.mTotalTransfers,
324 percentage(mStats.mTotalTransfers - mStats.mTotalFetches, mStats.mTotalTransfers));
325}
326
Sungtak Leec7f9e2c2018-09-14 16:23:40 -0700327void Accessor::Impl::BufferPool::Invalidation::onConnect(
328 ConnectionId conId, const sp<IObserver>& observer) {
329 mAcks[conId] = mInvalidationId; // starts from current invalidationId
330 mObservers.insert(std::make_pair(conId, observer));
331}
332
333void Accessor::Impl::BufferPool::Invalidation::onClose(ConnectionId conId) {
334 mAcks.erase(conId);
335 mObservers.erase(conId);
336}
337
338void Accessor::Impl::BufferPool::Invalidation::onAck(
339 ConnectionId conId,
340 uint32_t msgId) {
341 auto it = mAcks.find(conId);
Sungtak Leeb355f7c2018-11-19 14:49:10 -0800342 if (it == mAcks.end()) {
343 ALOGW("ACK from inconsistent connection! %lld", (long long)conId);
344 return;
345 }
346 if (isMessageLater(msgId, it->second)) {
Sungtak Leec7f9e2c2018-09-14 16:23:40 -0700347 mAcks[conId] = msgId;
348 }
349}
350
351void Accessor::Impl::BufferPool::Invalidation::onBufferInvalidated(
352 BufferId bufferId,
353 BufferInvalidationChannel &channel) {
354 for (auto it = mPendings.begin(); it != mPendings.end();) {
Sungtak Leed3128382018-11-07 17:30:37 -0800355 if (it->isInvalidated(bufferId)) {
Sungtak Leec7f9e2c2018-09-14 16:23:40 -0700356 uint32_t msgId = 0;
357 if (it->mNeedsAck) {
358 msgId = ++mInvalidationId;
359 if (msgId == 0) {
360 // wrap happens
361 msgId = ++mInvalidationId;
362 }
363 }
364 channel.postInvalidation(msgId, it->mFrom, it->mTo);
Sungtak Leed3128382018-11-07 17:30:37 -0800365 it = mPendings.erase(it);
Sungtak Leec7f9e2c2018-09-14 16:23:40 -0700366 continue;
367 }
368 ++it;
369 }
370}
371
372void Accessor::Impl::BufferPool::Invalidation::onInvalidationRequest(
373 bool needsAck,
374 uint32_t from,
375 uint32_t to,
376 size_t left,
377 BufferInvalidationChannel &channel,
378 const std::shared_ptr<Accessor::Impl> &impl) {
Sungtak Leec7f9e2c2018-09-14 16:23:40 -0700379 uint32_t msgId = 0;
Sungtak Leeb355f7c2018-11-19 14:49:10 -0800380 if (needsAck) {
381 msgId = ++mInvalidationId;
382 if (msgId == 0) {
383 // wrap happens
Sungtak Leec7f9e2c2018-09-14 16:23:40 -0700384 msgId = ++mInvalidationId;
Sungtak Leec7f9e2c2018-09-14 16:23:40 -0700385 }
Sungtak Leeb355f7c2018-11-19 14:49:10 -0800386 }
Sungtak Leed3318082018-09-07 15:52:43 -0700387 ALOGV("bufferpool2 invalidation requested and queued");
Sungtak Leeb355f7c2018-11-19 14:49:10 -0800388 if (left == 0) {
Sungtak Leec7f9e2c2018-09-14 16:23:40 -0700389 channel.postInvalidation(msgId, from, to);
Sungtak Leec7f9e2c2018-09-14 16:23:40 -0700390 } else {
391 // TODO: sending hint message?
Sungtak Leed3318082018-09-07 15:52:43 -0700392 ALOGV("bufferpoo2 invalidation requested and pending");
Sungtak Leec7f9e2c2018-09-14 16:23:40 -0700393 Pending pending(needsAck, from, to, left, impl);
394 mPendings.push_back(pending);
395 }
Sungtak Leeb355f7c2018-11-19 14:49:10 -0800396 sInvalidator->addAccessor(mId, impl);
Sungtak Leec7f9e2c2018-09-14 16:23:40 -0700397}
398
Sungtak Leebe6a1182018-12-17 19:00:40 -0800399void Accessor::Impl::BufferPool::Invalidation::onHandleAck(
400 std::map<ConnectionId, const sp<IObserver>> *observers,
401 uint32_t *invalidationId) {
Sungtak Leec7f9e2c2018-09-14 16:23:40 -0700402 if (mInvalidationId != 0) {
Sungtak Leebe6a1182018-12-17 19:00:40 -0800403 *invalidationId = mInvalidationId;
Sungtak Leec7f9e2c2018-09-14 16:23:40 -0700404 std::set<int> deads;
405 for (auto it = mAcks.begin(); it != mAcks.end(); ++it) {
406 if (it->second != mInvalidationId) {
Sungtak Leed3128382018-11-07 17:30:37 -0800407 const sp<IObserver> observer = mObservers[it->first];
Sungtak Leec7f9e2c2018-09-14 16:23:40 -0700408 if (observer) {
Sungtak Leebe6a1182018-12-17 19:00:40 -0800409 observers->emplace(it->first, observer);
410 ALOGV("connection %lld will call observer (%u: %u)",
Sungtak Leed3128382018-11-07 17:30:37 -0800411 (long long)it->first, it->second, mInvalidationId);
Sungtak Leebe6a1182018-12-17 19:00:40 -0800412 // N.B: onMessage will be called later. ignore possibility of
413 // onMessage# oneway call being lost.
Sungtak Leeb355f7c2018-11-19 14:49:10 -0800414 it->second = mInvalidationId;
Sungtak Leec7f9e2c2018-09-14 16:23:40 -0700415 } else {
Sungtak Leed3318082018-09-07 15:52:43 -0700416 ALOGV("bufferpool2 observer died %lld", (long long)it->first);
Sungtak Leec7f9e2c2018-09-14 16:23:40 -0700417 deads.insert(it->first);
418 }
419 }
420 }
421 if (deads.size() > 0) {
422 for (auto it = deads.begin(); it != deads.end(); ++it) {
423 onClose(*it);
424 }
425 }
426 }
Sungtak Leeb355f7c2018-11-19 14:49:10 -0800427 if (mPendings.size() == 0) {
428 // All invalidation Ids are synced and no more pending invalidations.
429 sInvalidator->delAccessor(mId);
430 }
Sungtak Leec7f9e2c2018-09-14 16:23:40 -0700431}
432
Sungtak Leebbe37b62018-08-29 15:15:48 -0700433bool Accessor::Impl::BufferPool::handleOwnBuffer(
434 ConnectionId connectionId, BufferId bufferId) {
435
436 bool added = insert(&mUsingBuffers, connectionId, bufferId);
437 if (added) {
438 auto iter = mBuffers.find(bufferId);
439 iter->second->mOwnerCount++;
440 }
441 insert(&mUsingConnections, bufferId, connectionId);
442 return added;
443}
444
445bool Accessor::Impl::BufferPool::handleReleaseBuffer(
446 ConnectionId connectionId, BufferId bufferId) {
447 bool deleted = erase(&mUsingBuffers, connectionId, bufferId);
448 if (deleted) {
449 auto iter = mBuffers.find(bufferId);
450 iter->second->mOwnerCount--;
451 if (iter->second->mOwnerCount == 0 &&
452 iter->second->mTransactionCount == 0) {
Sungtak Leec7f9e2c2018-09-14 16:23:40 -0700453 if (!iter->second->mInvalidated) {
454 mStats.onBufferUnused(iter->second->mAllocSize);
455 mFreeBuffers.insert(bufferId);
456 } else {
457 mStats.onBufferUnused(iter->second->mAllocSize);
458 mStats.onBufferEvicted(iter->second->mAllocSize);
459 mBuffers.erase(iter);
460 mInvalidation.onBufferInvalidated(bufferId, mInvalidationChannel);
461 }
Sungtak Leebbe37b62018-08-29 15:15:48 -0700462 }
463 }
464 erase(&mUsingConnections, bufferId, connectionId);
465 ALOGV("release buffer %u : %d", bufferId, deleted);
466 return deleted;
467}
468
469bool Accessor::Impl::BufferPool::handleTransferTo(const BufferStatusMessage &message) {
470 auto completed = mCompletedTransactions.find(
471 message.transactionId);
472 if (completed != mCompletedTransactions.end()) {
473 // already completed
474 mCompletedTransactions.erase(completed);
475 return true;
476 }
477 // the buffer should exist and be owned.
478 auto bufferIter = mBuffers.find(message.bufferId);
479 if (bufferIter == mBuffers.end() ||
480 !contains(&mUsingBuffers, message.connectionId, message.bufferId)) {
481 return false;
482 }
483 auto found = mTransactions.find(message.transactionId);
484 if (found != mTransactions.end()) {
485 // transfer_from was received earlier.
486 found->second->mSender = message.connectionId;
487 found->second->mSenderValidated = true;
488 return true;
489 }
Sungtak Leeccc32cb2019-08-20 18:07:54 -0700490 if (mConnectionIds.find(message.targetConnectionId) == mConnectionIds.end()) {
491 // N.B: it could be fake or receive connection already closed.
492 ALOGD("bufferpool2 %p receiver connection %lld is no longer valid",
493 this, (long long)message.targetConnectionId);
494 return false;
495 }
Sungtak Leebbe37b62018-08-29 15:15:48 -0700496 mStats.onBufferSent();
497 mTransactions.insert(std::make_pair(
498 message.transactionId,
499 std::make_unique<TransactionStatus>(message, mTimestampUs)));
500 insert(&mPendingTransactions, message.targetConnectionId,
501 message.transactionId);
502 bufferIter->second->mTransactionCount++;
503 return true;
504}
505
506bool Accessor::Impl::BufferPool::handleTransferFrom(const BufferStatusMessage &message) {
507 auto found = mTransactions.find(message.transactionId);
508 if (found == mTransactions.end()) {
509 // TODO: is it feasible to check ownership here?
510 mStats.onBufferSent();
511 mTransactions.insert(std::make_pair(
512 message.transactionId,
513 std::make_unique<TransactionStatus>(message, mTimestampUs)));
514 insert(&mPendingTransactions, message.connectionId,
515 message.transactionId);
516 auto bufferIter = mBuffers.find(message.bufferId);
517 bufferIter->second->mTransactionCount++;
518 } else {
519 if (message.connectionId == found->second->mReceiver) {
520 found->second->mStatus = BufferStatus::TRANSFER_FROM;
521 }
522 }
523 return true;
524}
525
526bool Accessor::Impl::BufferPool::handleTransferResult(const BufferStatusMessage &message) {
527 auto found = mTransactions.find(message.transactionId);
528 if (found != mTransactions.end()) {
529 bool deleted = erase(&mPendingTransactions, message.connectionId,
530 message.transactionId);
531 if (deleted) {
532 if (!found->second->mSenderValidated) {
533 mCompletedTransactions.insert(message.transactionId);
534 }
535 auto bufferIter = mBuffers.find(message.bufferId);
536 if (message.newStatus == BufferStatus::TRANSFER_OK) {
537 handleOwnBuffer(message.connectionId, message.bufferId);
538 }
539 bufferIter->second->mTransactionCount--;
540 if (bufferIter->second->mOwnerCount == 0
541 && bufferIter->second->mTransactionCount == 0) {
Sungtak Leec7f9e2c2018-09-14 16:23:40 -0700542 if (!bufferIter->second->mInvalidated) {
543 mStats.onBufferUnused(bufferIter->second->mAllocSize);
544 mFreeBuffers.insert(message.bufferId);
545 } else {
546 mStats.onBufferUnused(bufferIter->second->mAllocSize);
547 mStats.onBufferEvicted(bufferIter->second->mAllocSize);
548 mBuffers.erase(bufferIter);
549 mInvalidation.onBufferInvalidated(message.bufferId, mInvalidationChannel);
550 }
Sungtak Leebbe37b62018-08-29 15:15:48 -0700551 }
552 mTransactions.erase(found);
553 }
554 ALOGV("transfer finished %llu %u - %d", (unsigned long long)message.transactionId,
555 message.bufferId, deleted);
556 return deleted;
557 }
558 ALOGV("transfer not found %llu %u", (unsigned long long)message.transactionId,
559 message.bufferId);
560 return false;
561}
562
563void Accessor::Impl::BufferPool::processStatusMessages() {
564 std::vector<BufferStatusMessage> messages;
565 mObserver.getBufferStatusChanges(messages);
566 mTimestampUs = getTimestampNow();
567 for (BufferStatusMessage& message: messages) {
568 bool ret = false;
569 switch (message.newStatus) {
570 case BufferStatus::NOT_USED:
571 ret = handleReleaseBuffer(
572 message.connectionId, message.bufferId);
573 break;
574 case BufferStatus::USED:
575 // not happening
576 break;
577 case BufferStatus::TRANSFER_TO:
578 ret = handleTransferTo(message);
579 break;
580 case BufferStatus::TRANSFER_FROM:
581 ret = handleTransferFrom(message);
582 break;
583 case BufferStatus::TRANSFER_TIMEOUT:
584 // TODO
585 break;
586 case BufferStatus::TRANSFER_LOST:
587 // TODO
588 break;
589 case BufferStatus::TRANSFER_FETCH:
590 // not happening
591 break;
592 case BufferStatus::TRANSFER_OK:
593 case BufferStatus::TRANSFER_ERROR:
594 ret = handleTransferResult(message);
595 break;
Sungtak Leed491f1f2018-10-05 15:56:56 -0700596 case BufferStatus::INVALIDATION_ACK:
Sungtak Leec7f9e2c2018-09-14 16:23:40 -0700597 mInvalidation.onAck(message.connectionId, message.bufferId);
Sungtak Leed3128382018-11-07 17:30:37 -0800598 ret = true;
Sungtak Leed491f1f2018-10-05 15:56:56 -0700599 break;
Sungtak Leebbe37b62018-08-29 15:15:48 -0700600 }
601 if (ret == false) {
602 ALOGW("buffer status message processing failure - message : %d connection : %lld",
603 message.newStatus, (long long)message.connectionId);
604 }
605 }
606 messages.clear();
607}
608
609bool Accessor::Impl::BufferPool::handleClose(ConnectionId connectionId) {
610 // Cleaning buffers
611 auto buffers = mUsingBuffers.find(connectionId);
612 if (buffers != mUsingBuffers.end()) {
613 for (const BufferId& bufferId : buffers->second) {
614 bool deleted = erase(&mUsingConnections, bufferId, connectionId);
615 if (deleted) {
616 auto bufferIter = mBuffers.find(bufferId);
617 bufferIter->second->mOwnerCount--;
618 if (bufferIter->second->mOwnerCount == 0 &&
619 bufferIter->second->mTransactionCount == 0) {
620 // TODO: handle freebuffer insert fail
Sungtak Leec7f9e2c2018-09-14 16:23:40 -0700621 if (!bufferIter->second->mInvalidated) {
622 mStats.onBufferUnused(bufferIter->second->mAllocSize);
623 mFreeBuffers.insert(bufferId);
624 } else {
625 mStats.onBufferUnused(bufferIter->second->mAllocSize);
626 mStats.onBufferEvicted(bufferIter->second->mAllocSize);
627 mBuffers.erase(bufferIter);
628 mInvalidation.onBufferInvalidated(bufferId, mInvalidationChannel);
629 }
Sungtak Leebbe37b62018-08-29 15:15:48 -0700630 }
631 }
632 }
633 mUsingBuffers.erase(buffers);
634 }
635
636 // Cleaning transactions
637 auto pending = mPendingTransactions.find(connectionId);
638 if (pending != mPendingTransactions.end()) {
639 for (const TransactionId& transactionId : pending->second) {
640 auto iter = mTransactions.find(transactionId);
641 if (iter != mTransactions.end()) {
642 if (!iter->second->mSenderValidated) {
643 mCompletedTransactions.insert(transactionId);
644 }
645 BufferId bufferId = iter->second->mBufferId;
646 auto bufferIter = mBuffers.find(bufferId);
647 bufferIter->second->mTransactionCount--;
648 if (bufferIter->second->mOwnerCount == 0 &&
649 bufferIter->second->mTransactionCount == 0) {
650 // TODO: handle freebuffer insert fail
Sungtak Leec7f9e2c2018-09-14 16:23:40 -0700651 if (!bufferIter->second->mInvalidated) {
652 mStats.onBufferUnused(bufferIter->second->mAllocSize);
653 mFreeBuffers.insert(bufferId);
654 } else {
655 mStats.onBufferUnused(bufferIter->second->mAllocSize);
656 mStats.onBufferEvicted(bufferIter->second->mAllocSize);
657 mBuffers.erase(bufferIter);
658 mInvalidation.onBufferInvalidated(bufferId, mInvalidationChannel);
659 }
Sungtak Leebbe37b62018-08-29 15:15:48 -0700660 }
661 mTransactions.erase(iter);
662 }
663 }
664 }
Sungtak Leeccc32cb2019-08-20 18:07:54 -0700665 mConnectionIds.erase(connectionId);
Sungtak Leebbe37b62018-08-29 15:15:48 -0700666 return true;
667}
668
669bool Accessor::Impl::BufferPool::getFreeBuffer(
670 const std::shared_ptr<BufferPoolAllocator> &allocator,
671 const std::vector<uint8_t> &params, BufferId *pId,
672 const native_handle_t** handle) {
673 auto bufferIt = mFreeBuffers.begin();
674 for (;bufferIt != mFreeBuffers.end(); ++bufferIt) {
675 BufferId bufferId = *bufferIt;
676 if (allocator->compatible(params, mBuffers[bufferId]->mConfig)) {
677 break;
678 }
679 }
680 if (bufferIt != mFreeBuffers.end()) {
681 BufferId id = *bufferIt;
682 mFreeBuffers.erase(bufferIt);
683 mStats.onBufferRecycled(mBuffers[id]->mAllocSize);
684 *handle = mBuffers[id]->handle();
685 *pId = id;
686 ALOGV("recycle a buffer %u %p", id, *handle);
687 return true;
688 }
689 return false;
690}
691
692ResultStatus Accessor::Impl::BufferPool::addNewBuffer(
693 const std::shared_ptr<BufferPoolAllocation> &alloc,
694 const size_t allocSize,
695 const std::vector<uint8_t> &params,
696 BufferId *pId,
697 const native_handle_t** handle) {
698
699 BufferId bufferId = mSeq++;
700 if (mSeq == Connection::SYNC_BUFFERID) {
701 mSeq = 0;
702 }
703 std::unique_ptr<InternalBuffer> buffer =
704 std::make_unique<InternalBuffer>(
705 bufferId, alloc, allocSize, params);
706 if (buffer) {
707 auto res = mBuffers.insert(std::make_pair(
708 bufferId, std::move(buffer)));
709 if (res.second) {
710 mStats.onBufferAllocated(allocSize);
711 *handle = alloc->handle();
712 *pId = bufferId;
713 return ResultStatus::OK;
714 }
715 }
716 return ResultStatus::NO_MEMORY;
717}
718
719void Accessor::Impl::BufferPool::cleanUp(bool clearCache) {
720 if (clearCache || mTimestampUs > mLastCleanUpUs + kCleanUpDurationUs) {
721 mLastCleanUpUs = mTimestampUs;
722 if (mTimestampUs > mLastLogUs + kLogDurationUs) {
723 mLastLogUs = mTimestampUs;
Sungtak Leed3318082018-09-07 15:52:43 -0700724 ALOGD("bufferpool2 %p : %zu(%zu size) total buffers - "
Sungtak Leebbe37b62018-08-29 15:15:48 -0700725 "%zu(%zu size) used buffers - %zu/%zu (recycle/alloc) - "
726 "%zu/%zu (fetch/transfer)",
727 this, mStats.mBuffersCached, mStats.mSizeCached,
728 mStats.mBuffersInUse, mStats.mSizeInUse,
729 mStats.mTotalRecycles, mStats.mTotalAllocations,
730 mStats.mTotalFetches, mStats.mTotalTransfers);
731 }
732 for (auto freeIt = mFreeBuffers.begin(); freeIt != mFreeBuffers.end();) {
Sungtak Lee30dbaa22019-10-03 14:38:01 -0700733 if (!clearCache && (mStats.mSizeCached < kMinAllocBytesForEviction
734 || mBuffers.size() < kMinBufferCountForEviction)) {
Sungtak Leebbe37b62018-08-29 15:15:48 -0700735 break;
736 }
737 auto it = mBuffers.find(*freeIt);
738 if (it != mBuffers.end() &&
739 it->second->mOwnerCount == 0 && it->second->mTransactionCount == 0) {
740 mStats.onBufferEvicted(it->second->mAllocSize);
741 mBuffers.erase(it);
742 freeIt = mFreeBuffers.erase(freeIt);
743 } else {
744 ++freeIt;
Sungtak Leed3318082018-09-07 15:52:43 -0700745 ALOGW("bufferpool2 inconsistent!");
Sungtak Leebbe37b62018-08-29 15:15:48 -0700746 }
747 }
748 }
749}
750
Sungtak Leec7f9e2c2018-09-14 16:23:40 -0700751void Accessor::Impl::BufferPool::invalidate(
752 bool needsAck, BufferId from, BufferId to,
753 const std::shared_ptr<Accessor::Impl> &impl) {
754 for (auto freeIt = mFreeBuffers.begin(); freeIt != mFreeBuffers.end();) {
755 if (isBufferInRange(from, to, *freeIt)) {
756 auto it = mBuffers.find(*freeIt);
757 if (it != mBuffers.end() &&
758 it->second->mOwnerCount == 0 && it->second->mTransactionCount == 0) {
759 mStats.onBufferEvicted(it->second->mAllocSize);
760 mBuffers.erase(it);
761 freeIt = mFreeBuffers.erase(freeIt);
762 continue;
763 } else {
Sungtak Leed3318082018-09-07 15:52:43 -0700764 ALOGW("bufferpool2 inconsistent!");
Sungtak Leec7f9e2c2018-09-14 16:23:40 -0700765 }
766 }
767 ++freeIt;
768 }
769
770 size_t left = 0;
771 for (auto it = mBuffers.begin(); it != mBuffers.end(); ++it) {
772 if (isBufferInRange(from, to, it->first)) {
773 it->second->invalidate();
774 ++left;
775 }
776 }
777 mInvalidation.onInvalidationRequest(needsAck, from, to, left, mInvalidationChannel, impl);
778}
779
780void Accessor::Impl::BufferPool::flush(const std::shared_ptr<Accessor::Impl> &impl) {
781 BufferId from = mStartSeq;
782 BufferId to = mSeq;
783 mStartSeq = mSeq;
784 // TODO: needsAck params
Sungtak Leed3128382018-11-07 17:30:37 -0800785 ALOGV("buffer invalidation request bp:%u %u %u", mInvalidation.mId, from, to);
Sungtak Leec7f9e2c2018-09-14 16:23:40 -0700786 if (from != to) {
787 invalidate(true, from, to, impl);
788 }
789}
790
791void Accessor::Impl::invalidatorThread(
792 std::map<uint32_t, const std::weak_ptr<Accessor::Impl>> &accessors,
793 std::mutex &mutex,
794 std::condition_variable &cv,
795 bool &ready) {
Sungtak Leeccc32cb2019-08-20 18:07:54 -0700796 constexpr uint32_t NUM_SPIN_TO_INCREASE_SLEEP = 1024;
797 constexpr uint32_t NUM_SPIN_TO_LOG = 1024*8;
798 constexpr useconds_t MAX_SLEEP_US = 10000;
799 uint32_t numSpin = 0;
800 useconds_t sleepUs = 1;
801
Sungtak Leec7f9e2c2018-09-14 16:23:40 -0700802 while(true) {
803 std::map<uint32_t, const std::weak_ptr<Accessor::Impl>> copied;
804 {
805 std::unique_lock<std::mutex> lock(mutex);
806 if (!ready) {
Sungtak Leeccc32cb2019-08-20 18:07:54 -0700807 numSpin = 0;
808 sleepUs = 1;
Sungtak Leec7f9e2c2018-09-14 16:23:40 -0700809 cv.wait(lock);
810 }
811 copied.insert(accessors.begin(), accessors.end());
812 }
813 std::list<ConnectionId> erased;
814 for (auto it = copied.begin(); it != copied.end(); ++it) {
815 const std::shared_ptr<Accessor::Impl> impl = it->second.lock();
816 if (!impl) {
817 erased.push_back(it->first);
818 } else {
819 impl->handleInvalidateAck();
820 }
821 }
822 {
823 std::unique_lock<std::mutex> lock(mutex);
824 for (auto it = erased.begin(); it != erased.end(); ++it) {
825 accessors.erase(*it);
826 }
827 if (accessors.size() == 0) {
828 ready = false;
829 } else {
Sungtak Leeccc32cb2019-08-20 18:07:54 -0700830 // TODO Use an efficient way to wait over FMQ.
831 // N.B. Since there is not a efficient way to wait over FMQ,
832 // polling over the FMQ is the current way to prevent draining
833 // CPU.
Sungtak Leec7f9e2c2018-09-14 16:23:40 -0700834 lock.unlock();
Sungtak Leeccc32cb2019-08-20 18:07:54 -0700835 ++numSpin;
836 if (numSpin % NUM_SPIN_TO_INCREASE_SLEEP == 0 &&
837 sleepUs < MAX_SLEEP_US) {
838 sleepUs *= 10;
839 }
840 if (numSpin % NUM_SPIN_TO_LOG == 0) {
841 ALOGW("invalidator thread spinning");
842 }
843 ::usleep(sleepUs);
Sungtak Leec7f9e2c2018-09-14 16:23:40 -0700844 }
845 }
846 }
847}
848
849Accessor::Impl::AccessorInvalidator::AccessorInvalidator() : mReady(false) {
850 std::thread invalidator(
851 invalidatorThread,
852 std::ref(mAccessors),
853 std::ref(mMutex),
854 std::ref(mCv),
855 std::ref(mReady));
856 invalidator.detach();
857}
858
859void Accessor::Impl::AccessorInvalidator::addAccessor(
860 uint32_t accessorId, const std::weak_ptr<Accessor::Impl> &impl) {
861 bool notify = false;
862 std::unique_lock<std::mutex> lock(mMutex);
863 if (mAccessors.find(accessorId) == mAccessors.end()) {
864 if (!mReady) {
865 mReady = true;
866 notify = true;
867 }
868 mAccessors.insert(std::make_pair(accessorId, impl));
Sungtak Leed3128382018-11-07 17:30:37 -0800869 ALOGV("buffer invalidation added bp:%u %d", accessorId, notify);
Sungtak Leec7f9e2c2018-09-14 16:23:40 -0700870 }
871 lock.unlock();
872 if (notify) {
873 mCv.notify_one();
874 }
875}
876
877void Accessor::Impl::AccessorInvalidator::delAccessor(uint32_t accessorId) {
878 std::lock_guard<std::mutex> lock(mMutex);
879 mAccessors.erase(accessorId);
Sungtak Leed3128382018-11-07 17:30:37 -0800880 ALOGV("buffer invalidation deleted bp:%u", accessorId);
Sungtak Leec7f9e2c2018-09-14 16:23:40 -0700881 if (mAccessors.size() == 0) {
882 mReady = false;
883 }
884}
885
Sungtak Leed3128382018-11-07 17:30:37 -0800886std::unique_ptr<Accessor::Impl::AccessorInvalidator> Accessor::Impl::sInvalidator;
887
888void Accessor::Impl::createInvalidator() {
889 if (!sInvalidator) {
890 sInvalidator = std::make_unique<Accessor::Impl::AccessorInvalidator>();
891 }
892}
Sungtak Leec7f9e2c2018-09-14 16:23:40 -0700893
Sungtak Leebbe37b62018-08-29 15:15:48 -0700894} // namespace implementation
895} // namespace V2_0
896} // namespace bufferpool
897} // namespace media
898} // namespace hardware
899} // namespace android