blob: 342fef6b9d4256e5af0ae90dc7c02dc7707c45df [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
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
25namespace android {
26namespace hardware {
27namespace media {
28namespace bufferpool {
29namespace V2_0 {
30namespace implementation {
31
32static constexpr int64_t kReceiveTimeoutUs = 1000000; // 100ms
33static constexpr int kPostMaxRetry = 3;
34static constexpr int kCacheTtlUs = 1000000; // TODO: tune
35
36class BufferPoolClient::Impl
37 : public std::enable_shared_from_this<BufferPoolClient::Impl> {
38public:
Sungtak Leec7f9e2c2018-09-14 16:23:40 -070039 explicit Impl(const sp<Accessor> &accessor, const sp<IObserver> &observer);
Sungtak Leebbe37b62018-08-29 15:15:48 -070040
Sungtak Leec7f9e2c2018-09-14 16:23:40 -070041 explicit Impl(const sp<IAccessor> &accessor, const sp<IObserver> &observer);
Sungtak Leebbe37b62018-08-29 15:15:48 -070042
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
Sungtak Leec7f9e2c2018-09-14 16:23:40 -070061 void receiveInvalidation(uint32_t msgID);
62
63 ResultStatus flush();
64
Sungtak Leebbe37b62018-08-29 15:15:48 -070065 ResultStatus allocate(const std::vector<uint8_t> &params,
66 native_handle_t **handle,
67 std::shared_ptr<BufferPoolData> *buffer);
68
69 ResultStatus receive(
70 TransactionId transactionId, BufferId bufferId,
71 int64_t timestampUs,
72 native_handle_t **handle, std::shared_ptr<BufferPoolData> *buffer);
73
74 void postBufferRelease(BufferId bufferId);
75
76 bool postSend(
77 BufferId bufferId, ConnectionId receiver,
78 TransactionId *transactionId, int64_t *timestampUs);
79private:
80
81 bool postReceive(
82 BufferId bufferId, TransactionId transactionId,
83 int64_t timestampUs);
84
85 bool postReceiveResult(
86 BufferId bufferId, TransactionId transactionId, bool result, bool *needsSync);
87
88 void trySyncFromRemote();
89
Sungtak Leec7f9e2c2018-09-14 16:23:40 -070090 bool syncReleased(uint32_t msgId = 0);
Sungtak Leebbe37b62018-08-29 15:15:48 -070091
92 void evictCaches(bool clearCache = false);
93
Sungtak Leec7f9e2c2018-09-14 16:23:40 -070094 void invalidateBuffer(BufferId id);
95
96 void invalidateRange(BufferId from, BufferId to);
97
Sungtak Leebbe37b62018-08-29 15:15:48 -070098 ResultStatus allocateBufferHandle(
99 const std::vector<uint8_t>& params, BufferId *bufferId,
100 native_handle_t **handle);
101
102 ResultStatus fetchBufferHandle(
103 TransactionId transactionId, BufferId bufferId,
104 native_handle_t **handle);
105
106 struct BlockPoolDataDtor;
107 struct ClientBuffer;
108
109 bool mLocal;
110 bool mValid;
111 sp<IAccessor> mAccessor;
112 sp<Connection> mLocalConnection;
113 sp<IConnection> mRemoteConnection;
114 uint32_t mSeqId;
115 ConnectionId mConnectionId;
116 int64_t mLastEvictCacheUs;
Sungtak Leec7f9e2c2018-09-14 16:23:40 -0700117 std::unique_ptr<BufferInvalidationListener> mInvalidationListener;
Sungtak Leebbe37b62018-08-29 15:15:48 -0700118
119 // CachedBuffers
120 struct BufferCache {
121 std::mutex mLock;
122 bool mCreating;
123 std::condition_variable mCreateCv;
124 std::map<BufferId, std::unique_ptr<ClientBuffer>> mBuffers;
125 int mActive;
126 int64_t mLastChangeUs;
127
128 BufferCache() : mCreating(false), mActive(0), mLastChangeUs(getTimestampNow()) {}
129
130 void incActive_l() {
131 ++mActive;
132 mLastChangeUs = getTimestampNow();
133 }
134
135 void decActive_l() {
136 --mActive;
137 mLastChangeUs = getTimestampNow();
138 }
139 } mCache;
140
141 // FMQ - release notifier
Sungtak Leec7f9e2c2018-09-14 16:23:40 -0700142 struct ReleaseCache {
Sungtak Leebbe37b62018-08-29 15:15:48 -0700143 std::mutex mLock;
144 // TODO: use only one list?(using one list may dealy sending messages?)
145 std::list<BufferId> mReleasingIds;
146 std::list<BufferId> mReleasedIds;
Sungtak Leec7f9e2c2018-09-14 16:23:40 -0700147 uint32_t mInvalidateId; // TODO: invalidation ACK to bufferpool
148 bool mInvalidateAck;
Sungtak Leebbe37b62018-08-29 15:15:48 -0700149 std::unique_ptr<BufferStatusChannel> mStatusChannel;
Sungtak Leec7f9e2c2018-09-14 16:23:40 -0700150
151 ReleaseCache() : mInvalidateId(0), mInvalidateAck(true) {}
Sungtak Leebbe37b62018-08-29 15:15:48 -0700152 } mReleasing;
153
154 // This lock is held during synchronization from remote side.
155 // In order to minimize remote calls and locking durtaion, this lock is held
156 // by best effort approach using try_lock().
157 std::mutex mRemoteSyncLock;
158};
159
160struct BufferPoolClient::Impl::BlockPoolDataDtor {
161 BlockPoolDataDtor(const std::shared_ptr<BufferPoolClient::Impl> &impl)
162 : mImpl(impl) {}
163
164 void operator()(BufferPoolData *buffer) {
165 BufferId id = buffer->mId;
166 delete buffer;
167
168 auto impl = mImpl.lock();
169 if (impl && impl->isValid()) {
170 impl->postBufferRelease(id);
171 }
172 }
173 const std::weak_ptr<BufferPoolClient::Impl> mImpl;
174};
175
176struct BufferPoolClient::Impl::ClientBuffer {
177private:
Sungtak Leebbe37b62018-08-29 15:15:48 -0700178 int64_t mExpireUs;
179 bool mHasCache;
180 ConnectionId mConnectionId;
181 BufferId mId;
182 native_handle_t *mHandle;
183 std::weak_ptr<BufferPoolData> mCache;
184
185 void updateExpire() {
186 mExpireUs = getTimestampNow() + kCacheTtlUs;
187 }
188
189public:
190 ClientBuffer(
191 ConnectionId connectionId, BufferId id, native_handle_t *handle)
Sungtak Leec7f9e2c2018-09-14 16:23:40 -0700192 : mHasCache(false), mConnectionId(connectionId),
193 mId(id), mHandle(handle) {
Sungtak Leebbe37b62018-08-29 15:15:48 -0700194 mExpireUs = getTimestampNow() + kCacheTtlUs;
195 }
196
197 ~ClientBuffer() {
198 if (mHandle) {
199 native_handle_close(mHandle);
200 native_handle_delete(mHandle);
201 }
202 }
203
Sungtak Leec7f9e2c2018-09-14 16:23:40 -0700204 BufferId id() const {
205 return mId;
206 }
207
Sungtak Leebbe37b62018-08-29 15:15:48 -0700208 bool expire() const {
209 int64_t now = getTimestampNow();
210 return now >= mExpireUs;
211 }
212
213 bool hasCache() const {
214 return mHasCache;
215 }
216
217 std::shared_ptr<BufferPoolData> fetchCache(native_handle_t **pHandle) {
218 if (mHasCache) {
219 std::shared_ptr<BufferPoolData> cache = mCache.lock();
220 if (cache) {
221 *pHandle = mHandle;
222 }
223 return cache;
224 }
225 return nullptr;
226 }
227
228 std::shared_ptr<BufferPoolData> createCache(
229 const std::shared_ptr<BufferPoolClient::Impl> &impl,
230 native_handle_t **pHandle) {
231 if (!mHasCache) {
232 // Allocates a raw ptr in order to avoid sending #postBufferRelease
233 // from deleter, in case of native_handle_clone failure.
234 BufferPoolData *ptr = new BufferPoolData(mConnectionId, mId);
235 if (ptr) {
236 std::shared_ptr<BufferPoolData> cache(ptr, BlockPoolDataDtor(impl));
237 if (cache) {
238 mCache = cache;
239 mHasCache = true;
240 *pHandle = mHandle;
241 return cache;
242 }
243 }
244 if (ptr) {
245 delete ptr;
246 }
247 }
248 return nullptr;
249 }
250
251 bool onCacheRelease() {
252 if (mHasCache) {
253 // TODO: verify mCache is not valid;
254 updateExpire();
255 mHasCache = false;
256 return true;
257 }
258 return false;
259 }
260};
261
Sungtak Leec7f9e2c2018-09-14 16:23:40 -0700262BufferPoolClient::Impl::Impl(const sp<Accessor> &accessor, const sp<IObserver> &observer)
Sungtak Leebbe37b62018-08-29 15:15:48 -0700263 : mLocal(true), mValid(false), mAccessor(accessor), mSeqId(0),
264 mLastEvictCacheUs(getTimestampNow()) {
Sungtak Leec7f9e2c2018-09-14 16:23:40 -0700265 const StatusDescriptor *statusDesc;
266 const InvalidationDescriptor *invDesc;
Sungtak Leebbe37b62018-08-29 15:15:48 -0700267 ResultStatus status = accessor->connect(
Sungtak Leec7f9e2c2018-09-14 16:23:40 -0700268 observer, true,
269 &mLocalConnection, &mConnectionId, &mReleasing.mInvalidateId,
270 &statusDesc, &invDesc);
Sungtak Leebbe37b62018-08-29 15:15:48 -0700271 if (status == ResultStatus::OK) {
272 mReleasing.mStatusChannel =
Sungtak Leec7f9e2c2018-09-14 16:23:40 -0700273 std::make_unique<BufferStatusChannel>(*statusDesc);
274 mInvalidationListener =
275 std::make_unique<BufferInvalidationListener>(*invDesc);
Sungtak Leebbe37b62018-08-29 15:15:48 -0700276 mValid = mReleasing.mStatusChannel &&
Sungtak Leec7f9e2c2018-09-14 16:23:40 -0700277 mReleasing.mStatusChannel->isValid() &&
278 mInvalidationListener &&
279 mInvalidationListener->isValid();
Sungtak Leebbe37b62018-08-29 15:15:48 -0700280 }
281}
282
Sungtak Leec7f9e2c2018-09-14 16:23:40 -0700283BufferPoolClient::Impl::Impl(const sp<IAccessor> &accessor, const sp<IObserver> &observer)
Sungtak Leebbe37b62018-08-29 15:15:48 -0700284 : mLocal(false), mValid(false), mAccessor(accessor), mSeqId(0),
285 mLastEvictCacheUs(getTimestampNow()) {
286 bool valid = false;
287 sp<IConnection>& outConnection = mRemoteConnection;
288 ConnectionId& id = mConnectionId;
Sungtak Leec7f9e2c2018-09-14 16:23:40 -0700289 uint32_t& outMsgId = mReleasing.mInvalidateId;
Sungtak Leebbe37b62018-08-29 15:15:48 -0700290 std::unique_ptr<BufferStatusChannel>& outChannel =
291 mReleasing.mStatusChannel;
Sungtak Leec7f9e2c2018-09-14 16:23:40 -0700292 std::unique_ptr<BufferInvalidationListener>& outObserver =
293 mInvalidationListener;
Sungtak Leebbe37b62018-08-29 15:15:48 -0700294 Return<void> transResult = accessor->connect(
Sungtak Leed491f1f2018-10-05 15:56:56 -0700295 observer,
Sungtak Leec7f9e2c2018-09-14 16:23:40 -0700296 [&valid, &outConnection, &id, &outMsgId, &outChannel, &outObserver]
Sungtak Leebbe37b62018-08-29 15:15:48 -0700297 (ResultStatus status, sp<IConnection> connection,
Sungtak Leec7f9e2c2018-09-14 16:23:40 -0700298 ConnectionId connectionId, uint32_t msgId,
299 const StatusDescriptor& statusDesc,
Sungtak Lee1cb0ccb2018-09-05 14:47:36 -0700300 const InvalidationDescriptor& invDesc) {
Sungtak Leebbe37b62018-08-29 15:15:48 -0700301 if (status == ResultStatus::OK) {
302 outConnection = connection;
303 id = connectionId;
Sungtak Leec7f9e2c2018-09-14 16:23:40 -0700304 outMsgId = msgId;
305 outChannel = std::make_unique<BufferStatusChannel>(statusDesc);
306 outObserver = std::make_unique<BufferInvalidationListener>(invDesc);
307 if (outChannel && outChannel->isValid() &&
308 outObserver && outObserver->isValid()) {
Sungtak Leebbe37b62018-08-29 15:15:48 -0700309 valid = true;
310 }
311 }
312 });
313 mValid = transResult.isOk() && valid;
314}
315
316bool BufferPoolClient::Impl::isActive(int64_t *lastTransactionUs, bool clearCache) {
317 bool active = false;
318 {
319 std::lock_guard<std::mutex> lock(mCache.mLock);
320 syncReleased();
321 evictCaches(clearCache);
322 *lastTransactionUs = mCache.mLastChangeUs;
323 active = mCache.mActive > 0;
324 }
325 if (mValid && mLocal && mLocalConnection) {
326 mLocalConnection->cleanUp(clearCache);
327 return true;
328 }
329 return active;
330}
331
Sungtak Leec7f9e2c2018-09-14 16:23:40 -0700332void BufferPoolClient::Impl::receiveInvalidation(uint32_t messageId) {
333 std::lock_guard<std::mutex> lock(mCache.mLock);
334 syncReleased(messageId);
335 // TODO: evict cache required?
336}
337
338ResultStatus BufferPoolClient::Impl::flush() {
339 if (!mLocal || !mLocalConnection || !mValid) {
340 return ResultStatus::CRITICAL_ERROR;
341 }
342 {
343 std::unique_lock<std::mutex> lock(mCache.mLock);
344 syncReleased();
345 evictCaches();
346 return mLocalConnection->flush();
347 }
348}
349
Sungtak Leebbe37b62018-08-29 15:15:48 -0700350ResultStatus BufferPoolClient::Impl::allocate(
351 const std::vector<uint8_t> &params,
352 native_handle_t **pHandle,
353 std::shared_ptr<BufferPoolData> *buffer) {
354 if (!mLocal || !mLocalConnection || !mValid) {
355 return ResultStatus::CRITICAL_ERROR;
356 }
357 BufferId bufferId;
358 native_handle_t *handle = nullptr;
359 buffer->reset();
360 ResultStatus status = allocateBufferHandle(params, &bufferId, &handle);
361 if (status == ResultStatus::OK) {
362 if (handle) {
363 std::unique_lock<std::mutex> lock(mCache.mLock);
364 syncReleased();
365 evictCaches();
366 auto cacheIt = mCache.mBuffers.find(bufferId);
367 if (cacheIt != mCache.mBuffers.end()) {
368 // TODO: verify it is recycled. (not having active ref)
369 mCache.mBuffers.erase(cacheIt);
370 }
371 auto clientBuffer = std::make_unique<ClientBuffer>(
372 mConnectionId, bufferId, handle);
373 if (clientBuffer) {
374 auto result = mCache.mBuffers.insert(std::make_pair(
375 bufferId, std::move(clientBuffer)));
376 if (result.second) {
377 *buffer = result.first->second->createCache(
378 shared_from_this(), pHandle);
379 if (*buffer) {
380 mCache.incActive_l();
381 }
382 }
383 }
384 }
385 if (!*buffer) {
386 ALOGV("client cache creation failure %d: %lld",
387 handle != nullptr, (long long)mConnectionId);
388 status = ResultStatus::NO_MEMORY;
389 postBufferRelease(bufferId);
390 }
391 }
392 return status;
393}
394
395ResultStatus BufferPoolClient::Impl::receive(
396 TransactionId transactionId, BufferId bufferId, int64_t timestampUs,
397 native_handle_t **pHandle,
398 std::shared_ptr<BufferPoolData> *buffer) {
399 if (!mValid) {
400 return ResultStatus::CRITICAL_ERROR;
401 }
402 if (timestampUs != 0) {
403 timestampUs += kReceiveTimeoutUs;
404 }
405 if (!postReceive(bufferId, transactionId, timestampUs)) {
406 return ResultStatus::CRITICAL_ERROR;
407 }
408 ResultStatus status = ResultStatus::CRITICAL_ERROR;
409 buffer->reset();
410 while(1) {
411 std::unique_lock<std::mutex> lock(mCache.mLock);
412 syncReleased();
413 evictCaches();
414 auto cacheIt = mCache.mBuffers.find(bufferId);
415 if (cacheIt != mCache.mBuffers.end()) {
416 if (cacheIt->second->hasCache()) {
417 *buffer = cacheIt->second->fetchCache(pHandle);
418 if (!*buffer) {
419 // check transfer time_out
420 lock.unlock();
421 std::this_thread::yield();
422 continue;
423 }
424 ALOGV("client receive from reference %lld", (long long)mConnectionId);
425 break;
426 } else {
427 *buffer = cacheIt->second->createCache(shared_from_this(), pHandle);
428 if (*buffer) {
429 mCache.incActive_l();
430 }
431 ALOGV("client receive from cache %lld", (long long)mConnectionId);
432 break;
433 }
434 } else {
435 if (!mCache.mCreating) {
436 mCache.mCreating = true;
437 lock.unlock();
438 native_handle_t* handle = nullptr;
439 status = fetchBufferHandle(transactionId, bufferId, &handle);
440 lock.lock();
441 if (status == ResultStatus::OK) {
442 if (handle) {
443 auto clientBuffer = std::make_unique<ClientBuffer>(
444 mConnectionId, bufferId, handle);
445 if (clientBuffer) {
446 auto result = mCache.mBuffers.insert(
447 std::make_pair(bufferId, std::move(
448 clientBuffer)));
449 if (result.second) {
450 *buffer = result.first->second->createCache(
451 shared_from_this(), pHandle);
452 if (*buffer) {
453 mCache.incActive_l();
454 }
455 }
456 }
457 }
458 if (!*buffer) {
459 status = ResultStatus::NO_MEMORY;
460 }
461 }
462 mCache.mCreating = false;
463 lock.unlock();
464 mCache.mCreateCv.notify_all();
465 break;
466 }
467 mCache.mCreateCv.wait(lock);
468 }
469 }
470 bool needsSync = false;
471 bool posted = postReceiveResult(bufferId, transactionId,
472 *buffer ? true : false, &needsSync);
473 ALOGV("client receive %lld - %u : %s (%d)", (long long)mConnectionId, bufferId,
474 *buffer ? "ok" : "fail", posted);
475 if (mValid && mLocal && mLocalConnection) {
476 mLocalConnection->cleanUp(false);
477 }
478 if (needsSync && mRemoteConnection) {
479 trySyncFromRemote();
480 }
481 if (*buffer) {
482 if (!posted) {
483 buffer->reset();
484 return ResultStatus::CRITICAL_ERROR;
485 }
486 return ResultStatus::OK;
487 }
488 return status;
489}
490
491
492void BufferPoolClient::Impl::postBufferRelease(BufferId bufferId) {
493 std::lock_guard<std::mutex> lock(mReleasing.mLock);
494 mReleasing.mReleasingIds.push_back(bufferId);
495 mReleasing.mStatusChannel->postBufferRelease(
496 mConnectionId, mReleasing.mReleasingIds, mReleasing.mReleasedIds);
497}
498
499// TODO: revise ad-hoc posting data structure
500bool BufferPoolClient::Impl::postSend(
501 BufferId bufferId, ConnectionId receiver,
502 TransactionId *transactionId, int64_t *timestampUs) {
Sungtak Leec7f9e2c2018-09-14 16:23:40 -0700503 {
504 // TODO: don't need to call syncReleased every time
505 std::lock_guard<std::mutex> lock(mCache.mLock);
506 syncReleased();
507 }
Sungtak Leebbe37b62018-08-29 15:15:48 -0700508 bool ret = false;
509 bool needsSync = false;
510 {
511 std::lock_guard<std::mutex> lock(mReleasing.mLock);
512 *timestampUs = getTimestampNow();
513 *transactionId = (mConnectionId << 32) | mSeqId++;
514 // TODO: retry, add timeout, target?
515 ret = mReleasing.mStatusChannel->postBufferStatusMessage(
516 *transactionId, bufferId, BufferStatus::TRANSFER_TO, mConnectionId,
517 receiver, mReleasing.mReleasingIds, mReleasing.mReleasedIds);
518 needsSync = !mLocal && mReleasing.mStatusChannel->needsSync();
519 }
520 if (mValid && mLocal && mLocalConnection) {
521 mLocalConnection->cleanUp(false);
522 }
523 if (needsSync && mRemoteConnection) {
524 trySyncFromRemote();
525 }
526 return ret;
527}
528
529bool BufferPoolClient::Impl::postReceive(
530 BufferId bufferId, TransactionId transactionId, int64_t timestampUs) {
531 for (int i = 0; i < kPostMaxRetry; ++i) {
532 std::unique_lock<std::mutex> lock(mReleasing.mLock);
533 int64_t now = getTimestampNow();
534 if (timestampUs == 0 || now < timestampUs) {
535 bool result = mReleasing.mStatusChannel->postBufferStatusMessage(
536 transactionId, bufferId, BufferStatus::TRANSFER_FROM,
537 mConnectionId, -1, mReleasing.mReleasingIds,
538 mReleasing.mReleasedIds);
539 if (result) {
540 return true;
541 }
542 lock.unlock();
543 std::this_thread::yield();
544 } else {
545 mReleasing.mStatusChannel->postBufferStatusMessage(
546 transactionId, bufferId, BufferStatus::TRANSFER_TIMEOUT,
547 mConnectionId, -1, mReleasing.mReleasingIds,
548 mReleasing.mReleasedIds);
549 return false;
550 }
551 }
552 return false;
553}
554
555bool BufferPoolClient::Impl::postReceiveResult(
556 BufferId bufferId, TransactionId transactionId, bool result, bool *needsSync) {
557 std::lock_guard<std::mutex> lock(mReleasing.mLock);
558 // TODO: retry, add timeout
559 bool ret = mReleasing.mStatusChannel->postBufferStatusMessage(
560 transactionId, bufferId,
561 result ? BufferStatus::TRANSFER_OK : BufferStatus::TRANSFER_ERROR,
562 mConnectionId, -1, mReleasing.mReleasingIds,
563 mReleasing.mReleasedIds);
564 *needsSync = !mLocal && mReleasing.mStatusChannel->needsSync();
565 return ret;
566}
567
568void BufferPoolClient::Impl::trySyncFromRemote() {
569 if (mRemoteSyncLock.try_lock()) {
570 bool needsSync = false;
571 {
572 std::lock_guard<std::mutex> lock(mReleasing.mLock);
573 needsSync = mReleasing.mStatusChannel->needsSync();
574 }
575 if (needsSync) {
576 TransactionId transactionId = (mConnectionId << 32);
577 BufferId bufferId = Connection::SYNC_BUFFERID;
578 Return<void> transResult = mRemoteConnection->fetch(
579 transactionId, bufferId,
580 []
581 (ResultStatus outStatus, Buffer outBuffer) {
582 (void) outStatus;
583 (void) outBuffer;
584 });
Sungtak Lee603467b2019-05-16 16:48:00 -0700585 if (!transResult.isOk()) {
586 ALOGD("sync from client %lld failed: bufferpool process died.",
587 (long long)mConnectionId);
588 }
Sungtak Leebbe37b62018-08-29 15:15:48 -0700589 }
590 mRemoteSyncLock.unlock();
591 }
592}
593
594// should have mCache.mLock
Sungtak Leec7f9e2c2018-09-14 16:23:40 -0700595bool BufferPoolClient::Impl::syncReleased(uint32_t messageId) {
596 bool cleared = false;
597 {
598 std::lock_guard<std::mutex> lock(mReleasing.mLock);
599 if (mReleasing.mReleasingIds.size() > 0) {
600 mReleasing.mStatusChannel->postBufferRelease(
601 mConnectionId, mReleasing.mReleasingIds,
602 mReleasing.mReleasedIds);
603 }
604 if (mReleasing.mReleasedIds.size() > 0) {
605 for (BufferId& id: mReleasing.mReleasedIds) {
606 ALOGV("client release buffer %lld - %u", (long long)mConnectionId, id);
607 auto found = mCache.mBuffers.find(id);
608 if (found != mCache.mBuffers.end()) {
609 if (found->second->onCacheRelease()) {
610 mCache.decActive_l();
611 } else {
612 // should not happen!
613 ALOGW("client %lld cache release status inconsitent!",
614 (long long)mConnectionId);
615 }
Sungtak Leebbe37b62018-08-29 15:15:48 -0700616 } else {
617 // should not happen!
Sungtak Leec7f9e2c2018-09-14 16:23:40 -0700618 ALOGW("client %lld cache status inconsitent!", (long long)mConnectionId);
Sungtak Leebbe37b62018-08-29 15:15:48 -0700619 }
Sungtak Leec7f9e2c2018-09-14 16:23:40 -0700620 }
621 mReleasing.mReleasedIds.clear();
622 cleared = true;
623 }
624 }
625 std::vector<BufferInvalidationMessage> invalidations;
626 mInvalidationListener->getInvalidations(invalidations);
627 uint32_t lastMsgId = 0;
628 if (invalidations.size() > 0) {
629 for (auto it = invalidations.begin(); it != invalidations.end(); ++it) {
630 if (it->messageId != 0) {
631 lastMsgId = it->messageId;
632 }
633 if (it->fromBufferId == it->toBufferId) {
634 // TODO: handle fromBufferId = UINT32_MAX
635 invalidateBuffer(it->fromBufferId);
Sungtak Leebbe37b62018-08-29 15:15:48 -0700636 } else {
Sungtak Leec7f9e2c2018-09-14 16:23:40 -0700637 invalidateRange(it->fromBufferId, it->toBufferId);
Sungtak Leebbe37b62018-08-29 15:15:48 -0700638 }
639 }
Sungtak Leebbe37b62018-08-29 15:15:48 -0700640 }
Sungtak Leec7f9e2c2018-09-14 16:23:40 -0700641 {
642 std::lock_guard<std::mutex> lock(mReleasing.mLock);
643 if (lastMsgId != 0) {
644 if (isMessageLater(lastMsgId, mReleasing.mInvalidateId)) {
645 mReleasing.mInvalidateId = lastMsgId;
646 mReleasing.mInvalidateAck = false;
647 }
648 } else if (messageId != 0) {
649 // messages are drained.
650 if (isMessageLater(messageId, mReleasing.mInvalidateId)) {
Sungtak Leed3128382018-11-07 17:30:37 -0800651 mReleasing.mInvalidateId = messageId;
Sungtak Leec7f9e2c2018-09-14 16:23:40 -0700652 mReleasing.mInvalidateAck = true;
653 }
654 }
655 if (!mReleasing.mInvalidateAck) {
656 // post ACK
657 mReleasing.mStatusChannel->postBufferInvalidateAck(
658 mConnectionId,
659 mReleasing.mInvalidateId, &mReleasing.mInvalidateAck);
Sungtak Leed3128382018-11-07 17:30:37 -0800660 ALOGV("client %lld invalidateion ack (%d) %u",
661 (long long)mConnectionId,
662 mReleasing.mInvalidateAck, mReleasing.mInvalidateId);
Sungtak Leec7f9e2c2018-09-14 16:23:40 -0700663 }
664 }
665 return cleared;
Sungtak Leebbe37b62018-08-29 15:15:48 -0700666}
667
668// should have mCache.mLock
669void BufferPoolClient::Impl::evictCaches(bool clearCache) {
670 int64_t now = getTimestampNow();
671 if (now >= mLastEvictCacheUs + kCacheTtlUs || clearCache) {
672 size_t evicted = 0;
673 for (auto it = mCache.mBuffers.begin(); it != mCache.mBuffers.end();) {
674 if (!it->second->hasCache() && (it->second->expire() || clearCache)) {
675 it = mCache.mBuffers.erase(it);
676 ++evicted;
677 } else {
678 ++it;
679 }
680 }
681 ALOGV("cache count %lld : total %zu, active %d, evicted %zu",
682 (long long)mConnectionId, mCache.mBuffers.size(), mCache.mActive, evicted);
683 mLastEvictCacheUs = now;
684 }
685}
686
Sungtak Leec7f9e2c2018-09-14 16:23:40 -0700687// should have mCache.mLock
688void BufferPoolClient::Impl::invalidateBuffer(BufferId id) {
689 for (auto it = mCache.mBuffers.begin(); it != mCache.mBuffers.end(); ++it) {
690 if (id == it->second->id()) {
691 if (!it->second->hasCache()) {
692 mCache.mBuffers.erase(it);
693 ALOGV("cache invalidated %lld : buffer %u",
694 (long long)mConnectionId, id);
695 } else {
696 ALOGW("Inconsitent invalidation %lld : activer buffer!! %u",
697 (long long)mConnectionId, (unsigned int)id);
698 }
699 break;
700 }
701 }
702}
703
704// should have mCache.mLock
705void BufferPoolClient::Impl::invalidateRange(BufferId from, BufferId to) {
706 size_t invalidated = 0;
707 for (auto it = mCache.mBuffers.begin(); it != mCache.mBuffers.end();) {
708 if (!it->second->hasCache()) {
709 BufferId bid = it->second->id();
710 if (from < to) {
711 if (from <= bid && bid < to) {
712 ++invalidated;
713 it = mCache.mBuffers.erase(it);
714 continue;
715 }
716 } else {
717 if (from <= bid || bid < to) {
718 ++invalidated;
719 it = mCache.mBuffers.erase(it);
720 continue;
721 }
722 }
723 }
724 ++it;
725 }
726 ALOGV("cache invalidated %lld : # of invalidated %zu",
727 (long long)mConnectionId, invalidated);
728}
729
Sungtak Leebbe37b62018-08-29 15:15:48 -0700730ResultStatus BufferPoolClient::Impl::allocateBufferHandle(
731 const std::vector<uint8_t>& params, BufferId *bufferId,
732 native_handle_t** handle) {
733 if (mLocalConnection) {
734 const native_handle_t* allocHandle = nullptr;
735 ResultStatus status = mLocalConnection->allocate(
736 params, bufferId, &allocHandle);
737 if (status == ResultStatus::OK) {
738 *handle = native_handle_clone(allocHandle);
739 }
740 ALOGV("client allocate result %lld %d : %u clone %p",
741 (long long)mConnectionId, status == ResultStatus::OK,
742 *handle ? *bufferId : 0 , *handle);
743 return status;
744 }
745 return ResultStatus::CRITICAL_ERROR;
746}
747
748ResultStatus BufferPoolClient::Impl::fetchBufferHandle(
749 TransactionId transactionId, BufferId bufferId,
750 native_handle_t **handle) {
751 sp<IConnection> connection;
752 if (mLocal) {
753 connection = mLocalConnection;
754 } else {
755 connection = mRemoteConnection;
756 }
757 ResultStatus status;
758 Return<void> transResult = connection->fetch(
759 transactionId, bufferId,
760 [&status, &handle]
761 (ResultStatus outStatus, Buffer outBuffer) {
762 status = outStatus;
763 if (status == ResultStatus::OK) {
764 *handle = native_handle_clone(
765 outBuffer.buffer.getNativeHandle());
766 }
767 });
768 return transResult.isOk() ? status : ResultStatus::CRITICAL_ERROR;
769}
770
771
Sungtak Leec7f9e2c2018-09-14 16:23:40 -0700772BufferPoolClient::BufferPoolClient(const sp<Accessor> &accessor,
773 const sp<IObserver> &observer) {
774 mImpl = std::make_shared<Impl>(accessor, observer);
Sungtak Leebbe37b62018-08-29 15:15:48 -0700775}
776
Sungtak Leec7f9e2c2018-09-14 16:23:40 -0700777BufferPoolClient::BufferPoolClient(const sp<IAccessor> &accessor,
778 const sp<IObserver> &observer) {
779 mImpl = std::make_shared<Impl>(accessor, observer);
Sungtak Leebbe37b62018-08-29 15:15:48 -0700780}
781
782BufferPoolClient::~BufferPoolClient() {
783 // TODO: how to handle orphaned buffers?
784}
785
786bool BufferPoolClient::isValid() {
787 return mImpl && mImpl->isValid();
788}
789
790bool BufferPoolClient::isLocal() {
791 return mImpl && mImpl->isLocal();
792}
793
794bool BufferPoolClient::isActive(int64_t *lastTransactionUs, bool clearCache) {
795 if (!isValid()) {
796 *lastTransactionUs = 0;
797 return false;
798 }
799 return mImpl->isActive(lastTransactionUs, clearCache);
800}
801
802ConnectionId BufferPoolClient::getConnectionId() {
803 if (isValid()) {
804 return mImpl->getConnectionId();
805 }
806 return -1;
807}
808
809ResultStatus BufferPoolClient::getAccessor(sp<IAccessor> *accessor) {
810 if (isValid()) {
811 *accessor = mImpl->getAccessor();
812 return ResultStatus::OK;
813 }
814 return ResultStatus::CRITICAL_ERROR;
815}
816
Sungtak Leec7f9e2c2018-09-14 16:23:40 -0700817void BufferPoolClient::receiveInvalidation(uint32_t msgId) {
Sungtak Leed3318082018-09-07 15:52:43 -0700818 ALOGV("bufferpool2 client recv inv %u", msgId);
Sungtak Leec7f9e2c2018-09-14 16:23:40 -0700819 if (isValid()) {
820 mImpl->receiveInvalidation(msgId);
821 }
822}
823
824ResultStatus BufferPoolClient::flush() {
825 if (isValid()) {
826 return mImpl->flush();
827 }
828 return ResultStatus::CRITICAL_ERROR;
829}
830
Sungtak Leebbe37b62018-08-29 15:15:48 -0700831ResultStatus BufferPoolClient::allocate(
832 const std::vector<uint8_t> &params,
833 native_handle_t **handle,
834 std::shared_ptr<BufferPoolData> *buffer) {
835 if (isValid()) {
836 return mImpl->allocate(params, handle, buffer);
837 }
838 return ResultStatus::CRITICAL_ERROR;
839}
840
841ResultStatus BufferPoolClient::receive(
842 TransactionId transactionId, BufferId bufferId, int64_t timestampUs,
843 native_handle_t **handle, std::shared_ptr<BufferPoolData> *buffer) {
844 if (isValid()) {
845 return mImpl->receive(transactionId, bufferId, timestampUs, handle, buffer);
846 }
847 return ResultStatus::CRITICAL_ERROR;
848}
849
850ResultStatus BufferPoolClient::postSend(
851 ConnectionId receiverId,
852 const std::shared_ptr<BufferPoolData> &buffer,
853 TransactionId *transactionId,
854 int64_t *timestampUs) {
855 if (isValid()) {
856 bool result = mImpl->postSend(
857 buffer->mId, receiverId, transactionId, timestampUs);
858 return result ? ResultStatus::OK : ResultStatus::CRITICAL_ERROR;
859 }
860 return ResultStatus::CRITICAL_ERROR;
861}
862
863} // namespace implementation
864} // namespace V2_0
865} // namespace bufferpool
866} // namespace media
867} // namespace hardware
868} // namespace android