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