blob: 09258ef3e587a9ab9761eb24b2b05cfece04a0cc [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
Eino-Ville Talvala7c602c32021-03-20 17:00:18 -070034// Values from frameworks/base/services/core/java/com/android/server/am/ProcessList.java
35const int32_t INVALID_ADJ = -10000;
36const int32_t UNKNOWN_ADJ = 1001;
37const int32_t CACHED_APP_MAX_ADJ = 999;
38const int32_t CACHED_APP_MIN_ADJ = 900;
39const int32_t CACHED_APP_LMK_FIRST_ADJ = 950;
40const int32_t CACHED_APP_IMPORTANCE_LEVELS = 5;
41const int32_t SERVICE_B_ADJ = 800;
42const int32_t PREVIOUS_APP_ADJ = 700;
43const int32_t HOME_APP_ADJ = 600;
44const int32_t SERVICE_ADJ = 500;
45const int32_t HEAVY_WEIGHT_APP_ADJ = 400;
46const int32_t BACKUP_APP_ADJ = 300;
47const int32_t PERCEPTIBLE_LOW_APP_ADJ = 250;
48const int32_t PERCEPTIBLE_MEDIUM_APP_ADJ = 225;
49const int32_t PERCEPTIBLE_APP_ADJ = 200;
50const int32_t VISIBLE_APP_ADJ = 100;
51const int32_t VISIBLE_APP_LAYER_MAX = PERCEPTIBLE_APP_ADJ - VISIBLE_APP_ADJ - 1;
52const int32_t PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ = 50;
53const int32_t FOREGROUND_APP_ADJ = 0;
54const int32_t PERSISTENT_SERVICE_ADJ = -700;
55const int32_t PERSISTENT_PROC_ADJ = -800;
56const int32_t SYSTEM_ADJ = -900;
57const int32_t NATIVE_ADJ = -1000;
58
Emilian Peev8131a262017-02-01 12:33:43 +000059class ClientPriority {
60public:
Jayant Chowdharyc578a502019-05-08 10:57:54 -070061 /**
62 * Choosing to set mIsVendorClient through a parameter instead of calling
Steven Moreland89a2c5c2020-01-31 15:02:25 -080063 * getCurrentServingCall() == BinderCallType::HWBINDER to protect against the
Jayant Chowdharyc578a502019-05-08 10:57:54 -070064 * case where the construction is offloaded to another thread which isn't a
65 * hwbinder thread.
66 */
67 ClientPriority(int32_t score, int32_t state, bool isVendorClient) :
Eino-Ville Talvala7c602c32021-03-20 17:00:18 -070068 mScore((score == INVALID_ADJ) ? UNKNOWN_ADJ : score),
69 mState(state),
70 mIsVendorClient(isVendorClient) { }
Emilian Peev8131a262017-02-01 12:33:43 +000071
72 int32_t getScore() const { return mScore; }
73 int32_t getState() const { return mState; }
74
Jayant Chowdharyc578a502019-05-08 10:57:54 -070075 void setScore(int32_t score) {
76 // For vendor clients, the score is set once and for all during
77 // construction. Otherwise, it can get reset each time cameraserver
78 // queries ActivityManagerService for oom_adj scores / states .
79 if (!mIsVendorClient) {
Eino-Ville Talvala7c602c32021-03-20 17:00:18 -070080 mScore = (score == INVALID_ADJ) ? UNKNOWN_ADJ : score;
Jayant Chowdharyc578a502019-05-08 10:57:54 -070081 }
82 }
83
84 void setState(int32_t state) {
85 // For vendor clients, the score is set once and for all during
86 // construction. Otherwise, it can get reset each time cameraserver
87 // queries ActivityManagerService for oom_adj scores / states
88 // (ActivityManagerService returns a vendor process' state as
89 // PROCESS_STATE_NONEXISTENT.
90 if (!mIsVendorClient) {
91 mState = state;
92 }
93 }
94
Emilian Peev8131a262017-02-01 12:33:43 +000095 bool operator==(const ClientPriority& rhs) const {
96 return (this->mScore == rhs.mScore) && (this->mState == rhs.mState);
97 }
98
99 bool operator< (const ClientPriority& rhs) const {
100 if (this->mScore == rhs.mScore) {
101 return this->mState < rhs.mState;
102 } else {
103 return this->mScore < rhs.mScore;
104 }
105 }
106
107 bool operator> (const ClientPriority& rhs) const {
108 return rhs < *this;
109 }
110
111 bool operator<=(const ClientPriority& rhs) const {
112 return !(*this > rhs);
113 }
114
115 bool operator>=(const ClientPriority& rhs) const {
116 return !(*this < rhs);
117 }
118
119private:
120 int32_t mScore;
121 int32_t mState;
Jayant Chowdharyc578a502019-05-08 10:57:54 -0700122 bool mIsVendorClient = false;
Emilian Peev8131a262017-02-01 12:33:43 +0000123};
124
Ruben Brunkcc776712015-02-17 20:18:47 -0800125// --------------------------------------------------------------------------------
126
127/**
128 * The ClientDescriptor class is a container for a given key/value pair identifying a shared
129 * resource, and the corresponding cost, priority, owner ID, and conflicting keys list used
130 * in determining eviction behavior.
131 *
132 * Aside from the priority, these values are immutable once the ClientDescriptor has been
133 * constructed.
134 */
135template<class KEY, class VALUE>
136class ClientDescriptor final {
137public:
138 ClientDescriptor(const KEY& key, const VALUE& value, int32_t cost,
Jayant Chowdharyc578a502019-05-08 10:57:54 -0700139 const std::set<KEY>& conflictingKeys, int32_t score, int32_t ownerId, int32_t state,
140 bool isVendorClient);
Ruben Brunkcc776712015-02-17 20:18:47 -0800141 ClientDescriptor(KEY&& key, VALUE&& value, int32_t cost, std::set<KEY>&& conflictingKeys,
Jayant Chowdharyc578a502019-05-08 10:57:54 -0700142 int32_t score, int32_t ownerId, int32_t state, bool isVendorClient);
Ruben Brunkcc776712015-02-17 20:18:47 -0800143
144 ~ClientDescriptor();
145
146 /**
147 * Return the key for this descriptor.
148 */
149 const KEY& getKey() const;
150
151 /**
152 * Return the value for this descriptor.
153 */
154 const VALUE& getValue() const;
155
156 /**
157 * Return the cost for this descriptor.
158 */
159 int32_t getCost() const;
160
161 /**
162 * Return the priority for this descriptor.
163 */
Emilian Peev8131a262017-02-01 12:33:43 +0000164 const ClientPriority &getPriority() const;
Ruben Brunkcc776712015-02-17 20:18:47 -0800165
166 /**
167 * Return the owner ID for this descriptor.
168 */
169 int32_t getOwnerId() const;
170
171 /**
172 * Return true if the given key is in this descriptor's conflicting keys list.
173 */
174 bool isConflicting(const KEY& key) const;
175
176 /**
177 * Return the set of all conflicting keys for this descriptor.
178 */
179 std::set<KEY> getConflicting() const;
180
181 /**
182 * Set the proirity for this descriptor.
183 */
Emilian Peev8131a262017-02-01 12:33:43 +0000184 void setPriority(const ClientPriority& priority);
Ruben Brunkcc776712015-02-17 20:18:47 -0800185
186 // This class is ordered by key
187 template<class K, class V>
188 friend bool operator < (const ClientDescriptor<K, V>& a, const ClientDescriptor<K, V>& b);
189
190private:
191 KEY mKey;
192 VALUE mValue;
193 int32_t mCost;
194 std::set<KEY> mConflicting;
Emilian Peev8131a262017-02-01 12:33:43 +0000195 ClientPriority mPriority;
Ruben Brunkcc776712015-02-17 20:18:47 -0800196 int32_t mOwnerId;
197}; // class ClientDescriptor
198
199template<class K, class V>
200bool operator < (const ClientDescriptor<K, V>& a, const ClientDescriptor<K, V>& b) {
201 return a.mKey < b.mKey;
202}
203
204template<class KEY, class VALUE>
205ClientDescriptor<KEY, VALUE>::ClientDescriptor(const KEY& key, const VALUE& value, int32_t cost,
Jayant Chowdharyc578a502019-05-08 10:57:54 -0700206 const std::set<KEY>& conflictingKeys, int32_t score, int32_t ownerId, int32_t state,
207 bool isVendorClient) :
Emilian Peev8131a262017-02-01 12:33:43 +0000208 mKey{key}, mValue{value}, mCost{cost}, mConflicting{conflictingKeys},
Jayant Chowdharyc578a502019-05-08 10:57:54 -0700209 mPriority(score, state, isVendorClient),
Ruben Brunkcc776712015-02-17 20:18:47 -0800210 mOwnerId{ownerId} {}
211
212template<class KEY, class VALUE>
213ClientDescriptor<KEY, VALUE>::ClientDescriptor(KEY&& key, VALUE&& value, int32_t cost,
Jayant Chowdharyc578a502019-05-08 10:57:54 -0700214 std::set<KEY>&& conflictingKeys, int32_t score, int32_t ownerId, int32_t state,
215 bool isVendorClient) :
Ruben Brunkcc776712015-02-17 20:18:47 -0800216 mKey{std::forward<KEY>(key)}, mValue{std::forward<VALUE>(value)}, mCost{cost},
Emilian Peev8131a262017-02-01 12:33:43 +0000217 mConflicting{std::forward<std::set<KEY>>(conflictingKeys)},
Jayant Chowdharyc578a502019-05-08 10:57:54 -0700218 mPriority(score, state, isVendorClient), mOwnerId{ownerId} {}
Ruben Brunkcc776712015-02-17 20:18:47 -0800219
220template<class KEY, class VALUE>
221ClientDescriptor<KEY, VALUE>::~ClientDescriptor() {}
222
223template<class KEY, class VALUE>
224const KEY& ClientDescriptor<KEY, VALUE>::getKey() const {
225 return mKey;
226}
227
228template<class KEY, class VALUE>
229const VALUE& ClientDescriptor<KEY, VALUE>::getValue() const {
230 return mValue;
231}
232
233template<class KEY, class VALUE>
234int32_t ClientDescriptor<KEY, VALUE>::getCost() const {
235 return mCost;
236}
237
238template<class KEY, class VALUE>
Emilian Peev8131a262017-02-01 12:33:43 +0000239const ClientPriority& ClientDescriptor<KEY, VALUE>::getPriority() const {
Ruben Brunkcc776712015-02-17 20:18:47 -0800240 return mPriority;
241}
242
243template<class KEY, class VALUE>
244int32_t ClientDescriptor<KEY, VALUE>::getOwnerId() const {
245 return mOwnerId;
246}
247
248template<class KEY, class VALUE>
249bool ClientDescriptor<KEY, VALUE>::isConflicting(const KEY& key) const {
250 if (key == mKey) return true;
251 for (const auto& x : mConflicting) {
252 if (key == x) return true;
253 }
254 return false;
255}
256
257template<class KEY, class VALUE>
258std::set<KEY> ClientDescriptor<KEY, VALUE>::getConflicting() const {
259 return mConflicting;
260}
261
262template<class KEY, class VALUE>
Emilian Peev8131a262017-02-01 12:33:43 +0000263void ClientDescriptor<KEY, VALUE>::setPriority(const ClientPriority& priority) {
Jayant Chowdharyc578a502019-05-08 10:57:54 -0700264 // We don't use the usual copy constructor here since we want to remember
265 // whether a client is a vendor client or not. This could have been wiped
266 // off in the incoming priority argument since an AIDL thread might have
Steven Moreland89a2c5c2020-01-31 15:02:25 -0800267 // called getCurrentServingCall() == BinderCallType::HWBINDER after refreshing
Jayant Chowdharyc578a502019-05-08 10:57:54 -0700268 // priorities for old clients through ProcessInfoService::getProcessStatesScoresFromPids().
269 mPriority.setScore(priority.getScore());
270 mPriority.setState(priority.getState());
Ruben Brunkcc776712015-02-17 20:18:47 -0800271}
272
273// --------------------------------------------------------------------------------
274
275/**
Ruben Brunk99e69712015-05-26 17:25:07 -0700276 * A default class implementing the LISTENER interface used by ClientManager.
277 */
278template<class KEY, class VALUE>
279class DefaultEventListener {
280public:
281 void onClientAdded(const ClientDescriptor<KEY, VALUE>& descriptor);
282 void onClientRemoved(const ClientDescriptor<KEY, VALUE>& descriptor);
283};
284
285template<class KEY, class VALUE>
286void DefaultEventListener<KEY, VALUE>::onClientAdded(
287 const ClientDescriptor<KEY, VALUE>& /*descriptor*/) {}
288
289template<class KEY, class VALUE>
290void DefaultEventListener<KEY, VALUE>::onClientRemoved(
291 const ClientDescriptor<KEY, VALUE>& /*descriptor*/) {}
292
293// --------------------------------------------------------------------------------
294
295/**
Ruben Brunkcc776712015-02-17 20:18:47 -0800296 * The ClientManager class wraps an LRU-ordered list of active clients and implements eviction
297 * behavior for handling shared resource access.
298 *
299 * When adding a new descriptor, eviction behavior is as follows:
300 * - Keys are unique, adding a descriptor with the same key as an existing descriptor will
301 * result in the lower-priority of the two being removed. Priority ties result in the
302 * LRU descriptor being evicted (this means the incoming descriptor be added in this case).
303 * - Any descriptors with keys that are in the incoming descriptor's 'conflicting keys' list
304 * will be removed if they have an equal or lower priority than the incoming descriptor;
305 * if any have a higher priority, the incoming descriptor is removed instead.
306 * - If the sum of all descriptors' costs, including the incoming descriptor's, is more than
307 * the max cost allowed for this ClientManager, descriptors with non-zero cost, equal or lower
308 * priority, and a different owner will be evicted in LRU order until either the cost is less
309 * than the max cost, or all descriptors meeting this criteria have been evicted and the
310 * incoming descriptor has the highest priority. Otherwise, the incoming descriptor is
311 * removed instead.
312 */
Ruben Brunk99e69712015-05-26 17:25:07 -0700313template<class KEY, class VALUE, class LISTENER=DefaultEventListener<KEY, VALUE>>
Ruben Brunkcc776712015-02-17 20:18:47 -0800314class ClientManager {
315public:
316 // The default maximum "cost" allowed before evicting
317 static constexpr int32_t DEFAULT_MAX_COST = 100;
318
319 ClientManager();
Chih-Hung Hsieh8b0b9712016-08-09 14:25:53 -0700320 explicit ClientManager(int32_t totalCost);
Ruben Brunkcc776712015-02-17 20:18:47 -0800321
322 /**
323 * Add a given ClientDescriptor to the managed list. ClientDescriptors for clients that
324 * are evicted by this action are returned in a vector.
325 *
326 * This may return the ClientDescriptor passed in if it would be evicted.
327 */
328 std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>> addAndEvict(
329 const std::shared_ptr<ClientDescriptor<KEY, VALUE>>& client);
330
331 /**
332 * Given a map containing owner (pid) -> priority mappings, update the priority of each
333 * ClientDescriptor with an owner in this mapping.
334 */
Emilian Peev8131a262017-02-01 12:33:43 +0000335 void updatePriorities(const std::map<int32_t,ClientPriority>& ownerPriorityList);
Ruben Brunkcc776712015-02-17 20:18:47 -0800336
337 /**
338 * Remove all ClientDescriptors.
339 */
340 void removeAll();
341
342 /**
343 * Remove and return the ClientDescriptor with a given key.
344 */
345 std::shared_ptr<ClientDescriptor<KEY, VALUE>> remove(const KEY& key);
346
347 /**
348 * Remove the given ClientDescriptor.
349 */
350 void remove(const std::shared_ptr<ClientDescriptor<KEY, VALUE>>& value);
351
352 /**
353 * Return a vector of the ClientDescriptors that would be evicted by adding the given
354 * ClientDescriptor.
355 *
356 * This may return the ClientDescriptor passed in if it would be evicted.
357 */
358 std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>> wouldEvict(
359 const std::shared_ptr<ClientDescriptor<KEY, VALUE>>& client) const;
360
361 /**
362 * Return a vector of active ClientDescriptors that prevent this client from being added.
363 */
364 std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>> getIncompatibleClients(
365 const std::shared_ptr<ClientDescriptor<KEY, VALUE>>& client) const;
366
367 /**
368 * Return a vector containing all currently active ClientDescriptors.
369 */
370 std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>> getAll() const;
371
372 /**
373 * Return a vector containing all keys of currently active ClientDescriptors.
374 */
375 std::vector<KEY> getAllKeys() const;
376
377 /**
378 * Return a vector of the owner tags of all currently active ClientDescriptors (duplicates
379 * will be removed).
380 */
381 std::vector<int32_t> getAllOwners() const;
382
383 /**
384 * Return the ClientDescriptor corresponding to the given key, or an empty shared pointer
385 * if none exists.
386 */
387 std::shared_ptr<ClientDescriptor<KEY, VALUE>> get(const KEY& key) const;
388
Ruben Brunk4f9576b2015-04-10 17:26:56 -0700389 /**
390 * Block until the given client is no longer in the active clients list, or the timeout
391 * occurred.
392 *
393 * Returns NO_ERROR if this succeeded, -ETIMEDOUT on a timeout, or a negative error code on
394 * failure.
395 */
396 status_t waitUntilRemoved(const std::shared_ptr<ClientDescriptor<KEY, VALUE>> client,
397 nsecs_t timeout) const;
398
Ruben Brunk99e69712015-05-26 17:25:07 -0700399 /**
400 * Set the current listener for client add/remove events.
401 *
402 * The listener instance must inherit from the LISTENER class and implement the following
403 * methods:
404 * void onClientRemoved(const ClientDescriptor<KEY, VALUE>& descriptor);
405 * void onClientAdded(const ClientDescriptor<KEY, VALUE>& descriptor);
406 *
407 * These callback methods will be called with the ClientManager's lock held, and should
408 * not call any further ClientManager methods.
409 *
410 * The onClientRemoved method will be called when the client has been removed or evicted
411 * from the ClientManager that this event listener has been added to. The onClientAdded
412 * method will be called when the client has been added to the ClientManager that this
413 * event listener has been added to.
414 */
415 void setListener(const std::shared_ptr<LISTENER>& listener);
416
Ruben Brunkcc776712015-02-17 20:18:47 -0800417protected:
418 ~ClientManager();
419
420private:
421
422 /**
423 * Return a vector of the ClientDescriptors that would be evicted by adding the given
424 * ClientDescriptor. If returnIncompatibleClients is set to true, instead, return the
425 * vector of ClientDescriptors that are higher priority than the incoming client and
426 * either conflict with this client, or contribute to the resource cost if that would
427 * prevent the incoming client from being added.
428 *
429 * This may return the ClientDescriptor passed in.
430 */
431 std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>> wouldEvictLocked(
432 const std::shared_ptr<ClientDescriptor<KEY, VALUE>>& client,
433 bool returnIncompatibleClients = false) const;
434
435 int64_t getCurrentCostLocked() const;
436
437 mutable Mutex mLock;
Ruben Brunk4f9576b2015-04-10 17:26:56 -0700438 mutable Condition mRemovedCondition;
Ruben Brunkcc776712015-02-17 20:18:47 -0800439 int32_t mMaxCost;
440 // LRU ordered, most recent at end
441 std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>> mClients;
Ruben Brunk99e69712015-05-26 17:25:07 -0700442 std::shared_ptr<LISTENER> mListener;
Ruben Brunkcc776712015-02-17 20:18:47 -0800443}; // class ClientManager
444
Ruben Brunk99e69712015-05-26 17:25:07 -0700445template<class KEY, class VALUE, class LISTENER>
446ClientManager<KEY, VALUE, LISTENER>::ClientManager() :
Ruben Brunkcc776712015-02-17 20:18:47 -0800447 ClientManager(DEFAULT_MAX_COST) {}
448
Ruben Brunk99e69712015-05-26 17:25:07 -0700449template<class KEY, class VALUE, class LISTENER>
450ClientManager<KEY, VALUE, LISTENER>::ClientManager(int32_t totalCost) : mMaxCost(totalCost) {}
Ruben Brunkcc776712015-02-17 20:18:47 -0800451
Ruben Brunk99e69712015-05-26 17:25:07 -0700452template<class KEY, class VALUE, class LISTENER>
453ClientManager<KEY, VALUE, LISTENER>::~ClientManager() {}
Ruben Brunkcc776712015-02-17 20:18:47 -0800454
Ruben Brunk99e69712015-05-26 17:25:07 -0700455template<class KEY, class VALUE, class LISTENER>
456std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>>
457ClientManager<KEY, VALUE, LISTENER>::wouldEvict(
Ruben Brunkcc776712015-02-17 20:18:47 -0800458 const std::shared_ptr<ClientDescriptor<KEY, VALUE>>& client) const {
459 Mutex::Autolock lock(mLock);
460 return wouldEvictLocked(client);
461}
462
Ruben Brunk99e69712015-05-26 17:25:07 -0700463template<class KEY, class VALUE, class LISTENER>
Ruben Brunkcc776712015-02-17 20:18:47 -0800464std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>>
Ruben Brunk99e69712015-05-26 17:25:07 -0700465ClientManager<KEY, VALUE, LISTENER>::getIncompatibleClients(
Ruben Brunkcc776712015-02-17 20:18:47 -0800466 const std::shared_ptr<ClientDescriptor<KEY, VALUE>>& client) const {
467 Mutex::Autolock lock(mLock);
468 return wouldEvictLocked(client, /*returnIncompatibleClients*/true);
469}
470
Ruben Brunk99e69712015-05-26 17:25:07 -0700471template<class KEY, class VALUE, class LISTENER>
Ruben Brunkcc776712015-02-17 20:18:47 -0800472std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>>
Ruben Brunk99e69712015-05-26 17:25:07 -0700473ClientManager<KEY, VALUE, LISTENER>::wouldEvictLocked(
Ruben Brunkcc776712015-02-17 20:18:47 -0800474 const std::shared_ptr<ClientDescriptor<KEY, VALUE>>& client,
475 bool returnIncompatibleClients) const {
476
477 std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>> evictList;
478
479 // Disallow null clients, return input
480 if (client == nullptr) {
481 evictList.push_back(client);
482 return evictList;
483 }
484
485 const KEY& key = client->getKey();
486 int32_t cost = client->getCost();
Emilian Peev8131a262017-02-01 12:33:43 +0000487 ClientPriority priority = client->getPriority();
Ruben Brunkcc776712015-02-17 20:18:47 -0800488 int32_t owner = client->getOwnerId();
489
490 int64_t totalCost = getCurrentCostLocked() + cost;
491
492 // Determine the MRU of the owners tied for having the highest priority
493 int32_t highestPriorityOwner = owner;
Emilian Peev8131a262017-02-01 12:33:43 +0000494 ClientPriority highestPriority = priority;
Ruben Brunkcc776712015-02-17 20:18:47 -0800495 for (const auto& i : mClients) {
Emilian Peev8131a262017-02-01 12:33:43 +0000496 ClientPriority curPriority = i->getPriority();
497 if (curPriority <= highestPriority) {
Ruben Brunkcc776712015-02-17 20:18:47 -0800498 highestPriority = curPriority;
499 highestPriorityOwner = i->getOwnerId();
500 }
501 }
502
503 if (highestPriority == priority) {
504 // Switch back owner if the incoming client has the highest priority, as it is MRU
505 highestPriorityOwner = owner;
506 }
507
508 // Build eviction list of clients to remove
509 for (const auto& i : mClients) {
510 const KEY& curKey = i->getKey();
511 int32_t curCost = i->getCost();
Emilian Peev8131a262017-02-01 12:33:43 +0000512 ClientPriority curPriority = i->getPriority();
Ruben Brunkcc776712015-02-17 20:18:47 -0800513 int32_t curOwner = i->getOwnerId();
514
515 bool conflicting = (curKey == key || i->isConflicting(key) ||
516 client->isConflicting(curKey));
517
518 if (!returnIncompatibleClients) {
519 // Find evicted clients
520
Emilian Peev8131a262017-02-01 12:33:43 +0000521 if (conflicting && curPriority < priority) {
Ruben Brunkcc776712015-02-17 20:18:47 -0800522 // Pre-existing conflicting client with higher priority exists
523 evictList.clear();
524 evictList.push_back(client);
525 return evictList;
Yin-Chia Yeh8dfe4642020-06-01 11:57:45 -0700526 } else if (conflicting && owner == curOwner) {
527 // Pre-existing conflicting client with the same client owner exists
528 // Open the same device twice -> most recent open wins
529 // Otherwise let the existing client wins to avoid behaviors difference
530 // due to how HAL advertising conflicting devices (which is hidden from
531 // application)
532 if (curKey == key) {
533 evictList.push_back(i);
534 totalCost -= curCost;
535 } else {
536 evictList.clear();
537 evictList.push_back(client);
538 return evictList;
539 }
Ruben Brunkcc776712015-02-17 20:18:47 -0800540 } else if (conflicting || ((totalCost > mMaxCost && curCost > 0) &&
Emilian Peev8131a262017-02-01 12:33:43 +0000541 (curPriority >= priority) &&
Ruben Brunkcc776712015-02-17 20:18:47 -0800542 !(highestPriorityOwner == owner && owner == curOwner))) {
543 // Add a pre-existing client to the eviction list if:
544 // - We are adding a client with higher priority that conflicts with this one.
545 // - The total cost including the incoming client's is more than the allowable
546 // maximum, and the client has a non-zero cost, lower priority, and a different
547 // owner than the incoming client when the incoming client has the
548 // highest priority.
549 evictList.push_back(i);
550 totalCost -= curCost;
551 }
552 } else {
553 // Find clients preventing the incoming client from being added
554
Emilian Peev8131a262017-02-01 12:33:43 +0000555 if (curPriority < priority && (conflicting || (totalCost > mMaxCost && curCost > 0))) {
Ruben Brunkcc776712015-02-17 20:18:47 -0800556 // Pre-existing conflicting client with higher priority exists
557 evictList.push_back(i);
558 }
559 }
560 }
561
562 // Immediately return the incompatible clients if we are calculating these instead
563 if (returnIncompatibleClients) {
564 return evictList;
565 }
566
567 // If the total cost is too high, return the input unless the input has the highest priority
568 if (totalCost > mMaxCost && highestPriorityOwner != owner) {
569 evictList.clear();
570 evictList.push_back(client);
571 return evictList;
572 }
573
574 return evictList;
575
576}
577
Ruben Brunk99e69712015-05-26 17:25:07 -0700578template<class KEY, class VALUE, class LISTENER>
579std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>>
580ClientManager<KEY, VALUE, LISTENER>::addAndEvict(
Ruben Brunkcc776712015-02-17 20:18:47 -0800581 const std::shared_ptr<ClientDescriptor<KEY, VALUE>>& client) {
582 Mutex::Autolock lock(mLock);
583 auto evicted = wouldEvictLocked(client);
584 auto it = evicted.begin();
585 if (it != evicted.end() && *it == client) {
586 return evicted;
587 }
588
589 auto iter = evicted.cbegin();
590
Ruben Brunk80507212015-05-14 13:50:57 -0700591 if (iter != evicted.cend()) {
Ruben Brunk99e69712015-05-26 17:25:07 -0700592
593 if (mListener != nullptr) mListener->onClientRemoved(**iter);
594
Ruben Brunk80507212015-05-14 13:50:57 -0700595 // Remove evicted clients from list
596 mClients.erase(std::remove_if(mClients.begin(), mClients.end(),
597 [&iter] (std::shared_ptr<ClientDescriptor<KEY, VALUE>>& curClientPtr) {
598 if (curClientPtr->getKey() == (*iter)->getKey()) {
599 iter++;
600 return true;
601 }
602 return false;
603 }), mClients.end());
604 }
Ruben Brunkcc776712015-02-17 20:18:47 -0800605
Ruben Brunk99e69712015-05-26 17:25:07 -0700606 if (mListener != nullptr) mListener->onClientAdded(*client);
Ruben Brunkcc776712015-02-17 20:18:47 -0800607 mClients.push_back(client);
Ruben Brunk4f9576b2015-04-10 17:26:56 -0700608 mRemovedCondition.broadcast();
Ruben Brunkcc776712015-02-17 20:18:47 -0800609
610 return evicted;
611}
612
Ruben Brunk99e69712015-05-26 17:25:07 -0700613template<class KEY, class VALUE, class LISTENER>
Ruben Brunkcc776712015-02-17 20:18:47 -0800614std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>>
Ruben Brunk99e69712015-05-26 17:25:07 -0700615ClientManager<KEY, VALUE, LISTENER>::getAll() const {
Ruben Brunkcc776712015-02-17 20:18:47 -0800616 Mutex::Autolock lock(mLock);
617 return mClients;
618}
619
Ruben Brunk99e69712015-05-26 17:25:07 -0700620template<class KEY, class VALUE, class LISTENER>
621std::vector<KEY> ClientManager<KEY, VALUE, LISTENER>::getAllKeys() const {
Ruben Brunkcc776712015-02-17 20:18:47 -0800622 Mutex::Autolock lock(mLock);
623 std::vector<KEY> keys(mClients.size());
624 for (const auto& i : mClients) {
625 keys.push_back(i->getKey());
626 }
627 return keys;
628}
629
Ruben Brunk99e69712015-05-26 17:25:07 -0700630template<class KEY, class VALUE, class LISTENER>
631std::vector<int32_t> ClientManager<KEY, VALUE, LISTENER>::getAllOwners() const {
Ruben Brunkcc776712015-02-17 20:18:47 -0800632 Mutex::Autolock lock(mLock);
633 std::set<int32_t> owners;
634 for (const auto& i : mClients) {
635 owners.emplace(i->getOwnerId());
636 }
637 return std::vector<int32_t>(owners.begin(), owners.end());
638}
639
Ruben Brunk99e69712015-05-26 17:25:07 -0700640template<class KEY, class VALUE, class LISTENER>
641void ClientManager<KEY, VALUE, LISTENER>::updatePriorities(
Emilian Peev8131a262017-02-01 12:33:43 +0000642 const std::map<int32_t,ClientPriority>& ownerPriorityList) {
Ruben Brunkcc776712015-02-17 20:18:47 -0800643 Mutex::Autolock lock(mLock);
644 for (auto& i : mClients) {
645 auto j = ownerPriorityList.find(i->getOwnerId());
646 if (j != ownerPriorityList.end()) {
647 i->setPriority(j->second);
648 }
649 }
650}
651
Ruben Brunk99e69712015-05-26 17:25:07 -0700652template<class KEY, class VALUE, class LISTENER>
653std::shared_ptr<ClientDescriptor<KEY, VALUE>> ClientManager<KEY, VALUE, LISTENER>::get(
Ruben Brunkcc776712015-02-17 20:18:47 -0800654 const KEY& key) const {
655 Mutex::Autolock lock(mLock);
656 for (const auto& i : mClients) {
657 if (i->getKey() == key) return i;
658 }
659 return std::shared_ptr<ClientDescriptor<KEY, VALUE>>(nullptr);
660}
661
Ruben Brunk99e69712015-05-26 17:25:07 -0700662template<class KEY, class VALUE, class LISTENER>
663void ClientManager<KEY, VALUE, LISTENER>::removeAll() {
Ruben Brunkcc776712015-02-17 20:18:47 -0800664 Mutex::Autolock lock(mLock);
Ruben Brunk99e69712015-05-26 17:25:07 -0700665 if (mListener != nullptr) {
666 for (const auto& i : mClients) {
667 mListener->onClientRemoved(*i);
668 }
669 }
Ruben Brunkcc776712015-02-17 20:18:47 -0800670 mClients.clear();
Ruben Brunk4f9576b2015-04-10 17:26:56 -0700671 mRemovedCondition.broadcast();
Ruben Brunkcc776712015-02-17 20:18:47 -0800672}
673
Ruben Brunk99e69712015-05-26 17:25:07 -0700674template<class KEY, class VALUE, class LISTENER>
675std::shared_ptr<ClientDescriptor<KEY, VALUE>> ClientManager<KEY, VALUE, LISTENER>::remove(
676 const KEY& key) {
Ruben Brunkcc776712015-02-17 20:18:47 -0800677 Mutex::Autolock lock(mLock);
678
679 std::shared_ptr<ClientDescriptor<KEY, VALUE>> ret;
680
681 // Remove evicted clients from list
682 mClients.erase(std::remove_if(mClients.begin(), mClients.end(),
Ruben Brunk99e69712015-05-26 17:25:07 -0700683 [this, &key, &ret] (std::shared_ptr<ClientDescriptor<KEY, VALUE>>& curClientPtr) {
Ruben Brunkcc776712015-02-17 20:18:47 -0800684 if (curClientPtr->getKey() == key) {
Ruben Brunk99e69712015-05-26 17:25:07 -0700685 if (mListener != nullptr) mListener->onClientRemoved(*curClientPtr);
Ruben Brunkcc776712015-02-17 20:18:47 -0800686 ret = curClientPtr;
687 return true;
688 }
689 return false;
690 }), mClients.end());
691
Ruben Brunk4f9576b2015-04-10 17:26:56 -0700692 mRemovedCondition.broadcast();
693 return ret;
694}
695
Ruben Brunk99e69712015-05-26 17:25:07 -0700696template<class KEY, class VALUE, class LISTENER>
697status_t ClientManager<KEY, VALUE, LISTENER>::waitUntilRemoved(
Ruben Brunk4f9576b2015-04-10 17:26:56 -0700698 const std::shared_ptr<ClientDescriptor<KEY, VALUE>> client,
699 nsecs_t timeout) const {
700 status_t ret = NO_ERROR;
701 Mutex::Autolock lock(mLock);
702
703 bool isRemoved = false;
704
705 // Figure out what time in the future we should hit the timeout
706 nsecs_t failTime = systemTime(SYSTEM_TIME_MONOTONIC) + timeout;
707
708 while (!isRemoved) {
709 isRemoved = true;
710 for (const auto& i : mClients) {
711 if (i == client) {
712 isRemoved = false;
713 }
714 }
715
716 if (!isRemoved) {
717 ret = mRemovedCondition.waitRelative(mLock, timeout);
718 if (ret != NO_ERROR) {
719 break;
720 }
721 timeout = failTime - systemTime(SYSTEM_TIME_MONOTONIC);
722 }
723 }
724
Ruben Brunkcc776712015-02-17 20:18:47 -0800725 return ret;
726}
727
Ruben Brunk99e69712015-05-26 17:25:07 -0700728template<class KEY, class VALUE, class LISTENER>
729void ClientManager<KEY, VALUE, LISTENER>::setListener(const std::shared_ptr<LISTENER>& listener) {
730 Mutex::Autolock lock(mLock);
731 mListener = listener;
732}
733
734template<class KEY, class VALUE, class LISTENER>
735void ClientManager<KEY, VALUE, LISTENER>::remove(
Ruben Brunkcc776712015-02-17 20:18:47 -0800736 const std::shared_ptr<ClientDescriptor<KEY, VALUE>>& value) {
737 Mutex::Autolock lock(mLock);
738 // Remove evicted clients from list
739 mClients.erase(std::remove_if(mClients.begin(), mClients.end(),
Ruben Brunk99e69712015-05-26 17:25:07 -0700740 [this, &value] (std::shared_ptr<ClientDescriptor<KEY, VALUE>>& curClientPtr) {
Ruben Brunkcc776712015-02-17 20:18:47 -0800741 if (curClientPtr == value) {
Ruben Brunk99e69712015-05-26 17:25:07 -0700742 if (mListener != nullptr) mListener->onClientRemoved(*curClientPtr);
Ruben Brunkcc776712015-02-17 20:18:47 -0800743 return true;
744 }
745 return false;
746 }), mClients.end());
Ruben Brunk4f9576b2015-04-10 17:26:56 -0700747 mRemovedCondition.broadcast();
Ruben Brunkcc776712015-02-17 20:18:47 -0800748}
749
Ruben Brunk99e69712015-05-26 17:25:07 -0700750template<class KEY, class VALUE, class LISTENER>
751int64_t ClientManager<KEY, VALUE, LISTENER>::getCurrentCostLocked() const {
Ruben Brunkcc776712015-02-17 20:18:47 -0800752 int64_t totalCost = 0;
753 for (const auto& x : mClients) {
754 totalCost += x->getCost();
755 }
756 return totalCost;
757}
758
759// --------------------------------------------------------------------------------
760
761}; // namespace resource_policy
762}; // namespace android
763
764#endif // ANDROID_SERVICE_UTILS_EVICTION_POLICY_MANAGER_H