1 /* 2 * Copyright (C) 2015 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_SERVICE_UTILS_EVICTION_POLICY_MANAGER_H 18 #define ANDROID_SERVICE_UTILS_EVICTION_POLICY_MANAGER_H 19 20 #include <utils/Condition.h> 21 #include <utils/Mutex.h> 22 #include <utils/Timers.h> 23 24 #include <algorithm> 25 #include <utility> 26 #include <vector> 27 #include <set> 28 #include <map> 29 #include <memory> 30 31 namespace android { 32 namespace resource_policy { 33 34 class ClientPriority { 35 public: 36 /** 37 * Choosing to set mIsVendorClient through a parameter instead of calling 38 * hardware::IPCThreadState::self()->isServingCall() to protect against the 39 * case where the construction is offloaded to another thread which isn't a 40 * hwbinder thread. 41 */ 42 ClientPriority(int32_t score, int32_t state, bool isVendorClient) : 43 mScore(score), mState(state), mIsVendorClient(isVendorClient) { } 44 45 int32_t getScore() const { return mScore; } 46 int32_t getState() const { return mState; } 47 48 void setScore(int32_t score) { 49 // For vendor clients, the score is set once and for all during 50 // construction. Otherwise, it can get reset each time cameraserver 51 // queries ActivityManagerService for oom_adj scores / states . 52 if (!mIsVendorClient) { 53 mScore = score; 54 } 55 } 56 57 void setState(int32_t state) { 58 // For vendor clients, the score is set once and for all during 59 // construction. Otherwise, it can get reset each time cameraserver 60 // queries ActivityManagerService for oom_adj scores / states 61 // (ActivityManagerService returns a vendor process' state as 62 // PROCESS_STATE_NONEXISTENT. 63 if (!mIsVendorClient) { 64 mState = state; 65 } 66 } 67 68 bool operator==(const ClientPriority& rhs) const { 69 return (this->mScore == rhs.mScore) && (this->mState == rhs.mState); 70 } 71 72 bool operator< (const ClientPriority& rhs) const { 73 if (this->mScore == rhs.mScore) { 74 return this->mState < rhs.mState; 75 } else { 76 return this->mScore < rhs.mScore; 77 } 78 } 79 80 bool operator> (const ClientPriority& rhs) const { 81 return rhs < *this; 82 } 83 84 bool operator<=(const ClientPriority& rhs) const { 85 return !(*this > rhs); 86 } 87 88 bool operator>=(const ClientPriority& rhs) const { 89 return !(*this < rhs); 90 } 91 92 private: 93 int32_t mScore; 94 int32_t mState; 95 bool mIsVendorClient = false; 96 }; 97 98 // -------------------------------------------------------------------------------- 99 100 /** 101 * The ClientDescriptor class is a container for a given key/value pair identifying a shared 102 * resource, and the corresponding cost, priority, owner ID, and conflicting keys list used 103 * in determining eviction behavior. 104 * 105 * Aside from the priority, these values are immutable once the ClientDescriptor has been 106 * constructed. 107 */ 108 template<class KEY, class VALUE> 109 class ClientDescriptor final { 110 public: 111 ClientDescriptor(const KEY& key, const VALUE& value, int32_t cost, 112 const std::set<KEY>& conflictingKeys, int32_t score, int32_t ownerId, int32_t state, 113 bool isVendorClient); 114 ClientDescriptor(KEY&& key, VALUE&& value, int32_t cost, std::set<KEY>&& conflictingKeys, 115 int32_t score, int32_t ownerId, int32_t state, bool isVendorClient); 116 117 ~ClientDescriptor(); 118 119 /** 120 * Return the key for this descriptor. 121 */ 122 const KEY& getKey() const; 123 124 /** 125 * Return the value for this descriptor. 126 */ 127 const VALUE& getValue() const; 128 129 /** 130 * Return the cost for this descriptor. 131 */ 132 int32_t getCost() const; 133 134 /** 135 * Return the priority for this descriptor. 136 */ 137 const ClientPriority &getPriority() const; 138 139 /** 140 * Return the owner ID for this descriptor. 141 */ 142 int32_t getOwnerId() const; 143 144 /** 145 * Return true if the given key is in this descriptor's conflicting keys list. 146 */ 147 bool isConflicting(const KEY& key) const; 148 149 /** 150 * Return the set of all conflicting keys for this descriptor. 151 */ 152 std::set<KEY> getConflicting() const; 153 154 /** 155 * Set the proirity for this descriptor. 156 */ 157 void setPriority(const ClientPriority& priority); 158 159 // This class is ordered by key 160 template<class K, class V> 161 friend bool operator < (const ClientDescriptor<K, V>& a, const ClientDescriptor<K, V>& b); 162 163 private: 164 KEY mKey; 165 VALUE mValue; 166 int32_t mCost; 167 std::set<KEY> mConflicting; 168 ClientPriority mPriority; 169 int32_t mOwnerId; 170 }; // class ClientDescriptor 171 172 template<class K, class V> 173 bool operator < (const ClientDescriptor<K, V>& a, const ClientDescriptor<K, V>& b) { 174 return a.mKey < b.mKey; 175 } 176 177 template<class KEY, class VALUE> 178 ClientDescriptor<KEY, VALUE>::ClientDescriptor(const KEY& key, const VALUE& value, int32_t cost, 179 const std::set<KEY>& conflictingKeys, int32_t score, int32_t ownerId, int32_t state, 180 bool isVendorClient) : 181 mKey{key}, mValue{value}, mCost{cost}, mConflicting{conflictingKeys}, 182 mPriority(score, state, isVendorClient), 183 mOwnerId{ownerId} {} 184 185 template<class KEY, class VALUE> 186 ClientDescriptor<KEY, VALUE>::ClientDescriptor(KEY&& key, VALUE&& value, int32_t cost, 187 std::set<KEY>&& conflictingKeys, int32_t score, int32_t ownerId, int32_t state, 188 bool isVendorClient) : 189 mKey{std::forward<KEY>(key)}, mValue{std::forward<VALUE>(value)}, mCost{cost}, 190 mConflicting{std::forward<std::set<KEY>>(conflictingKeys)}, 191 mPriority(score, state, isVendorClient), mOwnerId{ownerId} {} 192 193 template<class KEY, class VALUE> 194 ClientDescriptor<KEY, VALUE>::~ClientDescriptor() {} 195 196 template<class KEY, class VALUE> 197 const KEY& ClientDescriptor<KEY, VALUE>::getKey() const { 198 return mKey; 199 } 200 201 template<class KEY, class VALUE> 202 const VALUE& ClientDescriptor<KEY, VALUE>::getValue() const { 203 return mValue; 204 } 205 206 template<class KEY, class VALUE> 207 int32_t ClientDescriptor<KEY, VALUE>::getCost() const { 208 return mCost; 209 } 210 211 template<class KEY, class VALUE> 212 const ClientPriority& ClientDescriptor<KEY, VALUE>::getPriority() const { 213 return mPriority; 214 } 215 216 template<class KEY, class VALUE> 217 int32_t ClientDescriptor<KEY, VALUE>::getOwnerId() const { 218 return mOwnerId; 219 } 220 221 template<class KEY, class VALUE> 222 bool ClientDescriptor<KEY, VALUE>::isConflicting(const KEY& key) const { 223 if (key == mKey) return true; 224 for (const auto& x : mConflicting) { 225 if (key == x) return true; 226 } 227 return false; 228 } 229 230 template<class KEY, class VALUE> 231 std::set<KEY> ClientDescriptor<KEY, VALUE>::getConflicting() const { 232 return mConflicting; 233 } 234 235 template<class KEY, class VALUE> 236 void ClientDescriptor<KEY, VALUE>::setPriority(const ClientPriority& priority) { 237 // We don't use the usual copy constructor here since we want to remember 238 // whether a client is a vendor client or not. This could have been wiped 239 // off in the incoming priority argument since an AIDL thread might have 240 // called hardware::IPCThreadState::self()->isServingCall() after refreshing 241 // priorities for old clients through ProcessInfoService::getProcessStatesScoresFromPids(). 242 mPriority.setScore(priority.getScore()); 243 mPriority.setState(priority.getState()); 244 } 245 246 // -------------------------------------------------------------------------------- 247 248 /** 249 * A default class implementing the LISTENER interface used by ClientManager. 250 */ 251 template<class KEY, class VALUE> 252 class DefaultEventListener { 253 public: 254 void onClientAdded(const ClientDescriptor<KEY, VALUE>& descriptor); 255 void onClientRemoved(const ClientDescriptor<KEY, VALUE>& descriptor); 256 }; 257 258 template<class KEY, class VALUE> 259 void DefaultEventListener<KEY, VALUE>::onClientAdded( 260 const ClientDescriptor<KEY, VALUE>& /*descriptor*/) {} 261 262 template<class KEY, class VALUE> 263 void DefaultEventListener<KEY, VALUE>::onClientRemoved( 264 const ClientDescriptor<KEY, VALUE>& /*descriptor*/) {} 265 266 // -------------------------------------------------------------------------------- 267 268 /** 269 * The ClientManager class wraps an LRU-ordered list of active clients and implements eviction 270 * behavior for handling shared resource access. 271 * 272 * When adding a new descriptor, eviction behavior is as follows: 273 * - Keys are unique, adding a descriptor with the same key as an existing descriptor will 274 * result in the lower-priority of the two being removed. Priority ties result in the 275 * LRU descriptor being evicted (this means the incoming descriptor be added in this case). 276 * - Any descriptors with keys that are in the incoming descriptor's 'conflicting keys' list 277 * will be removed if they have an equal or lower priority than the incoming descriptor; 278 * if any have a higher priority, the incoming descriptor is removed instead. 279 * - If the sum of all descriptors' costs, including the incoming descriptor's, is more than 280 * the max cost allowed for this ClientManager, descriptors with non-zero cost, equal or lower 281 * priority, and a different owner will be evicted in LRU order until either the cost is less 282 * than the max cost, or all descriptors meeting this criteria have been evicted and the 283 * incoming descriptor has the highest priority. Otherwise, the incoming descriptor is 284 * removed instead. 285 */ 286 template<class KEY, class VALUE, class LISTENER=DefaultEventListener<KEY, VALUE>> 287 class ClientManager { 288 public: 289 // The default maximum "cost" allowed before evicting 290 static constexpr int32_t DEFAULT_MAX_COST = 100; 291 292 ClientManager(); 293 explicit ClientManager(int32_t totalCost); 294 295 /** 296 * Add a given ClientDescriptor to the managed list. ClientDescriptors for clients that 297 * are evicted by this action are returned in a vector. 298 * 299 * This may return the ClientDescriptor passed in if it would be evicted. 300 */ 301 std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>> addAndEvict( 302 const std::shared_ptr<ClientDescriptor<KEY, VALUE>>& client); 303 304 /** 305 * Given a map containing owner (pid) -> priority mappings, update the priority of each 306 * ClientDescriptor with an owner in this mapping. 307 */ 308 void updatePriorities(const std::map<int32_t,ClientPriority>& ownerPriorityList); 309 310 /** 311 * Remove all ClientDescriptors. 312 */ 313 void removeAll(); 314 315 /** 316 * Remove and return the ClientDescriptor with a given key. 317 */ 318 std::shared_ptr<ClientDescriptor<KEY, VALUE>> remove(const KEY& key); 319 320 /** 321 * Remove the given ClientDescriptor. 322 */ 323 void remove(const std::shared_ptr<ClientDescriptor<KEY, VALUE>>& value); 324 325 /** 326 * Return a vector of the ClientDescriptors that would be evicted by adding the given 327 * ClientDescriptor. 328 * 329 * This may return the ClientDescriptor passed in if it would be evicted. 330 */ 331 std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>> wouldEvict( 332 const std::shared_ptr<ClientDescriptor<KEY, VALUE>>& client) const; 333 334 /** 335 * Return a vector of active ClientDescriptors that prevent this client from being added. 336 */ 337 std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>> getIncompatibleClients( 338 const std::shared_ptr<ClientDescriptor<KEY, VALUE>>& client) const; 339 340 /** 341 * Return a vector containing all currently active ClientDescriptors. 342 */ 343 std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>> getAll() const; 344 345 /** 346 * Return a vector containing all keys of currently active ClientDescriptors. 347 */ 348 std::vector<KEY> getAllKeys() const; 349 350 /** 351 * Return a vector of the owner tags of all currently active ClientDescriptors (duplicates 352 * will be removed). 353 */ 354 std::vector<int32_t> getAllOwners() const; 355 356 /** 357 * Return the ClientDescriptor corresponding to the given key, or an empty shared pointer 358 * if none exists. 359 */ 360 std::shared_ptr<ClientDescriptor<KEY, VALUE>> get(const KEY& key) const; 361 362 /** 363 * Block until the given client is no longer in the active clients list, or the timeout 364 * occurred. 365 * 366 * Returns NO_ERROR if this succeeded, -ETIMEDOUT on a timeout, or a negative error code on 367 * failure. 368 */ 369 status_t waitUntilRemoved(const std::shared_ptr<ClientDescriptor<KEY, VALUE>> client, 370 nsecs_t timeout) const; 371 372 /** 373 * Set the current listener for client add/remove events. 374 * 375 * The listener instance must inherit from the LISTENER class and implement the following 376 * methods: 377 * void onClientRemoved(const ClientDescriptor<KEY, VALUE>& descriptor); 378 * void onClientAdded(const ClientDescriptor<KEY, VALUE>& descriptor); 379 * 380 * These callback methods will be called with the ClientManager's lock held, and should 381 * not call any further ClientManager methods. 382 * 383 * The onClientRemoved method will be called when the client has been removed or evicted 384 * from the ClientManager that this event listener has been added to. The onClientAdded 385 * method will be called when the client has been added to the ClientManager that this 386 * event listener has been added to. 387 */ 388 void setListener(const std::shared_ptr<LISTENER>& listener); 389 390 protected: 391 ~ClientManager(); 392 393 private: 394 395 /** 396 * Return a vector of the ClientDescriptors that would be evicted by adding the given 397 * ClientDescriptor. If returnIncompatibleClients is set to true, instead, return the 398 * vector of ClientDescriptors that are higher priority than the incoming client and 399 * either conflict with this client, or contribute to the resource cost if that would 400 * prevent the incoming client from being added. 401 * 402 * This may return the ClientDescriptor passed in. 403 */ 404 std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>> wouldEvictLocked( 405 const std::shared_ptr<ClientDescriptor<KEY, VALUE>>& client, 406 bool returnIncompatibleClients = false) const; 407 408 int64_t getCurrentCostLocked() const; 409 410 mutable Mutex mLock; 411 mutable Condition mRemovedCondition; 412 int32_t mMaxCost; 413 // LRU ordered, most recent at end 414 std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>> mClients; 415 std::shared_ptr<LISTENER> mListener; 416 }; // class ClientManager 417 418 template<class KEY, class VALUE, class LISTENER> 419 ClientManager<KEY, VALUE, LISTENER>::ClientManager() : 420 ClientManager(DEFAULT_MAX_COST) {} 421 422 template<class KEY, class VALUE, class LISTENER> 423 ClientManager<KEY, VALUE, LISTENER>::ClientManager(int32_t totalCost) : mMaxCost(totalCost) {} 424 425 template<class KEY, class VALUE, class LISTENER> 426 ClientManager<KEY, VALUE, LISTENER>::~ClientManager() {} 427 428 template<class KEY, class VALUE, class LISTENER> 429 std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>> 430 ClientManager<KEY, VALUE, LISTENER>::wouldEvict( 431 const std::shared_ptr<ClientDescriptor<KEY, VALUE>>& client) const { 432 Mutex::Autolock lock(mLock); 433 return wouldEvictLocked(client); 434 } 435 436 template<class KEY, class VALUE, class LISTENER> 437 std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>> 438 ClientManager<KEY, VALUE, LISTENER>::getIncompatibleClients( 439 const std::shared_ptr<ClientDescriptor<KEY, VALUE>>& client) const { 440 Mutex::Autolock lock(mLock); 441 return wouldEvictLocked(client, /*returnIncompatibleClients*/true); 442 } 443 444 template<class KEY, class VALUE, class LISTENER> 445 std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>> 446 ClientManager<KEY, VALUE, LISTENER>::wouldEvictLocked( 447 const std::shared_ptr<ClientDescriptor<KEY, VALUE>>& client, 448 bool returnIncompatibleClients) const { 449 450 std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>> evictList; 451 452 // Disallow null clients, return input 453 if (client == nullptr) { 454 evictList.push_back(client); 455 return evictList; 456 } 457 458 const KEY& key = client->getKey(); 459 int32_t cost = client->getCost(); 460 ClientPriority priority = client->getPriority(); 461 int32_t owner = client->getOwnerId(); 462 463 int64_t totalCost = getCurrentCostLocked() + cost; 464 465 // Determine the MRU of the owners tied for having the highest priority 466 int32_t highestPriorityOwner = owner; 467 ClientPriority highestPriority = priority; 468 for (const auto& i : mClients) { 469 ClientPriority curPriority = i->getPriority(); 470 if (curPriority <= highestPriority) { 471 highestPriority = curPriority; 472 highestPriorityOwner = i->getOwnerId(); 473 } 474 } 475 476 if (highestPriority == priority) { 477 // Switch back owner if the incoming client has the highest priority, as it is MRU 478 highestPriorityOwner = owner; 479 } 480 481 // Build eviction list of clients to remove 482 for (const auto& i : mClients) { 483 const KEY& curKey = i->getKey(); 484 int32_t curCost = i->getCost(); 485 ClientPriority curPriority = i->getPriority(); 486 int32_t curOwner = i->getOwnerId(); 487 488 bool conflicting = (curKey == key || i->isConflicting(key) || 489 client->isConflicting(curKey)); 490 491 if (!returnIncompatibleClients) { 492 // Find evicted clients 493 494 if (conflicting && curPriority < priority) { 495 // Pre-existing conflicting client with higher priority exists 496 evictList.clear(); 497 evictList.push_back(client); 498 return evictList; 499 } else if (conflicting || ((totalCost > mMaxCost && curCost > 0) && 500 (curPriority >= priority) && 501 !(highestPriorityOwner == owner && owner == curOwner))) { 502 // Add a pre-existing client to the eviction list if: 503 // - We are adding a client with higher priority that conflicts with this one. 504 // - The total cost including the incoming client's is more than the allowable 505 // maximum, and the client has a non-zero cost, lower priority, and a different 506 // owner than the incoming client when the incoming client has the 507 // highest priority. 508 evictList.push_back(i); 509 totalCost -= curCost; 510 } 511 } else { 512 // Find clients preventing the incoming client from being added 513 514 if (curPriority < priority && (conflicting || (totalCost > mMaxCost && curCost > 0))) { 515 // Pre-existing conflicting client with higher priority exists 516 evictList.push_back(i); 517 } 518 } 519 } 520 521 // Immediately return the incompatible clients if we are calculating these instead 522 if (returnIncompatibleClients) { 523 return evictList; 524 } 525 526 // If the total cost is too high, return the input unless the input has the highest priority 527 if (totalCost > mMaxCost && highestPriorityOwner != owner) { 528 evictList.clear(); 529 evictList.push_back(client); 530 return evictList; 531 } 532 533 return evictList; 534 535 } 536 537 template<class KEY, class VALUE, class LISTENER> 538 std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>> 539 ClientManager<KEY, VALUE, LISTENER>::addAndEvict( 540 const std::shared_ptr<ClientDescriptor<KEY, VALUE>>& client) { 541 Mutex::Autolock lock(mLock); 542 auto evicted = wouldEvictLocked(client); 543 auto it = evicted.begin(); 544 if (it != evicted.end() && *it == client) { 545 return evicted; 546 } 547 548 auto iter = evicted.cbegin(); 549 550 if (iter != evicted.cend()) { 551 552 if (mListener != nullptr) mListener->onClientRemoved(**iter); 553 554 // Remove evicted clients from list 555 mClients.erase(std::remove_if(mClients.begin(), mClients.end(), 556 [&iter] (std::shared_ptr<ClientDescriptor<KEY, VALUE>>& curClientPtr) { 557 if (curClientPtr->getKey() == (*iter)->getKey()) { 558 iter++; 559 return true; 560 } 561 return false; 562 }), mClients.end()); 563 } 564 565 if (mListener != nullptr) mListener->onClientAdded(*client); 566 mClients.push_back(client); 567 mRemovedCondition.broadcast(); 568 569 return evicted; 570 } 571 572 template<class KEY, class VALUE, class LISTENER> 573 std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>> 574 ClientManager<KEY, VALUE, LISTENER>::getAll() const { 575 Mutex::Autolock lock(mLock); 576 return mClients; 577 } 578 579 template<class KEY, class VALUE, class LISTENER> 580 std::vector<KEY> ClientManager<KEY, VALUE, LISTENER>::getAllKeys() const { 581 Mutex::Autolock lock(mLock); 582 std::vector<KEY> keys(mClients.size()); 583 for (const auto& i : mClients) { 584 keys.push_back(i->getKey()); 585 } 586 return keys; 587 } 588 589 template<class KEY, class VALUE, class LISTENER> 590 std::vector<int32_t> ClientManager<KEY, VALUE, LISTENER>::getAllOwners() const { 591 Mutex::Autolock lock(mLock); 592 std::set<int32_t> owners; 593 for (const auto& i : mClients) { 594 owners.emplace(i->getOwnerId()); 595 } 596 return std::vector<int32_t>(owners.begin(), owners.end()); 597 } 598 599 template<class KEY, class VALUE, class LISTENER> 600 void ClientManager<KEY, VALUE, LISTENER>::updatePriorities( 601 const std::map<int32_t,ClientPriority>& ownerPriorityList) { 602 Mutex::Autolock lock(mLock); 603 for (auto& i : mClients) { 604 auto j = ownerPriorityList.find(i->getOwnerId()); 605 if (j != ownerPriorityList.end()) { 606 i->setPriority(j->second); 607 } 608 } 609 } 610 611 template<class KEY, class VALUE, class LISTENER> 612 std::shared_ptr<ClientDescriptor<KEY, VALUE>> ClientManager<KEY, VALUE, LISTENER>::get( 613 const KEY& key) const { 614 Mutex::Autolock lock(mLock); 615 for (const auto& i : mClients) { 616 if (i->getKey() == key) return i; 617 } 618 return std::shared_ptr<ClientDescriptor<KEY, VALUE>>(nullptr); 619 } 620 621 template<class KEY, class VALUE, class LISTENER> 622 void ClientManager<KEY, VALUE, LISTENER>::removeAll() { 623 Mutex::Autolock lock(mLock); 624 if (mListener != nullptr) { 625 for (const auto& i : mClients) { 626 mListener->onClientRemoved(*i); 627 } 628 } 629 mClients.clear(); 630 mRemovedCondition.broadcast(); 631 } 632 633 template<class KEY, class VALUE, class LISTENER> 634 std::shared_ptr<ClientDescriptor<KEY, VALUE>> ClientManager<KEY, VALUE, LISTENER>::remove( 635 const KEY& key) { 636 Mutex::Autolock lock(mLock); 637 638 std::shared_ptr<ClientDescriptor<KEY, VALUE>> ret; 639 640 // Remove evicted clients from list 641 mClients.erase(std::remove_if(mClients.begin(), mClients.end(), 642 [this, &key, &ret] (std::shared_ptr<ClientDescriptor<KEY, VALUE>>& curClientPtr) { 643 if (curClientPtr->getKey() == key) { 644 if (mListener != nullptr) mListener->onClientRemoved(*curClientPtr); 645 ret = curClientPtr; 646 return true; 647 } 648 return false; 649 }), mClients.end()); 650 651 mRemovedCondition.broadcast(); 652 return ret; 653 } 654 655 template<class KEY, class VALUE, class LISTENER> 656 status_t ClientManager<KEY, VALUE, LISTENER>::waitUntilRemoved( 657 const std::shared_ptr<ClientDescriptor<KEY, VALUE>> client, 658 nsecs_t timeout) const { 659 status_t ret = NO_ERROR; 660 Mutex::Autolock lock(mLock); 661 662 bool isRemoved = false; 663 664 // Figure out what time in the future we should hit the timeout 665 nsecs_t failTime = systemTime(SYSTEM_TIME_MONOTONIC) + timeout; 666 667 while (!isRemoved) { 668 isRemoved = true; 669 for (const auto& i : mClients) { 670 if (i == client) { 671 isRemoved = false; 672 } 673 } 674 675 if (!isRemoved) { 676 ret = mRemovedCondition.waitRelative(mLock, timeout); 677 if (ret != NO_ERROR) { 678 break; 679 } 680 timeout = failTime - systemTime(SYSTEM_TIME_MONOTONIC); 681 } 682 } 683 684 return ret; 685 } 686 687 template<class KEY, class VALUE, class LISTENER> 688 void ClientManager<KEY, VALUE, LISTENER>::setListener(const std::shared_ptr<LISTENER>& listener) { 689 Mutex::Autolock lock(mLock); 690 mListener = listener; 691 } 692 693 template<class KEY, class VALUE, class LISTENER> 694 void ClientManager<KEY, VALUE, LISTENER>::remove( 695 const std::shared_ptr<ClientDescriptor<KEY, VALUE>>& value) { 696 Mutex::Autolock lock(mLock); 697 // Remove evicted clients from list 698 mClients.erase(std::remove_if(mClients.begin(), mClients.end(), 699 [this, &value] (std::shared_ptr<ClientDescriptor<KEY, VALUE>>& curClientPtr) { 700 if (curClientPtr == value) { 701 if (mListener != nullptr) mListener->onClientRemoved(*curClientPtr); 702 return true; 703 } 704 return false; 705 }), mClients.end()); 706 mRemovedCondition.broadcast(); 707 } 708 709 template<class KEY, class VALUE, class LISTENER> 710 int64_t ClientManager<KEY, VALUE, LISTENER>::getCurrentCostLocked() const { 711 int64_t totalCost = 0; 712 for (const auto& x : mClients) { 713 totalCost += x->getCost(); 714 } 715 return totalCost; 716 } 717 718 // -------------------------------------------------------------------------------- 719 720 }; // namespace resource_policy 721 }; // namespace android 722 723 #endif // ANDROID_SERVICE_UTILS_EVICTION_POLICY_MANAGER_H 724