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      * getCurrentServingCall() == BinderCallType::HWBINDER to protect against the
39      * case where the construction is offloaded to another thread which isn't a
40      * hwbinder thread.
41      */
ClientPriority(int32_t score,int32_t state,bool isVendorClient)42     ClientPriority(int32_t score, int32_t state, bool isVendorClient) :
43             mScore(score), mState(state), mIsVendorClient(isVendorClient) { }
44 
getScore()45     int32_t getScore() const { return mScore; }
getState()46     int32_t getState() const { return mState; }
47 
setScore(int32_t score)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 
setState(int32_t state)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>
ClientDescriptor(const KEY & key,const VALUE & value,int32_t cost,const std::set<KEY> & conflictingKeys,int32_t score,int32_t ownerId,int32_t state,bool isVendorClient)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>
ClientDescriptor(KEY && key,VALUE && value,int32_t cost,std::set<KEY> && conflictingKeys,int32_t score,int32_t ownerId,int32_t state,bool isVendorClient)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>
~ClientDescriptor()194 ClientDescriptor<KEY, VALUE>::~ClientDescriptor() {}
195 
196 template<class KEY, class VALUE>
getKey()197 const KEY& ClientDescriptor<KEY, VALUE>::getKey() const {
198     return mKey;
199 }
200 
201 template<class KEY, class VALUE>
getValue()202 const VALUE& ClientDescriptor<KEY, VALUE>::getValue() const {
203     return mValue;
204 }
205 
206 template<class KEY, class VALUE>
getCost()207 int32_t ClientDescriptor<KEY, VALUE>::getCost() const {
208     return mCost;
209 }
210 
211 template<class KEY, class VALUE>
getPriority()212 const ClientPriority& ClientDescriptor<KEY, VALUE>::getPriority() const {
213     return mPriority;
214 }
215 
216 template<class KEY, class VALUE>
getOwnerId()217 int32_t ClientDescriptor<KEY, VALUE>::getOwnerId() const {
218     return mOwnerId;
219 }
220 
221 template<class KEY, class VALUE>
isConflicting(const KEY & key)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>
getConflicting()231 std::set<KEY> ClientDescriptor<KEY, VALUE>::getConflicting() const {
232     return mConflicting;
233 }
234 
235 template<class KEY, class VALUE>
setPriority(const ClientPriority & priority)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 getCurrentServingCall() == BinderCallType::HWBINDER 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>
onClientAdded(const ClientDescriptor<KEY,VALUE> &)259 void DefaultEventListener<KEY, VALUE>::onClientAdded(
260         const ClientDescriptor<KEY, VALUE>& /*descriptor*/) {}
261 
262 template<class KEY, class VALUE>
onClientRemoved(const ClientDescriptor<KEY,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>
ClientManager()419 ClientManager<KEY, VALUE, LISTENER>::ClientManager() :
420         ClientManager(DEFAULT_MAX_COST) {}
421 
422 template<class KEY, class VALUE, class LISTENER>
ClientManager(int32_t totalCost)423 ClientManager<KEY, VALUE, LISTENER>::ClientManager(int32_t totalCost) : mMaxCost(totalCost) {}
424 
425 template<class KEY, class VALUE, class LISTENER>
~ClientManager()426 ClientManager<KEY, VALUE, LISTENER>::~ClientManager() {}
427 
428 template<class KEY, class VALUE, class LISTENER>
429 std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>>
wouldEvict(const std::shared_ptr<ClientDescriptor<KEY,VALUE>> & client)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>>>
getIncompatibleClients(const std::shared_ptr<ClientDescriptor<KEY,VALUE>> & client)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>>>
wouldEvictLocked(const std::shared_ptr<ClientDescriptor<KEY,VALUE>> & client,bool returnIncompatibleClients)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 && owner == curOwner) {
500                 // Pre-existing conflicting client with the same client owner exists
501                 // Open the same device twice -> most recent open wins
502                 // Otherwise let the existing client wins to avoid behaviors difference
503                 // due to how HAL advertising conflicting devices (which is hidden from
504                 // application)
505                 if (curKey == key) {
506                     evictList.push_back(i);
507                     totalCost -= curCost;
508                 } else {
509                     evictList.clear();
510                     evictList.push_back(client);
511                     return evictList;
512                 }
513             } else if (conflicting || ((totalCost > mMaxCost && curCost > 0) &&
514                     (curPriority >= priority) &&
515                     !(highestPriorityOwner == owner && owner == curOwner))) {
516                 // Add a pre-existing client to the eviction list if:
517                 // - We are adding a client with higher priority that conflicts with this one.
518                 // - The total cost including the incoming client's is more than the allowable
519                 //   maximum, and the client has a non-zero cost, lower priority, and a different
520                 //   owner than the incoming client when the incoming client has the
521                 //   highest priority.
522                 evictList.push_back(i);
523                 totalCost -= curCost;
524             }
525         } else {
526             // Find clients preventing the incoming client from being added
527 
528             if (curPriority < priority && (conflicting || (totalCost > mMaxCost && curCost > 0))) {
529                 // Pre-existing conflicting client with higher priority exists
530                 evictList.push_back(i);
531             }
532         }
533     }
534 
535     // Immediately return the incompatible clients if we are calculating these instead
536     if (returnIncompatibleClients) {
537         return evictList;
538     }
539 
540     // If the total cost is too high, return the input unless the input has the highest priority
541     if (totalCost > mMaxCost && highestPriorityOwner != owner) {
542         evictList.clear();
543         evictList.push_back(client);
544         return evictList;
545     }
546 
547     return evictList;
548 
549 }
550 
551 template<class KEY, class VALUE, class LISTENER>
552 std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>>
addAndEvict(const std::shared_ptr<ClientDescriptor<KEY,VALUE>> & client)553 ClientManager<KEY, VALUE, LISTENER>::addAndEvict(
554         const std::shared_ptr<ClientDescriptor<KEY, VALUE>>& client) {
555     Mutex::Autolock lock(mLock);
556     auto evicted = wouldEvictLocked(client);
557     auto it = evicted.begin();
558     if (it != evicted.end() && *it == client) {
559         return evicted;
560     }
561 
562     auto iter = evicted.cbegin();
563 
564     if (iter != evicted.cend()) {
565 
566         if (mListener != nullptr) mListener->onClientRemoved(**iter);
567 
568         // Remove evicted clients from list
569         mClients.erase(std::remove_if(mClients.begin(), mClients.end(),
570             [&iter] (std::shared_ptr<ClientDescriptor<KEY, VALUE>>& curClientPtr) {
571                 if (curClientPtr->getKey() == (*iter)->getKey()) {
572                     iter++;
573                     return true;
574                 }
575                 return false;
576             }), mClients.end());
577     }
578 
579     if (mListener != nullptr) mListener->onClientAdded(*client);
580     mClients.push_back(client);
581     mRemovedCondition.broadcast();
582 
583     return evicted;
584 }
585 
586 template<class KEY, class VALUE, class LISTENER>
587 std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>>
getAll()588 ClientManager<KEY, VALUE, LISTENER>::getAll() const {
589     Mutex::Autolock lock(mLock);
590     return mClients;
591 }
592 
593 template<class KEY, class VALUE, class LISTENER>
getAllKeys()594 std::vector<KEY> ClientManager<KEY, VALUE, LISTENER>::getAllKeys() const {
595     Mutex::Autolock lock(mLock);
596     std::vector<KEY> keys(mClients.size());
597     for (const auto& i : mClients) {
598         keys.push_back(i->getKey());
599     }
600     return keys;
601 }
602 
603 template<class KEY, class VALUE, class LISTENER>
getAllOwners()604 std::vector<int32_t> ClientManager<KEY, VALUE, LISTENER>::getAllOwners() const {
605     Mutex::Autolock lock(mLock);
606     std::set<int32_t> owners;
607     for (const auto& i : mClients) {
608         owners.emplace(i->getOwnerId());
609     }
610     return std::vector<int32_t>(owners.begin(), owners.end());
611 }
612 
613 template<class KEY, class VALUE, class LISTENER>
updatePriorities(const std::map<int32_t,ClientPriority> & ownerPriorityList)614 void ClientManager<KEY, VALUE, LISTENER>::updatePriorities(
615         const std::map<int32_t,ClientPriority>& ownerPriorityList) {
616     Mutex::Autolock lock(mLock);
617     for (auto& i : mClients) {
618         auto j = ownerPriorityList.find(i->getOwnerId());
619         if (j != ownerPriorityList.end()) {
620             i->setPriority(j->second);
621         }
622     }
623 }
624 
625 template<class KEY, class VALUE, class LISTENER>
get(const KEY & key)626 std::shared_ptr<ClientDescriptor<KEY, VALUE>> ClientManager<KEY, VALUE, LISTENER>::get(
627         const KEY& key) const {
628     Mutex::Autolock lock(mLock);
629     for (const auto& i : mClients) {
630         if (i->getKey() == key) return i;
631     }
632     return std::shared_ptr<ClientDescriptor<KEY, VALUE>>(nullptr);
633 }
634 
635 template<class KEY, class VALUE, class LISTENER>
removeAll()636 void ClientManager<KEY, VALUE, LISTENER>::removeAll() {
637     Mutex::Autolock lock(mLock);
638     if (mListener != nullptr) {
639         for (const auto& i : mClients) {
640             mListener->onClientRemoved(*i);
641         }
642     }
643     mClients.clear();
644     mRemovedCondition.broadcast();
645 }
646 
647 template<class KEY, class VALUE, class LISTENER>
remove(const KEY & key)648 std::shared_ptr<ClientDescriptor<KEY, VALUE>> ClientManager<KEY, VALUE, LISTENER>::remove(
649     const KEY& key) {
650     Mutex::Autolock lock(mLock);
651 
652     std::shared_ptr<ClientDescriptor<KEY, VALUE>> ret;
653 
654     // Remove evicted clients from list
655     mClients.erase(std::remove_if(mClients.begin(), mClients.end(),
656         [this, &key, &ret] (std::shared_ptr<ClientDescriptor<KEY, VALUE>>& curClientPtr) {
657             if (curClientPtr->getKey() == key) {
658                 if (mListener != nullptr) mListener->onClientRemoved(*curClientPtr);
659                 ret = curClientPtr;
660                 return true;
661             }
662             return false;
663         }), mClients.end());
664 
665     mRemovedCondition.broadcast();
666     return ret;
667 }
668 
669 template<class KEY, class VALUE, class LISTENER>
waitUntilRemoved(const std::shared_ptr<ClientDescriptor<KEY,VALUE>> client,nsecs_t timeout)670 status_t ClientManager<KEY, VALUE, LISTENER>::waitUntilRemoved(
671         const std::shared_ptr<ClientDescriptor<KEY, VALUE>> client,
672         nsecs_t timeout) const {
673     status_t ret = NO_ERROR;
674     Mutex::Autolock lock(mLock);
675 
676     bool isRemoved = false;
677 
678     // Figure out what time in the future we should hit the timeout
679     nsecs_t failTime = systemTime(SYSTEM_TIME_MONOTONIC) + timeout;
680 
681     while (!isRemoved) {
682         isRemoved = true;
683         for (const auto& i : mClients) {
684             if (i == client) {
685                 isRemoved = false;
686             }
687         }
688 
689         if (!isRemoved) {
690             ret = mRemovedCondition.waitRelative(mLock, timeout);
691             if (ret != NO_ERROR) {
692                 break;
693             }
694             timeout = failTime - systemTime(SYSTEM_TIME_MONOTONIC);
695         }
696     }
697 
698     return ret;
699 }
700 
701 template<class KEY, class VALUE, class LISTENER>
setListener(const std::shared_ptr<LISTENER> & listener)702 void ClientManager<KEY, VALUE, LISTENER>::setListener(const std::shared_ptr<LISTENER>& listener) {
703     Mutex::Autolock lock(mLock);
704     mListener = listener;
705 }
706 
707 template<class KEY, class VALUE, class LISTENER>
remove(const std::shared_ptr<ClientDescriptor<KEY,VALUE>> & value)708 void ClientManager<KEY, VALUE, LISTENER>::remove(
709         const std::shared_ptr<ClientDescriptor<KEY, VALUE>>& value) {
710     Mutex::Autolock lock(mLock);
711     // Remove evicted clients from list
712     mClients.erase(std::remove_if(mClients.begin(), mClients.end(),
713         [this, &value] (std::shared_ptr<ClientDescriptor<KEY, VALUE>>& curClientPtr) {
714             if (curClientPtr == value) {
715                 if (mListener != nullptr) mListener->onClientRemoved(*curClientPtr);
716                 return true;
717             }
718             return false;
719         }), mClients.end());
720     mRemovedCondition.broadcast();
721 }
722 
723 template<class KEY, class VALUE, class LISTENER>
getCurrentCostLocked()724 int64_t ClientManager<KEY, VALUE, LISTENER>::getCurrentCostLocked() const {
725     int64_t totalCost = 0;
726     for (const auto& x : mClients) {
727             totalCost += x->getCost();
728     }
729     return totalCost;
730 }
731 
732 // --------------------------------------------------------------------------------
733 
734 }; // namespace resource_policy
735 }; // namespace android
736 
737 #endif // ANDROID_SERVICE_UTILS_EVICTION_POLICY_MANAGER_H
738