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

Commit 43b3cf17 authored by [D's avatar [D[1;5D
Browse files

Pass display owner uid explicitly for virtual displays.

This allows for creating a display with clean identity on behalf of
an app, prerequisite for virtual devices managed in the system server

Also, remove the ACCESS_COMPUTER_CONTROL permission checks that allow
for creating trusted and always unlocked displays. These are no longer
needed when the display is created with a clean identity

Bug: 432679227
Test: presubmit
Flag: EXEMPT no-op
Change-Id: I614d8ebe26993d8aee78b7b334fd002e43b75cab
parent a9492910
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -70,7 +70,7 @@ public abstract class DisplayManagerInternal {
     */
    public abstract int createVirtualDisplay(VirtualDisplayConfig config,
            IVirtualDisplayCallback callback, IVirtualDevice virtualDevice,
            DisplayWindowPolicyController dwpc, String packageName);
            DisplayWindowPolicyController dwpc, String packageName, int ownerUid);

    /**
     * Called by the power manager to request a new power state.
+6 −2
Original line number Diff line number Diff line
@@ -92,6 +92,7 @@ import android.os.IBinder;
import android.os.LocaleList;
import android.os.Looper;
import android.os.PowerManager;
import android.os.Process;
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.SystemClock;
@@ -1321,8 +1322,10 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
        // Create the display outside of the lock to avoid deadlock. DisplayManagerService will
        // acquire the global WM lock while creating the display. At the same time, WM may query
        // VDM and this virtual device to get policies, display ownership, etc.
        // We have already verified that the caller is the owner or the system, so pass the display
        // owner uid explicitly to allow creation of displays with clean identity.
        int displayId = mDisplayManagerInternal.createVirtualDisplay(virtualDisplayConfig,
                    callback, this, gwpc, mOwnerPackageName);
                    callback, this, gwpc, mOwnerPackageName, mOwnerUid);
        if (displayId == Display.INVALID_DISPLAY) {
            return displayId;
        }
@@ -1506,7 +1509,8 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
    }

    private void checkCallerIsDeviceOwner() {
        if (Binder.getCallingUid() != mOwnerUid) {
        final int callingUid = Binder.getCallingUid();
        if (callingUid != mOwnerUid && callingUid != Process.SYSTEM_UID) {
            throw new SecurityException(
                "Caller is not the owner of this virtual device");
        }
+13 −17
Original line number Diff line number Diff line
@@ -16,7 +16,6 @@

package com.android.server.display;

import static android.Manifest.permission.ACCESS_COMPUTER_CONTROL;
import static android.Manifest.permission.ADD_ALWAYS_UNLOCKED_DISPLAY;
import static android.Manifest.permission.ADD_TRUSTED_DISPLAY;
import static android.Manifest.permission.CAPTURE_SECURE_VIDEO_OUTPUT;
@@ -1844,10 +1843,11 @@ public final class DisplayManagerService extends SystemService {

    private int createVirtualDisplayInternal(VirtualDisplayConfig virtualDisplayConfig,
            IVirtualDisplayCallback callback, IMediaProjection projection,
            IVirtualDevice virtualDevice, DisplayWindowPolicyController dwpc, String packageName) {
            IVirtualDevice virtualDevice, DisplayWindowPolicyController dwpc, String packageName,
            int ownerUid) {
        final int callingUid = Binder.getCallingUid();
        if (!validatePackageName(callingUid, packageName)) {
            throw new SecurityException("packageName must match the calling uid");
        if (!validatePackageName(ownerUid, packageName)) {
            throw new SecurityException("packageName must match the owner uid");
        }
        if (callback == null) {
            throw new IllegalArgumentException("appToken must not be null");
@@ -1967,8 +1967,7 @@ public final class DisplayManagerService extends SystemService {
        }

        if (callingUid != Process.SYSTEM_UID && (flags & VIRTUAL_DISPLAY_FLAG_TRUSTED) != 0) {
            if (!checkCallingPermission(ADD_TRUSTED_DISPLAY, "createVirtualDisplay()")
                    && !checkCallingPermission(ACCESS_COMPUTER_CONTROL, "createVirtualDisplay()")) {
            if (!checkCallingPermission(ADD_TRUSTED_DISPLAY, "createVirtualDisplay()")) {
                EventLog.writeEvent(0x534e4554, "162627132", callingUid,
                        "Attempt to create a trusted display without holding permission!");
                throw new SecurityException("Requires ADD_TRUSTED_DISPLAY permission to "
@@ -1987,8 +1986,7 @@ public final class DisplayManagerService extends SystemService {

        if (callingUid != Process.SYSTEM_UID
                && (flags & VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP) != 0) {
            if (!(checkCallingPermission(ADD_TRUSTED_DISPLAY, "createVirtualDisplay()")
                    || checkCallingPermission(ACCESS_COMPUTER_CONTROL, "createVirtualDisplay()"))) {
            if (!checkCallingPermission(ADD_TRUSTED_DISPLAY, "createVirtualDisplay()")) {
                throw new SecurityException("Requires ADD_TRUSTED_DISPLAY permission to "
                        + "create a virtual display which is not in the default DisplayGroup.");
            }
@@ -2004,9 +2002,7 @@ public final class DisplayManagerService extends SystemService {

        if (callingUid != Process.SYSTEM_UID
                && (flags & VIRTUAL_DISPLAY_FLAG_ALWAYS_UNLOCKED) != 0) {
            if (!(checkCallingPermission(ADD_ALWAYS_UNLOCKED_DISPLAY, "createVirtualDisplay()")
                     || checkCallingPermission(ACCESS_COMPUTER_CONTROL,
                    "createVirtualDisplay()"))) {
            if (!checkCallingPermission(ADD_ALWAYS_UNLOCKED_DISPLAY, "createVirtualDisplay()")) {
                throw new SecurityException(
                        "Requires ADD_ALWAYS_UNLOCKED_DISPLAY permission to "
                                + "create an always unlocked virtual display.");
@@ -2052,7 +2048,7 @@ public final class DisplayManagerService extends SystemService {
        try {
            final int displayId;
            final String displayUniqueId = VirtualDisplayAdapter.generateDisplayUniqueId(
                    packageName, callingUid, virtualDisplayConfig);
                    packageName, ownerUid, virtualDisplayConfig);

            boolean shouldClearDisplayWindowSettings = false;
            if (virtualDisplayConfig.isHomeSupported()) {
@@ -2086,7 +2082,7 @@ public final class DisplayManagerService extends SystemService {
                        createVirtualDisplayLocked(
                                callback,
                                projection,
                                callingUid,
                                ownerUid,
                                packageName,
                                displayUniqueId,
                                virtualDevice,
@@ -2119,7 +2115,7 @@ public final class DisplayManagerService extends SystemService {
                        if (projection.isRecordingOverlay()) {
                            // Record an overlay session.
                            session = ContentRecordingSession.createOverlaySession(
                                    virtualDisplayConfig.getDisplayIdToMirror(), callingUid);
                                    virtualDisplayConfig.getDisplayIdToMirror(), ownerUid);
                        } else {
                            // Record a particular display.
                            session = ContentRecordingSession.createDisplaySession(
@@ -5051,7 +5047,7 @@ public final class DisplayManagerService extends SystemService {
                IVirtualDisplayCallback callback, IMediaProjection projection,
                String packageName) {
            return createVirtualDisplayInternal(virtualDisplayConfig, callback, projection,
                    null, null, packageName);
                    null, null, packageName, Binder.getCallingUid());
        }

        @Override // Binder call
@@ -5771,9 +5767,9 @@ public final class DisplayManagerService extends SystemService {
        @Override
        public int createVirtualDisplay(VirtualDisplayConfig config,
                IVirtualDisplayCallback callback, IVirtualDevice virtualDevice,
                DisplayWindowPolicyController dwpc, String packageName) {
                DisplayWindowPolicyController dwpc, String packageName, int ownerUid) {
            return createVirtualDisplayInternal(config, callback, null, virtualDevice, dwpc,
                    packageName);
                    packageName, ownerUid);
        }

        @Override
+31 −16
Original line number Diff line number Diff line
@@ -1256,7 +1256,8 @@ public class DisplayManagerServiceTest {
                        mMockAppToken2 /* callback */,
                        virtualDevice /* virtualDeviceToken */,
                        mock(DisplayWindowPolicyController.class),
                        PACKAGE_NAME);
                        PACKAGE_NAME,
                        Process.myUid());
        verify(mMockProjectionService, never()).setContentRecordingSession(any(),
                nullable(IMediaProjection.class));
        int displayGroupId1 = localService.getDisplayInfo(displayId1).displayGroupId;
