summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Naomi Musgrave <nmusgrave@google.com> 2023-07-25 10:53:10 +0000
committer Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> 2023-07-25 10:53:10 +0000
commit8ed46b633acab80a6e2004f87a50a3db293c2105 (patch)
tree7e41739958d27b503b0bc42bc02d6e892cfbb0b7
parent5765e44b7fa14c6ee447758ea67c029bdd95e1c8 (diff)
parentf8175e026f5fc60eef27a369e3bbe15707429644 (diff)
Merge "[MediaProjection] Address deadlock between multiple services" into udc-qpr-dev am: 11246dc79c am: f8175e026f
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/24177525 Change-Id: I8da20d259390cbbc61ec17b976b5549f69b271c5 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
-rw-r--r--services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java37
-rw-r--r--services/core/java/com/android/server/media/projection/mediaprojection.md5
2 files changed, 29 insertions, 13 deletions
diff --git a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
index c649164562d3..9ce6f8fec4b2 100644
--- a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
+++ b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
@@ -117,6 +117,10 @@ public final class MediaProjectionManagerService extends SystemService
// WindowManagerService -> MediaProjectionManagerService -> DisplayManagerService
// See mediaprojection.md
private final Object mLock = new Object();
+ // A handler for posting tasks that must interact with a service holding another lock,
+ // especially for services that will eventually acquire the WindowManager lock.
+ @NonNull private final Handler mHandler;
+
private final Map<IBinder, IBinder.DeathRecipient> mDeathEaters;
private final CallbackDelegate mCallbackDelegate;
@@ -145,6 +149,8 @@ public final class MediaProjectionManagerService extends SystemService
super(context);
mContext = context;
mInjector = injector;
+ // Post messages on the main thread; no need for a separate thread.
+ mHandler = new Handler(Looper.getMainLooper());
mClock = injector.createClock();
mDeathEaters = new ArrayMap<IBinder, IBinder.DeathRecipient>();
mCallbackDelegate = new CallbackDelegate(injector.createCallbackLooper());
@@ -243,14 +249,17 @@ public final class MediaProjectionManagerService extends SystemService
if (!mProjectionGrant.requiresForegroundService()) {
return;
}
+ }
- if (mActivityManagerInternal.hasRunningForegroundService(
- uid, ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION)) {
- // If there is any process within this UID running a FGS
- // with the mediaProjection type, that's Okay.
- return;
- }
+ // Run outside the lock when calling into ActivityManagerService.
+ if (mActivityManagerInternal.hasRunningForegroundService(
+ uid, ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION)) {
+ // If there is any process within this UID running a FGS
+ // with the mediaProjection type, that's Okay.
+ return;
+ }
+ synchronized (mLock) {
mProjectionGrant.stop();
}
}
@@ -849,7 +858,6 @@ public final class MediaProjectionManagerService extends SystemService
mTargetSdkVersion = targetSdkVersion;
mIsPrivileged = isPrivileged;
mCreateTimeMs = mClock.uptimeMillis();
- // TODO(b/267740338): Add unit test.
mActivityManagerInternal.notifyMediaProjectionEvent(uid, asBinder(),
MEDIA_PROJECTION_TOKEN_EVENT_CREATED);
}
@@ -903,6 +911,10 @@ public final class MediaProjectionManagerService extends SystemService
if (callback == null) {
throw new IllegalArgumentException("callback must not be null");
}
+ // Cache result of calling into ActivityManagerService outside of the lock, to prevent
+ // deadlock with WindowManagerService.
+ final boolean hasFGS = mActivityManagerInternal.hasRunningForegroundService(
+ uid, ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION);
synchronized (mLock) {
if (isCurrentProjection(asBinder())) {
Slog.w(TAG, "UID " + Binder.getCallingUid()
@@ -914,9 +926,7 @@ public final class MediaProjectionManagerService extends SystemService
}
if (REQUIRE_FG_SERVICE_FOR_PROJECTION
- && requiresForegroundService()
- && !mActivityManagerInternal.hasRunningForegroundService(
- uid, ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION)) {
+ && requiresForegroundService() && !hasFGS) {
throw new SecurityException("Media projections require a foreground service"
+ " of type ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION");
}
@@ -1005,10 +1015,11 @@ public final class MediaProjectionManagerService extends SystemService
mToken = null;
unregisterCallback(mCallback);
mCallback = null;
- // TODO(b/267740338): Add unit test.
- mActivityManagerInternal.notifyMediaProjectionEvent(uid, asBinder(),
- MEDIA_PROJECTION_TOKEN_EVENT_DESTROYED);
}
+ // Run on a separate thread, to ensure no lock is held when calling into
+ // ActivityManagerService.
+ mHandler.post(() -> mActivityManagerInternal.notifyMediaProjectionEvent(uid, asBinder(),
+ MEDIA_PROJECTION_TOKEN_EVENT_DESTROYED));
}
@Override // Binder call
diff --git a/services/core/java/com/android/server/media/projection/mediaprojection.md b/services/core/java/com/android/server/media/projection/mediaprojection.md
index bccdf3411903..34e7ecc6c6c5 100644
--- a/services/core/java/com/android/server/media/projection/mediaprojection.md
+++ b/services/core/java/com/android/server/media/projection/mediaprojection.md
@@ -11,6 +11,11 @@ Calls must follow the below invocation order while holding locks:
`WindowManagerService -> MediaProjectionManagerService -> DisplayManagerService`
+`MediaProjectionManagerService` should never lock when calling into a service that may acquire
+the `WindowManagerService` global lock (for example,
+`MediaProjectionManagerService -> ActivityManagerService` may result in deadlock, since
+`ActivityManagerService -> WindowManagerService`).
+
### Justification
`MediaProjectionManagerService` calls into `WindowManagerService` in the below cases. While handling