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

Commit e3f6b7e1 authored by Naomi Musgrave's avatar Naomi Musgrave
Browse files

[Media Projection] Require valid token to set session

When MediaProjection sets the session details in
MediaProjectiondManagerService, clear and re-set the
calling identity (since we have entered the system server
across the aidl boundary).

Additionaly, verify that the call originated from a valid
MediaProjection session. In the current model for
MediaProjection, signature-level permission
MANAGE_MEDIA_PROJECTION is held by the component that shows the
acceptance dialog to the user. The user allowing some app to
capture with MediaProjection is represented by
the IMediaProjection token (see MediaProjectionManagerService#
isValidMediaProjection).

Bug: 230748205
Test: Manual
Change-Id: Iace8eb7eea6c7a99fba7ea726481461a11bd1c90
parent 8ade0d82
Loading
Loading
Loading
Loading
+0 −12
Original line number Diff line number Diff line
@@ -32,7 +32,6 @@ import android.graphics.Region;
import android.os.Bundle;
import android.os.IRemoteCallback;
import android.os.ParcelFileDescriptor;
import android.view.ContentRecordingSession;
import android.view.DisplayCutout;
import android.view.DisplayInfo;
import android.view.IAppTransitionAnimationSpecsFuture;
@@ -873,17 +872,6 @@ interface IWindowManager
     */
    void detachWindowContextFromWindowContainer(IBinder clientToken);

    /**
     * Updates the content recording session. If a different session is already in progress, then
     * the pre-existing session is stopped, and the new incoming session takes over.
     *
     * The DisplayContent for the new session will begin recording when
     * {@link RootWindowContainer#onDisplayChanged} is invoked for the new {@link VirtualDisplay}.
     *
     * @param incomingSession the nullable incoming content recording session
     */
    void setContentRecordingSession(in ContentRecordingSession incomingSession);

    /**
     * Registers a listener, which is to be called whenever cross-window blur is enabled/disabled.
     *
+12 −0
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import android.media.projection.IMediaProjectionCallback;
import android.media.projection.IMediaProjectionWatcherCallback;
import android.media.projection.MediaProjectionInfo;
import android.os.IBinder;
import android.view.ContentRecordingSession;

/** {@hide} */
interface IMediaProjectionManager {
@@ -33,4 +34,15 @@ interface IMediaProjectionManager {
    void stopActiveProjection();
    void addCallback(IMediaProjectionWatcherCallback callback);
    void removeCallback(IMediaProjectionWatcherCallback callback);

    /**
     * Updates the content recording session. If a different session is already in progress, then
     * the pre-existing session is stopped, and the new incoming session takes over. Only updates
     * the session if the given projection is valid.
     *
     * @param incomingSession the nullable incoming content recording session
     * @param projection      the non-null projection the session describes
     */
    void setContentRecordingSession(in ContentRecordingSession incomingSession,
            in IMediaProjection projection);
}
+11 −4
Original line number Diff line number Diff line
@@ -26,12 +26,11 @@ import android.hardware.display.VirtualDisplay;
import android.hardware.display.VirtualDisplayConfig;
import android.os.Handler;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.util.ArrayMap;
import android.util.Log;
import android.view.ContentRecordingSession;
import android.view.IWindowManager;
import android.view.Surface;
import android.view.WindowManagerGlobal;
import android.window.WindowContainerToken;

import java.util.Map;
@@ -53,6 +52,7 @@ public final class MediaProjection {
    private final IMediaProjection mImpl;
    private final Context mContext;
    private final Map<Callback, CallbackRecord> mCallbacks;
    @Nullable private IMediaProjectionManager mProjectionService = null;

    /** @hide */
    public MediaProjection(Context context, IMediaProjection impl) {
@@ -172,7 +172,6 @@ public final class MediaProjection {
            @NonNull VirtualDisplayConfig.Builder virtualDisplayConfig,
            @Nullable VirtualDisplay.Callback callback, @Nullable Handler handler) {
        try {
            final IWindowManager wmService = WindowManagerGlobal.getWindowManagerService();
            final WindowContainerToken taskWindowContainerToken =
                    mImpl.getTaskRecordingWindowContainerToken();
            Context windowContext = null;
@@ -199,7 +198,7 @@ public final class MediaProjection {
            }
            session.setDisplayId(virtualDisplay.getDisplay().getDisplayId());
            // Successfully set up, so save the current session details.
            wmService.setContentRecordingSession(session);
            getProjectionService().setContentRecordingSession(session, mImpl);
            return virtualDisplay;
        } catch (RemoteException e) {
            // Can not capture if WMS is not accessible, so bail out.
@@ -207,6 +206,14 @@ public final class MediaProjection {
        }
    }

    private IMediaProjectionManager getProjectionService() {
        if (mProjectionService == null) {
            mProjectionService = IMediaProjectionManager.Stub.asInterface(
                    ServiceManager.getService(Context.MEDIA_PROJECTION_SERVICE));
        }
        return mProjectionService;
    }

    /**
     * Stops projection.
     */
+23 −1
Original line number Diff line number Diff line
@@ -45,14 +45,15 @@ import android.os.RemoteException;
import android.os.UserHandle;
import android.util.ArrayMap;
import android.util.Slog;
import android.view.ContentRecordingSession;
import android.window.WindowContainerToken;

import com.android.internal.util.ArrayUtils;
import com.android.internal.util.DumpUtils;
import com.android.server.LocalServices;
import com.android.server.SystemService;
import com.android.server.SystemService.TargetUser;
import com.android.server.Watchdog;
import com.android.server.wm.WindowManagerInternal;

import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -381,6 +382,27 @@ public final class MediaProjectionManagerService extends SystemService
            }
        }

        /**
         * Updates the current content mirroring session.
         */
        @Override
        public void setContentRecordingSession(@Nullable ContentRecordingSession incomingSession,
                @NonNull IMediaProjection projection) {
            final long origId = Binder.clearCallingIdentity();
            try {
                synchronized (mLock) {
                    if (!isValidMediaProjection(projection)) {
                        throw new SecurityException("Invalid media projection");
                    }
                    LocalServices.getService(
                            WindowManagerInternal.class).setContentRecordingSession(
                            incomingSession);
                }
            } finally {
                Binder.restoreCallingIdentity(origId);
            }
        }

        @Override // Binder call
        public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) {
            if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
+2 −1
Original line number Diff line number Diff line
@@ -207,7 +207,8 @@ final class ContentRecorder {
        // Update the cached session state first, since updating the service will result in always
        // returning to this instance to update recording state.
        mContentRecordingSession = null;
        mDisplayContent.mWmService.setContentRecordingSession(null);
        mDisplayContent.mWmService.mContentRecordingController.setContentRecordingSessionLocked(
                null, mDisplayContent.mWmService);
    }

    /**
Loading