@@ -1275,7 +1276,8 @@ public class DisplayManagerServiceTest {
                        mMockAppToken /* callback */,
                        virtualDevice /* virtualDeviceToken */,
                        mock(DisplayWindowPolicyController.class),
                        PACKAGE_NAME);
                        PACKAGE_NAME,
                        Process.myUid());
        verify(mMockProjectionService, never()).setContentRecordingSession(any(),
                nullable(IMediaProjection.class));
        int displayGroupId2 = localService.getDisplayInfo(displayId2).displayGroupId;
@@ -1309,7 +1311,8 @@ public class DisplayManagerServiceTest {
                        mMockAppToken /* callback */,
                        virtualDevice /* virtualDeviceToken */,
                        mock(DisplayWindowPolicyController.class),
                        PACKAGE_NAME);
                        PACKAGE_NAME,
                        Process.myUid());
        verify(mMockProjectionService, never()).setContentRecordingSession(any(),
                nullable(IMediaProjection.class));
        int displayGroupId = localService.getDisplayInfo(displayId).displayGroupId;
@@ -1349,7 +1352,8 @@ public class DisplayManagerServiceTest {
                        mMockAppToken /* callback */,
                        virtualDevice /* virtualDeviceToken */,
                        mock(DisplayWindowPolicyController.class),
                        PACKAGE_NAME);
                        PACKAGE_NAME,
                        Process.myUid());
        verify(mMockProjectionService, never()).setContentRecordingSession(any(),
                nullable(IMediaProjection.class));
        int displayGroupId1 = localService.getDisplayInfo(displayId1).displayGroupId;
