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 115 struct Invalidation { 116 static std::atomic<std::uint32_t> sInvSeqId; 117 118 struct Pending { 119 bool mNeedsAck; 120 uint32_t mFrom; 121 uint32_t mTo; 122 size_t mLeft; 123 const std::weak_ptr<Accessor::Impl> mImpl; PendingBufferPool::Invalidation::Pending124 Pending(bool needsAck, uint32_t from, uint32_t to, size_t left, 125 const std::shared_ptr<Accessor::Impl> &impl) 126 : mNeedsAck(needsAck), 127 mFrom(from), 128 mTo(to), 129 mLeft(left), 130 mImpl(impl) 131 {} 132 isInvalidatedBufferPool::Invalidation::Pending133 bool isInvalidated(uint32_t bufferId) { 134 return isBufferInRange(mFrom, mTo, bufferId) && --mLeft == 0; 135 } 136 }; 137 138 std::list<Pending> mPendings; 139 std::map<ConnectionId, uint32_t> mAcks; 140 std::map<ConnectionId, const sp<IObserver>> mObservers; 141 uint32_t mInvalidationId; 142 uint32_t mId; 143 InvalidationBufferPool::Invalidation144 Invalidation() : mInvalidationId(0), mId(sInvSeqId.fetch_add(1)) {} 145 146 void onConnect(ConnectionId conId, const sp<IObserver> &observer); 147 148 void onClose(ConnectionId conId); 149 150 void onAck(ConnectionId conId, uint32_t msgId); 151 152 void onBufferInvalidated( 153 BufferId bufferId, 154 BufferInvalidationChannel &channel); 155 156 void onInvalidationRequest( 157 bool needsAck, uint32_t from, uint32_t to, size_t left, 158 BufferInvalidationChannel &channel, 159 const std::shared_ptr<Accessor::Impl> &impl); 160 161 void onHandleAck( 162 std::map<ConnectionId, const sp<IObserver>> *observers, 163 uint32_t *invalidationId); 164 } mInvalidation; 165 /// Buffer pool statistics which tracks allocation and transfer statistics. 166 struct Stats { 167 /// Total size of allocations which are used or available to use. 168 /// (bytes or pixels) 169 size_t mSizeCached; 170 /// # of cached buffers which are used or available to use. 171 size_t mBuffersCached; 172 /// Total size of allocations which are currently used. (bytes or pixels) 173 size_t mSizeInUse; 174 /// # of currently used buffers 175 size_t mBuffersInUse; 176 177 /// # of allocations called on bufferpool. (# of fetched from BlockPool) 178 size_t mTotalAllocations; 179 /// # of allocations that were served from the cache. 180 /// (# of allocator alloc prevented) 181 size_t mTotalRecycles; 182 /// # of buffer transfers initiated. 183 size_t mTotalTransfers; 184 /// # of transfers that had to be fetched. 185 size_t mTotalFetches; 186 StatsBufferPool::Stats187 Stats() 188 : mSizeCached(0), mBuffersCached(0), mSizeInUse(0), mBuffersInUse(0), 189 mTotalAllocations(0), mTotalRecycles(0), mTotalTransfers(0), mTotalFetches(0) {} 190 191 /// A new buffer is allocated on an allocation request. onBufferAllocatedBufferPool::Stats192 void onBufferAllocated(size_t allocSize) { 193 mSizeCached += allocSize; 194 mBuffersCached++; 195 196 mSizeInUse += allocSize; 197 mBuffersInUse++; 198 199 mTotalAllocations++; 200 } 201 202 /// A buffer is evicted and destroyed. onBufferEvictedBufferPool::Stats203 void onBufferEvicted(size_t allocSize) { 204 mSizeCached -= allocSize; 205 mBuffersCached--; 206 } 207 208 /// A buffer is recycled on an allocation request. onBufferRecycledBufferPool::Stats209 void onBufferRecycled(size_t allocSize) { 210 mSizeInUse += allocSize; 211 mBuffersInUse++; 212 213 mTotalAllocations++; 214 mTotalRecycles++; 215 } 216 217 /// A buffer is available to be recycled. onBufferUnusedBufferPool::Stats218 void onBufferUnused(size_t allocSize) { 219 mSizeInUse -= allocSize; 220 mBuffersInUse--; 221 } 222 223 /// A buffer transfer is initiated. onBufferSentBufferPool::Stats224 void onBufferSent() { 225 mTotalTransfers++; 226 } 227 228 /// A buffer fetch is invoked by a buffer transfer. onBufferFetchedBufferPool::Stats229 void onBufferFetched() { 230 mTotalFetches++; 231 } 232 } mStats; 233 isValidBufferPool234 bool isValid() { 235 return mValid; 236 } 237 238 void invalidate(bool needsAck, BufferId from, BufferId to, 239 const std::shared_ptr<Accessor::Impl> &impl); 240 241 static void createInvalidator(); 242 243 public: 244 /** Creates a buffer pool. */ 245 BufferPool(); 246 247 /** Destroys a buffer pool. */ 248 ~BufferPool(); 249 250 /** 251 * Processes all pending buffer status messages, and returns the result. 252 * Each status message is handled by methods with 'handle' prefix. 253 */ 254 void processStatusMessages(); 255 256 /** 257 * Handles a buffer being owned by a connection. 258 * 259 * @param connectionId the id of the buffer owning connection. 260 * @param bufferId the id of the buffer. 261 * 262 * @return {@code true} when the buffer is owned, 263 * {@code false} otherwise. 264 */ 265 bool handleOwnBuffer(ConnectionId connectionId, BufferId bufferId); 266 267 /** 268 * Handles a buffer being released 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 ownership is released, 274 * {@code false} otherwise. 275 */ 276 bool handleReleaseBuffer(ConnectionId connectionId, BufferId bufferId); 277 278 /** 279 * Handles a transfer transaction start message from the sender. 280 * 281 * @param message a buffer status message for the transaction. 282 * 283 * @result {@code true} when transfer_to message is acknowledged, 284 * {@code false} otherwise. 285 */ 286 bool handleTransferTo(const BufferStatusMessage &message); 287 288 /** 289 * Handles a transfer transaction being acked by the receiver. 290 * 291 * @param message a buffer status message for the transaction. 292 * 293 * @result {@code true} when transfer_from message is acknowledged, 294 * {@code false} otherwise. 295 */ 296 bool handleTransferFrom(const BufferStatusMessage &message); 297 298 /** 299 * Handles a transfer transaction result message from the receiver. 300 * 301 * @param message a buffer status message for the transaction. 302 * 303 * @result {@code true} when the exisitng transaction is finished, 304 * {@code false} otherwise. 305 */ 306 bool handleTransferResult(const BufferStatusMessage &message); 307 308 /** 309 * Handles a connection being closed, and returns the result. All the 310 * buffers and transactions owned by the connection will be cleaned up. 311 * The related FMQ will be cleaned up too. 312 * 313 * @param connectionId the id of the connection. 314 * 315 * @result {@code true} when the connection existed, 316 * {@code false} otherwise. 317 */ 318 bool handleClose(ConnectionId connectionId); 319 320 /** 321 * Recycles a existing free buffer if it is possible. 322 * 323 * @param allocator the buffer allocator 324 * @param params the allocation parameters. 325 * @param pId the id of the recycled buffer. 326 * @param handle the native handle of the recycled buffer. 327 * 328 * @return {@code true} when a buffer is recycled, {@code false} 329 * otherwise. 330 */ 331 bool getFreeBuffer( 332 const std::shared_ptr<BufferPoolAllocator> &allocator, 333 const std::vector<uint8_t> ¶ms, 334 BufferId *pId, const native_handle_t **handle); 335 336 /** 337 * Adds a newly allocated buffer to bufferpool. 338 * 339 * @param alloc the newly allocated buffer. 340 * @param allocSize the size of the newly allocated buffer. 341 * @param params the allocation parameters. 342 * @param pId the buffer id for the newly allocated buffer. 343 * @param handle the native handle for the newly allocated buffer. 344 * 345 * @return OK when an allocation is successfully allocated. 346 * NO_MEMORY when there is no memory. 347 * CRITICAL_ERROR otherwise. 348 */ 349 ResultStatus addNewBuffer( 350 const std::shared_ptr<BufferPoolAllocation> &alloc, 351 const size_t allocSize, 352 const std::vector<uint8_t> ¶ms, 353 BufferId *pId, 354 const native_handle_t **handle); 355 356 /** 357 * Processes pending buffer status messages and performs periodic cache 358 * cleaning. 359 * 360 * @param clearCache if clearCache is true, it frees all buffers 361 * waiting to be recycled. 362 */ 363 void cleanUp(bool clearCache = false); 364 365 /** 366 * Processes pending buffer status messages and invalidate all current 367 * free buffers. Active buffers are invalidated after being inactive. 368 */ 369 void flush(const std::shared_ptr<Accessor::Impl> &impl); 370 371 friend class Accessor::Impl; 372 } mBufferPool; 373 374 struct AccessorInvalidator { 375 std::map<uint32_t, const std::weak_ptr<Accessor::Impl>> mAccessors; 376 std::mutex mMutex; 377 std::condition_variable mCv; 378 bool mReady; 379 380 AccessorInvalidator(); 381 void addAccessor(uint32_t accessorId, const std::weak_ptr<Accessor::Impl> &impl); 382 void delAccessor(uint32_t accessorId); 383 }; 384 385 static std::unique_ptr<AccessorInvalidator> sInvalidator; 386 387 static void invalidatorThread( 388 std::map<uint32_t, const std::weak_ptr<Accessor::Impl>> &accessors, 389 std::mutex &mutex, 390 std::condition_variable &cv, 391 bool &ready); 392 }; 393 394 } // namespace implementation 395 } // namespace V2_0 396 } // namespace ufferpool 397 } // namespace media 398 } // namespace hardware 399 } // namespace android 400 401 #endif // ANDROID_HARDWARE_MEDIA_BUFFERPOOL_V2_0_ACCESSORIMPL_H 402