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