@@ -1371,7 +1375,8 @@ public class DisplayManagerServiceTest {
                        mMockAppToken2 /* callback */,
                        virtualDevice /* virtualDeviceToken */,
                        mock(DisplayWindowPolicyController.class),
                        PACKAGE_NAME);
                        PACKAGE_NAME,
                        Process.myUid());
        verify(mMockProjectionService, never()).setContentRecordingSession(any(),
                nullable(IMediaProjection.class));
        int displayGroupId2 = localService.getDisplayInfo(displayId2).displayGroupId;
@@ -1420,7 +1425,8 @@ public class DisplayManagerServiceTest {
                        mMockAppToken /* callback */,
                        virtualDevice /* virtualDeviceToken */,
                        mock(DisplayWindowPolicyController.class),
                        PACKAGE_NAME);
                        PACKAGE_NAME,
                        Process.myUid());
        verify(mMockProjectionService, never()).setContentRecordingSession(any(),
                nullable(IMediaProjection.class));

@@ -1448,7 +1454,8 @@ public class DisplayManagerServiceTest {
                        mMockAppToken2 /* callback */,
                        virtualDevice /* virtualDeviceToken */,
                        mock(DisplayWindowPolicyController.class),
                        PACKAGE_NAME);
                        PACKAGE_NAME,
                        Process.myUid());
        verify(mMockProjectionService, never()).setContentRecordingSession(any(),
                nullable(IMediaProjection.class));

@@ -1473,7 +1480,8 @@ public class DisplayManagerServiceTest {
                        mMockAppToken3 /* callback */,
                        null /* virtualDeviceToken */,
                        mock(DisplayWindowPolicyController.class),
                        PACKAGE_NAME);
                        PACKAGE_NAME,
                        Process.myUid());
        verify(mMockProjectionService, never()).setContentRecordingSession(any(),
                nullable(IMediaProjection.class));

@@ -1509,7 +1517,8 @@ public class DisplayManagerServiceTest {
                    mMockAppToken /* callback */,
                    null /* virtualDeviceToken */,
                    mock(DisplayWindowPolicyController.class),
                    PACKAGE_NAME);
                    PACKAGE_NAME,
                    Process.myUid());
        });
    }

@@ -1540,7 +1549,8 @@ public class DisplayManagerServiceTest {
                    mMockAppToken /* callback */,
                    virtualDevice /* virtualDeviceToken */,
                    mock(DisplayWindowPolicyController.class),
                    PACKAGE_NAME);
                    PACKAGE_NAME,
                    Process.myUid());
        });
    }

