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