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_V1_0_ACCESSORIMPL_H
18 #define ANDROID_HARDWARE_MEDIA_BUFFERPOOL_V1_0_ACCESSORIMPL_H
19 
20 #include <map>
21 #include <set>
22 #include "Accessor.h"
23 
24 namespace android {
25 namespace hardware {
26 namespace media {
27 namespace bufferpool {
28 namespace V1_0 {
29 namespace implementation {
30 
31 struct InternalBuffer;
32 struct TransactionStatus;
33 
34 /**
35  * An implementation of a buffer pool accessor(or a buffer pool implementation.) */
36 class Accessor::Impl {
37 public:
38     Impl(const std::shared_ptr<BufferPoolAllocator> &allocator);
39 
40     ~Impl();
41 
42     ResultStatus connect(
43             const sp<Accessor> &accessor, sp<Connection> *connection,
44             ConnectionId *pConnectionId, const QueueDescriptor** fmqDescPtr);
45 
46     ResultStatus close(ConnectionId connectionId);
47 
48     ResultStatus allocate(ConnectionId connectionId,
49                           const std::vector<uint8_t>& params,
50                           BufferId *bufferId,
51                           const native_handle_t** handle);
52 
53     ResultStatus fetch(ConnectionId connectionId,
54                        TransactionId transactionId,
55                        BufferId bufferId,
56                        const native_handle_t** handle);
57 
58     void cleanUp(bool clearCache);
59 
60 private:
61     // ConnectionId = pid : (timestamp_created + seqId)
62     // in order to guarantee uniqueness for each connection
63     static uint32_t sSeqId;
64     static int32_t sPid;
65 
66     const std::shared_ptr<BufferPoolAllocator> mAllocator;
67 
68     /**
69      * Buffer pool implementation.
70      *
71      * Handles buffer status messages. Handles buffer allocation/recycling.
72      * Handles buffer transfer between buffer pool clients.
73      */
74     struct BufferPool {
75     private:
76         std::mutex mMutex;
77         int64_t mTimestampUs;
78         int64_t mLastCleanUpUs;
79         int64_t mLastLogUs;
80         BufferId mSeq;
81         BufferStatusObserver mObserver;
82 
83         std::map<ConnectionId, std::set<BufferId>> mUsingBuffers;
84         std::map<BufferId, std::set<ConnectionId>> mUsingConnections;
85 
86         std::map<ConnectionId, std::set<TransactionId>> mPendingTransactions;
87         // Transactions completed before TRANSFER_TO message arrival.
88         // Fetch does not occur for the transactions.
89         // Only transaction id is kept for the transactions in short duration.
90         std::set<TransactionId> mCompletedTransactions;
91         // Currently active(pending) transations' status & information.
92         std::map<TransactionId, std::unique_ptr<TransactionStatus>>
93                 mTransactions;
94 
95         std::map<BufferId, std::unique_ptr<InternalBuffer>> mBuffers;
96         std::set<BufferId> mFreeBuffers;
97 
98         /// Buffer pool statistics which tracks allocation and transfer statistics.
99         struct Stats {
100             /// Total size of allocations which are used or available to use.
101             /// (bytes or pixels)
102             size_t mSizeCached;
103             /// # of cached buffers which are used or available to use.
104             size_t mBuffersCached;
105             /// Total size of allocations which are currently used. (bytes or pixels)
106             size_t mSizeInUse;
107             /// # of currently used buffers
108             size_t mBuffersInUse;
109 
110             /// # of allocations called on bufferpool. (# of fetched from BlockPool)
111             size_t mTotalAllocations;
112             /// # of allocations that were served from the cache.
113             /// (# of allocator alloc prevented)
114             size_t mTotalRecycles;
115             /// # of buffer transfers initiated.
116             size_t mTotalTransfers;
117             /// # of transfers that had to be fetched.
118             size_t mTotalFetches;
119 
StatsBufferPool::Stats120             Stats()
121                 : mSizeCached(0), mBuffersCached(0), mSizeInUse(0), mBuffersInUse(0),
122                   mTotalAllocations(0), mTotalRecycles(0), mTotalTransfers(0), mTotalFetches(0) {}
123 
124             /// A new buffer is allocated on an allocation request.
onBufferAllocatedBufferPool::Stats125             void onBufferAllocated(size_t allocSize) {
126                 mSizeCached += allocSize;
127                 mBuffersCached++;
128 
129                 mSizeInUse += allocSize;
130                 mBuffersInUse++;
131 
132                 mTotalAllocations++;
133             }
134 
135             /// A buffer is evicted and destroyed.
onBufferEvictedBufferPool::Stats136             void onBufferEvicted(size_t allocSize) {
137                 mSizeCached -= allocSize;
138                 mBuffersCached--;
139             }
140 
141             /// A buffer is recycled on an allocation request.
onBufferRecycledBufferPool::Stats142             void onBufferRecycled(size_t allocSize) {
143                 mSizeInUse += allocSize;
144                 mBuffersInUse++;
145 
146                 mTotalAllocations++;
147                 mTotalRecycles++;
148             }
149 
150             /// A buffer is available to be recycled.
onBufferUnusedBufferPool::Stats151             void onBufferUnused(size_t allocSize) {
152                 mSizeInUse -= allocSize;
153                 mBuffersInUse--;
154             }
155 
156             /// A buffer transfer is initiated.
onBufferSentBufferPool::Stats157             void onBufferSent() {
158                 mTotalTransfers++;
159             }
160 
161             /// A buffer fetch is invoked by a buffer transfer.
onBufferFetchedBufferPool::Stats162             void onBufferFetched() {
163                 mTotalFetches++;
164             }
165         } mStats;
166 
167     public:
168         /** Creates a buffer pool. */
169         BufferPool();
170 
171         /** Destroys a buffer pool. */
172         ~BufferPool();
173 
174         /**
175          * Processes all pending buffer status messages, and returns the result.
176          * Each status message is handled by methods with 'handle' prefix.
177          */
178         void processStatusMessages();
179 
180         /**
181          * Handles a buffer being owned by a connection.
182          *
183          * @param connectionId  the id of the buffer owning connection.
184          * @param bufferId      the id of the buffer.
185          *
186          * @return {@code true} when the buffer is owned,
187          *         {@code false} otherwise.
188          */
189         bool handleOwnBuffer(ConnectionId connectionId, BufferId bufferId);
190 
191         /**
192          * Handles a buffer being released by a connection.
193          *
194          * @param connectionId  the id of the buffer owning connection.
195          * @param bufferId      the id of the buffer.
196          *
197          * @return {@code true} when the buffer ownership is released,
198          *         {@code false} otherwise.
199          */
200         bool handleReleaseBuffer(ConnectionId connectionId, BufferId bufferId);
201 
202         /**
203          * Handles a transfer transaction start message from the sender.
204          *
205          * @param message   a buffer status message for the transaction.
206          *
207          * @result {@code true} when transfer_to message is acknowledged,
208          *         {@code false} otherwise.
209          */
210         bool handleTransferTo(const BufferStatusMessage &message);
211 
212         /**
213          * Handles a transfer transaction being acked by the receiver.
214          *
215          * @param message   a buffer status message for the transaction.
216          *
217          * @result {@code true} when transfer_from message is acknowledged,
218          *         {@code false} otherwise.
219          */
220         bool handleTransferFrom(const BufferStatusMessage &message);
221 
222         /**
223          * Handles a transfer transaction result message from the receiver.
224          *
225          * @param message   a buffer status message for the transaction.
226          *
227          * @result {@code true} when the exisitng transaction is finished,
228          *         {@code false} otherwise.
229          */
230         bool handleTransferResult(const BufferStatusMessage &message);
231 
232         /**
233          * Handles a connection being closed, and returns the result. All the
234          * buffers and transactions owned by the connection will be cleaned up.
235          * The related FMQ will be cleaned up too.
236          *
237          * @param connectionId  the id of the connection.
238          *
239          * @result {@code true} when the connection existed,
240          *         {@code false} otherwise.
241          */
242         bool handleClose(ConnectionId connectionId);
243 
244         /**
245          * Recycles a existing free buffer if it is possible.
246          *
247          * @param allocator the buffer allocator
248          * @param params    the allocation parameters.
249          * @param pId       the id of the recycled buffer.
250          * @param handle    the native handle of the recycled buffer.
251          *
252          * @return {@code true} when a buffer is recycled, {@code false}
253          *         otherwise.
254          */
255         bool getFreeBuffer(
256                 const std::shared_ptr<BufferPoolAllocator> &allocator,
257                 const std::vector<uint8_t> &params,
258                 BufferId *pId, const native_handle_t **handle);
259 
260         /**
261          * Adds a newly allocated buffer to bufferpool.
262          *
263          * @param alloc     the newly allocated buffer.
264          * @param allocSize the size of the newly allocated buffer.
265          * @param params    the allocation parameters.
266          * @param pId       the buffer id for the newly allocated buffer.
267          * @param handle    the native handle for the newly allocated buffer.
268          *
269          * @return OK when an allocation is successfully allocated.
270          *         NO_MEMORY when there is no memory.
271          *         CRITICAL_ERROR otherwise.
272          */
273         ResultStatus addNewBuffer(
274                 const std::shared_ptr<BufferPoolAllocation> &alloc,
275                 const size_t allocSize,
276                 const std::vector<uint8_t> &params,
277                 BufferId *pId,
278                 const native_handle_t **handle);
279 
280         /**
281          * Processes pending buffer status messages and performs periodic cache
282          * cleaning.
283          *
284          * @param clearCache    if clearCache is true, it frees all buffers
285          *                      waiting to be recycled.
286          */
287         void cleanUp(bool clearCache = false);
288 
289         friend class Accessor::Impl;
290     } mBufferPool;
291 };
292 
293 }  // namespace implementation
294 }  // namespace V1_0
295 }  // namespace ufferpool
296 }  // namespace media
297 }  // namespace hardware
298 }  // namespace android
299 
300 #endif  // ANDROID_HARDWARE_MEDIA_BUFFERPOOL_V1_0_ACCESSORIMPL_H
301