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