@@ -1570,7 +1580,8 @@ public class DisplayManagerServiceTest {
                        mMockAppToken /* callback */,
                        virtualDevice /* virtualDeviceToken */,
                        mock(DisplayWindowPolicyController.class),
                        PACKAGE_NAME);
                        PACKAGE_NAME,
                        Process.myUid());

        // The virtual display should be in the default display group.
        assertEquals(Display.DEFAULT_DISPLAY_GROUP,
@@ -1603,7 +1614,8 @@ public class DisplayManagerServiceTest {
                        mMockAppToken /* callback */,
                        virtualDevice /* virtualDeviceToken */,
                        mock(DisplayWindowPolicyController.class),
                        PACKAGE_NAME);
                        PACKAGE_NAME,
                        Process.myUid());

        // The virtual display should mirror the default display.
        assertEquals(Display.DEFAULT_DISPLAY, localService.getDisplayIdToMirror(displayId));
@@ -1634,7 +1646,8 @@ public class DisplayManagerServiceTest {
                        mMockAppToken /* callback */,
                        virtualDevice /* virtualDeviceToken */,
                        mock(DisplayWindowPolicyController.class),
                        PACKAGE_NAME);
                        PACKAGE_NAME,
                        Process.myUid());

        // The virtual display should not mirror any display.
        assertEquals(Display.INVALID_DISPLAY, localService.getDisplayIdToMirror(displayId));
@@ -1673,7 +1686,8 @@ public class DisplayManagerServiceTest {
                        mMockAppToken /* callback */,
                        virtualDevice /* virtualDeviceToken */,
                        mock(DisplayWindowPolicyController.class),
                        PACKAGE_NAME);
                        PACKAGE_NAME,
                        Process.myUid());

        // The virtual display should not have FLAG_ALWAYS_UNLOCKED set.
        assertEquals(0, (displayManager.getDisplayDeviceInfoInternal(displayId).flags
@@ -1707,7 +1721,8 @@ public class DisplayManagerServiceTest {
                        mMockAppToken /* callback */,
                        virtualDevice /* virtualDeviceToken */,
                        mock(DisplayWindowPolicyController.class),
                        PACKAGE_NAME);
                        PACKAGE_NAME,
                        Process.myUid());

        // The virtual display should not have FLAG_PRESENTATION set.
        assertEquals(0, (displayManager.getDisplayDeviceInfoInternal(displayId).flags
@@ -2211,7 +2226,7 @@ public class DisplayManagerServiceTest {
        try {
            localService.createVirtualDisplay(builder.build(),
                    mMockAppToken /* callback */, virtualDevice /* virtualDeviceToken */,
                    mock(DisplayWindowPolicyController.class), PACKAGE_NAME);
                    mock(DisplayWindowPolicyController.class), PACKAGE_NAME, Process.myUid());
            fail("Creating virtual display with VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP without "
                    + "ADD_TRUSTED_DISPLAY permission should throw SecurityException even if "
                    + "called with a virtual device.");
+2 −2
Original line number Diff line number Diff line
@@ -279,7 +279,7 @@ public class VirtualDeviceManagerServiceTest {
    private Intent createRestrictedActivityBlockedIntent(Set<String> displayCategories,
            String targetDisplayCategory) {
        when(mDisplayManagerInternalMock.createVirtualDisplay(any(), any(), any(), any(),
                eq(VIRTUAL_DEVICE_OWNER_PACKAGE)))
                eq(VIRTUAL_DEVICE_OWNER_PACKAGE), eq(DEVICE_OWNER_UID_1)))
                .thenAnswer(inv -> {
                    mLocalService.onVirtualDisplayCreated(
                            mDeviceImpl, DISPLAY_ID_1, inv.getArgument(1), inv.getArgument(3));
@@ -1561,7 +1561,7 @@ public class VirtualDeviceManagerServiceTest {
        }).when(mDisplayManagerInternalMock).getDisplayInfo(eq(displayId));

        when(mDisplayManagerInternalMock.createVirtualDisplay(any(), eq(mVirtualDisplayCallback),
                eq(virtualDevice), any(), any())).thenAnswer(inv -> {
                eq(virtualDevice), any(), any(), anyInt())).thenAnswer(inv -> {
                    mLocalService.onVirtualDisplayCreated(
                            virtualDevice, displayId, mVirtualDisplayCallback, inv.getArgument(3));
                    return displayId;