• 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 // Values from frameworks/base/services/core/java/com/android/server/am/ProcessList.java
35 const int32_t INVALID_ADJ = -10000;
36 const int32_t UNKNOWN_ADJ = 1001;
37 const int32_t CACHED_APP_MAX_ADJ = 999;
38 const int32_t CACHED_APP_MIN_ADJ = 900;
39 const int32_t CACHED_APP_LMK_FIRST_ADJ = 950;
40 const int32_t CACHED_APP_IMPORTANCE_LEVELS = 5;
41 const int32_t SERVICE_B_ADJ = 800;
42 const int32_t PREVIOUS_APP_ADJ = 700;
43 const int32_t HOME_APP_ADJ = 600;
44 const int32_t SERVICE_ADJ = 500;
45 const int32_t HEAVY_WEIGHT_APP_ADJ = 400;
46 const int32_t BACKUP_APP_ADJ = 300;
47 const int32_t PERCEPTIBLE_LOW_APP_ADJ = 250;
48 const int32_t PERCEPTIBLE_MEDIUM_APP_ADJ = 225;
49 const int32_t PERCEPTIBLE_APP_ADJ = 200;
50 const int32_t VISIBLE_APP_ADJ = 100;
51 const int32_t VISIBLE_APP_LAYER_MAX = PERCEPTIBLE_APP_ADJ - VISIBLE_APP_ADJ - 1;
52 const int32_t PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ = 50;
53 const int32_t FOREGROUND_APP_ADJ = 0;
54 const int32_t PERSISTENT_SERVICE_ADJ = -700;
55 const int32_t PERSISTENT_PROC_ADJ = -800;
56 const int32_t SYSTEM_ADJ = -900;
57 const int32_t NATIVE_ADJ = -1000;
58 
59 class ClientPriority {
60 public:
61     /**
62      * Choosing to set mIsVendorClient through a parameter instead of calling
63      * getCurrentServingCall() == BinderCallType::HWBINDER to protect against the
64      * case where the construction is offloaded to another thread which isn't a
65      * hwbinder thread.
66      */
67     ClientPriority(int32_t score, int32_t state, bool isVendorClient, int32_t scoreOffset = 0) :
mIsVendorClient(isVendorClient)68             mIsVendorClient(isVendorClient), mScoreOffset(scoreOffset) {
69         setScore(score);
70         setState(state);
71     }
72 
getScore()73     int32_t getScore() const { return mScore; }
getState()74     int32_t getState() const { return mState; }
isVendorClient()75     int32_t isVendorClient() const { return mIsVendorClient; }
76 
setScore(int32_t score)77     void setScore(int32_t score) {
78         // For vendor clients, the score is set once and for all during
79         // construction. Otherwise, it can get reset each time cameraserver
80         // queries ActivityManagerService for oom_adj scores / states .
81         // For clients where the score offset is set by the app, add it to the
82         // score provided by ActivityManagerService.
83         if (score == INVALID_ADJ) {
84             mScore = UNKNOWN_ADJ;
85         } else {
86             mScore = mScoreOffset + score;
87         }
88     }
89 
setState(int32_t state)90     void setState(int32_t state) {
91       // For vendor clients, the score is set once and for all during
92       // construction. Otherwise, it can get reset each time cameraserver
93       // queries ActivityManagerService for oom_adj scores / states
94       // (ActivityManagerService returns a vendor process' state as
95       // PROCESS_STATE_NONEXISTENT.
96       mState = state;
97     }
98 
99     bool operator==(const ClientPriority& rhs) const {
100         return (this->mScore == rhs.mScore) && (this->mState == rhs.mState);
101     }
102 
103     bool operator< (const ClientPriority& rhs)  const {
104         if (this->mScore == rhs.mScore) {
105             return this->mState < rhs.mState;
106         } else {
107             return this->mScore < rhs.mScore;
108         }
109     }
110 
111     bool operator> (const ClientPriority& rhs) const {
112         return rhs < *this;
113     }
114 
115     bool operator<=(const ClientPriority& rhs) const {
116         return !(*this > rhs);
117     }
118 
119     bool operator>=(const ClientPriority& rhs) const {
120         return !(*this < rhs);
121     }
122 
123 private:
124         int32_t mScore;
125         int32_t mState;
126         bool mIsVendorClient = false;
127         int32_t mScoreOffset = 0;
128 };
129 
130 // --------------------------------------------------------------------------------
131 
132 /**
133  * The ClientDescriptor class is a container for a given key/value pair identifying a shared
134  * resource, and the corresponding cost, priority, owner ID, and conflicting keys list used
135  * in determining eviction behavior.
136  *
137  * Aside from the priority, these values are immutable once the ClientDescriptor has been
138  * constructed.
139  */
140 template<class KEY, class VALUE>
141 class ClientDescriptor final {
142 public:
143     ClientDescriptor(const KEY& key, const VALUE& value, int32_t cost,
144             const std::set<KEY>& conflictingKeys, int32_t score, int32_t ownerId, int32_t state,
145             bool isVendorClient, int32_t oomScoreOffset);
146     ClientDescriptor(KEY&& key, VALUE&& value, int32_t cost, std::set<KEY>&& conflictingKeys,
147             int32_t score, int32_t ownerId, int32_t state, bool isVendorClient,
148             int32_t oomScoreOffset);
149 
150     ~ClientDescriptor();
151 
152     /**
153      * Return the key for this descriptor.
154      */
155     const KEY& getKey() const;
156 
157     /**
158      * Return the value for this descriptor.
159      */
160     const VALUE& getValue() const;
161 
162     /**
163      * Return the cost for this descriptor.
164      */
165     int32_t getCost() const;
166 
167     /**
168      * Return the priority for this descriptor.
169      */
170     const ClientPriority &getPriority() const;
171 
172     /**
173      * Return the owner ID for this descriptor.
174      */
175     int32_t getOwnerId() const;
176 
177     /**
178      * Return true if the given key is in this descriptor's conflicting keys list.
179      */
180     bool isConflicting(const KEY& key) const;
181 
182     /**
183      * Return the set of all conflicting keys for this descriptor.
184      */
185     std::set<KEY> getConflicting() const;
186 
187     /**
188      * Set the proirity for this descriptor.
189      */
190     void setPriority(const ClientPriority& priority);
191 
192     // This class is ordered by key
193     template<class K, class V>
194     friend bool operator < (const ClientDescriptor<K, V>& a, const ClientDescriptor<K, V>& b);
195 
196 private:
197     KEY mKey;
198     VALUE mValue;
199     int32_t mCost;
200     std::set<KEY> mConflicting;
201     ClientPriority mPriority;
202     int32_t mOwnerId;
203 }; // class ClientDescriptor
204 
205 template<class K, class V>
206 bool operator < (const ClientDescriptor<K, V>& a, const ClientDescriptor<K, V>& b) {
207     return a.mKey < b.mKey;
208 }
209 
210 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,int32_t scoreOffset)211 ClientDescriptor<KEY, VALUE>::ClientDescriptor(const KEY& key, const VALUE& value, int32_t cost,
212         const std::set<KEY>& conflictingKeys, int32_t score, int32_t ownerId, int32_t state,
213         bool isVendorClient, int32_t scoreOffset) :
214         mKey{key}, mValue{value}, mCost{cost}, mConflicting{conflictingKeys},
215         mPriority(score, state, isVendorClient, scoreOffset),
216         mOwnerId{ownerId} {}
217 
218 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,int32_t scoreOffset)219 ClientDescriptor<KEY, VALUE>::ClientDescriptor(KEY&& key, VALUE&& value, int32_t cost,
220         std::set<KEY>&& conflictingKeys, int32_t score, int32_t ownerId, int32_t state,
221         bool isVendorClient, int32_t scoreOffset) :
222         mKey{std::forward<KEY>(key)}, mValue{std::forward<VALUE>(value)}, mCost{cost},
223         mConflicting{std::forward<std::set<KEY>>(conflictingKeys)},
224         mPriority(score, state, isVendorClient, scoreOffset), mOwnerId{ownerId} {}
225 
226 template<class KEY, class VALUE>
~ClientDescriptor()227 ClientDescriptor<KEY, VALUE>::~ClientDescriptor() {}
228 
229 template<class KEY, class VALUE>
getKey()230 const KEY& ClientDescriptor<KEY, VALUE>::getKey() const {
231     return mKey;
232 }
233 
234 template<class KEY, class VALUE>
getValue()235 const VALUE& ClientDescriptor<KEY, VALUE>::getValue() const {
236     return mValue;
237 }
238 
239 template<class KEY, class VALUE>
getCost()240 int32_t ClientDescriptor<KEY, VALUE>::getCost() const {
241     return mCost;
242 }
243 
244 template<class KEY, class VALUE>
getPriority()245 const ClientPriority& ClientDescriptor<KEY, VALUE>::getPriority() const {
246     return mPriority;
247 }
248 
249 template<class KEY, class VALUE>
getOwnerId()250 int32_t ClientDescriptor<KEY, VALUE>::getOwnerId() const {
251     return mOwnerId;
252 }
253 
254 template<class KEY, class VALUE>
isConflicting(const KEY & key)255 bool ClientDescriptor<KEY, VALUE>::isConflicting(const KEY& key) const {
256     if (key == mKey) return true;
257     for (const auto& x : mConflicting) {
258         if (key == x) return true;
259     }
260     return false;
261 }
262 
263 template<class KEY, class VALUE>
getConflicting()264 std::set<KEY> ClientDescriptor<KEY, VALUE>::getConflicting() const {
265     return mConflicting;
266 }
267 
268 template<class KEY, class VALUE>
setPriority(const ClientPriority & priority)269 void ClientDescriptor<KEY, VALUE>::setPriority(const ClientPriority& priority) {
270     // We don't use the usual copy constructor here since we want to remember
271     // whether a client is a vendor client or not. This could have been wiped
272     // off in the incoming priority argument since an AIDL thread might have
273     // called getCurrentServingCall() == BinderCallType::HWBINDER after refreshing
274     // priorities for old clients through ProcessInfoService::getProcessStatesScoresFromPids().
275     if (mPriority.isVendorClient()) {
276         return;
277     }
278     mPriority.setScore(priority.getScore());
279     mPriority.setState(priority.getState());
280 }
281 
282 // --------------------------------------------------------------------------------
283 
284 /**
285  * A default class implementing the LISTENER interface used by ClientManager.
286  */
287 template<class KEY, class VALUE>
288 class DefaultEventListener {
289 public:
290     void onClientAdded(const ClientDescriptor<KEY, VALUE>& descriptor);
291     void onClientRemoved(const ClientDescriptor<KEY, VALUE>& descriptor);
292 };
293 
294 template<class KEY, class VALUE>
onClientAdded(const ClientDescriptor<KEY,VALUE> &)295 void DefaultEventListener<KEY, VALUE>::onClientAdded(
296         const ClientDescriptor<KEY, VALUE>& /*descriptor*/) {}
297 
298 template<class KEY, class VALUE>
onClientRemoved(const ClientDescriptor<KEY,VALUE> &)299 void DefaultEventListener<KEY, VALUE>::onClientRemoved(
300         const ClientDescriptor<KEY, VALUE>& /*descriptor*/) {}
301 
302 // --------------------------------------------------------------------------------
303 
304 /**
305  * The ClientManager class wraps an LRU-ordered list of active clients and implements eviction
306  * behavior for handling shared resource access.
307  *
308  * When adding a new descriptor, eviction behavior is as follows:
309  *   - Keys are unique, adding a descriptor with the same key as an existing descriptor will
310  *     result in the lower-priority of the two being removed.  Priority ties result in the
311  *     LRU descriptor being evicted (this means the incoming descriptor be added in this case).
312  *   - Any descriptors with keys that are in the incoming descriptor's 'conflicting keys' list
313  *     will be removed if they have an equal or lower priority than the incoming descriptor;
314  *     if any have a higher priority, the incoming descriptor is removed instead.
315  *   - If the sum of all descriptors' costs, including the incoming descriptor's, is more than
316  *     the max cost allowed for this ClientManager, descriptors with non-zero cost, equal or lower
317  *     priority, and a different owner will be evicted in LRU order until either the cost is less
318  *     than the max cost, or all descriptors meeting this criteria have been evicted and the
319  *     incoming descriptor has the highest priority.  Otherwise, the incoming descriptor is
320  *     removed instead.
321  */
322 template<class KEY, class VALUE, class LISTENER=DefaultEventListener<KEY, VALUE>>
323 class ClientManager {
324 public:
325     // The default maximum "cost" allowed before evicting
326     static constexpr int32_t DEFAULT_MAX_COST = 100;
327 
328     ClientManager();
329     explicit ClientManager(int32_t totalCost);
330 
331     /**
332      * Add a given ClientDescriptor to the managed list.  ClientDescriptors for clients that
333      * are evicted by this action are returned in a vector.
334      *
335      * This may return the ClientDescriptor passed in if it would be evicted.
336      */
337     std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>> addAndEvict(
338             const std::shared_ptr<ClientDescriptor<KEY, VALUE>>& client);
339 
340     /**
341      * Given a map containing owner (pid) -> priority mappings, update the priority of each
342      * ClientDescriptor with an owner in this mapping.
343      */
344     void updatePriorities(const std::map<int32_t,ClientPriority>& ownerPriorityList);
345 
346     /**
347      * Remove all ClientDescriptors.
348      */
349     void removeAll();
350 
351     /**
352      * Remove and return the ClientDescriptor with a given key.
353      */
354     std::shared_ptr<ClientDescriptor<KEY, VALUE>> remove(const KEY& key);
355 
356     /**
357      * Remove the given ClientDescriptor.
358      */
359     void remove(const std::shared_ptr<ClientDescriptor<KEY, VALUE>>& value);
360 
361     /**
362      * Return a vector of the ClientDescriptors that would be evicted by adding the given
363      * ClientDescriptor.
364      *
365      * This may return the ClientDescriptor passed in if it would be evicted.
366      */
367     std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>> wouldEvict(
368             const std::shared_ptr<ClientDescriptor<KEY, VALUE>>& client) const;
369 
370     /**
371      * Return a vector of active ClientDescriptors that prevent this client from being added.
372      */
373     std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>> getIncompatibleClients(
374             const std::shared_ptr<ClientDescriptor<KEY, VALUE>>& client) const;
375 
376     /**
377      * Return a vector containing all currently active ClientDescriptors.
378      */
379     std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>> getAll() const;
380 
381     /**
382      * Return a vector containing all keys of currently active ClientDescriptors.
383      */
384     std::vector<KEY> getAllKeys() const;
385 
386     /**
387      * Return a vector of the owner tags of all currently active ClientDescriptors (duplicates
388      * will be removed).
389      */
390     std::vector<int32_t> getAllOwners() const;
391 
392     /**
393      * Return the ClientDescriptor corresponding to the given key, or an empty shared pointer
394      * if none exists.
395      */
396     std::shared_ptr<ClientDescriptor<KEY, VALUE>> get(const KEY& key) const;
397 
398     /**
399      * Block until the given client is no longer in the active clients list, or the timeout
400      * occurred.
401      *
402      * Returns NO_ERROR if this succeeded, -ETIMEDOUT on a timeout, or a negative error code on
403      * failure.
404      */
405     status_t waitUntilRemoved(const std::shared_ptr<ClientDescriptor<KEY, VALUE>> client,
406             nsecs_t timeout) const;
407 
408     /**
409      * Set the current listener for client add/remove events.
410      *
411      * The listener instance must inherit from the LISTENER class and implement the following
412      * methods:
413      *    void onClientRemoved(const ClientDescriptor<KEY, VALUE>& descriptor);
414      *    void onClientAdded(const ClientDescriptor<KEY, VALUE>& descriptor);
415      *
416      * These callback methods will be called with the ClientManager's lock held, and should
417      * not call any further ClientManager methods.
418      *
419      * The onClientRemoved method will be called when the client has been removed or evicted
420      * from the ClientManager that this event listener has been added to. The onClientAdded
421      * method will be called when the client has been added to the ClientManager that this
422      * event listener has been added to.
423      */
424     void setListener(const std::shared_ptr<LISTENER>& listener);
425 
426 protected:
427     ~ClientManager();
428 
429 private:
430 
431     /**
432      * Return a vector of the ClientDescriptors that would be evicted by adding the given
433      * ClientDescriptor.  If returnIncompatibleClients is set to true, instead, return the
434      * vector of ClientDescriptors that are higher priority than the incoming client and
435      * either conflict with this client, or contribute to the resource cost if that would
436      * prevent the incoming client from being added.
437      *
438      * This may return the ClientDescriptor passed in.
439      */
440     std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>> wouldEvictLocked(
441             const std::shared_ptr<ClientDescriptor<KEY, VALUE>>& client,
442             bool returnIncompatibleClients = false) const;
443 
444     int64_t getCurrentCostLocked() const;
445 
446     mutable Mutex mLock;
447     mutable Condition mRemovedCondition;
448     int32_t mMaxCost;
449     // LRU ordered, most recent at end
450     std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>> mClients;
451     std::shared_ptr<LISTENER> mListener;
452 }; // class ClientManager
453 
454 template<class KEY, class VALUE, class LISTENER>
ClientManager()455 ClientManager<KEY, VALUE, LISTENER>::ClientManager() :
456         ClientManager(DEFAULT_MAX_COST) {}
457 
458 template<class KEY, class VALUE, class LISTENER>
ClientManager(int32_t totalCost)459 ClientManager<KEY, VALUE, LISTENER>::ClientManager(int32_t totalCost) : mMaxCost(totalCost) {}
460 
461 template<class KEY, class VALUE, class LISTENER>
~ClientManager()462 ClientManager<KEY, VALUE, LISTENER>::~ClientManager() {}
463 
464 template<class KEY, class VALUE, class LISTENER>
465 std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>>
wouldEvict(const std::shared_ptr<ClientDescriptor<KEY,VALUE>> & client)466 ClientManager<KEY, VALUE, LISTENER>::wouldEvict(
467         const std::shared_ptr<ClientDescriptor<KEY, VALUE>>& client) const {
468     Mutex::Autolock lock(mLock);
469     return wouldEvictLocked(client);
470 }
471 
472 template<class KEY, class VALUE, class LISTENER>
473 std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>>
getIncompatibleClients(const std::shared_ptr<ClientDescriptor<KEY,VALUE>> & client)474 ClientManager<KEY, VALUE, LISTENER>::getIncompatibleClients(
475         const std::shared_ptr<ClientDescriptor<KEY, VALUE>>& client) const {
476     Mutex::Autolock lock(mLock);
477     return wouldEvictLocked(client, /*returnIncompatibleClients*/true);
478 }
479 
480 template<class KEY, class VALUE, class LISTENER>
481 std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>>
wouldEvictLocked(const std::shared_ptr<ClientDescriptor<KEY,VALUE>> & client,bool returnIncompatibleClients)482 ClientManager<KEY, VALUE, LISTENER>::wouldEvictLocked(
483         const std::shared_ptr<ClientDescriptor<KEY, VALUE>>& client,
484         bool returnIncompatibleClients) const {
485 
486     std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>> evictList;
487 
488     // Disallow null clients, return input
489     if (client == nullptr) {
490         evictList.push_back(client);
491         return evictList;
492     }
493 
494     const KEY& key = client->getKey();
495     int32_t cost = client->getCost();
496     ClientPriority priority = client->getPriority();
497     int32_t owner = client->getOwnerId();
498 
499     int64_t totalCost = getCurrentCostLocked() + cost;
500 
501     // Determine the MRU of the owners tied for having the highest priority
502     int32_t highestPriorityOwner = owner;
503     ClientPriority highestPriority = priority;
504     for (const auto& i : mClients) {
505         ClientPriority curPriority = i->getPriority();
506         if (curPriority <= highestPriority) {
507             highestPriority = curPriority;
508             highestPriorityOwner = i->getOwnerId();
509         }
510     }
511 
512     if (highestPriority == priority) {
513         // Switch back owner if the incoming client has the highest priority, as it is MRU
514         highestPriorityOwner = owner;
515     }
516 
517     // Build eviction list of clients to remove
518     for (const auto& i : mClients) {
519         const KEY& curKey = i->getKey();
520         int32_t curCost = i->getCost();
521         ClientPriority curPriority = i->getPriority();
522         int32_t curOwner = i->getOwnerId();
523 
524         bool conflicting = (curKey == key || i->isConflicting(key) ||
525                 client->isConflicting(curKey));
526 
527         if (!returnIncompatibleClients) {
528             // Find evicted clients
529 
530             if (conflicting && curPriority < priority) {
531                 // Pre-existing conflicting client with higher priority exists
532                 evictList.clear();
533                 evictList.push_back(client);
534                 return evictList;
535             } else if (conflicting && owner == curOwner) {
536                 // Pre-existing conflicting client with the same client owner exists
537                 // Open the same device twice -> most recent open wins
538                 // Otherwise let the existing client wins to avoid behaviors difference
539                 // due to how HAL advertising conflicting devices (which is hidden from
540                 // application)
541                 if (curKey == key) {
542                     evictList.push_back(i);
543                     totalCost -= curCost;
544                 } else {
545                     evictList.clear();
546                     evictList.push_back(client);
547                     return evictList;
548                 }
549             } else if (conflicting || ((totalCost > mMaxCost && curCost > 0) &&
550                     (curPriority >= priority) &&
551                     !(highestPriorityOwner == owner && owner == curOwner))) {
552                 // Add a pre-existing client to the eviction list if:
553                 // - We are adding a client with higher priority that conflicts with this one.
554                 // - The total cost including the incoming client's is more than the allowable
555                 //   maximum, and the client has a non-zero cost, lower priority, and a different
556                 //   owner than the incoming client when the incoming client has the
557                 //   highest priority.
558                 evictList.push_back(i);
559                 totalCost -= curCost;
560             }
561         } else {
562             // Find clients preventing the incoming client from being added
563 
564             if (curPriority < priority && (conflicting || (totalCost > mMaxCost && curCost > 0))) {
565                 // Pre-existing conflicting client with higher priority exists
566                 evictList.push_back(i);
567             }
568         }
569     }
570 
571     // Immediately return the incompatible clients if we are calculating these instead
572     if (returnIncompatibleClients) {
573         return evictList;
574     }
575 
576     // If the total cost is too high, return the input unless the input has the highest priority
577     if (totalCost > mMaxCost && highestPriorityOwner != owner) {
578         evictList.clear();
579         evictList.push_back(client);
580         return evictList;
581     }
582 
583     return evictList;
584 
585 }
586 
587 template<class KEY, class VALUE, class LISTENER>
588 std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>>
addAndEvict(const std::shared_ptr<ClientDescriptor<KEY,VALUE>> & client)589 ClientManager<KEY, VALUE, LISTENER>::addAndEvict(
590         const std::shared_ptr<ClientDescriptor<KEY, VALUE>>& client) {
591     Mutex::Autolock lock(mLock);
592     auto evicted = wouldEvictLocked(client);
593     auto it = evicted.begin();
594     if (it != evicted.end() && *it == client) {
595         return evicted;
596     }
597 
598     auto iter = evicted.cbegin();
599 
600     if (iter != evicted.cend()) {
601 
602         if (mListener != nullptr) mListener->onClientRemoved(**iter);
603 
604         // Remove evicted clients from list
605         mClients.erase(std::remove_if(mClients.begin(), mClients.end(),
606             [&iter] (std::shared_ptr<ClientDescriptor<KEY, VALUE>>& curClientPtr) {
607                 if (curClientPtr->getKey() == (*iter)->getKey()) {
608                     iter++;
609                     return true;
610                 }
611                 return false;
612             }), mClients.end());
613     }
614 
615     if (mListener != nullptr) mListener->onClientAdded(*client);
616     mClients.push_back(client);
617     mRemovedCondition.broadcast();
618 
619     return evicted;
620 }
621 
622 template<class KEY, class VALUE, class LISTENER>
623 std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>>
getAll()624 ClientManager<KEY, VALUE, LISTENER>::getAll() const {
625     Mutex::Autolock lock(mLock);
626     return mClients;
627 }
628 
629 template<class KEY, class VALUE, class LISTENER>
getAllKeys()630 std::vector<KEY> ClientManager<KEY, VALUE, LISTENER>::getAllKeys() const {
631     Mutex::Autolock lock(mLock);
632     std::vector<KEY> keys(mClients.size());
633     for (const auto& i : mClients) {
634         keys.push_back(i->getKey());
635     }
636     return keys;
637 }
638 
639 template<class KEY, class VALUE, class LISTENER>
getAllOwners()640 std::vector<int32_t> ClientManager<KEY, VALUE, LISTENER>::getAllOwners() const {
641     Mutex::Autolock lock(mLock);
642     std::set<int32_t> owners;
643     for (const auto& i : mClients) {
644         owners.emplace(i->getOwnerId());
645     }
646     return std::vector<int32_t>(owners.begin(), owners.end());
647 }
648 
649 template<class KEY, class VALUE, class LISTENER>
updatePriorities(const std::map<int32_t,ClientPriority> & ownerPriorityList)650 void ClientManager<KEY, VALUE, LISTENER>::updatePriorities(
651         const std::map<int32_t,ClientPriority>& ownerPriorityList) {
652     Mutex::Autolock lock(mLock);
653     for (auto& i : mClients) {
654         auto j = ownerPriorityList.find(i->getOwnerId());
655         if (j != ownerPriorityList.end()) {
656             i->setPriority(j->second);
657         }
658     }
659 }
660 
661 template<class KEY, class VALUE, class LISTENER>
get(const KEY & key)662 std::shared_ptr<ClientDescriptor<KEY, VALUE>> ClientManager<KEY, VALUE, LISTENER>::get(
663         const KEY& key) const {
664     Mutex::Autolock lock(mLock);
665     for (const auto& i : mClients) {
666         if (i->getKey() == key) return i;
667     }
668     return std::shared_ptr<ClientDescriptor<KEY, VALUE>>(nullptr);
669 }
670 
671 template<class KEY, class VALUE, class LISTENER>
removeAll()672 void ClientManager<KEY, VALUE, LISTENER>::removeAll() {
673     Mutex::Autolock lock(mLock);
674     if (mListener != nullptr) {
675         for (const auto& i : mClients) {
676             mListener->onClientRemoved(*i);
677         }
678     }
679     mClients.clear();
680     mRemovedCondition.broadcast();
681 }
682 
683 template<class KEY, class VALUE, class LISTENER>
remove(const KEY & key)684 std::shared_ptr<ClientDescriptor<KEY, VALUE>> ClientManager<KEY, VALUE, LISTENER>::remove(
685     const KEY& key) {
686     Mutex::Autolock lock(mLock);
687 
688     std::shared_ptr<ClientDescriptor<KEY, VALUE>> ret;
689 
690     // Remove evicted clients from list
691     mClients.erase(std::remove_if(mClients.begin(), mClients.end(),
692         [this, &key, &ret] (std::shared_ptr<ClientDescriptor<KEY, VALUE>>& curClientPtr) {
693             if (curClientPtr->getKey() == key) {
694                 if (mListener != nullptr) mListener->onClientRemoved(*curClientPtr);
695                 ret = curClientPtr;
696                 return true;
697             }
698             return false;
699         }), mClients.end());
700 
701     mRemovedCondition.broadcast();
702     return ret;
703 }
704 
705 template<class KEY, class VALUE, class LISTENER>
waitUntilRemoved(const std::shared_ptr<ClientDescriptor<KEY,VALUE>> client,nsecs_t timeout)706 status_t ClientManager<KEY, VALUE, LISTENER>::waitUntilRemoved(
707         const std::shared_ptr<ClientDescriptor<KEY, VALUE>> client,
708         nsecs_t timeout) const {
709     status_t ret = NO_ERROR;
710     Mutex::Autolock lock(mLock);
711 
712     bool isRemoved = false;
713 
714     // Figure out what time in the future we should hit the timeout
715     nsecs_t failTime = systemTime(SYSTEM_TIME_MONOTONIC) + timeout;
716 
717     while (!isRemoved) {
718         isRemoved = true;
719         for (const auto& i : mClients) {
720             if (i == client) {
721                 isRemoved = false;
722             }
723         }
724 
725         if (!isRemoved) {
726             ret = mRemovedCondition.waitRelative(mLock, timeout);
727             if (ret != NO_ERROR) {
728                 break;
729             }
730             timeout = failTime - systemTime(SYSTEM_TIME_MONOTONIC);
731         }
732     }
733 
734     return ret;
735 }
736 
737 template<class KEY, class VALUE, class LISTENER>
setListener(const std::shared_ptr<LISTENER> & listener)738 void ClientManager<KEY, VALUE, LISTENER>::setListener(const std::shared_ptr<LISTENER>& listener) {
739     Mutex::Autolock lock(mLock);
740     mListener = listener;
741 }
742 
743 template<class KEY, class VALUE, class LISTENER>
remove(const std::shared_ptr<ClientDescriptor<KEY,VALUE>> & value)744 void ClientManager<KEY, VALUE, LISTENER>::remove(
745         const std::shared_ptr<ClientDescriptor<KEY, VALUE>>& value) {
746     Mutex::Autolock lock(mLock);
747     // Remove evicted clients from list
748     mClients.erase(std::remove_if(mClients.begin(), mClients.end(),
749         [this, &value] (std::shared_ptr<ClientDescriptor<KEY, VALUE>>& curClientPtr) {
750             if (curClientPtr == value) {
751                 if (mListener != nullptr) mListener->onClientRemoved(*curClientPtr);
752                 return true;
753             }
754             return false;
755         }), mClients.end());
756     mRemovedCondition.broadcast();
757 }
758 
759 template<class KEY, class VALUE, class LISTENER>
getCurrentCostLocked()760 int64_t ClientManager<KEY, VALUE, LISTENER>::getCurrentCostLocked() const {
761     int64_t totalCost = 0;
762     for (const auto& x : mClients) {
763             totalCost += x->getCost();
764     }
765     return totalCost;
766 }
767 
768 // --------------------------------------------------------------------------------
769 
770 }; // namespace resource_policy
771 }; // namespace android
772 
773 #endif // ANDROID_SERVICE_UTILS_EVICTION_POLICY_MANAGER_H
774