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>
ClientDescriptor(const KEY & key,const VALUE & value,int32_t cost,const std::set<KEY> & conflictingKeys,int32_t priority,int32_t ownerId)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>
ClientDescriptor(KEY && key,VALUE && value,int32_t cost,std::set<KEY> && conflictingKeys,int32_t priority,int32_t ownerId)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>
~ClientDescriptor()126 ClientDescriptor<KEY, VALUE>::~ClientDescriptor() {}
127 
128 template<class KEY, class VALUE>
getKey()129 const KEY& ClientDescriptor<KEY, VALUE>::getKey() const {
130     return mKey;
131 }
132 
133 template<class KEY, class VALUE>
getValue()134 const VALUE& ClientDescriptor<KEY, VALUE>::getValue() const {
135     return mValue;
136 }
137 
138 template<class KEY, class VALUE>
getCost()139 int32_t ClientDescriptor<KEY, VALUE>::getCost() const {
140     return mCost;
141 }
142 
143 template<class KEY, class VALUE>
getPriority()144 int32_t ClientDescriptor<KEY, VALUE>::getPriority() const {
145     return mPriority;
146 }
147 
148 template<class KEY, class VALUE>
getOwnerId()149 int32_t ClientDescriptor<KEY, VALUE>::getOwnerId() const {
150     return mOwnerId;
151 }
152 
153 template<class KEY, class VALUE>
isConflicting(const KEY & key)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>
getConflicting()163 std::set<KEY> ClientDescriptor<KEY, VALUE>::getConflicting() const {
164     return mConflicting;
165 }
166 
167 template<class KEY, class VALUE>
setPriority(int32_t priority)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>
onClientAdded(const ClientDescriptor<KEY,VALUE> &)185 void DefaultEventListener<KEY, VALUE>::onClientAdded(
186         const ClientDescriptor<KEY, VALUE>& /*descriptor*/) {}
187 
188 template<class KEY, class VALUE>
onClientRemoved(const ClientDescriptor<KEY,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>
ClientManager()345 ClientManager<KEY, VALUE, LISTENER>::ClientManager() :
346         ClientManager(DEFAULT_MAX_COST) {}
347 
348 template<class KEY, class VALUE, class LISTENER>
ClientManager(int32_t totalCost)349 ClientManager<KEY, VALUE, LISTENER>::ClientManager(int32_t totalCost) : mMaxCost(totalCost) {}
350 
351 template<class KEY, class VALUE, class LISTENER>
~ClientManager()352 ClientManager<KEY, VALUE, LISTENER>::~ClientManager() {}
353 
354 template<class KEY, class VALUE, class LISTENER>
355 std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>>
wouldEvict(const std::shared_ptr<ClientDescriptor<KEY,VALUE>> & client)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>>>
getIncompatibleClients(const std::shared_ptr<ClientDescriptor<KEY,VALUE>> & client)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>>>
wouldEvictLocked(const std::shared_ptr<ClientDescriptor<KEY,VALUE>> & client,bool returnIncompatibleClients)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>>>
addAndEvict(const std::shared_ptr<ClientDescriptor<KEY,VALUE>> & client)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>>>
getAll()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>
getAllKeys()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>
getAllOwners()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>
updatePriorities(const std::map<int32_t,int32_t> & ownerPriorityList)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>
get(const KEY & key)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>
removeAll()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>
remove(const KEY & key)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>
waitUntilRemoved(const std::shared_ptr<ClientDescriptor<KEY,VALUE>> client,nsecs_t timeout)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>
setListener(const std::shared_ptr<LISTENER> & 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>
remove(const std::shared_ptr<ClientDescriptor<KEY,VALUE>> & value)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>
getCurrentCostLocked()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