1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef ANDROID_HARDWARE_MEDIA_BUFFERPOOL_V2_0_ACCESSORIMPL_H
18 #define ANDROID_HARDWARE_MEDIA_BUFFERPOOL_V2_0_ACCESSORIMPL_H
19 
20 #include <map>
21 #include <set>
22 #include <condition_variable>
23 #include <utils/Timers.h>
24 #include "Accessor.h"
25 
26 namespace android {
27 namespace hardware {
28 namespace media {
29 namespace bufferpool {
30 namespace V2_0 {
31 namespace implementation {
32 
33 struct InternalBuffer;
34 struct TransactionStatus;
35 
36 /**
37  * An implementation of a buffer pool accessor(or a buffer pool implementation.) */
38 class Accessor::Impl
39     : public std::enable_shared_from_this<Accessor::Impl> {
40 public:
41     Impl(const std::shared_ptr<BufferPoolAllocator> &allocator);
42 
43     ~Impl();
44 
45     ResultStatus connect(
46             const sp<Accessor> &accessor, const sp<IObserver> &observer,
47             sp<Connection> *connection,
48             ConnectionId *pConnectionId,
49             uint32_t *pMsgId,
50             const StatusDescriptor** statusDescPtr,
51             const InvalidationDescriptor** invDescPtr);
52 
53     ResultStatus close(ConnectionId connectionId);
54 
55     ResultStatus allocate(ConnectionId connectionId,
56                           const std::vector<uint8_t>& params,
57                           BufferId *bufferId,
58                           const native_handle_t** handle);
59 
60     ResultStatus fetch(ConnectionId connectionId,
61                        TransactionId transactionId,
62                        BufferId bufferId,
63                        const native_handle_t** handle);
64 
65     void flush();
66 
67     void cleanUp(bool clearCache);
68 
69     bool isValid();
70 
71     void handleInvalidateAck();
72 
73     static void createInvalidator();
74 
75     static void createEvictor();
76 
77 private:
78     // ConnectionId = pid : (timestamp_created + seqId)
79     // in order to guarantee uniqueness for each connection
80     struct ConnectionIdGenerator {
81         int32_t mPid;
82         uint32_t mSeqId;
83         std::mutex mLock;
84 
85         ConnectionIdGenerator();
86         ConnectionId getConnectionId();
87     };
88 
89     const std::shared_ptr<BufferPoolAllocator> mAllocator;
90 
91     nsecs_t mScheduleEvictTs;
92 
93     /**
94      * Buffer pool implementation.
95      *
96      * Handles buffer status messages. Handles buffer allocation/recycling.
97      * Handles buffer transfer between buffer pool clients.
98      */
99     struct BufferPool {
100     private:
101         std::mutex mMutex;
102         int64_t mTimestampUs;
103         int64_t mLastCleanUpUs;
104         int64_t mLastLogUs;
105         BufferId mSeq;
106         BufferId mStartSeq;
107         bool mValid;
108         BufferStatusObserver mObserver;
109         BufferInvalidationChannel mInvalidationChannel;
110 
111         std::map<ConnectionId, std::set<BufferId>> mUsingBuffers;
112         std::map<BufferId, std::set<ConnectionId>> mUsingConnections;
113 
114         std::map<ConnectionId, std::set<TransactionId>> mPendingTransactions;
115         // Transactions completed before TRANSFER_TO message arrival.
116         // Fetch does not occur for the transactions.
117         // Only transaction id is kept for the transactions in short duration.
118         std::set<TransactionId> mCompletedTransactions;
119         // Currently active(pending) transations' status & information.
120         std::map<TransactionId, std::unique_ptr<TransactionStatus>>
121                 mTransactions;
122 
123         std::map<BufferId, std::unique_ptr<InternalBuffer>> mBuffers;
124         std::set<BufferId> mFreeBuffers;
125         std::set<ConnectionId> mConnectionIds;
126 
127         struct Invalidation {
128             static std::atomic<std::uint32_t> sInvSeqId;
129 
130             struct Pending {
131                 bool mNeedsAck;
132                 uint32_t mFrom;
133                 uint32_t mTo;
134                 size_t mLeft;
135                 const std::weak_ptr<Accessor::Impl> mImpl;
PendingBufferPool::Invalidation::Pending136                 Pending(bool needsAck, uint32_t from, uint32_t to, size_t left,
137                         const std::shared_ptr<Accessor::Impl> &impl)
138                         : mNeedsAck(needsAck),
139                           mFrom(from),
140                           mTo(to),
141                           mLeft(left),
142                           mImpl(impl)
143                 {}
144 
isInvalidatedBufferPool::Invalidation::Pending145                 bool isInvalidated(uint32_t bufferId) {
146                     return isBufferInRange(mFrom, mTo, bufferId) && --mLeft == 0;
147                 }
148             };
149 
150             std::list<Pending> mPendings;
151             std::map<ConnectionId, uint32_t> mAcks;
152             std::map<ConnectionId, const sp<IObserver>> mObservers;
153             uint32_t mInvalidationId;
154             uint32_t mId;
155 
InvalidationBufferPool::Invalidation156             Invalidation() : mInvalidationId(0), mId(sInvSeqId.fetch_add(1)) {}
157 
158             void onConnect(ConnectionId conId, const sp<IObserver> &observer);
159 
160             void onClose(ConnectionId conId);
161 
162             void onAck(ConnectionId conId, uint32_t msgId);
163 
164             void onBufferInvalidated(
165                     BufferId bufferId,
166                     BufferInvalidationChannel &channel);
167 
168             void onInvalidationRequest(
169                     bool needsAck, uint32_t from, uint32_t to, size_t left,
170                     BufferInvalidationChannel &channel,
171                     const std::shared_ptr<Accessor::Impl> &impl);
172 
173             void onHandleAck(
174                     std::map<ConnectionId, const sp<IObserver>> *observers,
175                     uint32_t *invalidationId);
176         } mInvalidation;
177         /// Buffer pool statistics which tracks allocation and transfer statistics.
178         struct Stats {
179             /// Total size of allocations which are used or available to use.
180             /// (bytes or pixels)
181             size_t mSizeCached;
182             /// # of cached buffers which are used or available to use.
183             size_t mBuffersCached;
184             /// Total size of allocations which are currently used. (bytes or pixels)
185             size_t mSizeInUse;
186             /// # of currently used buffers
187             size_t mBuffersInUse;
188 
189             /// # of allocations called on bufferpool. (# of fetched from BlockPool)
190             size_t mTotalAllocations;
191             /// # of allocations that were served from the cache.
192             /// (# of allocator alloc prevented)
193             size_t mTotalRecycles;
194             /// # of buffer transfers initiated.
195             size_t mTotalTransfers;
196             /// # of transfers that had to be fetched.
197             size_t mTotalFetches;
198 
StatsBufferPool::Stats199             Stats()
200                 : mSizeCached(0), mBuffersCached(0), mSizeInUse(0), mBuffersInUse(0),
201                   mTotalAllocations(0), mTotalRecycles(0), mTotalTransfers(0), mTotalFetches(0) {}
202 
203             /// # of currently unused buffers
buffersNotInUseBufferPool::Stats204             size_t buffersNotInUse() const {
205                 ALOG_ASSERT(mBuffersCached >= mBuffersInUse);
206                 return mBuffersCached - mBuffersInUse;
207             }
208 
209             /// A new buffer is allocated on an allocation request.
onBufferAllocatedBufferPool::Stats210             void onBufferAllocated(size_t allocSize) {
211                 mSizeCached += allocSize;
212                 mBuffersCached++;
213 
214                 mSizeInUse += allocSize;
215                 mBuffersInUse++;
216 
217                 mTotalAllocations++;
218             }
219 
220             /// A buffer is evicted and destroyed.
onBufferEvictedBufferPool::Stats221             void onBufferEvicted(size_t allocSize) {
222                 mSizeCached -= allocSize;
223                 mBuffersCached--;
224             }
225 
226             /// A buffer is recycled on an allocation request.
onBufferRecycledBufferPool::Stats227             void onBufferRecycled(size_t allocSize) {
228                 mSizeInUse += allocSize;
229                 mBuffersInUse++;
230 
231                 mTotalAllocations++;
232                 mTotalRecycles++;
233             }
234 
235             /// A buffer is available to be recycled.
onBufferUnusedBufferPool::Stats236             void onBufferUnused(size_t allocSize) {
237                 mSizeInUse -= allocSize;
238                 mBuffersInUse--;
239             }
240 
241             /// A buffer transfer is initiated.
onBufferSentBufferPool::Stats242             void onBufferSent() {
243                 mTotalTransfers++;
244             }
245 
246             /// A buffer fetch is invoked by a buffer transfer.
onBufferFetchedBufferPool::Stats247             void onBufferFetched() {
248                 mTotalFetches++;
249             }
250         } mStats;
251 
isValidBufferPool252         bool isValid() {
253             return mValid;
254         }
255 
256         void invalidate(bool needsAck, BufferId from, BufferId to,
257                         const std::shared_ptr<Accessor::Impl> &impl);
258 
259         static void createInvalidator();
260 
261     public:
262         /** Creates a buffer pool. */
263         BufferPool();
264 
265         /** Destroys a buffer pool. */
266         ~BufferPool();
267 
268         /**
269          * Processes all pending buffer status messages, and returns the result.
270          * Each status message is handled by methods with 'handle' prefix.
271          */
272         void processStatusMessages();
273 
274         /**
275          * Handles a buffer being owned by a connection.
276          *
277          * @param connectionId  the id of the buffer owning connection.
278          * @param bufferId      the id of the buffer.
279          *
280          * @return {@code true} when the buffer is owned,
281          *         {@code false} otherwise.
282          */
283         bool handleOwnBuffer(ConnectionId connectionId, BufferId bufferId);
284 
285         /**
286          * Handles a buffer being released by a connection.
287          *
288          * @param connectionId  the id of the buffer owning connection.
289          * @param bufferId      the id of the buffer.
290          *
291          * @return {@code true} when the buffer ownership is released,
292          *         {@code false} otherwise.
293          */
294         bool handleReleaseBuffer(ConnectionId connectionId, BufferId bufferId);
295 
296         /**
297          * Handles a transfer transaction start message from the sender.
298          *
299          * @param message   a buffer status message for the transaction.
300          *
301          * @result {@code true} when transfer_to message is acknowledged,
302          *         {@code false} otherwise.
303          */
304         bool handleTransferTo(const BufferStatusMessage &message);
305 
306         /**
307          * Handles a transfer transaction being acked by the receiver.
308          *
309          * @param message   a buffer status message for the transaction.
310          *
311          * @result {@code true} when transfer_from message is acknowledged,
312          *         {@code false} otherwise.
313          */
314         bool handleTransferFrom(const BufferStatusMessage &message);
315 
316         /**
317          * Handles a transfer transaction result message from the receiver.
318          *
319          * @param message   a buffer status message for the transaction.
320          *
321          * @result {@code true} when the exisitng transaction is finished,
322          *         {@code false} otherwise.
323          */
324         bool handleTransferResult(const BufferStatusMessage &message);
325 
326         /**
327          * Handles a connection being closed, and returns the result. All the
328          * buffers and transactions owned by the connection will be cleaned up.
329          * The related FMQ will be cleaned up too.
330          *
331          * @param connectionId  the id of the connection.
332          *
333          * @result {@code true} when the connection existed,
334          *         {@code false} otherwise.
335          */
336         bool handleClose(ConnectionId connectionId);
337 
338         /**
339          * Recycles a existing free buffer if it is possible.
340          *
341          * @param allocator the buffer allocator
342          * @param params    the allocation parameters.
343          * @param pId       the id of the recycled buffer.
344          * @param handle    the native handle of the recycled buffer.
345          *
346          * @return {@code true} when a buffer is recycled, {@code false}
347          *         otherwise.
348          */
349         bool getFreeBuffer(
350                 const std::shared_ptr<BufferPoolAllocator> &allocator,
351                 const std::vector<uint8_t> &params,
352                 BufferId *pId, const native_handle_t **handle);
353 
354         /**
355          * Adds a newly allocated buffer to bufferpool.
356          *
357          * @param alloc     the newly allocated buffer.
358          * @param allocSize the size of the newly allocated buffer.
359          * @param params    the allocation parameters.
360          * @param pId       the buffer id for the newly allocated buffer.
361          * @param handle    the native handle for the newly allocated buffer.
362          *
363          * @return OK when an allocation is successfully allocated.
364          *         NO_MEMORY when there is no memory.
365          *         CRITICAL_ERROR otherwise.
366          */
367         ResultStatus addNewBuffer(
368                 const std::shared_ptr<BufferPoolAllocation> &alloc,
369                 const size_t allocSize,
370                 const std::vector<uint8_t> &params,
371                 BufferId *pId,
372                 const native_handle_t **handle);
373 
374         /**
375          * Processes pending buffer status messages and performs periodic cache
376          * cleaning.
377          *
378          * @param clearCache    if clearCache is true, it frees all buffers
379          *                      waiting to be recycled.
380          */
381         void cleanUp(bool clearCache = false);
382 
383         /**
384          * Processes pending buffer status messages and invalidate all current
385          * free buffers. Active buffers are invalidated after being inactive.
386          */
387         void flush(const std::shared_ptr<Accessor::Impl> &impl);
388 
389         friend class Accessor::Impl;
390     } mBufferPool;
391 
392     struct  AccessorInvalidator {
393         std::map<uint32_t, const std::weak_ptr<Accessor::Impl>> mAccessors;
394         std::mutex mMutex;
395         std::condition_variable mCv;
396         bool mReady;
397 
398         AccessorInvalidator();
399         void addAccessor(uint32_t accessorId, const std::weak_ptr<Accessor::Impl> &impl);
400         void delAccessor(uint32_t accessorId);
401     };
402 
403     static std::unique_ptr<AccessorInvalidator> sInvalidator;
404 
405     static void invalidatorThread(
406         std::map<uint32_t, const std::weak_ptr<Accessor::Impl>> &accessors,
407         std::mutex &mutex,
408         std::condition_variable &cv,
409         bool &ready);
410 
411     struct AccessorEvictor {
412         std::map<const std::weak_ptr<Accessor::Impl>, nsecs_t, std::owner_less<>> mAccessors;
413         std::mutex mMutex;
414         std::condition_variable mCv;
415 
416         AccessorEvictor();
417         void addAccessor(const std::weak_ptr<Accessor::Impl> &impl, nsecs_t ts);
418     };
419 
420     static std::unique_ptr<AccessorEvictor> sEvictor;
421 
422     static void evictorThread(
423         std::map<const std::weak_ptr<Accessor::Impl>, nsecs_t, std::owner_less<>> &accessors,
424         std::mutex &mutex,
425         std::condition_variable &cv);
426 
427     void scheduleEvictIfNeeded();
428 
429 };
430 
431 }  // namespace implementation
432 }  // namespace V2_0
433 }  // namespace ufferpool
434 }  // namespace media
435 }  // namespace hardware
436 }  // namespace android
437 
438 #endif  // ANDROID_HARDWARE_MEDIA_BUFFERPOOL_V2_0_ACCESSORIMPL_H
439