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 /// # of currently unused buffers buffersNotInUseBufferPool::Stats197 size_t buffersNotInUse() const { 198 ALOG_ASSERT(mBuffersCached >= mBuffersInUse); 199 return mBuffersCached - mBuffersInUse; 200 } 201 202 /// A new buffer is allocated on an allocation request. onBufferAllocatedBufferPool::Stats203 void onBufferAllocated(size_t allocSize) { 204 mSizeCached += allocSize; 205 mBuffersCached++; 206 207 mSizeInUse += allocSize; 208 mBuffersInUse++; 209 210 mTotalAllocations++; 211 } 212 213 /// A buffer is evicted and destroyed. onBufferEvictedBufferPool::Stats214 void onBufferEvicted(size_t allocSize) { 215 mSizeCached -= allocSize; 216 mBuffersCached--; 217 } 218 219 /// A buffer is recycled on an allocation request. onBufferRecycledBufferPool::Stats220 void onBufferRecycled(size_t allocSize) { 221 mSizeInUse += allocSize; 222 mBuffersInUse++; 223 224 mTotalAllocations++; 225 mTotalRecycles++; 226 } 227 228 /// A buffer is available to be recycled. onBufferUnusedBufferPool::Stats229 void onBufferUnused(size_t allocSize) { 230 mSizeInUse -= allocSize; 231 mBuffersInUse--; 232 } 233 234 /// A buffer transfer is initiated. onBufferSentBufferPool::Stats235 void onBufferSent() { 236 mTotalTransfers++; 237 } 238 239 /// A buffer fetch is invoked by a buffer transfer. onBufferFetchedBufferPool::Stats240 void onBufferFetched() { 241 mTotalFetches++; 242 } 243 } mStats; 244 isValidBufferPool245 bool isValid() { 246 return mValid; 247 } 248 249 void invalidate(bool needsAck, BufferId from, BufferId to, 250 const std::shared_ptr<Accessor::Impl> &impl); 251 252 static void createInvalidator(); 253 254 public: 255 /** Creates a buffer pool. */ 256 BufferPool(); 257 258 /** Destroys a buffer pool. */ 259 ~BufferPool(); 260 261 /** 262 * Processes all pending buffer status messages, and returns the result. 263 * Each status message is handled by methods with 'handle' prefix. 264 */ 265 void processStatusMessages(); 266 267 /** 268 * Handles a buffer being owned by a connection. 269 * 270 * @param connectionId the id of the buffer owning connection. 271 * @param bufferId the id of the buffer. 272 * 273 * @return {@code true} when the buffer is owned, 274 * {@code false} otherwise. 275 */ 276 bool handleOwnBuffer(ConnectionId connectionId, BufferId bufferId); 277 278 /** 279 * Handles a buffer being released by a connection. 280 * 281 * @param connectionId the id of the buffer owning connection. 282 * @param bufferId the id of the buffer. 283 * 284 * @return {@code true} when the buffer ownership is released, 285 * {@code false} otherwise. 286 */ 287 bool handleReleaseBuffer(ConnectionId connectionId, BufferId bufferId); 288 289 /** 290 * Handles a transfer transaction start message from the sender. 291 * 292 * @param message a buffer status message for the transaction. 293 * 294 * @result {@code true} when transfer_to message is acknowledged, 295 * {@code false} otherwise. 296 */ 297 bool handleTransferTo(const BufferStatusMessage &message); 298 299 /** 300 * Handles a transfer transaction being acked by the receiver. 301 * 302 * @param message a buffer status message for the transaction. 303 * 304 * @result {@code true} when transfer_from message is acknowledged, 305 * {@code false} otherwise. 306 */ 307 bool handleTransferFrom(const BufferStatusMessage &message); 308 309 /** 310 * Handles a transfer transaction result message from the receiver. 311 * 312 * @param message a buffer status message for the transaction. 313 * 314 * @result {@code true} when the exisitng transaction is finished, 315 * {@code false} otherwise. 316 */ 317 bool handleTransferResult(const BufferStatusMessage &message); 318 319 /** 320 * Handles a connection being closed, and returns the result. All the 321 * buffers and transactions owned by the connection will be cleaned up. 322 * The related FMQ will be cleaned up too. 323 * 324 * @param connectionId the id of the connection. 325 * 326 * @result {@code true} when the connection existed, 327 * {@code false} otherwise. 328 */ 329 bool handleClose(ConnectionId connectionId); 330 331 /** 332 * Recycles a existing free buffer if it is possible. 333 * 334 * @param allocator the buffer allocator 335 * @param params the allocation parameters. 336 * @param pId the id of the recycled buffer. 337 * @param handle the native handle of the recycled buffer. 338 * 339 * @return {@code true} when a buffer is recycled, {@code false} 340 * otherwise. 341 */ 342 bool getFreeBuffer( 343 const std::shared_ptr<BufferPoolAllocator> &allocator, 344 const std::vector<uint8_t> ¶ms, 345 BufferId *pId, const native_handle_t **handle); 346 347 /** 348 * Adds a newly allocated buffer to bufferpool. 349 * 350 * @param alloc the newly allocated buffer. 351 * @param allocSize the size of the newly allocated buffer. 352 * @param params the allocation parameters. 353 * @param pId the buffer id for the newly allocated buffer. 354 * @param handle the native handle for the newly allocated buffer. 355 * 356 * @return OK when an allocation is successfully allocated. 357 * NO_MEMORY when there is no memory. 358 * CRITICAL_ERROR otherwise. 359 */ 360 ResultStatus addNewBuffer( 361 const std::shared_ptr<BufferPoolAllocation> &alloc, 362 const size_t allocSize, 363 const std::vector<uint8_t> ¶ms, 364 BufferId *pId, 365 const native_handle_t **handle); 366 367 /** 368 * Processes pending buffer status messages and performs periodic cache 369 * cleaning. 370 * 371 * @param clearCache if clearCache is true, it frees all buffers 372 * waiting to be recycled. 373 */ 374 void cleanUp(bool clearCache = false); 375 376 /** 377 * Processes pending buffer status messages and invalidate all current 378 * free buffers. Active buffers are invalidated after being inactive. 379 */ 380 void flush(const std::shared_ptr<Accessor::Impl> &impl); 381 382 friend class Accessor::Impl; 383 } mBufferPool; 384 385 struct AccessorInvalidator { 386 std::map<uint32_t, const std::weak_ptr<Accessor::Impl>> mAccessors; 387 std::mutex mMutex; 388 std::condition_variable mCv; 389 bool mReady; 390 391 AccessorInvalidator(); 392 void addAccessor(uint32_t accessorId, const std::weak_ptr<Accessor::Impl> &impl); 393 void delAccessor(uint32_t accessorId); 394 }; 395 396 static std::unique_ptr<AccessorInvalidator> sInvalidator; 397 398 static void invalidatorThread( 399 std::map<uint32_t, const std::weak_ptr<Accessor::Impl>> &accessors, 400 std::mutex &mutex, 401 std::condition_variable &cv, 402 bool &ready); 403 404 struct AccessorEvictor { 405 std::map<const std::weak_ptr<Accessor::Impl>, nsecs_t, std::owner_less<>> mAccessors; 406 std::mutex mMutex; 407 std::condition_variable mCv; 408 409 AccessorEvictor(); 410 void addAccessor(const std::weak_ptr<Accessor::Impl> &impl, nsecs_t ts); 411 }; 412 413 static std::unique_ptr<AccessorEvictor> sEvictor; 414 415 static void evictorThread( 416 std::map<const std::weak_ptr<Accessor::Impl>, nsecs_t, std::owner_less<>> &accessors, 417 std::mutex &mutex, 418 std::condition_variable &cv); 419 420 void scheduleEvictIfNeeded(); 421 422 }; 423 424 } // namespace implementation 425 } // namespace V2_0 426 } // namespace ufferpool 427 } // namespace media 428 } // namespace hardware 429 } // namespace android 430 431 #endif // ANDROID_HARDWARE_MEDIA_BUFFERPOOL_V2_0_ACCESSORIMPL_H 432