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