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         std::set<ConnectionId> mConnectionIds;
115 
116         struct Invalidation {
117             static std::atomic<std::uint32_t> sInvSeqId;
118 
119             struct Pending {
120                 bool mNeedsAck;
121                 uint32_t mFrom;
122                 uint32_t mTo;
123                 size_t mLeft;
124                 const std::weak_ptr<Accessor::Impl> mImpl;
PendingBufferPool::Invalidation::Pending125                 Pending(bool needsAck, uint32_t from, uint32_t to, size_t left,
126                         const std::shared_ptr<Accessor::Impl> &impl)
127                         : mNeedsAck(needsAck),
128                           mFrom(from),
129                           mTo(to),
130                           mLeft(left),
131                           mImpl(impl)
132                 {}
133 
isInvalidatedBufferPool::Invalidation::Pending134                 bool isInvalidated(uint32_t bufferId) {
135                     return isBufferInRange(mFrom, mTo, bufferId) && --mLeft == 0;
136                 }
137             };
138 
139             std::list<Pending> mPendings;
140             std::map<ConnectionId, uint32_t> mAcks;
141             std::map<ConnectionId, const sp<IObserver>> mObservers;
142             uint32_t mInvalidationId;
143             uint32_t mId;
144 
InvalidationBufferPool::Invalidation145             Invalidation() : mInvalidationId(0), mId(sInvSeqId.fetch_add(1)) {}
146 
147             void onConnect(ConnectionId conId, const sp<IObserver> &observer);
148 
149             void onClose(ConnectionId conId);
150 
151             void onAck(ConnectionId conId, uint32_t msgId);
152 
153             void onBufferInvalidated(
154                     BufferId bufferId,
155                     BufferInvalidationChannel &channel);
156 
157             void onInvalidationRequest(
158                     bool needsAck, uint32_t from, uint32_t to, size_t left,
159                     BufferInvalidationChannel &channel,
160                     const std::shared_ptr<Accessor::Impl> &impl);
161 
162             void onHandleAck(
163                     std::map<ConnectionId, const sp<IObserver>> *observers,
164                     uint32_t *invalidationId);
165         } mInvalidation;
166         /// Buffer pool statistics which tracks allocation and transfer statistics.
167         struct Stats {
168             /// Total size of allocations which are used or available to use.
169             /// (bytes or pixels)
170             size_t mSizeCached;
171             /// # of cached buffers which are used or available to use.
172             size_t mBuffersCached;
173             /// Total size of allocations which are currently used. (bytes or pixels)
174             size_t mSizeInUse;
175             /// # of currently used buffers
176             size_t mBuffersInUse;
177 
178             /// # of allocations called on bufferpool. (# of fetched from BlockPool)
179             size_t mTotalAllocations;
180             /// # of allocations that were served from the cache.
181             /// (# of allocator alloc prevented)
182             size_t mTotalRecycles;
183             /// # of buffer transfers initiated.
184             size_t mTotalTransfers;
185             /// # of transfers that had to be fetched.
186             size_t mTotalFetches;
187 
StatsBufferPool::Stats188             Stats()
189                 : mSizeCached(0), mBuffersCached(0), mSizeInUse(0), mBuffersInUse(0),
190                   mTotalAllocations(0), mTotalRecycles(0), mTotalTransfers(0), mTotalFetches(0) {}
191 
192             /// A new buffer is allocated on an allocation request.
onBufferAllocatedBufferPool::Stats193             void onBufferAllocated(size_t allocSize) {
194                 mSizeCached += allocSize;
195                 mBuffersCached++;
196 
197                 mSizeInUse += allocSize;
198                 mBuffersInUse++;
199 
200                 mTotalAllocations++;
201             }
202 
203             /// A buffer is evicted and destroyed.
onBufferEvictedBufferPool::Stats204             void onBufferEvicted(size_t allocSize) {
205                 mSizeCached -= allocSize;
206                 mBuffersCached--;
207             }
208 
209             /// A buffer is recycled on an allocation request.
onBufferRecycledBufferPool::Stats210             void onBufferRecycled(size_t allocSize) {
211                 mSizeInUse += allocSize;
212                 mBuffersInUse++;
213 
214                 mTotalAllocations++;
215                 mTotalRecycles++;
216             }
217 
218             /// A buffer is available to be recycled.
onBufferUnusedBufferPool::Stats219             void onBufferUnused(size_t allocSize) {
220                 mSizeInUse -= allocSize;
221                 mBuffersInUse--;
222             }
223 
224             /// A buffer transfer is initiated.
onBufferSentBufferPool::Stats225             void onBufferSent() {
226                 mTotalTransfers++;
227             }
228 
229             /// A buffer fetch is invoked by a buffer transfer.
onBufferFetchedBufferPool::Stats230             void onBufferFetched() {
231                 mTotalFetches++;
232             }
233         } mStats;
234 
isValidBufferPool235         bool isValid() {
236             return mValid;
237         }
238 
239         void invalidate(bool needsAck, BufferId from, BufferId to,
240                         const std::shared_ptr<Accessor::Impl> &impl);
241 
242         static void createInvalidator();
243 
244     public:
245         /** Creates a buffer pool. */
246         BufferPool();
247 
248         /** Destroys a buffer pool. */
249         ~BufferPool();
250 
251         /**
252          * Processes all pending buffer status messages, and returns the result.
253          * Each status message is handled by methods with 'handle' prefix.
254          */
255         void processStatusMessages();
256 
257         /**
258          * Handles a buffer being owned by a connection.
259          *
260          * @param connectionId  the id of the buffer owning connection.
261          * @param bufferId      the id of the buffer.
262          *
263          * @return {@code true} when the buffer is owned,
264          *         {@code false} otherwise.
265          */
266         bool handleOwnBuffer(ConnectionId connectionId, BufferId bufferId);
267 
268         /**
269          * Handles a buffer being released by a connection.
270          *
271          * @param connectionId  the id of the buffer owning connection.
272          * @param bufferId      the id of the buffer.
273          *
274          * @return {@code true} when the buffer ownership is released,
275          *         {@code false} otherwise.
276          */
277         bool handleReleaseBuffer(ConnectionId connectionId, BufferId bufferId);
278 
279         /**
280          * Handles a transfer transaction start message from the sender.
281          *
282          * @param message   a buffer status message for the transaction.
283          *
284          * @result {@code true} when transfer_to message is acknowledged,
285          *         {@code false} otherwise.
286          */
287         bool handleTransferTo(const BufferStatusMessage &message);
288 
289         /**
290          * Handles a transfer transaction being acked by the receiver.
291          *
292          * @param message   a buffer status message for the transaction.
293          *
294          * @result {@code true} when transfer_from message is acknowledged,
295          *         {@code false} otherwise.
296          */
297         bool handleTransferFrom(const BufferStatusMessage &message);
298 
299         /**
300          * Handles a transfer transaction result message from the receiver.
301          *
302          * @param message   a buffer status message for the transaction.
303          *
304          * @result {@code true} when the exisitng transaction is finished,
305          *         {@code false} otherwise.
306          */
307         bool handleTransferResult(const BufferStatusMessage &message);
308 
309         /**
310          * Handles a connection being closed, and returns the result. All the
311          * buffers and transactions owned by the connection will be cleaned up.
312          * The related FMQ will be cleaned up too.
313          *
314          * @param connectionId  the id of the connection.
315          *
316          * @result {@code true} when the connection existed,
317          *         {@code false} otherwise.
318          */
319         bool handleClose(ConnectionId connectionId);
320 
321         /**
322          * Recycles a existing free buffer if it is possible.
323          *
324          * @param allocator the buffer allocator
325          * @param params    the allocation parameters.
326          * @param pId       the id of the recycled buffer.
327          * @param handle    the native handle of the recycled buffer.
328          *
329          * @return {@code true} when a buffer is recycled, {@code false}
330          *         otherwise.
331          */
332         bool getFreeBuffer(
333                 const std::shared_ptr<BufferPoolAllocator> &allocator,
334                 const std::vector<uint8_t> &params,
335                 BufferId *pId, const native_handle_t **handle);
336 
337         /**
338          * Adds a newly allocated buffer to bufferpool.
339          *
340          * @param alloc     the newly allocated buffer.
341          * @param allocSize the size of the newly allocated buffer.
342          * @param params    the allocation parameters.
343          * @param pId       the buffer id for the newly allocated buffer.
344          * @param handle    the native handle for the newly allocated buffer.
345          *
346          * @return OK when an allocation is successfully allocated.
347          *         NO_MEMORY when there is no memory.
348          *         CRITICAL_ERROR otherwise.
349          */
350         ResultStatus addNewBuffer(
351                 const std::shared_ptr<BufferPoolAllocation> &alloc,
352                 const size_t allocSize,
353                 const std::vector<uint8_t> &params,
354                 BufferId *pId,
355                 const native_handle_t **handle);
356 
357         /**
358          * Processes pending buffer status messages and performs periodic cache
359          * cleaning.
360          *
361          * @param clearCache    if clearCache is true, it frees all buffers
362          *                      waiting to be recycled.
363          */
364         void cleanUp(bool clearCache = false);
365 
366         /**
367          * Processes pending buffer status messages and invalidate all current
368          * free buffers. Active buffers are invalidated after being inactive.
369          */
370         void flush(const std::shared_ptr<Accessor::Impl> &impl);
371 
372         friend class Accessor::Impl;
373     } mBufferPool;
374 
375     struct  AccessorInvalidator {
376         std::map<uint32_t, const std::weak_ptr<Accessor::Impl>> mAccessors;
377         std::mutex mMutex;
378         std::condition_variable mCv;
379         bool mReady;
380 
381         AccessorInvalidator();
382         void addAccessor(uint32_t accessorId, const std::weak_ptr<Accessor::Impl> &impl);
383         void delAccessor(uint32_t accessorId);
384     };
385 
386     static std::unique_ptr<AccessorInvalidator> sInvalidator;
387 
388     static void invalidatorThread(
389         std::map<uint32_t, const std::weak_ptr<Accessor::Impl>> &accessors,
390         std::mutex &mutex,
391         std::condition_variable &cv,
392         bool &ready);
393 };
394 
395 }  // namespace implementation
396 }  // namespace V2_0
397 }  // namespace ufferpool
398 }  // namespace media
399 }  // namespace hardware
400 }  // namespace android
401 
402 #endif  // ANDROID_HARDWARE_MEDIA_BUFFERPOOL_V2_0_ACCESSORIMPL_H
403