• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
ClientPriority(int32_t score,int32_t state)36     ClientPriority(int32_t score, int32_t state) :
37         mScore(score), mState(state) {}
38 
getScore()39     int32_t getScore() const { return mScore; }
getState()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 
66 private:
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  */
81 template<class KEY, class VALUE>
82 class ClientDescriptor final {
83 public:
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 
135 private:
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 
144 template<class K, class V>
145 bool operator < (const ClientDescriptor<K, V>& a, const ClientDescriptor<K, V>& b) {
146     return a.mKey < b.mKey;
147 }
148 
149 template<class KEY, class VALUE>
ClientDescriptor(const KEY & key,const VALUE & value,int32_t cost,const std::set<KEY> & conflictingKeys,int32_t score,int32_t ownerId,int32_t state)150 ClientDescriptor<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 
156 template<class KEY, class VALUE>
ClientDescriptor(KEY && key,VALUE && value,int32_t cost,std::set<KEY> && conflictingKeys,int32_t score,int32_t ownerId,int32_t state)157 ClientDescriptor<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 
163 template<class KEY, class VALUE>
~ClientDescriptor()164 ClientDescriptor<KEY, VALUE>::~ClientDescriptor() {}
165 
166 template<class KEY, class VALUE>
getKey()167 const KEY& ClientDescriptor<KEY, VALUE>::getKey() const {
168     return mKey;
169 }
170 
171 template<class KEY, class VALUE>
getValue()172 const VALUE& ClientDescriptor<KEY, VALUE>::getValue() const {
173     return mValue;
174 }
175 
176 template<class KEY, class VALUE>
getCost()177 int32_t ClientDescriptor<KEY, VALUE>::getCost() const {
178     return mCost;
179 }
180 
181 template<class KEY, class VALUE>
getPriority()182 const ClientPriority& ClientDescriptor<KEY, VALUE>::getPriority() const {
183     return mPriority;
184 }
185 
186 template<class KEY, class VALUE>
getOwnerId()187 int32_t ClientDescriptor<KEY, VALUE>::getOwnerId() const {
188     return mOwnerId;
189 }
190 
191 template<class KEY, class VALUE>
isConflicting(const KEY & key)192 bool 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 
200 template<class KEY, class VALUE>
getConflicting()201 std::set<KEY> ClientDescriptor<KEY, VALUE>::getConflicting() const {
202     return mConflicting;
203 }
204 
205 template<class KEY, class VALUE>
setPriority(const ClientPriority & priority)206 void 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  */
215 template<class KEY, class VALUE>
216 class DefaultEventListener {
217 public:
218     void onClientAdded(const ClientDescriptor<KEY, VALUE>& descriptor);
219     void onClientRemoved(const ClientDescriptor<KEY, VALUE>& descriptor);
220 };
221 
222 template<class KEY, class VALUE>
onClientAdded(const ClientDescriptor<KEY,VALUE> &)223 void DefaultEventListener<KEY, VALUE>::onClientAdded(
224         const ClientDescriptor<KEY, VALUE>& /*descriptor*/) {}
225 
226 template<class KEY, class VALUE>
onClientRemoved(const ClientDescriptor<KEY,VALUE> &)227 void 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  */
250 template<class KEY, class VALUE, class LISTENER=DefaultEventListener<KEY, VALUE>>
251 class ClientManager {
252 public:
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 
354 protected:
355     ~ClientManager();
356 
357 private:
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 
382 template<class KEY, class VALUE, class LISTENER>
ClientManager()383 ClientManager<KEY, VALUE, LISTENER>::ClientManager() :
384         ClientManager(DEFAULT_MAX_COST) {}
385 
386 template<class KEY, class VALUE, class LISTENER>
ClientManager(int32_t totalCost)387 ClientManager<KEY, VALUE, LISTENER>::ClientManager(int32_t totalCost) : mMaxCost(totalCost) {}
388 
389 template<class KEY, class VALUE, class LISTENER>
~ClientManager()390 ClientManager<KEY, VALUE, LISTENER>::~ClientManager() {}
391 
392 template<class KEY, class VALUE, class LISTENER>
393 std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>>
wouldEvict(const std::shared_ptr<ClientDescriptor<KEY,VALUE>> & client)394 ClientManager<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 
400 template<class KEY, class VALUE, class LISTENER>
401 std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>>
getIncompatibleClients(const std::shared_ptr<ClientDescriptor<KEY,VALUE>> & client)402 ClientManager<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 
408 template<class KEY, class VALUE, class LISTENER>
409 std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>>
wouldEvictLocked(const std::shared_ptr<ClientDescriptor<KEY,VALUE>> & client,bool returnIncompatibleClients)410 ClientManager<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 
501 template<class KEY, class VALUE, class LISTENER>
502 std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>>
addAndEvict(const std::shared_ptr<ClientDescriptor<KEY,VALUE>> & client)503 ClientManager<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 
536 template<class KEY, class VALUE, class LISTENER>
537 std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>>
getAll()538 ClientManager<KEY, VALUE, LISTENER>::getAll() const {
539     Mutex::Autolock lock(mLock);
540     return mClients;
541 }
542 
543 template<class KEY, class VALUE, class LISTENER>
getAllKeys()544 std::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 
553 template<class KEY, class VALUE, class LISTENER>
getAllOwners()554 std::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 
563 template<class KEY, class VALUE, class LISTENER>
updatePriorities(const std::map<int32_t,ClientPriority> & ownerPriorityList)564 void 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 
575 template<class KEY, class VALUE, class LISTENER>
get(const KEY & key)576 std::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 
585 template<class KEY, class VALUE, class LISTENER>
removeAll()586 void 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 
597 template<class KEY, class VALUE, class LISTENER>
remove(const KEY & key)598 std::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 
619 template<class KEY, class VALUE, class LISTENER>
waitUntilRemoved(const std::shared_ptr<ClientDescriptor<KEY,VALUE>> client,nsecs_t timeout)620 status_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 
651 template<class KEY, class VALUE, class LISTENER>
setListener(const std::shared_ptr<LISTENER> & listener)652 void ClientManager<KEY, VALUE, LISTENER>::setListener(const std::shared_ptr<LISTENER>& listener) {
653     Mutex::Autolock lock(mLock);
654     mListener = listener;
655 }
656 
657 template<class KEY, class VALUE, class LISTENER>
remove(const std::shared_ptr<ClientDescriptor<KEY,VALUE>> & value)658 void 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 
673 template<class KEY, class VALUE, class LISTENER>
getCurrentCostLocked()674 int64_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