1 /* 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 28 namespace aidl::android::hardware::media::bufferpool2::implementation { 29 30 using BufferStatus = aidl::android::hardware::media::bufferpool2::BufferStatus; 31 using BufferStatusMessage = aidl::android::hardware::media::bufferpool2::BufferStatusMessage; 32 33 struct Accessor; 34 struct InternalBuffer; 35 struct 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 */ 43 struct BufferPool { 44 private: 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; PendingBufferPool::Invalidation::Pending80 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 isInvalidatedBufferPool::Invalidation::Pending89 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 InvalidationBufferPool::Invalidation100 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 StatsBufferPool::Stats143 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 buffersNotInUseBufferPool::Stats148 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. onBufferAllocatedBufferPool::Stats154 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. onBufferEvictedBufferPool::Stats165 void onBufferEvicted(size_t allocSize) { 166 mSizeCached -= allocSize; 167 mBuffersCached--; 168 } 169 170 /// A buffer is recycled on an allocation request. onBufferRecycledBufferPool::Stats171 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. onBufferUnusedBufferPool::Stats180 void onBufferUnused(size_t allocSize) { 181 mSizeInUse -= allocSize; 182 mBuffersInUse--; 183 } 184 185 /// A buffer transfer is initiated. onBufferSentBufferPool::Stats186 void onBufferSent() { 187 mTotalTransfers++; 188 } 189 190 /// A buffer fetch is invoked by a buffer transfer. onBufferFetchedBufferPool::Stats191 void onBufferFetched() { 192 mTotalFetches++; 193 } 194 } mStats; 195 isValidBufferPool196 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 205 public: 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> ¶ms, 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> ¶ms, 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 338