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 && owner == curOwner) {
500 // Pre-existing conflicting client with the same client owner exists
501 // Open the same device twice -> most recent open wins
502 // Otherwise let the existing client wins to avoid behaviors difference
503 // due to how HAL advertising conflicting devices (which is hidden from
504 // application)
505 if (curKey == key) {
506 evictList.push_back(i);
507 totalCost -= curCost;
508 } else {
509 evictList.clear();
510 evictList.push_back(client);
511 return evictList;
512 }
513 } else if (conflicting || ((totalCost > mMaxCost && curCost > 0) &&
514 (curPriority >= priority) &&
515 !(highestPriorityOwner == owner && owner == curOwner))) {
516 // Add a pre-existing client to the eviction list if:
517 // - We are adding a client with higher priority that conflicts with this one.
518 // - The total cost including the incoming client's is more than the allowable
519 // maximum, and the client has a non-zero cost, lower priority, and a different
520 // owner than the incoming client when the incoming client has the
521 // highest priority.
522 evictList.push_back(i);
523 totalCost -= curCost;
524 }
525 } else {
526 // Find clients preventing the incoming client from being added
527
528 if (curPriority < priority && (conflicting || (totalCost > mMaxCost && curCost > 0))) {
529 // Pre-existing conflicting client with higher priority exists
530 evictList.push_back(i);
531 }
532 }
533 }
534
535 // Immediately return the incompatible clients if we are calculating these instead
536 if (returnIncompatibleClients) {
537 return evictList;
538 }
539
540 // If the total cost is too high, return the input unless the input has the highest priority
541 if (totalCost > mMaxCost && highestPriorityOwner != owner) {
542 evictList.clear();
543 evictList.push_back(client);
544 return evictList;
545 }
546
547 return evictList;
548
549 }
550
551 template<class KEY, class VALUE, class LISTENER>
552 std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>>
addAndEvict(const std::shared_ptr<ClientDescriptor<KEY,VALUE>> & client)553 ClientManager<KEY, VALUE, LISTENER>::addAndEvict(
554 const std::shared_ptr<ClientDescriptor<KEY, VALUE>>& client) {
555 Mutex::Autolock lock(mLock);
556 auto evicted = wouldEvictLocked(client);
557 auto it = evicted.begin();
558 if (it != evicted.end() && *it == client) {
559 return evicted;
560 }
561
562 auto iter = evicted.cbegin();
563
564 if (iter != evicted.cend()) {
565
566 if (mListener != nullptr) mListener->onClientRemoved(**iter);
567
568 // Remove evicted clients from list
569 mClients.erase(std::remove_if(mClients.begin(), mClients.end(),
570 [&iter] (std::shared_ptr<ClientDescriptor<KEY, VALUE>>& curClientPtr) {
571 if (curClientPtr->getKey() == (*iter)->getKey()) {
572 iter++;
573 return true;
574 }
575 return false;
576 }), mClients.end());
577 }
578
579 if (mListener != nullptr) mListener->onClientAdded(*client);
580 mClients.push_back(client);
581 mRemovedCondition.broadcast();
582
583 return evicted;
584 }
585
586 template<class KEY, class VALUE, class LISTENER>
587 std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>>
getAll()588 ClientManager<KEY, VALUE, LISTENER>::getAll() const {
589 Mutex::Autolock lock(mLock);
590 return mClients;
591 }
592
593 template<class KEY, class VALUE, class LISTENER>
getAllKeys()594 std::vector<KEY> ClientManager<KEY, VALUE, LISTENER>::getAllKeys() const {
595 Mutex::Autolock lock(mLock);
596 std::vector<KEY> keys(mClients.size());
597 for (const auto& i : mClients) {
598 keys.push_back(i->getKey());
599 }
600 return keys;
601 }
602
603 template<class KEY, class VALUE, class LISTENER>
getAllOwners()604 std::vector<int32_t> ClientManager<KEY, VALUE, LISTENER>::getAllOwners() const {
605 Mutex::Autolock lock(mLock);
606 std::set<int32_t> owners;
607 for (const auto& i : mClients) {
608 owners.emplace(i->getOwnerId());
609 }
610 return std::vector<int32_t>(owners.begin(), owners.end());
611 }
612
613 template<class KEY, class VALUE, class LISTENER>
updatePriorities(const std::map<int32_t,ClientPriority> & ownerPriorityList)614 void ClientManager<KEY, VALUE, LISTENER>::updatePriorities(
615 const std::map<int32_t,ClientPriority>& ownerPriorityList) {
616 Mutex::Autolock lock(mLock);
617 for (auto& i : mClients) {
618 auto j = ownerPriorityList.find(i->getOwnerId());
619 if (j != ownerPriorityList.end()) {
620 i->setPriority(j->second);
621 }
622 }
623 }
624
625 template<class KEY, class VALUE, class LISTENER>
get(const KEY & key)626 std::shared_ptr<ClientDescriptor<KEY, VALUE>> ClientManager<KEY, VALUE, LISTENER>::get(
627 const KEY& key) const {
628 Mutex::Autolock lock(mLock);
629 for (const auto& i : mClients) {
630 if (i->getKey() == key) return i;
631 }
632 return std::shared_ptr<ClientDescriptor<KEY, VALUE>>(nullptr);
633 }
634
635 template<class KEY, class VALUE, class LISTENER>
removeAll()636 void ClientManager<KEY, VALUE, LISTENER>::removeAll() {
637 Mutex::Autolock lock(mLock);
638 if (mListener != nullptr) {
639 for (const auto& i : mClients) {
640 mListener->onClientRemoved(*i);
641 }
642 }
643 mClients.clear();
644 mRemovedCondition.broadcast();
645 }
646
647 template<class KEY, class VALUE, class LISTENER>
remove(const KEY & key)648 std::shared_ptr<ClientDescriptor<KEY, VALUE>> ClientManager<KEY, VALUE, LISTENER>::remove(
649 const KEY& key) {
650 Mutex::Autolock lock(mLock);
651
652 std::shared_ptr<ClientDescriptor<KEY, VALUE>> ret;
653
654 // Remove evicted clients from list
655 mClients.erase(std::remove_if(mClients.begin(), mClients.end(),
656 [this, &key, &ret] (std::shared_ptr<ClientDescriptor<KEY, VALUE>>& curClientPtr) {
657 if (curClientPtr->getKey() == key) {
658 if (mListener != nullptr) mListener->onClientRemoved(*curClientPtr);
659 ret = curClientPtr;
660 return true;
661 }
662 return false;
663 }), mClients.end());
664
665 mRemovedCondition.broadcast();
666 return ret;
667 }
668
669 template<class KEY, class VALUE, class LISTENER>
waitUntilRemoved(const std::shared_ptr<ClientDescriptor<KEY,VALUE>> client,nsecs_t timeout)670 status_t ClientManager<KEY, VALUE, LISTENER>::waitUntilRemoved(
671 const std::shared_ptr<ClientDescriptor<KEY, VALUE>> client,
672 nsecs_t timeout) const {
673 status_t ret = NO_ERROR;
674 Mutex::Autolock lock(mLock);
675
676 bool isRemoved = false;
677
678 // Figure out what time in the future we should hit the timeout
679 nsecs_t failTime = systemTime(SYSTEM_TIME_MONOTONIC) + timeout;
680
681 while (!isRemoved) {
682 isRemoved = true;
683 for (const auto& i : mClients) {
684 if (i == client) {
685 isRemoved = false;
686 }
687 }
688
689 if (!isRemoved) {
690 ret = mRemovedCondition.waitRelative(mLock, timeout);
691 if (ret != NO_ERROR) {
692 break;
693 }
694 timeout = failTime - systemTime(SYSTEM_TIME_MONOTONIC);
695 }
696 }
697
698 return ret;
699 }
700
701 template<class KEY, class VALUE, class LISTENER>
setListener(const std::shared_ptr<LISTENER> & listener)702 void ClientManager<KEY, VALUE, LISTENER>::setListener(const std::shared_ptr<LISTENER>& listener) {
703 Mutex::Autolock lock(mLock);
704 mListener = listener;
705 }
706
707 template<class KEY, class VALUE, class LISTENER>
remove(const std::shared_ptr<ClientDescriptor<KEY,VALUE>> & value)708 void ClientManager<KEY, VALUE, LISTENER>::remove(
709 const std::shared_ptr<ClientDescriptor<KEY, VALUE>>& value) {
710 Mutex::Autolock lock(mLock);
711 // Remove evicted clients from list
712 mClients.erase(std::remove_if(mClients.begin(), mClients.end(),
713 [this, &value] (std::shared_ptr<ClientDescriptor<KEY, VALUE>>& curClientPtr) {
714 if (curClientPtr == value) {
715 if (mListener != nullptr) mListener->onClientRemoved(*curClientPtr);
716 return true;
717 }
718 return false;
719 }), mClients.end());
720 mRemovedCondition.broadcast();
721 }
722
723 template<class KEY, class VALUE, class LISTENER>
getCurrentCostLocked()724 int64_t ClientManager<KEY, VALUE, LISTENER>::getCurrentCostLocked() const {
725 int64_t totalCost = 0;
726 for (const auto& x : mClients) {
727 totalCost += x->getCost();
728 }
729 return totalCost;
730 }
731
732 // --------------------------------------------------------------------------------
733
734 }; // namespace resource_policy
735 }; // namespace android
736
737 #endif // ANDROID_SERVICE_UTILS_EVICTION_POLICY_MANAGER_H
738