1 /*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #ifndef ANDROID_SERVICE_UTILS_EVICTION_POLICY_MANAGER_H
18 #define ANDROID_SERVICE_UTILS_EVICTION_POLICY_MANAGER_H
19
20 #include <utils/Condition.h>
21 #include <utils/Mutex.h>
22 #include <utils/Timers.h>
23
24 #include <algorithm>
25 #include <utility>
26 #include <vector>
27 #include <set>
28 #include <map>
29 #include <memory>
30
31 namespace android {
32 namespace resource_policy {
33
34 class ClientPriority {
35 public:
ClientPriority(int32_t score,int32_t state)36 ClientPriority(int32_t score, int32_t state) :
37 mScore(score), mState(state) {}
38
getScore()39 int32_t getScore() const { return mScore; }
getState()40 int32_t getState() const { return mState; }
41
42 bool operator==(const ClientPriority& rhs) const {
43 return (this->mScore == rhs.mScore) && (this->mState == rhs.mState);
44 }
45
46 bool operator< (const ClientPriority& rhs) const {
47 if (this->mScore == rhs.mScore) {
48 return this->mState < rhs.mState;
49 } else {
50 return this->mScore < rhs.mScore;
51 }
52 }
53
54 bool operator> (const ClientPriority& rhs) const {
55 return rhs < *this;
56 }
57
58 bool operator<=(const ClientPriority& rhs) const {
59 return !(*this > rhs);
60 }
61
62 bool operator>=(const ClientPriority& rhs) const {
63 return !(*this < rhs);
64 }
65
66 private:
67 int32_t mScore;
68 int32_t mState;
69 };
70
71 // --------------------------------------------------------------------------------
72
73 /**
74 * The ClientDescriptor class is a container for a given key/value pair identifying a shared
75 * resource, and the corresponding cost, priority, owner ID, and conflicting keys list used
76 * in determining eviction behavior.
77 *
78 * Aside from the priority, these values are immutable once the ClientDescriptor has been
79 * constructed.
80 */
81 template<class KEY, class VALUE>
82 class ClientDescriptor final {
83 public:
84 ClientDescriptor(const KEY& key, const VALUE& value, int32_t cost,
85 const std::set<KEY>& conflictingKeys, int32_t score, int32_t ownerId, int32_t state);
86 ClientDescriptor(KEY&& key, VALUE&& value, int32_t cost, std::set<KEY>&& conflictingKeys,
87 int32_t score, int32_t ownerId, int32_t state);
88
89 ~ClientDescriptor();
90
91 /**
92 * Return the key for this descriptor.
93 */
94 const KEY& getKey() const;
95
96 /**
97 * Return the value for this descriptor.
98 */
99 const VALUE& getValue() const;
100
101 /**
102 * Return the cost for this descriptor.
103 */
104 int32_t getCost() const;
105
106 /**
107 * Return the priority for this descriptor.
108 */
109 const ClientPriority &getPriority() const;
110
111 /**
112 * Return the owner ID for this descriptor.
113 */
114 int32_t getOwnerId() const;
115
116 /**
117 * Return true if the given key is in this descriptor's conflicting keys list.
118 */
119 bool isConflicting(const KEY& key) const;
120
121 /**
122 * Return the set of all conflicting keys for this descriptor.
123 */
124 std::set<KEY> getConflicting() const;
125
126 /**
127 * Set the proirity for this descriptor.
128 */
129 void setPriority(const ClientPriority& priority);
130
131 // This class is ordered by key
132 template<class K, class V>
133 friend bool operator < (const ClientDescriptor<K, V>& a, const ClientDescriptor<K, V>& b);
134
135 private:
136 KEY mKey;
137 VALUE mValue;
138 int32_t mCost;
139 std::set<KEY> mConflicting;
140 ClientPriority mPriority;
141 int32_t mOwnerId;
142 }; // class ClientDescriptor
143
144 template<class K, class V>
145 bool operator < (const ClientDescriptor<K, V>& a, const ClientDescriptor<K, V>& b) {
146 return a.mKey < b.mKey;
147 }
148
149 template<class KEY, class VALUE>
ClientDescriptor(const KEY & key,const VALUE & value,int32_t cost,const std::set<KEY> & conflictingKeys,int32_t score,int32_t ownerId,int32_t state)150 ClientDescriptor<KEY, VALUE>::ClientDescriptor(const KEY& key, const VALUE& value, int32_t cost,
151 const std::set<KEY>& conflictingKeys, int32_t score, int32_t ownerId, int32_t state) :
152 mKey{key}, mValue{value}, mCost{cost}, mConflicting{conflictingKeys},
153 mPriority(score, state),
154 mOwnerId{ownerId} {}
155
156 template<class KEY, class VALUE>
ClientDescriptor(KEY && key,VALUE && value,int32_t cost,std::set<KEY> && conflictingKeys,int32_t score,int32_t ownerId,int32_t state)157 ClientDescriptor<KEY, VALUE>::ClientDescriptor(KEY&& key, VALUE&& value, int32_t cost,
158 std::set<KEY>&& conflictingKeys, int32_t score, int32_t ownerId, int32_t state) :
159 mKey{std::forward<KEY>(key)}, mValue{std::forward<VALUE>(value)}, mCost{cost},
160 mConflicting{std::forward<std::set<KEY>>(conflictingKeys)},
161 mPriority(score, state), mOwnerId{ownerId} {}
162
163 template<class KEY, class VALUE>
~ClientDescriptor()164 ClientDescriptor<KEY, VALUE>::~ClientDescriptor() {}
165
166 template<class KEY, class VALUE>
getKey()167 const KEY& ClientDescriptor<KEY, VALUE>::getKey() const {
168 return mKey;
169 }
170
171 template<class KEY, class VALUE>
getValue()172 const VALUE& ClientDescriptor<KEY, VALUE>::getValue() const {
173 return mValue;
174 }
175
176 template<class KEY, class VALUE>
getCost()177 int32_t ClientDescriptor<KEY, VALUE>::getCost() const {
178 return mCost;
179 }
180
181 template<class KEY, class VALUE>
getPriority()182 const ClientPriority& ClientDescriptor<KEY, VALUE>::getPriority() const {
183 return mPriority;
184 }
185
186 template<class KEY, class VALUE>
getOwnerId()187 int32_t ClientDescriptor<KEY, VALUE>::getOwnerId() const {
188 return mOwnerId;
189 }
190
191 template<class KEY, class VALUE>
isConflicting(const KEY & key)192 bool ClientDescriptor<KEY, VALUE>::isConflicting(const KEY& key) const {
193 if (key == mKey) return true;
194 for (const auto& x : mConflicting) {
195 if (key == x) return true;
196 }
197 return false;
198 }
199
200 template<class KEY, class VALUE>
getConflicting()201 std::set<KEY> ClientDescriptor<KEY, VALUE>::getConflicting() const {
202 return mConflicting;
203 }
204
205 template<class KEY, class VALUE>
setPriority(const ClientPriority & priority)206 void ClientDescriptor<KEY, VALUE>::setPriority(const ClientPriority& priority) {
207 mPriority = priority;
208 }
209
210 // --------------------------------------------------------------------------------
211
212 /**
213 * A default class implementing the LISTENER interface used by ClientManager.
214 */
215 template<class KEY, class VALUE>
216 class DefaultEventListener {
217 public:
218 void onClientAdded(const ClientDescriptor<KEY, VALUE>& descriptor);
219 void onClientRemoved(const ClientDescriptor<KEY, VALUE>& descriptor);
220 };
221
222 template<class KEY, class VALUE>
onClientAdded(const ClientDescriptor<KEY,VALUE> &)223 void DefaultEventListener<KEY, VALUE>::onClientAdded(
224 const ClientDescriptor<KEY, VALUE>& /*descriptor*/) {}
225
226 template<class KEY, class VALUE>
onClientRemoved(const ClientDescriptor<KEY,VALUE> &)227 void DefaultEventListener<KEY, VALUE>::onClientRemoved(
228 const ClientDescriptor<KEY, VALUE>& /*descriptor*/) {}
229
230 // --------------------------------------------------------------------------------
231
232 /**
233 * The ClientManager class wraps an LRU-ordered list of active clients and implements eviction
234 * behavior for handling shared resource access.
235 *
236 * When adding a new descriptor, eviction behavior is as follows:
237 * - Keys are unique, adding a descriptor with the same key as an existing descriptor will
238 * result in the lower-priority of the two being removed. Priority ties result in the
239 * LRU descriptor being evicted (this means the incoming descriptor be added in this case).
240 * - Any descriptors with keys that are in the incoming descriptor's 'conflicting keys' list
241 * will be removed if they have an equal or lower priority than the incoming descriptor;
242 * if any have a higher priority, the incoming descriptor is removed instead.
243 * - If the sum of all descriptors' costs, including the incoming descriptor's, is more than
244 * the max cost allowed for this ClientManager, descriptors with non-zero cost, equal or lower
245 * priority, and a different owner will be evicted in LRU order until either the cost is less
246 * than the max cost, or all descriptors meeting this criteria have been evicted and the
247 * incoming descriptor has the highest priority. Otherwise, the incoming descriptor is
248 * removed instead.
249 */
250 template<class KEY, class VALUE, class LISTENER=DefaultEventListener<KEY, VALUE>>
251 class ClientManager {
252 public:
253 // The default maximum "cost" allowed before evicting
254 static constexpr int32_t DEFAULT_MAX_COST = 100;
255
256 ClientManager();
257 explicit ClientManager(int32_t totalCost);
258
259 /**
260 * Add a given ClientDescriptor to the managed list. ClientDescriptors for clients that
261 * are evicted by this action are returned in a vector.
262 *
263 * This may return the ClientDescriptor passed in if it would be evicted.
264 */
265 std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>> addAndEvict(
266 const std::shared_ptr<ClientDescriptor<KEY, VALUE>>& client);
267
268 /**
269 * Given a map containing owner (pid) -> priority mappings, update the priority of each
270 * ClientDescriptor with an owner in this mapping.
271 */
272 void updatePriorities(const std::map<int32_t,ClientPriority>& ownerPriorityList);
273
274 /**
275 * Remove all ClientDescriptors.
276 */
277 void removeAll();
278
279 /**
280 * Remove and return the ClientDescriptor with a given key.
281 */
282 std::shared_ptr<ClientDescriptor<KEY, VALUE>> remove(const KEY& key);
283
284 /**
285 * Remove the given ClientDescriptor.
286 */
287 void remove(const std::shared_ptr<ClientDescriptor<KEY, VALUE>>& value);
288
289 /**
290 * Return a vector of the ClientDescriptors that would be evicted by adding the given
291 * ClientDescriptor.
292 *
293 * This may return the ClientDescriptor passed in if it would be evicted.
294 */
295 std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>> wouldEvict(
296 const std::shared_ptr<ClientDescriptor<KEY, VALUE>>& client) const;
297
298 /**
299 * Return a vector of active ClientDescriptors that prevent this client from being added.
300 */
301 std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>> getIncompatibleClients(
302 const std::shared_ptr<ClientDescriptor<KEY, VALUE>>& client) const;
303
304 /**
305 * Return a vector containing all currently active ClientDescriptors.
306 */
307 std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>> getAll() const;
308
309 /**
310 * Return a vector containing all keys of currently active ClientDescriptors.
311 */
312 std::vector<KEY> getAllKeys() const;
313
314 /**
315 * Return a vector of the owner tags of all currently active ClientDescriptors (duplicates
316 * will be removed).
317 */
318 std::vector<int32_t> getAllOwners() const;
319
320 /**
321 * Return the ClientDescriptor corresponding to the given key, or an empty shared pointer
322 * if none exists.
323 */
324 std::shared_ptr<ClientDescriptor<KEY, VALUE>> get(const KEY& key) const;
325
326 /**
327 * Block until the given client is no longer in the active clients list, or the timeout
328 * occurred.
329 *
330 * Returns NO_ERROR if this succeeded, -ETIMEDOUT on a timeout, or a negative error code on
331 * failure.
332 */
333 status_t waitUntilRemoved(const std::shared_ptr<ClientDescriptor<KEY, VALUE>> client,
334 nsecs_t timeout) const;
335
336 /**
337 * Set the current listener for client add/remove events.
338 *
339 * The listener instance must inherit from the LISTENER class and implement the following
340 * methods:
341 * void onClientRemoved(const ClientDescriptor<KEY, VALUE>& descriptor);
342 * void onClientAdded(const ClientDescriptor<KEY, VALUE>& descriptor);
343 *
344 * These callback methods will be called with the ClientManager's lock held, and should
345 * not call any further ClientManager methods.
346 *
347 * The onClientRemoved method will be called when the client has been removed or evicted
348 * from the ClientManager that this event listener has been added to. The onClientAdded
349 * method will be called when the client has been added to the ClientManager that this
350 * event listener has been added to.
351 */
352 void setListener(const std::shared_ptr<LISTENER>& listener);
353
354 protected:
355 ~ClientManager();
356
357 private:
358
359 /**
360 * Return a vector of the ClientDescriptors that would be evicted by adding the given
361 * ClientDescriptor. If returnIncompatibleClients is set to true, instead, return the
362 * vector of ClientDescriptors that are higher priority than the incoming client and
363 * either conflict with this client, or contribute to the resource cost if that would
364 * prevent the incoming client from being added.
365 *
366 * This may return the ClientDescriptor passed in.
367 */
368 std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>> wouldEvictLocked(
369 const std::shared_ptr<ClientDescriptor<KEY, VALUE>>& client,
370 bool returnIncompatibleClients = false) const;
371
372 int64_t getCurrentCostLocked() const;
373
374 mutable Mutex mLock;
375 mutable Condition mRemovedCondition;
376 int32_t mMaxCost;
377 // LRU ordered, most recent at end
378 std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>> mClients;
379 std::shared_ptr<LISTENER> mListener;
380 }; // class ClientManager
381
382 template<class KEY, class VALUE, class LISTENER>
ClientManager()383 ClientManager<KEY, VALUE, LISTENER>::ClientManager() :
384 ClientManager(DEFAULT_MAX_COST) {}
385
386 template<class KEY, class VALUE, class LISTENER>
ClientManager(int32_t totalCost)387 ClientManager<KEY, VALUE, LISTENER>::ClientManager(int32_t totalCost) : mMaxCost(totalCost) {}
388
389 template<class KEY, class VALUE, class LISTENER>
~ClientManager()390 ClientManager<KEY, VALUE, LISTENER>::~ClientManager() {}
391
392 template<class KEY, class VALUE, class LISTENER>
393 std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>>
wouldEvict(const std::shared_ptr<ClientDescriptor<KEY,VALUE>> & client)394 ClientManager<KEY, VALUE, LISTENER>::wouldEvict(
395 const std::shared_ptr<ClientDescriptor<KEY, VALUE>>& client) const {
396 Mutex::Autolock lock(mLock);
397 return wouldEvictLocked(client);
398 }
399
400 template<class KEY, class VALUE, class LISTENER>
401 std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>>
getIncompatibleClients(const std::shared_ptr<ClientDescriptor<KEY,VALUE>> & client)402 ClientManager<KEY, VALUE, LISTENER>::getIncompatibleClients(
403 const std::shared_ptr<ClientDescriptor<KEY, VALUE>>& client) const {
404 Mutex::Autolock lock(mLock);
405 return wouldEvictLocked(client, /*returnIncompatibleClients*/true);
406 }
407
408 template<class KEY, class VALUE, class LISTENER>
409 std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>>
wouldEvictLocked(const std::shared_ptr<ClientDescriptor<KEY,VALUE>> & client,bool returnIncompatibleClients)410 ClientManager<KEY, VALUE, LISTENER>::wouldEvictLocked(
411 const std::shared_ptr<ClientDescriptor<KEY, VALUE>>& client,
412 bool returnIncompatibleClients) const {
413
414 std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>> evictList;
415
416 // Disallow null clients, return input
417 if (client == nullptr) {
418 evictList.push_back(client);
419 return evictList;
420 }
421
422 const KEY& key = client->getKey();
423 int32_t cost = client->getCost();
424 ClientPriority priority = client->getPriority();
425 int32_t owner = client->getOwnerId();
426
427 int64_t totalCost = getCurrentCostLocked() + cost;
428
429 // Determine the MRU of the owners tied for having the highest priority
430 int32_t highestPriorityOwner = owner;
431 ClientPriority highestPriority = priority;
432 for (const auto& i : mClients) {
433 ClientPriority curPriority = i->getPriority();
434 if (curPriority <= highestPriority) {
435 highestPriority = curPriority;
436 highestPriorityOwner = i->getOwnerId();
437 }
438 }
439
440 if (highestPriority == priority) {
441 // Switch back owner if the incoming client has the highest priority, as it is MRU
442 highestPriorityOwner = owner;
443 }
444
445 // Build eviction list of clients to remove
446 for (const auto& i : mClients) {
447 const KEY& curKey = i->getKey();
448 int32_t curCost = i->getCost();
449 ClientPriority curPriority = i->getPriority();
450 int32_t curOwner = i->getOwnerId();
451
452 bool conflicting = (curKey == key || i->isConflicting(key) ||
453 client->isConflicting(curKey));
454
455 if (!returnIncompatibleClients) {
456 // Find evicted clients
457
458 if (conflicting && curPriority < priority) {
459 // Pre-existing conflicting client with higher priority exists
460 evictList.clear();
461 evictList.push_back(client);
462 return evictList;
463 } else if (conflicting || ((totalCost > mMaxCost && curCost > 0) &&
464 (curPriority >= priority) &&
465 !(highestPriorityOwner == owner && owner == curOwner))) {
466 // Add a pre-existing client to the eviction list if:
467 // - We are adding a client with higher priority that conflicts with this one.
468 // - The total cost including the incoming client's is more than the allowable
469 // maximum, and the client has a non-zero cost, lower priority, and a different
470 // owner than the incoming client when the incoming client has the
471 // highest priority.
472 evictList.push_back(i);
473 totalCost -= curCost;
474 }
475 } else {
476 // Find clients preventing the incoming client from being added
477
478 if (curPriority < priority && (conflicting || (totalCost > mMaxCost && curCost > 0))) {
479 // Pre-existing conflicting client with higher priority exists
480 evictList.push_back(i);
481 }
482 }
483 }
484
485 // Immediately return the incompatible clients if we are calculating these instead
486 if (returnIncompatibleClients) {
487 return evictList;
488 }
489
490 // If the total cost is too high, return the input unless the input has the highest priority
491 if (totalCost > mMaxCost && highestPriorityOwner != owner) {
492 evictList.clear();
493 evictList.push_back(client);
494 return evictList;
495 }
496
497 return evictList;
498
499 }
500
501 template<class KEY, class VALUE, class LISTENER>
502 std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>>
addAndEvict(const std::shared_ptr<ClientDescriptor<KEY,VALUE>> & client)503 ClientManager<KEY, VALUE, LISTENER>::addAndEvict(
504 const std::shared_ptr<ClientDescriptor<KEY, VALUE>>& client) {
505 Mutex::Autolock lock(mLock);
506 auto evicted = wouldEvictLocked(client);
507 auto it = evicted.begin();
508 if (it != evicted.end() && *it == client) {
509 return evicted;
510 }
511
512 auto iter = evicted.cbegin();
513
514 if (iter != evicted.cend()) {
515
516 if (mListener != nullptr) mListener->onClientRemoved(**iter);
517
518 // Remove evicted clients from list
519 mClients.erase(std::remove_if(mClients.begin(), mClients.end(),
520 [&iter] (std::shared_ptr<ClientDescriptor<KEY, VALUE>>& curClientPtr) {
521 if (curClientPtr->getKey() == (*iter)->getKey()) {
522 iter++;
523 return true;
524 }
525 return false;
526 }), mClients.end());
527 }
528
529 if (mListener != nullptr) mListener->onClientAdded(*client);
530 mClients.push_back(client);
531 mRemovedCondition.broadcast();
532
533 return evicted;
534 }
535
536 template<class KEY, class VALUE, class LISTENER>
537 std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>>
getAll()538 ClientManager<KEY, VALUE, LISTENER>::getAll() const {
539 Mutex::Autolock lock(mLock);
540 return mClients;
541 }
542
543 template<class KEY, class VALUE, class LISTENER>
getAllKeys()544 std::vector<KEY> ClientManager<KEY, VALUE, LISTENER>::getAllKeys() const {
545 Mutex::Autolock lock(mLock);
546 std::vector<KEY> keys(mClients.size());
547 for (const auto& i : mClients) {
548 keys.push_back(i->getKey());
549 }
550 return keys;
551 }
552
553 template<class KEY, class VALUE, class LISTENER>
getAllOwners()554 std::vector<int32_t> ClientManager<KEY, VALUE, LISTENER>::getAllOwners() const {
555 Mutex::Autolock lock(mLock);
556 std::set<int32_t> owners;
557 for (const auto& i : mClients) {
558 owners.emplace(i->getOwnerId());
559 }
560 return std::vector<int32_t>(owners.begin(), owners.end());
561 }
562
563 template<class KEY, class VALUE, class LISTENER>
updatePriorities(const std::map<int32_t,ClientPriority> & ownerPriorityList)564 void ClientManager<KEY, VALUE, LISTENER>::updatePriorities(
565 const std::map<int32_t,ClientPriority>& ownerPriorityList) {
566 Mutex::Autolock lock(mLock);
567 for (auto& i : mClients) {
568 auto j = ownerPriorityList.find(i->getOwnerId());
569 if (j != ownerPriorityList.end()) {
570 i->setPriority(j->second);
571 }
572 }
573 }
574
575 template<class KEY, class VALUE, class LISTENER>
get(const KEY & key)576 std::shared_ptr<ClientDescriptor<KEY, VALUE>> ClientManager<KEY, VALUE, LISTENER>::get(
577 const KEY& key) const {
578 Mutex::Autolock lock(mLock);
579 for (const auto& i : mClients) {
580 if (i->getKey() == key) return i;
581 }
582 return std::shared_ptr<ClientDescriptor<KEY, VALUE>>(nullptr);
583 }
584
585 template<class KEY, class VALUE, class LISTENER>
removeAll()586 void ClientManager<KEY, VALUE, LISTENER>::removeAll() {
587 Mutex::Autolock lock(mLock);
588 if (mListener != nullptr) {
589 for (const auto& i : mClients) {
590 mListener->onClientRemoved(*i);
591 }
592 }
593 mClients.clear();
594 mRemovedCondition.broadcast();
595 }
596
597 template<class KEY, class VALUE, class LISTENER>
remove(const KEY & key)598 std::shared_ptr<ClientDescriptor<KEY, VALUE>> ClientManager<KEY, VALUE, LISTENER>::remove(
599 const KEY& key) {
600 Mutex::Autolock lock(mLock);
601
602 std::shared_ptr<ClientDescriptor<KEY, VALUE>> ret;
603
604 // Remove evicted clients from list
605 mClients.erase(std::remove_if(mClients.begin(), mClients.end(),
606 [this, &key, &ret] (std::shared_ptr<ClientDescriptor<KEY, VALUE>>& curClientPtr) {
607 if (curClientPtr->getKey() == key) {
608 if (mListener != nullptr) mListener->onClientRemoved(*curClientPtr);
609 ret = curClientPtr;
610 return true;
611 }
612 return false;
613 }), mClients.end());
614
615 mRemovedCondition.broadcast();
616 return ret;
617 }
618
619 template<class KEY, class VALUE, class LISTENER>
waitUntilRemoved(const std::shared_ptr<ClientDescriptor<KEY,VALUE>> client,nsecs_t timeout)620 status_t ClientManager<KEY, VALUE, LISTENER>::waitUntilRemoved(
621 const std::shared_ptr<ClientDescriptor<KEY, VALUE>> client,
622 nsecs_t timeout) const {
623 status_t ret = NO_ERROR;
624 Mutex::Autolock lock(mLock);
625
626 bool isRemoved = false;
627
628 // Figure out what time in the future we should hit the timeout
629 nsecs_t failTime = systemTime(SYSTEM_TIME_MONOTONIC) + timeout;
630
631 while (!isRemoved) {
632 isRemoved = true;
633 for (const auto& i : mClients) {
634 if (i == client) {
635 isRemoved = false;
636 }
637 }
638
639 if (!isRemoved) {
640 ret = mRemovedCondition.waitRelative(mLock, timeout);
641 if (ret != NO_ERROR) {
642 break;
643 }
644 timeout = failTime - systemTime(SYSTEM_TIME_MONOTONIC);
645 }
646 }
647
648 return ret;
649 }
650
651 template<class KEY, class VALUE, class LISTENER>
setListener(const std::shared_ptr<LISTENER> & listener)652 void ClientManager<KEY, VALUE, LISTENER>::setListener(const std::shared_ptr<LISTENER>& listener) {
653 Mutex::Autolock lock(mLock);
654 mListener = listener;
655 }
656
657 template<class KEY, class VALUE, class LISTENER>
remove(const std::shared_ptr<ClientDescriptor<KEY,VALUE>> & value)658 void ClientManager<KEY, VALUE, LISTENER>::remove(
659 const std::shared_ptr<ClientDescriptor<KEY, VALUE>>& value) {
660 Mutex::Autolock lock(mLock);
661 // Remove evicted clients from list
662 mClients.erase(std::remove_if(mClients.begin(), mClients.end(),
663 [this, &value] (std::shared_ptr<ClientDescriptor<KEY, VALUE>>& curClientPtr) {
664 if (curClientPtr == value) {
665 if (mListener != nullptr) mListener->onClientRemoved(*curClientPtr);
666 return true;
667 }
668 return false;
669 }), mClients.end());
670 mRemovedCondition.broadcast();
671 }
672
673 template<class KEY, class VALUE, class LISTENER>
getCurrentCostLocked()674 int64_t ClientManager<KEY, VALUE, LISTENER>::getCurrentCostLocked() const {
675 int64_t totalCost = 0;
676 for (const auto& x : mClients) {
677 totalCost += x->getCost();
678 }
679 return totalCost;
680 }
681
682 // --------------------------------------------------------------------------------
683
684 }; // namespace resource_policy
685 }; // namespace android
686
687 #endif // ANDROID_SERVICE_UTILS_EVICTION_POLICY_MANAGER_H
688