blob: d7135f1bdf508d457277099e45e43d212527ef0e [file] [log] [blame]
Ruben Brunkcc776712015-02-17 20:18:47 -08001/*
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
Ruben Brunk4f9576b2015-04-10 17:26:56 -070020#include <utils/Condition.h>
Ruben Brunkcc776712015-02-17 20:18:47 -080021#include <utils/Mutex.h>
Ruben Brunk4f9576b2015-04-10 17:26:56 -070022#include <utils/Timers.h>
Ruben Brunkcc776712015-02-17 20:18:47 -080023
24#include <algorithm>
25#include <utility>
26#include <vector>
27#include <set>
28#include <map>
29#include <memory>
30
31namespace android {
32namespace resource_policy {
33
Emilian Peev8131a262017-02-01 12:33:43 +000034class ClientPriority {
35public:
36 ClientPriority(int32_t score, int32_t state) :
37 mScore(score), mState(state) {}
38
39 int32_t getScore() const { return mScore; }
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
66private:
67 int32_t mScore;
68 int32_t mState;
69};
70
Ruben Brunkcc776712015-02-17 20:18:47 -080071// --------------------------------------------------------------------------------
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 */
81template<class KEY, class VALUE>
82class ClientDescriptor final {
83public:
84 ClientDescriptor(const KEY& key, const VALUE& value, int32_t cost,
Emilian Peev8131a262017-02-01 12:33:43 +000085 const std::set<KEY>& conflictingKeys, int32_t score, int32_t ownerId, int32_t state);
Ruben Brunkcc776712015-02-17 20:18:47 -080086 ClientDescriptor(KEY&& key, VALUE&& value, int32_t cost, std::set<KEY>&& conflictingKeys,
Emilian Peev8131a262017-02-01 12:33:43 +000087 int32_t score, int32_t ownerId, int32_t state);
Ruben Brunkcc776712015-02-17 20:18:47 -080088
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 */
Emilian Peev8131a262017-02-01 12:33:43 +0000109 const ClientPriority &getPriority() const;
Ruben Brunkcc776712015-02-17 20:18:47 -0800110
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 */
Emilian Peev8131a262017-02-01 12:33:43 +0000129 void setPriority(const ClientPriority& priority);
Ruben Brunkcc776712015-02-17 20:18:47 -0800130
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
135private:
136 KEY mKey;
137 VALUE mValue;
138 int32_t mCost;
139 std::set<KEY> mConflicting;
Emilian Peev8131a262017-02-01 12:33:43 +0000140 ClientPriority mPriority;
Ruben Brunkcc776712015-02-17 20:18:47 -0800141 int32_t mOwnerId;
142}; // class ClientDescriptor
143
144template<class K, class V>
145bool operator < (const ClientDescriptor<K, V>& a, const ClientDescriptor<K, V>& b) {
146 return a.mKey < b.mKey;
147}
148
149template<class KEY, class VALUE>
150ClientDescriptor<KEY, VALUE>::ClientDescriptor(const KEY& key, const VALUE& value, int32_t cost,
Emilian Peev8131a262017-02-01 12:33:43 +0000151 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),
Ruben Brunkcc776712015-02-17 20:18:47 -0800154 mOwnerId{ownerId} {}
155
156template<class KEY, class VALUE>
157ClientDescriptor<KEY, VALUE>::ClientDescriptor(KEY&& key, VALUE&& value, int32_t cost,
Emilian Peev8131a262017-02-01 12:33:43 +0000158 std::set<KEY>&& conflictingKeys, int32_t score, int32_t ownerId, int32_t state) :
Ruben Brunkcc776712015-02-17 20:18:47 -0800159 mKey{std::forward<KEY>(key)}, mValue{std::forward<VALUE>(value)}, mCost{cost},
Emilian Peev8131a262017-02-01 12:33:43 +0000160 mConflicting{std::forward<std::set<KEY>>(conflictingKeys)},
161 mPriority(score, state), mOwnerId{ownerId} {}
Ruben Brunkcc776712015-02-17 20:18:47 -0800162
163template<class KEY, class VALUE>
164ClientDescriptor<KEY, VALUE>::~ClientDescriptor() {}
165
166template<class KEY, class VALUE>
167const KEY& ClientDescriptor<KEY, VALUE>::getKey() const {
168 return mKey;
169}
170
171template<class KEY, class VALUE>
172const VALUE& ClientDescriptor<KEY, VALUE>::getValue() const {
173 return mValue;
174}
175
176template<class KEY, class VALUE>
177int32_t ClientDescriptor<KEY, VALUE>::getCost() const {
178 return mCost;
179}
180
181template<class KEY, class VALUE>
Emilian Peev8131a262017-02-01 12:33:43 +0000182const ClientPriority& ClientDescriptor<KEY, VALUE>::getPriority() const {
Ruben Brunkcc776712015-02-17 20:18:47 -0800183 return mPriority;
184}
185
186template<class KEY, class VALUE>
187int32_t ClientDescriptor<KEY, VALUE>::getOwnerId() const {
188 return mOwnerId;
189}
190
191template<class KEY, class VALUE>
192bool 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
200template<class KEY, class VALUE>
201std::set<KEY> ClientDescriptor<KEY, VALUE>::getConflicting() const {
202 return mConflicting;
203}
204
205template<class KEY, class VALUE>
Emilian Peev8131a262017-02-01 12:33:43 +0000206void ClientDescriptor<KEY, VALUE>::setPriority(const ClientPriority& priority) {
Ruben Brunkcc776712015-02-17 20:18:47 -0800207 mPriority = priority;
208}
209
210// --------------------------------------------------------------------------------
211
212/**
Ruben Brunk99e69712015-05-26 17:25:07 -0700213 * A default class implementing the LISTENER interface used by ClientManager.
214 */
215template<class KEY, class VALUE>
216class DefaultEventListener {
217public:
218 void onClientAdded(const ClientDescriptor<KEY, VALUE>& descriptor);
219 void onClientRemoved(const ClientDescriptor<KEY, VALUE>& descriptor);
220};
221
222template<class KEY, class VALUE>
223void DefaultEventListener<KEY, VALUE>::onClientAdded(
224 const ClientDescriptor<KEY, VALUE>& /*descriptor*/) {}
225
226template<class KEY, class VALUE>
227void DefaultEventListener<KEY, VALUE>::onClientRemoved(
228 const ClientDescriptor<KEY, VALUE>& /*descriptor*/) {}
229
230// --------------------------------------------------------------------------------
231
232/**
Ruben Brunkcc776712015-02-17 20:18:47 -0800233 * 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 */
Ruben Brunk99e69712015-05-26 17:25:07 -0700250template<class KEY, class VALUE, class LISTENER=DefaultEventListener<KEY, VALUE>>
Ruben Brunkcc776712015-02-17 20:18:47 -0800251class ClientManager {
252public:
253 // The default maximum "cost" allowed before evicting
254 static constexpr int32_t DEFAULT_MAX_COST = 100;
255
256 ClientManager();
Chih-Hung Hsieh8b0b9712016-08-09 14:25:53 -0700257 explicit ClientManager(int32_t totalCost);
Ruben Brunkcc776712015-02-17 20:18:47 -0800258
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 */
Emilian Peev8131a262017-02-01 12:33:43 +0000272 void updatePriorities(const std::map<int32_t,ClientPriority>& ownerPriorityList);
Ruben Brunkcc776712015-02-17 20:18:47 -0800273
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
Ruben Brunk4f9576b2015-04-10 17:26:56 -0700326 /**
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
Ruben Brunk99e69712015-05-26 17:25:07 -0700336 /**
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
Ruben Brunkcc776712015-02-17 20:18:47 -0800354protected:
355 ~ClientManager();
356
357private:
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;
Ruben Brunk4f9576b2015-04-10 17:26:56 -0700375 mutable Condition mRemovedCondition;
Ruben Brunkcc776712015-02-17 20:18:47 -0800376 int32_t mMaxCost;
377 // LRU ordered, most recent at end
378 std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>> mClients;
Ruben Brunk99e69712015-05-26 17:25:07 -0700379 std::shared_ptr<LISTENER> mListener;
Ruben Brunkcc776712015-02-17 20:18:47 -0800380}; // class ClientManager
381
Ruben Brunk99e69712015-05-26 17:25:07 -0700382template<class KEY, class VALUE, class LISTENER>
383ClientManager<KEY, VALUE, LISTENER>::ClientManager() :
Ruben Brunkcc776712015-02-17 20:18:47 -0800384 ClientManager(DEFAULT_MAX_COST) {}
385
Ruben Brunk99e69712015-05-26 17:25:07 -0700386template<class KEY, class VALUE, class LISTENER>
387ClientManager<KEY, VALUE, LISTENER>::ClientManager(int32_t totalCost) : mMaxCost(totalCost) {}
Ruben Brunkcc776712015-02-17 20:18:47 -0800388
Ruben Brunk99e69712015-05-26 17:25:07 -0700389template<class KEY, class VALUE, class LISTENER>
390ClientManager<KEY, VALUE, LISTENER>::~ClientManager() {}
Ruben Brunkcc776712015-02-17 20:18:47 -0800391
Ruben Brunk99e69712015-05-26 17:25:07 -0700392template<class KEY, class VALUE, class LISTENER>
393std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>>
394ClientManager<KEY, VALUE, LISTENER>::wouldEvict(
Ruben Brunkcc776712015-02-17 20:18:47 -0800395 const std::shared_ptr<ClientDescriptor<KEY, VALUE>>& client) const {
396 Mutex::Autolock lock(mLock);
397 return wouldEvictLocked(client);
398}
399
Ruben Brunk99e69712015-05-26 17:25:07 -0700400template<class KEY, class VALUE, class LISTENER>
Ruben Brunkcc776712015-02-17 20:18:47 -0800401std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>>
Ruben Brunk99e69712015-05-26 17:25:07 -0700402ClientManager<KEY, VALUE, LISTENER>::getIncompatibleClients(
Ruben Brunkcc776712015-02-17 20:18:47 -0800403 const std::shared_ptr<ClientDescriptor<KEY, VALUE>>& client) const {
404 Mutex::Autolock lock(mLock);
405 return wouldEvictLocked(client, /*returnIncompatibleClients*/true);
406}
407
Ruben Brunk99e69712015-05-26 17:25:07 -0700408template<class KEY, class VALUE, class LISTENER>
Ruben Brunkcc776712015-02-17 20:18:47 -0800409std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>>
Ruben Brunk99e69712015-05-26 17:25:07 -0700410ClientManager<KEY, VALUE, LISTENER>::wouldEvictLocked(
Ruben Brunkcc776712015-02-17 20:18:47 -0800411 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();
Emilian Peev8131a262017-02-01 12:33:43 +0000424 ClientPriority priority = client->getPriority();
Ruben Brunkcc776712015-02-17 20:18:47 -0800425 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;
Emilian Peev8131a262017-02-01 12:33:43 +0000431 ClientPriority highestPriority = priority;
Ruben Brunkcc776712015-02-17 20:18:47 -0800432 for (const auto& i : mClients) {
Emilian Peev8131a262017-02-01 12:33:43 +0000433 ClientPriority curPriority = i->getPriority();
434 if (curPriority <= highestPriority) {
Ruben Brunkcc776712015-02-17 20:18:47 -0800435 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();
Emilian Peev8131a262017-02-01 12:33:43 +0000449 ClientPriority curPriority = i->getPriority();
Ruben Brunkcc776712015-02-17 20:18:47 -0800450 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
Emilian Peev8131a262017-02-01 12:33:43 +0000458 if (conflicting && curPriority < priority) {
Ruben Brunkcc776712015-02-17 20:18:47 -0800459 // 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) &&
Emilian Peev8131a262017-02-01 12:33:43 +0000464 (curPriority >= priority) &&
Ruben Brunkcc776712015-02-17 20:18:47 -0800465 !(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
Emilian Peev8131a262017-02-01 12:33:43 +0000478 if (curPriority < priority && (conflicting || (totalCost > mMaxCost && curCost > 0))) {
Ruben Brunkcc776712015-02-17 20:18:47 -0800479 // 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
Ruben Brunk99e69712015-05-26 17:25:07 -0700501template<class KEY, class VALUE, class LISTENER>
502std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>>
503ClientManager<KEY, VALUE, LISTENER>::addAndEvict(
Ruben Brunkcc776712015-02-17 20:18:47 -0800504 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
Ruben Brunk80507212015-05-14 13:50:57 -0700514 if (iter != evicted.cend()) {
Ruben Brunk99e69712015-05-26 17:25:07 -0700515
516 if (mListener != nullptr) mListener->onClientRemoved(**iter);
517
Ruben Brunk80507212015-05-14 13:50:57 -0700518 // 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 }
Ruben Brunkcc776712015-02-17 20:18:47 -0800528
Ruben Brunk99e69712015-05-26 17:25:07 -0700529 if (mListener != nullptr) mListener->onClientAdded(*client);
Ruben Brunkcc776712015-02-17 20:18:47 -0800530 mClients.push_back(client);
Ruben Brunk4f9576b2015-04-10 17:26:56 -0700531 mRemovedCondition.broadcast();
Ruben Brunkcc776712015-02-17 20:18:47 -0800532
533 return evicted;
534}
535
Ruben Brunk99e69712015-05-26 17:25:07 -0700536template<class KEY, class VALUE, class LISTENER>
Ruben Brunkcc776712015-02-17 20:18:47 -0800537std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>>
Ruben Brunk99e69712015-05-26 17:25:07 -0700538ClientManager<KEY, VALUE, LISTENER>::getAll() const {
Ruben Brunkcc776712015-02-17 20:18:47 -0800539 Mutex::Autolock lock(mLock);
540 return mClients;
541}
542
Ruben Brunk99e69712015-05-26 17:25:07 -0700543template<class KEY, class VALUE, class LISTENER>
544std::vector<KEY> ClientManager<KEY, VALUE, LISTENER>::getAllKeys() const {
Ruben Brunkcc776712015-02-17 20:18:47 -0800545 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
Ruben Brunk99e69712015-05-26 17:25:07 -0700553template<class KEY, class VALUE, class LISTENER>
554std::vector<int32_t> ClientManager<KEY, VALUE, LISTENER>::getAllOwners() const {
Ruben Brunkcc776712015-02-17 20:18:47 -0800555 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
Ruben Brunk99e69712015-05-26 17:25:07 -0700563template<class KEY, class VALUE, class LISTENER>
564void ClientManager<KEY, VALUE, LISTENER>::updatePriorities(
Emilian Peev8131a262017-02-01 12:33:43 +0000565 const std::map<int32_t,ClientPriority>& ownerPriorityList) {
Ruben Brunkcc776712015-02-17 20:18:47 -0800566 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
Ruben Brunk99e69712015-05-26 17:25:07 -0700575template<class KEY, class VALUE, class LISTENER>
576std::shared_ptr<ClientDescriptor<KEY, VALUE>> ClientManager<KEY, VALUE, LISTENER>::get(
Ruben Brunkcc776712015-02-17 20:18:47 -0800577 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
Ruben Brunk99e69712015-05-26 17:25:07 -0700585template<class KEY, class VALUE, class LISTENER>
586void ClientManager<KEY, VALUE, LISTENER>::removeAll() {
Ruben Brunkcc776712015-02-17 20:18:47 -0800587 Mutex::Autolock lock(mLock);
Ruben Brunk99e69712015-05-26 17:25:07 -0700588 if (mListener != nullptr) {
589 for (const auto& i : mClients) {
590 mListener->onClientRemoved(*i);
591 }
592 }
Ruben Brunkcc776712015-02-17 20:18:47 -0800593 mClients.clear();
Ruben Brunk4f9576b2015-04-10 17:26:56 -0700594 mRemovedCondition.broadcast();
Ruben Brunkcc776712015-02-17 20:18:47 -0800595}
596
Ruben Brunk99e69712015-05-26 17:25:07 -0700597template<class KEY, class VALUE, class LISTENER>
598std::shared_ptr<ClientDescriptor<KEY, VALUE>> ClientManager<KEY, VALUE, LISTENER>::remove(
599 const KEY& key) {
Ruben Brunkcc776712015-02-17 20:18:47 -0800600 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(),
Ruben Brunk99e69712015-05-26 17:25:07 -0700606 [this, &key, &ret] (std::shared_ptr<ClientDescriptor<KEY, VALUE>>& curClientPtr) {
Ruben Brunkcc776712015-02-17 20:18:47 -0800607 if (curClientPtr->getKey() == key) {
Ruben Brunk99e69712015-05-26 17:25:07 -0700608 if (mListener != nullptr) mListener->onClientRemoved(*curClientPtr);
Ruben Brunkcc776712015-02-17 20:18:47 -0800609 ret = curClientPtr;
610 return true;
611 }
612 return false;
613 }), mClients.end());
614
Ruben Brunk4f9576b2015-04-10 17:26:56 -0700615 mRemovedCondition.broadcast();
616 return ret;
617}
618
Ruben Brunk99e69712015-05-26 17:25:07 -0700619template<class KEY, class VALUE, class LISTENER>
620status_t ClientManager<KEY, VALUE, LISTENER>::waitUntilRemoved(
Ruben Brunk4f9576b2015-04-10 17:26:56 -0700621 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
Ruben Brunkcc776712015-02-17 20:18:47 -0800648 return ret;
649}
650
Ruben Brunk99e69712015-05-26 17:25:07 -0700651template<class KEY, class VALUE, class LISTENER>
652void ClientManager<KEY, VALUE, LISTENER>::setListener(const std::shared_ptr<LISTENER>& listener) {
653 Mutex::Autolock lock(mLock);
654 mListener = listener;
655}
656
657template<class KEY, class VALUE, class LISTENER>
658void ClientManager<KEY, VALUE, LISTENER>::remove(
Ruben Brunkcc776712015-02-17 20:18:47 -0800659 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(),
Ruben Brunk99e69712015-05-26 17:25:07 -0700663 [this, &value] (std::shared_ptr<ClientDescriptor<KEY, VALUE>>& curClientPtr) {
Ruben Brunkcc776712015-02-17 20:18:47 -0800664 if (curClientPtr == value) {
Ruben Brunk99e69712015-05-26 17:25:07 -0700665 if (mListener != nullptr) mListener->onClientRemoved(*curClientPtr);
Ruben Brunkcc776712015-02-17 20:18:47 -0800666 return true;
667 }
668 return false;
669 }), mClients.end());
Ruben Brunk4f9576b2015-04-10 17:26:56 -0700670 mRemovedCondition.broadcast();
Ruben Brunkcc776712015-02-17 20:18:47 -0800671}
672
Ruben Brunk99e69712015-05-26 17:25:07 -0700673template<class KEY, class VALUE, class LISTENER>
674int64_t ClientManager<KEY, VALUE, LISTENER>::getCurrentCostLocked() const {
Ruben Brunkcc776712015-02-17 20:18:47 -0800675 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