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 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