Camera service: Update client eviction priorities
Use both oom score and process state for client eviction.
The score will have higher priority over the process state.
This should resolve the state ambiguity when PiP clients
try to connect to exclusive camera resources while
foreground clients are running.
BUG: 34701266
Test: Manual testing, complete CTS Camera package
Change-Id: Ic775b011a20e50f9c0c1c0a4bc1cf7ca75410740
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index f429df8..579e87a 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -651,22 +651,6 @@
return String8(formattedTime);
}
-int CameraService::getCameraPriorityFromProcState(int procState) {
- // Find the priority for the camera usage based on the process state. Higher priority clients
- // win for evictions.
- if (procState < 0) {
- ALOGE("%s: Received invalid process state %d from ActivityManagerService!", __FUNCTION__,
- procState);
- return -1;
- }
- // Treat sleeping TOP processes the same as regular TOP processes, for
- // access priority. This is important for lock-screen camera launch scenarios
- if (procState == PROCESS_STATE_TOP_SLEEPING) {
- procState = PROCESS_STATE_TOP;
- }
- return INT_MAX - procState;
-}
-
Status CameraService::getCameraVendorTagDescriptor(
/*out*/
hardware::camera2::params::VendorTagDescriptor* desc) {
@@ -1212,20 +1196,24 @@
std::vector<int> ownerPids(mActiveClientManager.getAllOwners());
ownerPids.push_back(clientPid);
- // Use the value +PROCESS_STATE_NONEXISTENT, to avoid taking
- // address of PROCESS_STATE_NONEXISTENT as a reference argument
- // for the vector constructor. PROCESS_STATE_NONEXISTENT does
- // not have an out-of-class definition.
- std::vector<int> priorities(ownerPids.size(), +PROCESS_STATE_NONEXISTENT);
+ std::vector<int> priorityScores(ownerPids.size());
+ std::vector<int> states(ownerPids.size());
- // Get priorites of all active PIDs
- ProcessInfoService::getProcessStatesFromPids(ownerPids.size(), &ownerPids[0],
- /*out*/&priorities[0]);
+ // Get priority scores of all active PIDs
+ status_t err = ProcessInfoService::getProcessStatesScoresFromPids(
+ ownerPids.size(), &ownerPids[0], /*out*/&states[0],
+ /*out*/&priorityScores[0]);
+ if (err != OK) {
+ ALOGE("%s: Priority score query failed: %d",
+ __FUNCTION__, err);
+ return err;
+ }
// Update all active clients' priorities
- std::map<int,int> pidToPriorityMap;
+ std::map<int,resource_policy::ClientPriority> pidToPriorityMap;
for (size_t i = 0; i < ownerPids.size() - 1; i++) {
- pidToPriorityMap.emplace(ownerPids[i], getCameraPriorityFromProcState(priorities[i]));
+ pidToPriorityMap.emplace(ownerPids[i],
+ resource_policy::ClientPriority(priorityScores[i], states[i]));
}
mActiveClientManager.updatePriorities(pidToPriorityMap);
@@ -1242,7 +1230,9 @@
clientDescriptor = CameraClientManager::makeClientDescriptor(cameraId,
sp<BasicClient>{nullptr}, static_cast<int32_t>(state->getCost()),
state->getConflicting(),
- getCameraPriorityFromProcState(priorities[priorities.size() - 1]), clientPid);
+ priorityScores[priorityScores.size() - 1],
+ clientPid,
+ states[states.size() - 1]);
// Find clients that would be evicted
auto evicted = mActiveClientManager.wouldEvict(clientDescriptor);
@@ -1259,19 +1249,22 @@
mActiveClientManager.getIncompatibleClients(clientDescriptor);
String8 msg = String8::format("%s : DENIED connect device %s client for package %s "
- "(PID %d, priority %d) due to eviction policy", curTime.string(),
+ "(PID %d, score %d state %d) due to eviction policy", curTime.string(),
cameraId.string(), packageName.string(), clientPid,
- getCameraPriorityFromProcState(priorities[priorities.size() - 1]));
+ priorityScores[priorityScores.size() - 1],
+ states[states.size() - 1]);
for (auto& i : incompatibleClients) {
msg.appendFormat("\n - Blocked by existing device %s client for package %s"
- "(PID %" PRId32 ", priority %" PRId32 ")", i->getKey().string(),
- String8{i->getValue()->getPackageName()}.string(), i->getOwnerId(),
- i->getPriority());
+ "(PID %" PRId32 ", score %" PRId32 ", state %" PRId32 ")",
+ i->getKey().string(),
+ String8{i->getValue()->getPackageName()}.string(),
+ i->getOwnerId(), i->getPriority().getScore(),
+ i->getPriority().getState());
ALOGE(" Conflicts with: Device %s, client package %s (PID %"
- PRId32 ", priority %" PRId32 ")", i->getKey().string(),
+ PRId32 ", score %" PRId32 ", state %" PRId32 ")", i->getKey().string(),
String8{i->getValue()->getPackageName()}.string(), i->getOwnerId(),
- i->getPriority());
+ i->getPriority().getScore(), i->getPriority().getState());
}
// Log the client's attempt
@@ -1299,12 +1292,14 @@
// Log the clients evicted
logEvent(String8::format("EVICT device %s client held by package %s (PID"
- " %" PRId32 ", priority %" PRId32 ")\n - Evicted by device %s client for"
- " package %s (PID %d, priority %" PRId32 ")",
+ " %" PRId32 ", score %" PRId32 ", state %" PRId32 ")\n - Evicted by device %s client for"
+ " package %s (PID %d, score %" PRId32 ", state %" PRId32 ")",
i->getKey().string(), String8{clientSp->getPackageName()}.string(),
- i->getOwnerId(), i->getPriority(), cameraId.string(),
+ i->getOwnerId(), i->getPriority().getScore(),
+ i->getPriority().getState(), cameraId.string(),
packageName.string(), clientPid,
- getCameraPriorityFromProcState(priorities[priorities.size() - 1])));
+ priorityScores[priorityScores.size() - 1],
+ states[states.size() - 1]));
// Notify the client of disconnection
clientSp->notifyError(hardware::camera2::ICameraDeviceCallbacks::ERROR_CAMERA_DISCONNECTED,
@@ -2142,9 +2137,11 @@
// Log the clients evicted
logEvent(String8::format("EVICT device %s client held by package %s (PID %"
- PRId32 ", priority %" PRId32 ")\n - Evicted due to user switch.",
- i->getKey().string(), String8{clientSp->getPackageName()}.string(),
- i->getOwnerId(), i->getPriority()));
+ PRId32 ", score %" PRId32 ", state %" PRId32 ")\n - Evicted due"
+ " to user switch.", i->getKey().string(),
+ String8{clientSp->getPackageName()}.string(),
+ i->getOwnerId(), i->getPriority().getScore(),
+ i->getPriority().getState()));
}
@@ -2680,7 +2677,8 @@
String8 key = i->getKey();
int32_t cost = i->getCost();
int32_t pid = i->getOwnerId();
- int32_t priority = i->getPriority();
+ int32_t score = i->getPriority().getScore();
+ int32_t state = i->getPriority().getState();
auto conflicting = i->getConflicting();
auto clientSp = i->getValue();
String8 packageName;
@@ -2690,8 +2688,8 @@
uid_t clientUid = clientSp->getClientUid();
clientUserId = multiuser_get_user_id(clientUid);
}
- ret.appendFormat("\n(Camera ID: %s, Cost: %" PRId32 ", PID: %" PRId32 ", Priority: %"
- PRId32 ", ", key.string(), cost, pid, priority);
+ ret.appendFormat("\n(Camera ID: %s, Cost: %" PRId32 ", PID: %" PRId32 ", Score: %"
+ PRId32 ", State: %" PRId32, key.string(), cost, pid, score, state);
if (clientSp.get() != nullptr) {
ret.appendFormat("User Id: %d, ", clientUserId);
@@ -2713,16 +2711,18 @@
CameraService::DescriptorPtr CameraService::CameraClientManager::makeClientDescriptor(
const String8& key, const sp<BasicClient>& value, int32_t cost,
- const std::set<String8>& conflictingKeys, int32_t priority, int32_t ownerId) {
+ const std::set<String8>& conflictingKeys, int32_t score, int32_t ownerId,
+ int32_t state) {
return std::make_shared<resource_policy::ClientDescriptor<String8, sp<BasicClient>>>(
- key, value, cost, conflictingKeys, priority, ownerId);
+ key, value, cost, conflictingKeys, score, ownerId, state);
}
CameraService::DescriptorPtr CameraService::CameraClientManager::makeClientDescriptor(
const sp<BasicClient>& value, const CameraService::DescriptorPtr& partial) {
return makeClientDescriptor(partial->getKey(), value, partial->getCost(),
- partial->getConflicting(), partial->getPriority(), partial->getOwnerId());
+ partial->getConflicting(), partial->getPriority().getScore(),
+ partial->getOwnerId(), partial->getPriority().getState());
}
// ----------------------------------------------------------------------------
@@ -2800,7 +2800,9 @@
}
dprintf(fd, " Device %s is open. Client instance dump:\n",
cameraId.string());
- dprintf(fd, " Client priority level: %d\n", clientDescriptor->getPriority());
+ dprintf(fd, " Client priority score: %d state: %d\n",
+ clientDescriptor->getPriority().getScore(),
+ clientDescriptor->getPriority().getState());
dprintf(fd, " Client PID: %d\n", clientDescriptor->getOwnerId());
auto client = clientDescriptor->getValue();
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index d463b59..c7acdc9 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -75,11 +75,6 @@
API_2 = 2
};
- // Process state (mirrors frameworks/base/core/java/android/app/ActivityManager.java)
- static const int PROCESS_STATE_NONEXISTENT = -1;
- static const int PROCESS_STATE_TOP = 2;
- static const int PROCESS_STATE_TOP_SLEEPING = 5;
-
// 3 second busy timeout when other clients are connecting
static const nsecs_t DEFAULT_CONNECT_TIMEOUT_NS = 3000000000;
@@ -402,8 +397,8 @@
* Make a ClientDescriptor object wrapping the given BasicClient strong pointer.
*/
static DescriptorPtr makeClientDescriptor(const String8& key, const sp<BasicClient>& value,
- int32_t cost, const std::set<String8>& conflictingKeys, int32_t priority,
- int32_t ownerId);
+ int32_t cost, const std::set<String8>& conflictingKeys, int32_t score,
+ int32_t ownerId, int32_t state);
/**
* Make a ClientDescriptor object wrapping the given BasicClient strong pointer with
@@ -775,11 +770,6 @@
*/
static String8 getFormattedCurrentTime();
- /**
- * Get the camera eviction priority from the current process state given by ActivityManager.
- */
- static int getCameraPriorityFromProcState(int procState);
-
static binder::Status makeClient(const sp<CameraService>& cameraService,
const sp<IInterface>& cameraCb, const String16& packageName, const String8& cameraId,
int facing, int clientPid, uid_t clientUid, int servicePid, bool legacyMode,
diff --git a/services/camera/libcameraservice/utils/ClientManager.h b/services/camera/libcameraservice/utils/ClientManager.h
index 830c50b..d7135f1 100644
--- a/services/camera/libcameraservice/utils/ClientManager.h
+++ b/services/camera/libcameraservice/utils/ClientManager.h
@@ -31,6 +31,43 @@
namespace android {
namespace resource_policy {
+class ClientPriority {
+public:
+ ClientPriority(int32_t score, int32_t state) :
+ mScore(score), mState(state) {}
+
+ int32_t getScore() const { return mScore; }
+ int32_t getState() const { return mState; }
+
+ bool operator==(const ClientPriority& rhs) const {
+ return (this->mScore == rhs.mScore) && (this->mState == rhs.mState);
+ }
+
+ bool operator< (const ClientPriority& rhs) const {
+ if (this->mScore == rhs.mScore) {
+ return this->mState < rhs.mState;
+ } else {
+ return this->mScore < rhs.mScore;
+ }
+ }
+
+ bool operator> (const ClientPriority& rhs) const {
+ return rhs < *this;
+ }
+
+ bool operator<=(const ClientPriority& rhs) const {
+ return !(*this > rhs);
+ }
+
+ bool operator>=(const ClientPriority& rhs) const {
+ return !(*this < rhs);
+ }
+
+private:
+ int32_t mScore;
+ int32_t mState;
+};
+
// --------------------------------------------------------------------------------
/**
@@ -45,9 +82,9 @@
class ClientDescriptor final {
public:
ClientDescriptor(const KEY& key, const VALUE& value, int32_t cost,
- const std::set<KEY>& conflictingKeys, int32_t priority, int32_t ownerId);
+ const std::set<KEY>& conflictingKeys, int32_t score, int32_t ownerId, int32_t state);
ClientDescriptor(KEY&& key, VALUE&& value, int32_t cost, std::set<KEY>&& conflictingKeys,
- int32_t priority, int32_t ownerId);
+ int32_t score, int32_t ownerId, int32_t state);
~ClientDescriptor();
@@ -69,7 +106,7 @@
/**
* Return the priority for this descriptor.
*/
- int32_t getPriority() const;
+ const ClientPriority &getPriority() const;
/**
* Return the owner ID for this descriptor.
@@ -89,7 +126,7 @@
/**
* Set the proirity for this descriptor.
*/
- void setPriority(int32_t priority);
+ void setPriority(const ClientPriority& priority);
// This class is ordered by key
template<class K, class V>
@@ -100,7 +137,7 @@
VALUE mValue;
int32_t mCost;
std::set<KEY> mConflicting;
- int32_t mPriority;
+ ClientPriority mPriority;
int32_t mOwnerId;
}; // class ClientDescriptor
@@ -111,16 +148,17 @@
template<class KEY, class VALUE>
ClientDescriptor<KEY, VALUE>::ClientDescriptor(const KEY& key, const VALUE& value, int32_t cost,
- const std::set<KEY>& conflictingKeys, int32_t priority, int32_t ownerId) : mKey{key},
- mValue{value}, mCost{cost}, mConflicting{conflictingKeys}, mPriority{priority},
+ const std::set<KEY>& conflictingKeys, int32_t score, int32_t ownerId, int32_t state) :
+ mKey{key}, mValue{value}, mCost{cost}, mConflicting{conflictingKeys},
+ mPriority(score, state),
mOwnerId{ownerId} {}
template<class KEY, class VALUE>
ClientDescriptor<KEY, VALUE>::ClientDescriptor(KEY&& key, VALUE&& value, int32_t cost,
- std::set<KEY>&& conflictingKeys, int32_t priority, int32_t ownerId) :
+ std::set<KEY>&& conflictingKeys, int32_t score, int32_t ownerId, int32_t state) :
mKey{std::forward<KEY>(key)}, mValue{std::forward<VALUE>(value)}, mCost{cost},
- mConflicting{std::forward<std::set<KEY>>(conflictingKeys)}, mPriority{priority},
- mOwnerId{ownerId} {}
+ mConflicting{std::forward<std::set<KEY>>(conflictingKeys)},
+ mPriority(score, state), mOwnerId{ownerId} {}
template<class KEY, class VALUE>
ClientDescriptor<KEY, VALUE>::~ClientDescriptor() {}
@@ -141,7 +179,7 @@
}
template<class KEY, class VALUE>
-int32_t ClientDescriptor<KEY, VALUE>::getPriority() const {
+const ClientPriority& ClientDescriptor<KEY, VALUE>::getPriority() const {
return mPriority;
}
@@ -165,7 +203,7 @@
}
template<class KEY, class VALUE>
-void ClientDescriptor<KEY, VALUE>::setPriority(int32_t priority) {
+void ClientDescriptor<KEY, VALUE>::setPriority(const ClientPriority& priority) {
mPriority = priority;
}
@@ -231,7 +269,7 @@
* Given a map containing owner (pid) -> priority mappings, update the priority of each
* ClientDescriptor with an owner in this mapping.
*/
- void updatePriorities(const std::map<int32_t,int32_t>& ownerPriorityList);
+ void updatePriorities(const std::map<int32_t,ClientPriority>& ownerPriorityList);
/**
* Remove all ClientDescriptors.
@@ -383,17 +421,17 @@
const KEY& key = client->getKey();
int32_t cost = client->getCost();
- int32_t priority = client->getPriority();
+ ClientPriority priority = client->getPriority();
int32_t owner = client->getOwnerId();
int64_t totalCost = getCurrentCostLocked() + cost;
// Determine the MRU of the owners tied for having the highest priority
int32_t highestPriorityOwner = owner;
- int32_t highestPriority = priority;
+ ClientPriority highestPriority = priority;
for (const auto& i : mClients) {
- int32_t curPriority = i->getPriority();
- if (curPriority >= highestPriority) {
+ ClientPriority curPriority = i->getPriority();
+ if (curPriority <= highestPriority) {
highestPriority = curPriority;
highestPriorityOwner = i->getOwnerId();
}
@@ -408,7 +446,7 @@
for (const auto& i : mClients) {
const KEY& curKey = i->getKey();
int32_t curCost = i->getCost();
- int32_t curPriority = i->getPriority();
+ ClientPriority curPriority = i->getPriority();
int32_t curOwner = i->getOwnerId();
bool conflicting = (curKey == key || i->isConflicting(key) ||
@@ -417,13 +455,13 @@
if (!returnIncompatibleClients) {
// Find evicted clients
- if (conflicting && curPriority > priority) {
+ if (conflicting && curPriority < priority) {
// Pre-existing conflicting client with higher priority exists
evictList.clear();
evictList.push_back(client);
return evictList;
} else if (conflicting || ((totalCost > mMaxCost && curCost > 0) &&
- (curPriority <= priority) &&
+ (curPriority >= priority) &&
!(highestPriorityOwner == owner && owner == curOwner))) {
// Add a pre-existing client to the eviction list if:
// - We are adding a client with higher priority that conflicts with this one.
@@ -437,7 +475,7 @@
} else {
// Find clients preventing the incoming client from being added
- if (curPriority > priority && (conflicting || (totalCost > mMaxCost && curCost > 0))) {
+ if (curPriority < priority && (conflicting || (totalCost > mMaxCost && curCost > 0))) {
// Pre-existing conflicting client with higher priority exists
evictList.push_back(i);
}
@@ -524,7 +562,7 @@
template<class KEY, class VALUE, class LISTENER>
void ClientManager<KEY, VALUE, LISTENER>::updatePriorities(
- const std::map<int32_t,int32_t>& ownerPriorityList) {
+ const std::map<int32_t,ClientPriority>& ownerPriorityList) {
Mutex::Autolock lock(mLock);
for (auto& i : mClients) {
auto j = ownerPriorityList.find(i->getOwnerId());