Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1422e557 authored by Naomi Musgrave's avatar Naomi Musgrave Committed by Automerger Merge Worker
Browse files

Merge "[MediaProjection] Address deadlock between multiple services" into...

Merge "[MediaProjection] Address deadlock between multiple services" into udc-dev am: 607bd36f am: 91660e8b

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/24150805



Change-Id: If80c9df523bd480f6b55607d07f8a2695bcf062b
Signed-off-by: default avatarAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
parents 8ad856ac 91660e8b
Loading
Loading
Loading
Loading
+27 −14
Original line number Original line Diff line number Diff line
@@ -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
+5 −0
Original line number Original line Diff line number Diff line
@@ -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