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> ¶ms, 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> ¶ms, 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