UidObserver / Camera: Track the OOM adj of a uid via UidObserver.
Previously, onUidProcAdjChanged merely signaled that the OOM adj of a
uid changed, but did not provide the actual OOM adj score. Having this
information allows the camera service to cut out redundant calls to
onCameraAccessPrioritiesChanged and avoid overwhelming apps.
The number of calls to onCameraAccessPrioritiesChanged is reduced by
only signaling when it's likely the uid owning a camera would lose
access to it if another uid tried to open that camera. This is opposed
to the status quo, which signals every time a watched uid changes its
OOM adj, which is highly inefficient.
Bug: 274486653
Test: -- on physical device:
-- testCamera2AccessCallbackInSplitMode x10
-- ActivityManagerServiceTest
-- ActivityManagerProcessStateTest
-- ActivityManagerFgsBgStartTest
-- UidObserverControllerTest
-- Alternate focus in split screen between Camera2 + GCA x20
Change-Id: I3e00490b835aefb74443c047e02c47d784e45f67
diff --git a/services/audiopolicy/service/AudioPolicyService.cpp b/services/audiopolicy/service/AudioPolicyService.cpp
index 974ae38..6fd2ccd 100644
--- a/services/audiopolicy/service/AudioPolicyService.cpp
+++ b/services/audiopolicy/service/AudioPolicyService.cpp
@@ -1694,7 +1694,7 @@
}
}
-void AudioPolicyService::UidPolicy::onUidProcAdjChanged(uid_t uid __unused) {
+void AudioPolicyService::UidPolicy::onUidProcAdjChanged(uid_t uid __unused, int32_t adj __unused) {
}
void AudioPolicyService::UidPolicy::updateOverrideUid(uid_t uid, bool active, bool insert) {
diff --git a/services/audiopolicy/service/AudioPolicyService.h b/services/audiopolicy/service/AudioPolicyService.h
index 59aabac..9255b15 100644
--- a/services/audiopolicy/service/AudioPolicyService.h
+++ b/services/audiopolicy/service/AudioPolicyService.h
@@ -484,7 +484,7 @@
void onUidIdle(uid_t uid, bool disabled) override;
void onUidStateChanged(uid_t uid, int32_t procState, int64_t procStateSeq,
int32_t capability) override;
- void onUidProcAdjChanged(uid_t uid) override;
+ void onUidProcAdjChanged(uid_t uid, int32_t adj) override;
void addOverrideUid(uid_t uid, bool active) { updateOverrideUid(uid, active, true); }
void removeOverrideUid(uid_t uid) { updateOverrideUid(uid, false, false); }
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index a2aafdf..cecced4 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -2602,6 +2602,19 @@
}
}
+void CameraService::notifyMonitoredUids(const std::unordered_set<uid_t> ¬ifyUidSet) {
+ Mutex::Autolock lock(mStatusListenerLock);
+
+ for (const auto& it : mListenerList) {
+ if (notifyUidSet.find(it->getListenerUid()) != notifyUidSet.end()) {
+ ALOGV("%s: notifying uid %d", __FUNCTION__, it->getListenerUid());
+ auto ret = it->getListener()->onCameraAccessPrioritiesChanged();
+ it->handleBinderStatus(ret, "%s: Failed to trigger permission callback for %d:%d: %d",
+ __FUNCTION__, it->getListenerUid(), it->getListenerPid(), ret.exceptionCode());
+ }
+ }
+}
+
Status CameraService::notifyDeviceStateChange(int64_t newState) {
const int pid = CameraThreadState::getCallingPid();
const int selfPid = getpid();
@@ -2823,7 +2836,7 @@
// permissions the listener process has / whether it is a vendor listener. Since it might be
// eligible to listen to other camera ids.
mListenerList.emplace_back(serviceListener);
- mUidPolicy->registerMonitorUid(clientUid);
+ mUidPolicy->registerMonitorUid(clientUid, /*openCamera*/false);
}
/* Collect current devices and status */
@@ -2891,7 +2904,7 @@
Mutex::Autolock lock(mStatusListenerLock);
for (auto it = mListenerList.begin(); it != mListenerList.end(); it++) {
if (IInterface::asBinder((*it)->getListener()) == IInterface::asBinder(listener)) {
- mUidPolicy->unregisterMonitorUid((*it)->getListenerUid());
+ mUidPolicy->unregisterMonitorUid((*it)->getListenerUid(), /*closeCamera*/false);
IInterface::asBinder(listener)->unlinkToDeath(*it);
mListenerList.erase(it);
return Status::ok();
@@ -3680,7 +3693,7 @@
// Transition device availability listeners from PRESENT -> NOT_AVAILABLE
sCameraService->updateStatus(StatusInternal::NOT_AVAILABLE, mCameraIdStr);
- sCameraService->mUidPolicy->registerMonitorUid(mClientUid);
+ sCameraService->mUidPolicy->registerMonitorUid(mClientUid, /*openCamera*/true);
// Notify listeners of camera open/close status
sCameraService->updateOpenCloseStatus(mCameraIdStr, true/*open*/, mClientPackageName);
@@ -3788,7 +3801,7 @@
}
mOpsCallback.clear();
- sCameraService->mUidPolicy->unregisterMonitorUid(mClientUid);
+ sCameraService->mUidPolicy->unregisterMonitorUid(mClientUid, /*closeCamera*/true);
// Notify listeners of camera open/close status
sCameraService->updateOpenCloseStatus(mCameraIdStr, false/*open*/, mClientPackageName);
@@ -3988,24 +4001,51 @@
}
}
-void CameraService::UidPolicy::onUidProcAdjChanged(uid_t uid) {
- bool procAdjChange = false;
+/**
+ * When the OOM adj of the uid owning the camera changes, a different uid waiting on camera
+ * privileges may take precedence if the owner's new OOM adj is greater than the waiting package.
+ * Here, we track which monitoredUid has the camera, and track its adj relative to other
+ * monitoredUids. If it is revised above some other monitoredUid, signal
+ * onCameraAccessPrioritiesChanged. This only needs to capture the case where there are two
+ * foreground apps in split screen - state changes will capture all other cases.
+ */
+void CameraService::UidPolicy::onUidProcAdjChanged(uid_t uid, int32_t adj) {
+ std::unordered_set<uid_t> notifyUidSet;
{
Mutex::Autolock _l(mUidLock);
- if (mMonitoredUids.find(uid) != mMonitoredUids.end()) {
- procAdjChange = true;
+ auto it = mMonitoredUids.find(uid);
+
+ if (it != mMonitoredUids.end()) {
+ if (it->second.hasCamera) {
+ for (auto &monitoredUid : mMonitoredUids) {
+ if (monitoredUid.first != uid && adj > monitoredUid.second.procAdj) {
+ notifyUidSet.emplace(monitoredUid.first);
+ }
+ }
+ notifyUidSet.emplace(uid);
+ } else {
+ for (auto &monitoredUid : mMonitoredUids) {
+ if (monitoredUid.second.hasCamera && adj < monitoredUid.second.procAdj) {
+ notifyUidSet.emplace(uid);
+ }
+ }
+ }
+ it->second.procAdj = adj;
}
}
- if (procAdjChange) {
+ if (notifyUidSet.size() > 0) {
sp<CameraService> service = mService.promote();
if (service != nullptr) {
- service->notifyMonitoredUids();
+ service->notifyMonitoredUids(notifyUidSet);
}
}
}
-void CameraService::UidPolicy::registerMonitorUid(uid_t uid) {
+/**
+ * Register a uid for monitoring, and note whether it owns a camera.
+ */
+void CameraService::UidPolicy::registerMonitorUid(uid_t uid, bool openCamera) {
Mutex::Autolock _l(mUidLock);
auto it = mMonitoredUids.find(uid);
if (it != mMonitoredUids.end()) {
@@ -4013,18 +4053,28 @@
} else {
MonitoredUid monitoredUid;
monitoredUid.procState = ActivityManager::PROCESS_STATE_NONEXISTENT;
+ monitoredUid.procAdj = resource_policy::UNKNOWN_ADJ;
monitoredUid.refCount = 1;
- mMonitoredUids.emplace(std::pair<uid_t, MonitoredUid>(uid, monitoredUid));
+ it = mMonitoredUids.emplace(std::pair<uid_t, MonitoredUid>(uid, monitoredUid)).first;
+ }
+
+ if (openCamera) {
+ it->second.hasCamera = true;
}
}
-void CameraService::UidPolicy::unregisterMonitorUid(uid_t uid) {
+/**
+ * Unregister a uid for monitoring, and note whether it lost ownership of a camera.
+ */
+void CameraService::UidPolicy::unregisterMonitorUid(uid_t uid, bool closeCamera) {
Mutex::Autolock _l(mUidLock);
auto it = mMonitoredUids.find(uid);
if (it != mMonitoredUids.end()) {
it->second.refCount--;
if (it->second.refCount == 0) {
mMonitoredUids.erase(it);
+ } else if (closeCamera) {
+ it->second.hasCamera = false;
}
} else {
ALOGE("%s: Trying to unregister uid: %d which is not monitored!", __FUNCTION__, uid);
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index ecec15f..8c57d26 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -233,6 +233,7 @@
// Monitored UIDs availability notification
void notifyMonitoredUids();
+ void notifyMonitoredUids(const std::unordered_set<uid_t> ¬ifyUidSet);
// Stores current open session device info in temp file.
void cacheDump();
@@ -763,13 +764,13 @@
void onUidIdle(uid_t uid, bool disabled) override;
void onUidStateChanged(uid_t uid, int32_t procState, int64_t procStateSeq,
int32_t capability) override;
- void onUidProcAdjChanged(uid_t uid) override;
+ void onUidProcAdjChanged(uid_t uid, int adj) override;
void addOverrideUid(uid_t uid, String16 callingPackage, bool active);
void removeOverrideUid(uid_t uid, String16 callingPackage);
- void registerMonitorUid(uid_t uid);
- void unregisterMonitorUid(uid_t uid);
+ void registerMonitorUid(uid_t uid, bool openCamera);
+ void unregisterMonitorUid(uid_t uid, bool closeCamera);
// Implementation of IServiceManager::LocalRegistrationCallback
virtual void onServiceRegistration(const String16& name,
@@ -784,6 +785,8 @@
struct MonitoredUid {
int32_t procState;
+ int32_t procAdj;
+ bool hasCamera;
size_t refCount;
};
diff --git a/services/camera/libcameraservice/api2/CameraOfflineSessionClient.cpp b/services/camera/libcameraservice/api2/CameraOfflineSessionClient.cpp
index 66077c5..86a0ebc 100644
--- a/services/camera/libcameraservice/api2/CameraOfflineSessionClient.cpp
+++ b/services/camera/libcameraservice/api2/CameraOfflineSessionClient.cpp
@@ -264,7 +264,7 @@
mOpsActive = true;
// Transition device state to OPEN
- sCameraService->mUidPolicy->registerMonitorUid(mClientUid);
+ sCameraService->mUidPolicy->registerMonitorUid(mClientUid, /*openCamera*/true);
return OK;
}
@@ -288,7 +288,7 @@
}
mOpsCallback.clear();
- sCameraService->mUidPolicy->unregisterMonitorUid(mClientUid);
+ sCameraService->mUidPolicy->unregisterMonitorUid(mClientUid, /*closeCamera*/true);
return OK;
}
diff --git a/services/mediaresourcemanager/UidObserver.cpp b/services/mediaresourcemanager/UidObserver.cpp
index f321ebc..4bcd325 100644
--- a/services/mediaresourcemanager/UidObserver.cpp
+++ b/services/mediaresourcemanager/UidObserver.cpp
@@ -170,7 +170,7 @@
int32_t /*capability*/) {
}
-void UidObserver::onUidProcAdjChanged(uid_t /*uid*/) {
+void UidObserver::onUidProcAdjChanged(uid_t /*uid*/, int32_t /*adj*/) {
}
void UidObserver::binderDied(const wp<IBinder>& /*who*/) {
diff --git a/services/mediaresourcemanager/UidObserver.h b/services/mediaresourcemanager/UidObserver.h
index ed76839..b5cc3b9 100644
--- a/services/mediaresourcemanager/UidObserver.h
+++ b/services/mediaresourcemanager/UidObserver.h
@@ -74,7 +74,7 @@
void onUidIdle(uid_t uid, bool disabled) override;
void onUidStateChanged(uid_t uid, int32_t procState, int64_t procStateSeq,
int32_t capability) override;
- void onUidProcAdjChanged(uid_t uid) override;
+ void onUidProcAdjChanged(uid_t uid, int32_t adj) override;
// IServiceManager::LocalRegistrationCallback implementation.
void onServiceRegistration(const String16& name,