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 "Accessor.h"
24 
25 namespace android {
26 namespace hardware {
27 namespace media {
28 namespace bufferpool {
29 namespace V2_0 {
30 namespace implementation {
31 
32 struct InternalBuffer;
33 struct TransactionStatus;
34 
35 /**
36  * An implementation of a buffer pool accessor(or a buffer pool implementation.) */
37 class Accessor::Impl
38     : public std::enable_shared_from_this<Accessor::Impl> {
39 public:
40     Impl(const std::shared_ptr<BufferPoolAllocator> &allocator);
41 
42     ~Impl();
43 
44     ResultStatus connect(
45             const sp<Accessor> &accessor, const sp<IObserver> &observer,
46             sp<Connection> *connection,
47             ConnectionId *pConnectionId,
48             uint32_t *pMsgId,
49             const StatusDescriptor** statusDescPtr,
50             const InvalidationDescriptor** invDescPtr);
51 
52     ResultStatus close(ConnectionId connectionId);
53 
54     ResultStatus allocate(ConnectionId connectionId,
55                           const std::vector<uint8_t>& params,
56                           BufferId *bufferId,
57                           const native_handle_t** handle);
58 
59     ResultStatus fetch(ConnectionId connectionId,
60                        TransactionId transactionId,
61                        BufferId bufferId,
62                        const native_handle_t** handle);
63 
64     void flush();
65 
66     void cleanUp(bool clearCache);
67 
68     bool isValid();
69 
70     void handleInvalidateAck();
71 
72     static void createInvalidator();
73 
74 private:
75     // ConnectionId = pid : (timestamp_created + seqId)
76     // in order to guarantee uniqueness for each connection
77     static uint32_t sSeqId;
78     static int32_t sPid;
79 
80     const std::shared_ptr<BufferPoolAllocator> mAllocator;
81 
82     /**
83      * Buffer pool implementation.
84      *
85      * Handles buffer status messages. Handles buffer allocation/recycling.
86      * Handles buffer transfer between buffer pool clients.
87      */
88     struct BufferPool {
89     private:
90         std::mutex mMutex;
91         int64_t mTimestampUs;
92         int64_t mLastCleanUpUs;
93         int64_t mLastLogUs;
94         BufferId mSeq;
95         BufferId mStartSeq;
96         bool mValid;
97         BufferStatusObserver mObserver;
98         BufferInvalidationChannel mInvalidationChannel;
99 
100         std::map<ConnectionId, std::set<BufferId>> mUsingBuffers;
101         std::map<BufferId, std::set<ConnectionId>> mUsingConnections;
102 
103         std::map<ConnectionId, std::set<TransactionId>> mPendingTransactions;
104         // Transactions completed before TRANSFER_TO message arrival.
105         // Fetch does not occur for the transactions.
106         // Only transaction id is kept for the transactions in short duration.
107         std::set<TransactionId> mCompletedTransactions;
108         // Currently active(pending) transations' status & information.
109         std::map<TransactionId, std::unique_ptr<TransactionStatus>>
110                 mTransactions;
111 
112         std::map<BufferId, std::unique_ptr<InternalBuffer>> mBuffers;
113         std::set<BufferId> mFreeBuffers;
114 
115         struct Invalidation {
116             static std::atomic<std::uint32_t> sInvSeqId;
117 
118             struct Pending {
119                 bool mNeedsAck;
120                 uint32_t mFrom;
121                 uint32_t mTo;
122                 size_t mLeft;
123                 const std::weak_ptr<Accessor::Impl> mImpl;
PendingBufferPool::Invalidation::Pending124                 Pending(bool needsAck, uint32_t from, uint32_t to, size_t left,
125                         const std::shared_ptr<Accessor::Impl> &impl)
126                         : mNeedsAck(needsAck),
127                           mFrom(from),
128                           mTo(to),
129                           mLeft(left),
130                           mImpl(impl)
131                 {}
132 
isInvalidatedBufferPool::Invalidation::Pending133                 bool isInvalidated(uint32_t bufferId) {
134                     return isBufferInRange(mFrom, mTo, bufferId) && --mLeft == 0;
135                 }
136             };
137 
138             std::list<Pending> mPendings;
139             std::map<ConnectionId, uint32_t> mAcks;
140             std::map<ConnectionId, const sp<IObserver>> mObservers;
141             uint32_t mInvalidationId;
142             uint32_t mId;
143 
InvalidationBufferPool::Invalidation144             Invalidation() : mInvalidationId(0), mId(sInvSeqId.fetch_add(1)) {}
145 
146             void onConnect(ConnectionId conId, const sp<IObserver> &observer);
147 
148             void onClose(ConnectionId conId);
149 
150             void onAck(ConnectionId conId, uint32_t msgId);
151 
152             void onBufferInvalidated(
153                     BufferId bufferId,
154                     BufferInvalidationChannel &channel);
155 
156             void onInvalidationRequest(
157                     bool needsAck, uint32_t from, uint32_t to, size_t left,
158                     BufferInvalidationChannel &channel,
159                     const std::shared_ptr<Accessor::Impl> &impl);
160 
161             void onHandleAck(
162                     std::map<ConnectionId, const sp<IObserver>> *observers,
163                     uint32_t *invalidationId);
164         } mInvalidation;
165         /// Buffer pool statistics which tracks allocation and transfer statistics.
166         struct Stats {
167             /// Total size of allocations which are used or available to use.
168             /// (bytes or pixels)
169             size_t mSizeCached;
170             /// # of cached buffers which are used or available to use.
171             size_t mBuffersCached;
172             /// Total size of allocations which are currently used. (bytes or pixels)
173             size_t mSizeInUse;
174             /// # of currently used buffers
175             size_t mBuffersInUse;
176 
177             /// # of allocations called on bufferpool. (# of fetched from BlockPool)
178             size_t mTotalAllocations;
179             /// # of allocations that were served from the cache.
180             /// (# of allocator alloc prevented)
181             size_t mTotalRecycles;
182             /// # of buffer transfers initiated.
183             size_t mTotalTransfers;
184             /// # of transfers that had to be fetched.
185             size_t mTotalFetches;
186 
StatsBufferPool::Stats187             Stats()
188                 : mSizeCached(0), mBuffersCached(0), mSizeInUse(0), mBuffersInUse(0),
189                   mTotalAllocations(0), mTotalRecycles(0), mTotalTransfers(0), mTotalFetches(0) {}
190 
191             /// A new buffer is allocated on an allocation request.
onBufferAllocatedBufferPool::Stats192             void onBufferAllocated(size_t allocSize) {
193                 mSizeCached += allocSize;
194                 mBuffersCached++;
195 
196                 mSizeInUse += allocSize;
197                 mBuffersInUse++;
198 
199                 mTotalAllocations++;
200             }
201 
202             /// A buffer is evicted and destroyed.
onBufferEvictedBufferPool::Stats203             void onBufferEvicted(size_t allocSize) {
204                 mSizeCached -= allocSize;
205                 mBuffersCached--;
206             }
207 
208             /// A buffer is recycled on an allocation request.
onBufferRecycledBufferPool::Stats209             void onBufferRecycled(size_t allocSize) {
210                 mSizeInUse += allocSize;
211                 mBuffersInUse++;
212 
213                 mTotalAllocations++;
214                 mTotalRecycles++;
215             }
216 
217             /// A buffer is available to be recycled.
onBufferUnusedBufferPool::Stats218             void onBufferUnused(size_t allocSize) {
219                 mSizeInUse -= allocSize;
220                 mBuffersInUse--;
221             }
222 
223             /// A buffer transfer is initiated.
onBufferSentBufferPool::Stats224             void onBufferSent() {
225                 mTotalTransfers++;
226             }
227 
228             /// A buffer fetch is invoked by a buffer transfer.
onBufferFetchedBufferPool::Stats229             void onBufferFetched() {
230                 mTotalFetches++;
231             }
232         } mStats;
233 
isValidBufferPool234         bool isValid() {
235             return mValid;
236         }
237 
238         void invalidate(bool needsAck, BufferId from, BufferId to,
239                         const std::shared_ptr<Accessor::Impl> &impl);
240 
241         static void createInvalidator();
242 
243     public:
244         /** Creates a buffer pool. */
245         BufferPool();
246 
247         /** Destroys a buffer pool. */
248         ~BufferPool();
249 
250         /**
251          * Processes all pending buffer status messages, and returns the result.
252          * Each status message is handled by methods with 'handle' prefix.
253          */
254         void processStatusMessages();
255 
256         /**
257          * Handles a buffer being owned by a connection.
258          *
259          * @param connectionId  the id of the buffer owning connection.
260          * @param bufferId      the id of the buffer.
261          *
262          * @return {@code true} when the buffer is owned,
263          *         {@code false} otherwise.
264          */
265         bool handleOwnBuffer(ConnectionId connectionId, BufferId bufferId);
266 
267         /**
268          * Handles a buffer being released by a connection.
269          *
270          * @param connectionId  the id of the buffer owning connection.
271          * @param bufferId      the id of the buffer.
272          *
273          * @return {@code true} when the buffer ownership is released,
274          *         {@code false} otherwise.
275          */
276         bool handleReleaseBuffer(ConnectionId connectionId, BufferId bufferId);
277 
278         /**
279          * Handles a transfer transaction start message from the sender.
280          *
281          * @param message   a buffer status message for the transaction.
282          *
283          * @result {@code true} when transfer_to message is acknowledged,
284          *         {@code false} otherwise.
285          */
286         bool handleTransferTo(const BufferStatusMessage &message);
287 
288         /**
289          * Handles a transfer transaction being acked by the receiver.
290          *
291          * @param message   a buffer status message for the transaction.
292          *
293          * @result {@code true} when transfer_from message is acknowledged,
294          *         {@code false} otherwise.
295          */
296         bool handleTransferFrom(const BufferStatusMessage &message);
297 
298         /**
299          * Handles a transfer transaction result message from the receiver.
300          *
301          * @param message   a buffer status message for the transaction.
302          *
303          * @result {@code true} when the exisitng transaction is finished,
304          *         {@code false} otherwise.
305          */
306         bool handleTransferResult(const BufferStatusMessage &message);
307 
308         /**
309          * Handles a connection being closed, and returns the result. All the
310          * buffers and transactions owned by the connection will be cleaned up.
311          * The related FMQ will be cleaned up too.
312          *
313          * @param connectionId  the id of the connection.
314          *
315          * @result {@code true} when the connection existed,
316          *         {@code false} otherwise.
317          */
318         bool handleClose(ConnectionId connectionId);
319 
320         /**
321          * Recycles a existing free buffer if it is possible.
322          *
323          * @param allocator the buffer allocator
324          * @param params    the allocation parameters.
325          * @param pId       the id of the recycled buffer.
326          * @param handle    the native handle of the recycled buffer.
327          *
328          * @return {@code true} when a buffer is recycled, {@code false}
329          *         otherwise.
330          */
331         bool getFreeBuffer(
332                 const std::shared_ptr<BufferPoolAllocator> &allocator,
333                 const std::vector<uint8_t> &params,
334                 BufferId *pId, const native_handle_t **handle);
335 
336         /**
337          * Adds a newly allocated buffer to bufferpool.
338          *
339          * @param alloc     the newly allocated buffer.
340          * @param allocSize the size of the newly allocated buffer.
341          * @param params    the allocation parameters.
342          * @param pId       the buffer id for the newly allocated buffer.
343          * @param handle    the native handle for the newly allocated buffer.
344          *
345          * @return OK when an allocation is successfully allocated.
346          *         NO_MEMORY when there is no memory.
347          *         CRITICAL_ERROR otherwise.
348          */
349         ResultStatus addNewBuffer(
350                 const std::shared_ptr<BufferPoolAllocation> &alloc,
351                 const size_t allocSize,
352                 const std::vector<uint8_t> &params,
353                 BufferId *pId,
354                 const native_handle_t **handle);
355 
356         /**
357          * Processes pending buffer status messages and performs periodic cache
358          * cleaning.
359          *
360          * @param clearCache    if clearCache is true, it frees all buffers
361          *                      waiting to be recycled.
362          */
363         void cleanUp(bool clearCache = false);
364 
365         /**
366          * Processes pending buffer status messages and invalidate all current
367          * free buffers. Active buffers are invalidated after being inactive.
368          */
369         void flush(const std::shared_ptr<Accessor::Impl> &impl);
370 
371         friend class Accessor::Impl;
372     } mBufferPool;
373 
374     struct  AccessorInvalidator {
375         std::map<uint32_t, const std::weak_ptr<Accessor::Impl>> mAccessors;
376         std::mutex mMutex;
377         std::condition_variable mCv;
378         bool mReady;
379 
380         AccessorInvalidator();
381         void addAccessor(uint32_t accessorId, const std::weak_ptr<Accessor::Impl> &impl);
382         void delAccessor(uint32_t accessorId);
383     };
384 
385     static std::unique_ptr<AccessorInvalidator> sInvalidator;
386 
387     static void invalidatorThread(
388         std::map<uint32_t, const std::weak_ptr<Accessor::Impl>> &accessors,
389         std::mutex &mutex,
390         std::condition_variable &cv,
391         bool &ready);
392 };
393 
394 }  // namespace implementation
395 }  // namespace V2_0
396 }  // namespace ufferpool
397 }  // namespace media
398 }  // namespace hardware
399 }  // namespace android
400 
401 #endif  // ANDROID_HARDWARE_MEDIA_BUFFERPOOL_V2_0_ACCESSORIMPL_H
402