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