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