Merge "[MediaProjection] Address deadlock between multiple services" into udc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
607bd36fba
@@ -117,6 +117,10 @@ public final class MediaProjectionManagerService extends SystemService
|
|||||||
// WindowManagerService -> MediaProjectionManagerService -> DisplayManagerService
|
// WindowManagerService -> MediaProjectionManagerService -> DisplayManagerService
|
||||||
// See mediaprojection.md
|
// See mediaprojection.md
|
||||||
private final Object mLock = new Object();
|
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 Map<IBinder, IBinder.DeathRecipient> mDeathEaters;
|
||||||
private final CallbackDelegate mCallbackDelegate;
|
private final CallbackDelegate mCallbackDelegate;
|
||||||
|
|
||||||
@@ -145,6 +149,8 @@ public final class MediaProjectionManagerService extends SystemService
|
|||||||
super(context);
|
super(context);
|
||||||
mContext = context;
|
mContext = context;
|
||||||
mInjector = injector;
|
mInjector = injector;
|
||||||
|
// Post messages on the main thread; no need for a separate thread.
|
||||||
|
mHandler = new Handler(Looper.getMainLooper());
|
||||||
mClock = injector.createClock();
|
mClock = injector.createClock();
|
||||||
mDeathEaters = new ArrayMap<IBinder, IBinder.DeathRecipient>();
|
mDeathEaters = new ArrayMap<IBinder, IBinder.DeathRecipient>();
|
||||||
mCallbackDelegate = new CallbackDelegate();
|
mCallbackDelegate = new CallbackDelegate();
|
||||||
@@ -238,7 +244,9 @@ public final class MediaProjectionManagerService extends SystemService
|
|||||||
if (!mProjectionGrant.requiresForegroundService()) {
|
if (!mProjectionGrant.requiresForegroundService()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run outside the lock when calling into ActivityManagerService.
|
||||||
if (mActivityManagerInternal.hasRunningForegroundService(
|
if (mActivityManagerInternal.hasRunningForegroundService(
|
||||||
uid, ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION)) {
|
uid, ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION)) {
|
||||||
// If there is any process within this UID running a FGS
|
// If there is any process within this UID running a FGS
|
||||||
@@ -246,9 +254,12 @@ public final class MediaProjectionManagerService extends SystemService
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
synchronized (mLock) {
|
||||||
|
if (mProjectionGrant != null) {
|
||||||
mProjectionGrant.stop();
|
mProjectionGrant.stop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void startProjectionLocked(final MediaProjection projection) {
|
private void startProjectionLocked(final MediaProjection projection) {
|
||||||
if (mProjectionGrant != null) {
|
if (mProjectionGrant != null) {
|
||||||
@@ -854,7 +865,6 @@ public final class MediaProjectionManagerService extends SystemService
|
|||||||
mTargetSdkVersion = targetSdkVersion;
|
mTargetSdkVersion = targetSdkVersion;
|
||||||
mIsPrivileged = isPrivileged;
|
mIsPrivileged = isPrivileged;
|
||||||
mCreateTimeMs = mClock.uptimeMillis();
|
mCreateTimeMs = mClock.uptimeMillis();
|
||||||
// TODO(b/267740338): Add unit test.
|
|
||||||
mActivityManagerInternal.notifyMediaProjectionEvent(uid, asBinder(),
|
mActivityManagerInternal.notifyMediaProjectionEvent(uid, asBinder(),
|
||||||
MEDIA_PROJECTION_TOKEN_EVENT_CREATED);
|
MEDIA_PROJECTION_TOKEN_EVENT_CREATED);
|
||||||
}
|
}
|
||||||
@@ -911,6 +921,10 @@ public final class MediaProjectionManagerService extends SystemService
|
|||||||
if (callback == null) {
|
if (callback == null) {
|
||||||
throw new IllegalArgumentException("callback must not be 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) {
|
synchronized (mLock) {
|
||||||
if (isCurrentProjection(asBinder())) {
|
if (isCurrentProjection(asBinder())) {
|
||||||
Slog.w(TAG, "UID " + Binder.getCallingUid()
|
Slog.w(TAG, "UID " + Binder.getCallingUid()
|
||||||
@@ -922,9 +936,7 @@ public final class MediaProjectionManagerService extends SystemService
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (REQUIRE_FG_SERVICE_FOR_PROJECTION
|
if (REQUIRE_FG_SERVICE_FOR_PROJECTION
|
||||||
&& requiresForegroundService()
|
&& requiresForegroundService() && !hasFGS) {
|
||||||
&& !mActivityManagerInternal.hasRunningForegroundService(
|
|
||||||
uid, ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION)) {
|
|
||||||
throw new SecurityException("Media projections require a foreground service"
|
throw new SecurityException("Media projections require a foreground service"
|
||||||
+ " of type ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION");
|
+ " of type ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION");
|
||||||
}
|
}
|
||||||
@@ -1013,10 +1025,11 @@ public final class MediaProjectionManagerService extends SystemService
|
|||||||
mToken = null;
|
mToken = null;
|
||||||
unregisterCallback(mCallback);
|
unregisterCallback(mCallback);
|
||||||
mCallback = null;
|
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
|
@Override // Binder call
|
||||||
|
|||||||
@@ -11,6 +11,11 @@ Calls must follow the below invocation order while holding locks:
|
|||||||
|
|
||||||
`WindowManagerService -> MediaProjectionManagerService -> DisplayManagerService`
|
`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
|
### Justification
|
||||||
|
|
||||||
`MediaProjectionManagerService` calls into `WindowManagerService` in the below cases. While handling
|
`MediaProjectionManagerService` calls into `WindowManagerService` in the below cases. While handling
|
||||||
|
|||||||
Reference in New Issue
Block a user