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