blob: 1529a531df04b7885e03b5126998d2aeb809274e [file] [log] [blame]
Sungtak Lee76937c62022-12-07 11:42:03 +00001/*
2 * Copyright (C) 2022 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#pragma once
18
19#include <map>
20#include <set>
21#include <vector>
22#include <mutex>
23#include <condition_variable>
24#include <utils/Timers.h>
25
26#include "BufferStatus.h"
27
28namespace aidl::android::hardware::media::bufferpool2::implementation {
29
30using BufferStatus = aidl::android::hardware::media::bufferpool2::BufferStatus;
31using BufferStatusMessage = aidl::android::hardware::media::bufferpool2::BufferStatusMessage;
32
33struct Accessor;
34struct InternalBuffer;
35struct TransactionStatus;
36
37/**
38 * Buffer pool implementation.
39 *
40 * Handles buffer status messages. Handles buffer allocation/recycling.
41 * Handles buffer transfer between buffer pool clients.
42 */
43struct BufferPool {
44private:
45 std::mutex mMutex;
46 int64_t mTimestampMs;
47 int64_t mLastCleanUpMs;
48 int64_t mLastLogMs;
49 BufferId mSeq;
50 BufferId mStartSeq;
51 bool mValid;
52 BufferStatusObserver mObserver;
53 BufferInvalidationChannel mInvalidationChannel;
54
55 std::map<ConnectionId, std::set<BufferId>> mUsingBuffers;
56 std::map<BufferId, std::set<ConnectionId>> mUsingConnections;
57
58 std::map<ConnectionId, std::set<TransactionId>> mPendingTransactions;
59 // Transactions completed before TRANSFER_TO message arrival.
60 // Fetch does not occur for the transactions.
61 // Only transaction id is kept for the transactions in short duration.
62 std::set<TransactionId> mCompletedTransactions;
63 // Currently active(pending) transations' status & information.
64 std::map<TransactionId, std::unique_ptr<TransactionStatus>>
65 mTransactions;
66
67 std::map<BufferId, std::unique_ptr<InternalBuffer>> mBuffers;
68 std::set<BufferId> mFreeBuffers;
69 std::set<ConnectionId> mConnectionIds;
70
71 struct Invalidation {
72 static std::atomic<std::uint32_t> sInvSeqId;
73
74 struct Pending {
75 bool mNeedsAck;
76 uint32_t mFrom;
77 uint32_t mTo;
78 size_t mLeft;
79 const std::weak_ptr<Accessor> mImpl;
80 Pending(bool needsAck, uint32_t from, uint32_t to, size_t left,
81 const std::shared_ptr<Accessor> &impl)
82 : mNeedsAck(needsAck),
83 mFrom(from),
84 mTo(to),
85 mLeft(left),
86 mImpl(impl)
87 {}
88
89 bool isInvalidated(uint32_t bufferId) {
90 return isBufferInRange(mFrom, mTo, bufferId) && --mLeft == 0;
91 }
92 };
93
94 std::list<Pending> mPendings;
95 std::map<ConnectionId, uint32_t> mAcks;
96 std::map<ConnectionId, const std::shared_ptr<IObserver>> mObservers;
97 uint32_t mInvalidationId;
98 uint32_t mId;
99
100 Invalidation() : mInvalidationId(0), mId(sInvSeqId.fetch_add(1)) {}
101
102 void onConnect(ConnectionId conId, const std::shared_ptr<IObserver> &observer);
103
104 void onClose(ConnectionId conId);
105
106 void onAck(ConnectionId conId, uint32_t msgId);
107
108 void onBufferInvalidated(
109 BufferId bufferId,
110 BufferInvalidationChannel &channel);
111
112 void onInvalidationRequest(
113 bool needsAck, uint32_t from, uint32_t to, size_t left,
114 BufferInvalidationChannel &channel,
115 const std::shared_ptr<Accessor> &impl);
116
117 void onHandleAck(
118 std::map<ConnectionId, const std::shared_ptr<IObserver>> *observers,
119 uint32_t *invalidationId);
120 } mInvalidation;
121 /// Buffer pool statistics which tracks allocation and transfer statistics.
122 struct Stats {
123 /// Total size of allocations which are used or available to use.
124 /// (bytes or pixels)
125 size_t mSizeCached;
126 /// # of cached buffers which are used or available to use.
127 size_t mBuffersCached;
128 /// Total size of allocations which are currently used. (bytes or pixels)
129 size_t mSizeInUse;
130 /// # of currently used buffers
131 size_t mBuffersInUse;
132
133 /// # of allocations called on bufferpool. (# of fetched from BlockPool)
134 size_t mTotalAllocations;
135 /// # of allocations that were served from the cache.
136 /// (# of allocator alloc prevented)
137 size_t mTotalRecycles;
138 /// # of buffer transfers initiated.
139 size_t mTotalTransfers;
140 /// # of transfers that had to be fetched.
141 size_t mTotalFetches;
142
143 Stats()
144 : mSizeCached(0), mBuffersCached(0), mSizeInUse(0), mBuffersInUse(0),
145 mTotalAllocations(0), mTotalRecycles(0), mTotalTransfers(0), mTotalFetches(0) {}
146
147 /// # of currently unused buffers
148 size_t buffersNotInUse() const {
149 ALOG_ASSERT(mBuffersCached >= mBuffersInUse);
150 return mBuffersCached - mBuffersInUse;
151 }
152
153 /// A new buffer is allocated on an allocation request.
154 void onBufferAllocated(size_t allocSize) {
155 mSizeCached += allocSize;
156 mBuffersCached++;
157
158 mSizeInUse += allocSize;
159 mBuffersInUse++;
160
161 mTotalAllocations++;
162 }
163
164 /// A buffer is evicted and destroyed.
165 void onBufferEvicted(size_t allocSize) {
166 mSizeCached -= allocSize;
167 mBuffersCached--;
168 }
169
170 /// A buffer is recycled on an allocation request.
171 void onBufferRecycled(size_t allocSize) {
172 mSizeInUse += allocSize;
173 mBuffersInUse++;
174
175 mTotalAllocations++;
176 mTotalRecycles++;
177 }
178
179 /// A buffer is available to be recycled.
180 void onBufferUnused(size_t allocSize) {
181 mSizeInUse -= allocSize;
182 mBuffersInUse--;
183 }
184
185 /// A buffer transfer is initiated.
186 void onBufferSent() {
187 mTotalTransfers++;
188 }
189
190 /// A buffer fetch is invoked by a buffer transfer.
191 void onBufferFetched() {
192 mTotalFetches++;
193 }
194 } mStats;
195
196 bool isValid() {
197 return mValid;
198 }
199
200 void invalidate(bool needsAck, BufferId from, BufferId to,
201 const std::shared_ptr<Accessor> &impl);
202
203 static void createInvalidator();
204
205public:
206 /** Creates a buffer pool. */
207 BufferPool();
208
209 /** Destroys a buffer pool. */
210 ~BufferPool();
211
212 /**
213 * Processes all pending buffer status messages, and returns the result.
214 * Each status message is handled by methods with 'handle' prefix.
215 */
216 void processStatusMessages();
217
218 /**
219 * Handles a buffer being owned by a connection.
220 *
221 * @param connectionId the id of the buffer owning connection.
222 * @param bufferId the id of the buffer.
223 *
224 * @return {@code true} when the buffer is owned,
225 * {@code false} otherwise.
226 */
227 bool handleOwnBuffer(ConnectionId connectionId, BufferId bufferId);
228
229 /**
230 * Handles a buffer being released by a connection.
231 *
232 * @param connectionId the id of the buffer owning connection.
233 * @param bufferId the id of the buffer.
234 *
235 * @return {@code true} when the buffer ownership is released,
236 * {@code false} otherwise.
237 */
238 bool handleReleaseBuffer(ConnectionId connectionId, BufferId bufferId);
239
240 /**
241 * Handles a transfer transaction start message from the sender.
242 *
243 * @param message a buffer status message for the transaction.
244 *
245 * @result {@code true} when transfer_to message is acknowledged,
246 * {@code false} otherwise.
247 */
248 bool handleTransferTo(const BufferStatusMessage &message);
249
250 /**
251 * Handles a transfer transaction being acked by the receiver.
252 *
253 * @param message a buffer status message for the transaction.
254 *
255 * @result {@code true} when transfer_from message is acknowledged,
256 * {@code false} otherwise.
257 */
258 bool handleTransferFrom(const BufferStatusMessage &message);
259
260 /**
261 * Handles a transfer transaction result message from the receiver.
262 *
263 * @param message a buffer status message for the transaction.
264 *
265 * @result {@code true} when the existing transaction is finished,
266 * {@code false} otherwise.
267 */
268 bool handleTransferResult(const BufferStatusMessage &message);
269
270 /**
271 * Handles a connection being closed, and returns the result. All the
272 * buffers and transactions owned by the connection will be cleaned up.
273 * The related FMQ will be cleaned up too.
274 *
275 * @param connectionId the id of the connection.
276 *
277 * @result {@code true} when the connection existed,
278 * {@code false} otherwise.
279 */
280 bool handleClose(ConnectionId connectionId);
281
282 /**
283 * Recycles a existing free buffer if it is possible.
284 *
285 * @param allocator the buffer allocator
286 * @param params the allocation parameters.
287 * @param pId the id of the recycled buffer.
288 * @param handle the native handle of the recycled buffer.
289 *
290 * @return {@code true} when a buffer is recycled, {@code false}
291 * otherwise.
292 */
293 bool getFreeBuffer(
294 const std::shared_ptr<BufferPoolAllocator> &allocator,
295 const std::vector<uint8_t> &params,
296 BufferId *pId, const native_handle_t **handle);
297
298 /**
299 * Adds a newly allocated buffer to bufferpool.
300 *
301 * @param alloc the newly allocated buffer.
302 * @param allocSize the size of the newly allocated buffer.
303 * @param params the allocation parameters.
304 * @param pId the buffer id for the newly allocated buffer.
305 * @param handle the native handle for the newly allocated buffer.
306 *
307 * @return OK when an allocation is successfully allocated.
308 * NO_MEMORY when there is no memory.
309 * CRITICAL_ERROR otherwise.
310 */
311 BufferPoolStatus addNewBuffer(
312 const std::shared_ptr<BufferPoolAllocation> &alloc,
313 const size_t allocSize,
314 const std::vector<uint8_t> &params,
315 BufferId *pId,
316 const native_handle_t **handle);
317
318 /**
319 * Processes pending buffer status messages and performs periodic cache
320 * cleaning.
321 *
322 * @param clearCache if clearCache is true, it frees all buffers
323 * waiting to be recycled.
324 */
325 void cleanUp(bool clearCache = false);
326
327 /**
328 * Processes pending buffer status messages and invalidate all current
329 * free buffers. Active buffers are invalidated after being inactive.
330 */
331 void flush(const std::shared_ptr<Accessor> &impl);
332
333 friend struct Accessor;
334};
335
336
337} // namespace aidl::android::hardware::media::bufferpool2::implementation