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