blob: d1648851168e174956314fdc4b54e23d75a11fdd [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 */
Jayant Chowdhary8eb8d912021-05-18 17:41:56 +000067 ClientPriority(int32_t score, int32_t state, bool isVendorClient, int32_t scoreOffset = 0) :
68 mIsVendorClient(isVendorClient), mScoreOffset(scoreOffset) {
69 setScore(score);
70 setState(state);
71 }
Emilian Peev8131a262017-02-01 12:33:43 +000072
73 int32_t getScore() const { return mScore; }
74 int32_t getState() const { return mState; }
Jayant Chowdhary8eb8d912021-05-18 17:41:56 +000075 int32_t isVendorClient() const { return mIsVendorClient; }
Emilian Peev8131a262017-02-01 12:33:43 +000076
Jayant Chowdharyc578a502019-05-08 10:57:54 -070077 void setScore(int32_t score) {
78 // For vendor clients, the score is set once and for all during
79 // construction. Otherwise, it can get reset each time cameraserver
80 // queries ActivityManagerService for oom_adj scores / states .
Jayant Chowdhary8eb8d912021-05-18 17:41:56 +000081 // For clients where the score offset is set by the app, add it to the
82 // score provided by ActivityManagerService.
83 if (score == INVALID_ADJ) {
84 mScore = UNKNOWN_ADJ;
85 } else {
86 mScore = mScoreOffset + score;
Jayant Chowdharyc578a502019-05-08 10:57:54 -070087 }
88 }
89
90 void setState(int32_t state) {
91 // For vendor clients, the score is set once and for all during
92 // construction. Otherwise, it can get reset each time cameraserver
93 // queries ActivityManagerService for oom_adj scores / states
94 // (ActivityManagerService returns a vendor process' state as
95 // PROCESS_STATE_NONEXISTENT.
Jayant Chowdhary8eb8d912021-05-18 17:41:56 +000096 mState = state;
Jayant Chowdharyc578a502019-05-08 10:57:54 -070097 }
98
Emilian Peev8131a262017-02-01 12:33:43 +000099 bool operator==(const ClientPriority& rhs) const {
100 return (this->mScore == rhs.mScore) && (this->mState == rhs.mState);
101 }
102
103 bool operator< (const ClientPriority& rhs) const {
104 if (this->mScore == rhs.mScore) {
105 return this->mState < rhs.mState;
106 } else {
107 return this->mScore < rhs.mScore;
108 }
109 }
110
111 bool operator> (const ClientPriority& rhs) const {
112 return rhs < *this;
113 }
114
115 bool operator<=(const ClientPriority& rhs) const {
116 return !(*this > rhs);
117 }
118
119 bool operator>=(const ClientPriority& rhs) const {
120 return !(*this < rhs);
121 }
122
123private:
124 int32_t mScore;
125 int32_t mState;
Jayant Chowdharyc578a502019-05-08 10:57:54 -0700126 bool mIsVendorClient = false;
Jayant Chowdhary8eb8d912021-05-18 17:41:56 +0000127 int32_t mScoreOffset = 0;
Emilian Peev8131a262017-02-01 12:33:43 +0000128};
129
Ruben Brunkcc776712015-02-17 20:18:47 -0800130// --------------------------------------------------------------------------------
131
132/**
133 * The ClientDescriptor class is a container for a given key/value pair identifying a shared
134 * resource, and the corresponding cost, priority, owner ID, and conflicting keys list used
135 * in determining eviction behavior.
136 *
137 * Aside from the priority, these values are immutable once the ClientDescriptor has been
138 * constructed.
139 */
140template<class KEY, class VALUE>
141class ClientDescriptor final {
142public:
143 ClientDescriptor(const KEY& key, const VALUE& value, int32_t cost,
Jayant Chowdharyc578a502019-05-08 10:57:54 -0700144 const std::set<KEY>& conflictingKeys, int32_t score, int32_t ownerId, int32_t state,
Jayant Chowdhary8eb8d912021-05-18 17:41:56 +0000145 bool isVendorClient, int32_t oomScoreOffset);
Ruben Brunkcc776712015-02-17 20:18:47 -0800146 ClientDescriptor(KEY&& key, VALUE&& value, int32_t cost, std::set<KEY>&& conflictingKeys,
Jayant Chowdhary8eb8d912021-05-18 17:41:56 +0000147 int32_t score, int32_t ownerId, int32_t state, bool isVendorClient,
148 int32_t oomScoreOffset);
Ruben Brunkcc776712015-02-17 20:18:47 -0800149
150 ~ClientDescriptor();
151
152 /**
153 * Return the key for this descriptor.
154 */
155 const KEY& getKey() const;
156
157 /**
158 * Return the value for this descriptor.
159 */
160 const VALUE& getValue() const;
161
162 /**
163 * Return the cost for this descriptor.
164 */
165 int32_t getCost() const;
166
167 /**
168 * Return the priority for this descriptor.
169 */
Emilian Peev8131a262017-02-01 12:33:43 +0000170 const ClientPriority &getPriority() const;
Ruben Brunkcc776712015-02-17 20:18:47 -0800171
172 /**
173 * Return the owner ID for this descriptor.
174 */
175 int32_t getOwnerId() const;
176
177 /**
178 * Return true if the given key is in this descriptor's conflicting keys list.
179 */
180 bool isConflicting(const KEY& key) const;
181
182 /**
183 * Return the set of all conflicting keys for this descriptor.
184 */
185 std::set<KEY> getConflicting() const;
186
187 /**
188 * Set the proirity for this descriptor.
189 */
Emilian Peev8131a262017-02-01 12:33:43 +0000190 void setPriority(const ClientPriority& priority);
Ruben Brunkcc776712015-02-17 20:18:47 -0800191
192 // This class is ordered by key
193 template<class K, class V>
194 friend bool operator < (const ClientDescriptor<K, V>& a, const ClientDescriptor<K, V>& b);
195
196private:
197 KEY mKey;
198 VALUE mValue;
199 int32_t mCost;
200 std::set<KEY> mConflicting;
Emilian Peev8131a262017-02-01 12:33:43 +0000201 ClientPriority mPriority;
Ruben Brunkcc776712015-02-17 20:18:47 -0800202 int32_t mOwnerId;
203}; // class ClientDescriptor
204
205template<class K, class V>
206bool operator < (const ClientDescriptor<K, V>& a, const ClientDescriptor<K, V>& b) {
207 return a.mKey < b.mKey;
208}
209
210template<class KEY, class VALUE>
211ClientDescriptor<KEY, VALUE>::ClientDescriptor(const KEY& key, const VALUE& value, int32_t cost,
Jayant Chowdharyc578a502019-05-08 10:57:54 -0700212 const std::set<KEY>& conflictingKeys, int32_t score, int32_t ownerId, int32_t state,
Jayant Chowdhary8eb8d912021-05-18 17:41:56 +0000213 bool isVendorClient, int32_t scoreOffset) :
Emilian Peev8131a262017-02-01 12:33:43 +0000214 mKey{key}, mValue{value}, mCost{cost}, mConflicting{conflictingKeys},
Jayant Chowdhary8eb8d912021-05-18 17:41:56 +0000215 mPriority(score, state, isVendorClient, scoreOffset),
Ruben Brunkcc776712015-02-17 20:18:47 -0800216 mOwnerId{ownerId} {}
217
218template<class KEY, class VALUE>
219ClientDescriptor<KEY, VALUE>::ClientDescriptor(KEY&& key, VALUE&& value, int32_t cost,
Jayant Chowdharyc578a502019-05-08 10:57:54 -0700220 std::set<KEY>&& conflictingKeys, int32_t score, int32_t ownerId, int32_t state,
Jayant Chowdhary8eb8d912021-05-18 17:41:56 +0000221 bool isVendorClient, int32_t scoreOffset) :
Ruben Brunkcc776712015-02-17 20:18:47 -0800222 mKey{std::forward<KEY>(key)}, mValue{std::forward<VALUE>(value)}, mCost{cost},
Emilian Peev8131a262017-02-01 12:33:43 +0000223 mConflicting{std::forward<std::set<KEY>>(conflictingKeys)},
Jayant Chowdhary8eb8d912021-05-18 17:41:56 +0000224 mPriority(score, state, isVendorClient, scoreOffset), mOwnerId{ownerId} {}
Ruben Brunkcc776712015-02-17 20:18:47 -0800225
226template<class KEY, class VALUE>
227ClientDescriptor<KEY, VALUE>::~ClientDescriptor() {}
228
229template<class KEY, class VALUE>
230const KEY& ClientDescriptor<KEY, VALUE>::getKey() const {
231 return mKey;
232}
233
234template<class KEY, class VALUE>
235const VALUE& ClientDescriptor<KEY, VALUE>::getValue() const {
236 return mValue;
237}
238
239template<class KEY, class VALUE>
240int32_t ClientDescriptor<KEY, VALUE>::getCost() const {
241 return mCost;
242}
243
244template<class KEY, class VALUE>
Emilian Peev8131a262017-02-01 12:33:43 +0000245const ClientPriority& ClientDescriptor<KEY, VALUE>::getPriority() const {
Ruben Brunkcc776712015-02-17 20:18:47 -0800246 return mPriority;
247}
248
249template<class KEY, class VALUE>
250int32_t ClientDescriptor<KEY, VALUE>::getOwnerId() const {
251 return mOwnerId;
252}
253
254template<class KEY, class VALUE>
255bool ClientDescriptor<KEY, VALUE>::isConflicting(const KEY& key) const {
256 if (key == mKey) return true;
257 for (const auto& x : mConflicting) {
258 if (key == x) return true;
259 }
260 return false;
261}
262
263template<class KEY, class VALUE>
264std::set<KEY> ClientDescriptor<KEY, VALUE>::getConflicting() const {
265 return mConflicting;
266}
267
268template<class KEY, class VALUE>
Emilian Peev8131a262017-02-01 12:33:43 +0000269void ClientDescriptor<KEY, VALUE>::setPriority(const ClientPriority& priority) {
Jayant Chowdharyc578a502019-05-08 10:57:54 -0700270 // We don't use the usual copy constructor here since we want to remember
271 // whether a client is a vendor client or not. This could have been wiped
272 // off in the incoming priority argument since an AIDL thread might have
Steven Moreland89a2c5c2020-01-31 15:02:25 -0800273 // called getCurrentServingCall() == BinderCallType::HWBINDER after refreshing
Jayant Chowdharyc578a502019-05-08 10:57:54 -0700274 // priorities for old clients through ProcessInfoService::getProcessStatesScoresFromPids().
Jayant Chowdhary8eb8d912021-05-18 17:41:56 +0000275 if (mPriority.isVendorClient()) {
276 return;
277 }
Jayant Chowdharyc578a502019-05-08 10:57:54 -0700278 mPriority.setScore(priority.getScore());
279 mPriority.setState(priority.getState());
Ruben Brunkcc776712015-02-17 20:18:47 -0800280}
281
282// --------------------------------------------------------------------------------
283
284/**
Ruben Brunk99e69712015-05-26 17:25:07 -0700285 * A default class implementing the LISTENER interface used by ClientManager.
286 */
287template<class KEY, class VALUE>
288class DefaultEventListener {
289public:
290 void onClientAdded(const ClientDescriptor<KEY, VALUE>& descriptor);
291 void onClientRemoved(const ClientDescriptor<KEY, VALUE>& descriptor);
292};
293
294template<class KEY, class VALUE>
295void DefaultEventListener<KEY, VALUE>::onClientAdded(
296 const ClientDescriptor<KEY, VALUE>& /*descriptor*/) {}
297
298template<class KEY, class VALUE>
299void DefaultEventListener<KEY, VALUE>::onClientRemoved(
300 const ClientDescriptor<KEY, VALUE>& /*descriptor*/) {}
301
302// --------------------------------------------------------------------------------
303
304/**
Ruben Brunkcc776712015-02-17 20:18:47 -0800305 * The ClientManager class wraps an LRU-ordered list of active clients and implements eviction
306 * behavior for handling shared resource access.
307 *
308 * When adding a new descriptor, eviction behavior is as follows:
309 * - Keys are unique, adding a descriptor with the same key as an existing descriptor will
310 * result in the lower-priority of the two being removed. Priority ties result in the
311 * LRU descriptor being evicted (this means the incoming descriptor be added in this case).
312 * - Any descriptors with keys that are in the incoming descriptor's 'conflicting keys' list
313 * will be removed if they have an equal or lower priority than the incoming descriptor;
314 * if any have a higher priority, the incoming descriptor is removed instead.
315 * - If the sum of all descriptors' costs, including the incoming descriptor's, is more than
316 * the max cost allowed for this ClientManager, descriptors with non-zero cost, equal or lower
317 * priority, and a different owner will be evicted in LRU order until either the cost is less
318 * than the max cost, or all descriptors meeting this criteria have been evicted and the
319 * incoming descriptor has the highest priority. Otherwise, the incoming descriptor is
320 * removed instead.
321 */
Ruben Brunk99e69712015-05-26 17:25:07 -0700322template<class KEY, class VALUE, class LISTENER=DefaultEventListener<KEY, VALUE>>
Ruben Brunkcc776712015-02-17 20:18:47 -0800323class ClientManager {
324public:
325 // The default maximum "cost" allowed before evicting
326 static constexpr int32_t DEFAULT_MAX_COST = 100;
327
328 ClientManager();
Chih-Hung Hsieh8b0b9712016-08-09 14:25:53 -0700329 explicit ClientManager(int32_t totalCost);
Ruben Brunkcc776712015-02-17 20:18:47 -0800330
331 /**
332 * Add a given ClientDescriptor to the managed list. ClientDescriptors for clients that
333 * are evicted by this action are returned in a vector.
334 *
335 * This may return the ClientDescriptor passed in if it would be evicted.
336 */
337 std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>> addAndEvict(
338 const std::shared_ptr<ClientDescriptor<KEY, VALUE>>& client);
339
340 /**
341 * Given a map containing owner (pid) -> priority mappings, update the priority of each
342 * ClientDescriptor with an owner in this mapping.
343 */
Emilian Peev8131a262017-02-01 12:33:43 +0000344 void updatePriorities(const std::map<int32_t,ClientPriority>& ownerPriorityList);
Ruben Brunkcc776712015-02-17 20:18:47 -0800345
346 /**
347 * Remove all ClientDescriptors.
348 */
349 void removeAll();
350
351 /**
352 * Remove and return the ClientDescriptor with a given key.
353 */
354 std::shared_ptr<ClientDescriptor<KEY, VALUE>> remove(const KEY& key);
355
356 /**
357 * Remove the given ClientDescriptor.
358 */
359 void remove(const std::shared_ptr<ClientDescriptor<KEY, VALUE>>& value);
360
361 /**
362 * Return a vector of the ClientDescriptors that would be evicted by adding the given
363 * ClientDescriptor.
364 *
365 * This may return the ClientDescriptor passed in if it would be evicted.
366 */
367 std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>> wouldEvict(
368 const std::shared_ptr<ClientDescriptor<KEY, VALUE>>& client) const;
369
370 /**
371 * Return a vector of active ClientDescriptors that prevent this client from being added.
372 */
373 std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>> getIncompatibleClients(
374 const std::shared_ptr<ClientDescriptor<KEY, VALUE>>& client) const;
375
376 /**
377 * Return a vector containing all currently active ClientDescriptors.
378 */
379 std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>> getAll() const;
380
381 /**
382 * Return a vector containing all keys of currently active ClientDescriptors.
383 */
384 std::vector<KEY> getAllKeys() const;
385
386 /**
387 * Return a vector of the owner tags of all currently active ClientDescriptors (duplicates
388 * will be removed).
389 */
390 std::vector<int32_t> getAllOwners() const;
391
392 /**
393 * Return the ClientDescriptor corresponding to the given key, or an empty shared pointer
394 * if none exists.
395 */
396 std::shared_ptr<ClientDescriptor<KEY, VALUE>> get(const KEY& key) const;
397
Ruben Brunk4f9576b2015-04-10 17:26:56 -0700398 /**
399 * Block until the given client is no longer in the active clients list, or the timeout
400 * occurred.
401 *
402 * Returns NO_ERROR if this succeeded, -ETIMEDOUT on a timeout, or a negative error code on
403 * failure.
404 */
405 status_t waitUntilRemoved(const std::shared_ptr<ClientDescriptor<KEY, VALUE>> client,
406 nsecs_t timeout) const;
407
Ruben Brunk99e69712015-05-26 17:25:07 -0700408 /**
409 * Set the current listener for client add/remove events.
410 *
411 * The listener instance must inherit from the LISTENER class and implement the following
412 * methods:
413 * void onClientRemoved(const ClientDescriptor<KEY, VALUE>& descriptor);
414 * void onClientAdded(const ClientDescriptor<KEY, VALUE>& descriptor);
415 *
416 * These callback methods will be called with the ClientManager's lock held, and should
417 * not call any further ClientManager methods.
418 *
419 * The onClientRemoved method will be called when the client has been removed or evicted
420 * from the ClientManager that this event listener has been added to. The onClientAdded
421 * method will be called when the client has been added to the ClientManager that this
422 * event listener has been added to.
423 */
424 void setListener(const std::shared_ptr<LISTENER>& listener);
425
Ruben Brunkcc776712015-02-17 20:18:47 -0800426protected:
427 ~ClientManager();
428
429private:
430
431 /**
432 * Return a vector of the ClientDescriptors that would be evicted by adding the given
433 * ClientDescriptor. If returnIncompatibleClients is set to true, instead, return the
434 * vector of ClientDescriptors that are higher priority than the incoming client and
435 * either conflict with this client, or contribute to the resource cost if that would
436 * prevent the incoming client from being added.
437 *
438 * This may return the ClientDescriptor passed in.
439 */
440 std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>> wouldEvictLocked(
441 const std::shared_ptr<ClientDescriptor<KEY, VALUE>>& client,
442 bool returnIncompatibleClients = false) const;
443
444 int64_t getCurrentCostLocked() const;
445
446 mutable Mutex mLock;
Ruben Brunk4f9576b2015-04-10 17:26:56 -0700447 mutable Condition mRemovedCondition;
Ruben Brunkcc776712015-02-17 20:18:47 -0800448 int32_t mMaxCost;
449 // LRU ordered, most recent at end
450 std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>> mClients;
Ruben Brunk99e69712015-05-26 17:25:07 -0700451 std::shared_ptr<LISTENER> mListener;
Ruben Brunkcc776712015-02-17 20:18:47 -0800452}; // class ClientManager
453
Ruben Brunk99e69712015-05-26 17:25:07 -0700454template<class KEY, class VALUE, class LISTENER>
455ClientManager<KEY, VALUE, LISTENER>::ClientManager() :
Ruben Brunkcc776712015-02-17 20:18:47 -0800456 ClientManager(DEFAULT_MAX_COST) {}
457
Ruben Brunk99e69712015-05-26 17:25:07 -0700458template<class KEY, class VALUE, class LISTENER>
459ClientManager<KEY, VALUE, LISTENER>::ClientManager(int32_t totalCost) : mMaxCost(totalCost) {}
Ruben Brunkcc776712015-02-17 20:18:47 -0800460
Ruben Brunk99e69712015-05-26 17:25:07 -0700461template<class KEY, class VALUE, class LISTENER>
462ClientManager<KEY, VALUE, LISTENER>::~ClientManager() {}
Ruben Brunkcc776712015-02-17 20:18:47 -0800463
Ruben Brunk99e69712015-05-26 17:25:07 -0700464template<class KEY, class VALUE, class LISTENER>
465std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>>
466ClientManager<KEY, VALUE, LISTENER>::wouldEvict(
Ruben Brunkcc776712015-02-17 20:18:47 -0800467 const std::shared_ptr<ClientDescriptor<KEY, VALUE>>& client) const {
468 Mutex::Autolock lock(mLock);
469 return wouldEvictLocked(client);
470}
471
Ruben Brunk99e69712015-05-26 17:25:07 -0700472template<class KEY, class VALUE, class LISTENER>
Ruben Brunkcc776712015-02-17 20:18:47 -0800473std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>>
Ruben Brunk99e69712015-05-26 17:25:07 -0700474ClientManager<KEY, VALUE, LISTENER>::getIncompatibleClients(
Ruben Brunkcc776712015-02-17 20:18:47 -0800475 const std::shared_ptr<ClientDescriptor<KEY, VALUE>>& client) const {
476 Mutex::Autolock lock(mLock);
477 return wouldEvictLocked(client, /*returnIncompatibleClients*/true);
478}
479
Ruben Brunk99e69712015-05-26 17:25:07 -0700480template<class KEY, class VALUE, class LISTENER>
Ruben Brunkcc776712015-02-17 20:18:47 -0800481std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>>
Ruben Brunk99e69712015-05-26 17:25:07 -0700482ClientManager<KEY, VALUE, LISTENER>::wouldEvictLocked(
Ruben Brunkcc776712015-02-17 20:18:47 -0800483 const std::shared_ptr<ClientDescriptor<KEY, VALUE>>& client,
484 bool returnIncompatibleClients) const {
485
486 std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>> evictList;
487
488 // Disallow null clients, return input
489 if (client == nullptr) {
490 evictList.push_back(client);
491 return evictList;
492 }
493
494 const KEY& key = client->getKey();
495 int32_t cost = client->getCost();
Emilian Peev8131a262017-02-01 12:33:43 +0000496 ClientPriority priority = client->getPriority();
Ruben Brunkcc776712015-02-17 20:18:47 -0800497 int32_t owner = client->getOwnerId();
498
499 int64_t totalCost = getCurrentCostLocked() + cost;
500
501 // Determine the MRU of the owners tied for having the highest priority
502 int32_t highestPriorityOwner = owner;
Emilian Peev8131a262017-02-01 12:33:43 +0000503 ClientPriority highestPriority = priority;
Ruben Brunkcc776712015-02-17 20:18:47 -0800504 for (const auto& i : mClients) {
Emilian Peev8131a262017-02-01 12:33:43 +0000505 ClientPriority curPriority = i->getPriority();
506 if (curPriority <= highestPriority) {
Ruben Brunkcc776712015-02-17 20:18:47 -0800507 highestPriority = curPriority;
508 highestPriorityOwner = i->getOwnerId();
509 }
510 }
511
512 if (highestPriority == priority) {
513 // Switch back owner if the incoming client has the highest priority, as it is MRU
514 highestPriorityOwner = owner;
515 }
516
517 // Build eviction list of clients to remove
518 for (const auto& i : mClients) {
519 const KEY& curKey = i->getKey();
520 int32_t curCost = i->getCost();
Emilian Peev8131a262017-02-01 12:33:43 +0000521 ClientPriority curPriority = i->getPriority();
Ruben Brunkcc776712015-02-17 20:18:47 -0800522 int32_t curOwner = i->getOwnerId();
523
524 bool conflicting = (curKey == key || i->isConflicting(key) ||
525 client->isConflicting(curKey));
526
527 if (!returnIncompatibleClients) {
528 // Find evicted clients
529
Emilian Peev8131a262017-02-01 12:33:43 +0000530 if (conflicting && curPriority < priority) {
Ruben Brunkcc776712015-02-17 20:18:47 -0800531 // Pre-existing conflicting client with higher priority exists
532 evictList.clear();
533 evictList.push_back(client);
534 return evictList;
Yin-Chia Yeh8dfe4642020-06-01 11:57:45 -0700535 } else if (conflicting && owner == curOwner) {
536 // Pre-existing conflicting client with the same client owner exists
537 // Open the same device twice -> most recent open wins
538 // Otherwise let the existing client wins to avoid behaviors difference
539 // due to how HAL advertising conflicting devices (which is hidden from
540 // application)
541 if (curKey == key) {
542 evictList.push_back(i);
543 totalCost -= curCost;
544 } else {
545 evictList.clear();
546 evictList.push_back(client);
547 return evictList;
548 }
Ruben Brunkcc776712015-02-17 20:18:47 -0800549 } else if (conflicting || ((totalCost > mMaxCost && curCost > 0) &&
Emilian Peev8131a262017-02-01 12:33:43 +0000550 (curPriority >= priority) &&
Ruben Brunkcc776712015-02-17 20:18:47 -0800551 !(highestPriorityOwner == owner && owner == curOwner))) {
552 // Add a pre-existing client to the eviction list if:
553 // - We are adding a client with higher priority that conflicts with this one.
554 // - The total cost including the incoming client's is more than the allowable
555 // maximum, and the client has a non-zero cost, lower priority, and a different
556 // owner than the incoming client when the incoming client has the
557 // highest priority.
558 evictList.push_back(i);
559 totalCost -= curCost;
560 }
561 } else {
562 // Find clients preventing the incoming client from being added
563
Emilian Peev8131a262017-02-01 12:33:43 +0000564 if (curPriority < priority && (conflicting || (totalCost > mMaxCost && curCost > 0))) {
Ruben Brunkcc776712015-02-17 20:18:47 -0800565 // Pre-existing conflicting client with higher priority exists
566 evictList.push_back(i);
567 }
568 }
569 }
570
571 // Immediately return the incompatible clients if we are calculating these instead
572 if (returnIncompatibleClients) {
573 return evictList;
574 }
575
576 // If the total cost is too high, return the input unless the input has the highest priority
577 if (totalCost > mMaxCost && highestPriorityOwner != owner) {
578 evictList.clear();
579 evictList.push_back(client);
580 return evictList;
581 }
582
583 return evictList;
584
585}
586
Ruben Brunk99e69712015-05-26 17:25:07 -0700587template<class KEY, class VALUE, class LISTENER>
588std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>>
589ClientManager<KEY, VALUE, LISTENER>::addAndEvict(
Ruben Brunkcc776712015-02-17 20:18:47 -0800590 const std::shared_ptr<ClientDescriptor<KEY, VALUE>>& client) {
591 Mutex::Autolock lock(mLock);
592 auto evicted = wouldEvictLocked(client);
593 auto it = evicted.begin();
594 if (it != evicted.end() && *it == client) {
595 return evicted;
596 }
597
598 auto iter = evicted.cbegin();
599
Ruben Brunk80507212015-05-14 13:50:57 -0700600 if (iter != evicted.cend()) {
Ruben Brunk99e69712015-05-26 17:25:07 -0700601
602 if (mListener != nullptr) mListener->onClientRemoved(**iter);
603
Ruben Brunk80507212015-05-14 13:50:57 -0700604 // Remove evicted clients from list
605 mClients.erase(std::remove_if(mClients.begin(), mClients.end(),
606 [&iter] (std::shared_ptr<ClientDescriptor<KEY, VALUE>>& curClientPtr) {
607 if (curClientPtr->getKey() == (*iter)->getKey()) {
608 iter++;
609 return true;
610 }
611 return false;
612 }), mClients.end());
613 }
Ruben Brunkcc776712015-02-17 20:18:47 -0800614
Ruben Brunk99e69712015-05-26 17:25:07 -0700615 if (mListener != nullptr) mListener->onClientAdded(*client);
Ruben Brunkcc776712015-02-17 20:18:47 -0800616 mClients.push_back(client);
Ruben Brunk4f9576b2015-04-10 17:26:56 -0700617 mRemovedCondition.broadcast();
Ruben Brunkcc776712015-02-17 20:18:47 -0800618
619 return evicted;
620}
621
Ruben Brunk99e69712015-05-26 17:25:07 -0700622template<class KEY, class VALUE, class LISTENER>
Ruben Brunkcc776712015-02-17 20:18:47 -0800623std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>>
Ruben Brunk99e69712015-05-26 17:25:07 -0700624ClientManager<KEY, VALUE, LISTENER>::getAll() const {
Ruben Brunkcc776712015-02-17 20:18:47 -0800625 Mutex::Autolock lock(mLock);
626 return mClients;
627}
628
Ruben Brunk99e69712015-05-26 17:25:07 -0700629template<class KEY, class VALUE, class LISTENER>
630std::vector<KEY> ClientManager<KEY, VALUE, LISTENER>::getAllKeys() const {
Ruben Brunkcc776712015-02-17 20:18:47 -0800631 Mutex::Autolock lock(mLock);
632 std::vector<KEY> keys(mClients.size());
633 for (const auto& i : mClients) {
634 keys.push_back(i->getKey());
635 }
636 return keys;
637}
638
Ruben Brunk99e69712015-05-26 17:25:07 -0700639template<class KEY, class VALUE, class LISTENER>
640std::vector<int32_t> ClientManager<KEY, VALUE, LISTENER>::getAllOwners() const {
Ruben Brunkcc776712015-02-17 20:18:47 -0800641 Mutex::Autolock lock(mLock);
642 std::set<int32_t> owners;
643 for (const auto& i : mClients) {
644 owners.emplace(i->getOwnerId());
645 }
646 return std::vector<int32_t>(owners.begin(), owners.end());
647}
648
Ruben Brunk99e69712015-05-26 17:25:07 -0700649template<class KEY, class VALUE, class LISTENER>
650void ClientManager<KEY, VALUE, LISTENER>::updatePriorities(
Emilian Peev8131a262017-02-01 12:33:43 +0000651 const std::map<int32_t,ClientPriority>& ownerPriorityList) {
Ruben Brunkcc776712015-02-17 20:18:47 -0800652 Mutex::Autolock lock(mLock);
653 for (auto& i : mClients) {
654 auto j = ownerPriorityList.find(i->getOwnerId());
655 if (j != ownerPriorityList.end()) {
656 i->setPriority(j->second);
657 }
658 }
659}
660
Ruben Brunk99e69712015-05-26 17:25:07 -0700661template<class KEY, class VALUE, class LISTENER>
662std::shared_ptr<ClientDescriptor<KEY, VALUE>> ClientManager<KEY, VALUE, LISTENER>::get(
Ruben Brunkcc776712015-02-17 20:18:47 -0800663 const KEY& key) const {
664 Mutex::Autolock lock(mLock);
665 for (const auto& i : mClients) {
666 if (i->getKey() == key) return i;
667 }
668 return std::shared_ptr<ClientDescriptor<KEY, VALUE>>(nullptr);
669}
670
Ruben Brunk99e69712015-05-26 17:25:07 -0700671template<class KEY, class VALUE, class LISTENER>
672void ClientManager<KEY, VALUE, LISTENER>::removeAll() {
Ruben Brunkcc776712015-02-17 20:18:47 -0800673 Mutex::Autolock lock(mLock);
Ruben Brunk99e69712015-05-26 17:25:07 -0700674 if (mListener != nullptr) {
675 for (const auto& i : mClients) {
676 mListener->onClientRemoved(*i);
677 }
678 }
Ruben Brunkcc776712015-02-17 20:18:47 -0800679 mClients.clear();
Ruben Brunk4f9576b2015-04-10 17:26:56 -0700680 mRemovedCondition.broadcast();
Ruben Brunkcc776712015-02-17 20:18:47 -0800681}
682
Ruben Brunk99e69712015-05-26 17:25:07 -0700683template<class KEY, class VALUE, class LISTENER>
684std::shared_ptr<ClientDescriptor<KEY, VALUE>> ClientManager<KEY, VALUE, LISTENER>::remove(
685 const KEY& key) {
Ruben Brunkcc776712015-02-17 20:18:47 -0800686 Mutex::Autolock lock(mLock);
687
688 std::shared_ptr<ClientDescriptor<KEY, VALUE>> ret;
689
690 // Remove evicted clients from list
691 mClients.erase(std::remove_if(mClients.begin(), mClients.end(),
Ruben Brunk99e69712015-05-26 17:25:07 -0700692 [this, &key, &ret] (std::shared_ptr<ClientDescriptor<KEY, VALUE>>& curClientPtr) {
Ruben Brunkcc776712015-02-17 20:18:47 -0800693 if (curClientPtr->getKey() == key) {
Ruben Brunk99e69712015-05-26 17:25:07 -0700694 if (mListener != nullptr) mListener->onClientRemoved(*curClientPtr);
Ruben Brunkcc776712015-02-17 20:18:47 -0800695 ret = curClientPtr;
696 return true;
697 }
698 return false;
699 }), mClients.end());
700
Ruben Brunk4f9576b2015-04-10 17:26:56 -0700701 mRemovedCondition.broadcast();
702 return ret;
703}
704
Ruben Brunk99e69712015-05-26 17:25:07 -0700705template<class KEY, class VALUE, class LISTENER>
706status_t ClientManager<KEY, VALUE, LISTENER>::waitUntilRemoved(
Ruben Brunk4f9576b2015-04-10 17:26:56 -0700707 const std::shared_ptr<ClientDescriptor<KEY, VALUE>> client,
708 nsecs_t timeout) const {
709 status_t ret = NO_ERROR;
710 Mutex::Autolock lock(mLock);
711
712 bool isRemoved = false;
713
714 // Figure out what time in the future we should hit the timeout
715 nsecs_t failTime = systemTime(SYSTEM_TIME_MONOTONIC) + timeout;
716
717 while (!isRemoved) {
718 isRemoved = true;
719 for (const auto& i : mClients) {
720 if (i == client) {
721 isRemoved = false;
722 }
723 }
724
725 if (!isRemoved) {
726 ret = mRemovedCondition.waitRelative(mLock, timeout);
727 if (ret != NO_ERROR) {
728 break;
729 }
730 timeout = failTime - systemTime(SYSTEM_TIME_MONOTONIC);
731 }
732 }
733
Ruben Brunkcc776712015-02-17 20:18:47 -0800734 return ret;
735}
736
Ruben Brunk99e69712015-05-26 17:25:07 -0700737template<class KEY, class VALUE, class LISTENER>
738void ClientManager<KEY, VALUE, LISTENER>::setListener(const std::shared_ptr<LISTENER>& listener) {
739 Mutex::Autolock lock(mLock);
740 mListener = listener;
741}
742
743template<class KEY, class VALUE, class LISTENER>
744void ClientManager<KEY, VALUE, LISTENER>::remove(
Ruben Brunkcc776712015-02-17 20:18:47 -0800745 const std::shared_ptr<ClientDescriptor<KEY, VALUE>>& value) {
746 Mutex::Autolock lock(mLock);
747 // Remove evicted clients from list
748 mClients.erase(std::remove_if(mClients.begin(), mClients.end(),
Ruben Brunk99e69712015-05-26 17:25:07 -0700749 [this, &value] (std::shared_ptr<ClientDescriptor<KEY, VALUE>>& curClientPtr) {
Ruben Brunkcc776712015-02-17 20:18:47 -0800750 if (curClientPtr == value) {
Ruben Brunk99e69712015-05-26 17:25:07 -0700751 if (mListener != nullptr) mListener->onClientRemoved(*curClientPtr);
Ruben Brunkcc776712015-02-17 20:18:47 -0800752 return true;
753 }
754 return false;
755 }), mClients.end());
Ruben Brunk4f9576b2015-04-10 17:26:56 -0700756 mRemovedCondition.broadcast();
Ruben Brunkcc776712015-02-17 20:18:47 -0800757}
758
Ruben Brunk99e69712015-05-26 17:25:07 -0700759template<class KEY, class VALUE, class LISTENER>
760int64_t ClientManager<KEY, VALUE, LISTENER>::getCurrentCostLocked() const {
Ruben Brunkcc776712015-02-17 20:18:47 -0800761 int64_t totalCost = 0;
762 for (const auto& x : mClients) {
763 totalCost += x->getCost();
764 }
765 return totalCost;
766}
767
768// --------------------------------------------------------------------------------
769
770}; // namespace resource_policy
771}; // namespace android
772
773#endif // ANDROID_SERVICE_UTILS_EVICTION_POLICY_MANAGER_H