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

Commit 7beb3787 authored by Sean Stout's avatar Sean Stout
Browse files

Allow virtual displays to launch activities if trusted

This CL updates ActivityStackSupervisor to allow virtual displays to
launch Activities if they are trusted displays. Trusted virtual displays
can only be created if the ADD_TRUSTED_DISPLAY permission is held.

Bug: 162255799
Bug: 162042798
Test: atest WmTests:ActivityStackSupervisorTests
Change-Id: I0ec3ef91e7ee2cbea34183d2607b31a4b0dd0fc3
parent bbdf17a4
Loading
Loading
Loading
Loading
+5 −4
Original line number Diff line number Diff line
@@ -130,6 +130,7 @@ import android.util.MergedConfiguration;
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseIntArray;
import android.view.Display;

import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
@@ -1090,9 +1091,9 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks {
        // Check if caller is already present on display
        final boolean uidPresentOnDisplay = displayContent.isUidPresent(callingUid);

        final int displayOwnerUid = displayContent.mDisplay.getOwnerUid();
        if (displayContent.mDisplay.getType() == TYPE_VIRTUAL && displayOwnerUid != SYSTEM_UID) {
            // Limit launching on virtual displays, because their contents can be read from Surface
        final Display display = displayContent.mDisplay;
        if (!display.isTrusted()) {
            // Limit launching on untrusted displays because their contents can be read from Surface
            // by apps that created them.
            if ((aInfo.flags & ActivityInfo.FLAG_ALLOW_EMBEDDED) == 0) {
                if (DEBUG_TASKS) Slog.d(TAG, "Launch on display check:"
@@ -1116,7 +1117,7 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks {
        }

        // Check if the caller is the owner of the display.
        if (displayOwnerUid == callingUid) {
        if (display.getOwnerUid() == callingUid) {
            if (DEBUG_TASKS) Slog.d(TAG, "Launch on display check:"
                    + " allow launch for owner of the display");
            return true;
+1 −0
Original line number Diff line number Diff line
@@ -38,6 +38,7 @@
    <uses-permission android:name="android.permission.REORDER_TASKS" />
    <uses-permission android:name="android.permission.READ_DEVICE_CONFIG" />
    <uses-permission android:name="android.permission.STATUS_BAR" />
    <uses-permission android:name="android.permission.CAPTURE_VIDEO_OUTPUT" />

    <!-- TODO: Remove largeHeap hack when memory leak is fixed (b/123984854) -->
    <application android:debuggable="true"
+52 −0
Original line number Diff line number Diff line
@@ -38,7 +38,13 @@ import static org.mockito.ArgumentMatchers.eq;

import android.app.WaitResult;
import android.content.pm.ActivityInfo;
import android.graphics.PixelFormat;
import android.hardware.display.DisplayManager;
import android.hardware.display.VirtualDisplay;
import android.media.ImageReader;
import android.platform.test.annotations.Presubmit;
import android.view.Display;
import android.view.DisplayInfo;

import androidx.test.filters.MediumTest;

@@ -173,4 +179,50 @@ public class ActivityStackSupervisorTests extends ActivityTestsBase {
        verify(taskChangeNotifier).notifyTaskFocusChanged(eq(taskB.mTaskId) /* taskId */,
                eq(true) /* focused */);
    }

    @Test
    /** Ensures that a trusted virtual display can launch arbitrary activities. */
    public void testTrustedVirtualDisplayCanLaunchActivities() {
        final DisplayContent newDisplay = addNewDisplayContentAt(DisplayContent.POSITION_TOP);
        final Task stack = new StackBuilder(mRootWindowContainer)
                .setDisplay(newDisplay).build();
        final ActivityRecord unresizableActivity = stack.getTopNonFinishingActivity();
        VirtualDisplay virtualDisplay = createVirtualDisplay(true);
        final boolean allowed = mSupervisor.isCallerAllowedToLaunchOnDisplay(1234, 1234,
                virtualDisplay.getDisplay().getDisplayId(), unresizableActivity.info);

        assertThat(allowed).isTrue();
    }

    @Test
    /** Ensures that an untrusted virtual display cannot launch arbitrary activities. */
    public void testUntrustedVirtualDisplayCannotLaunchActivities() {
        final DisplayContent newDisplay = addNewDisplayContentAt(DisplayContent.POSITION_TOP);
        final Task stack = new StackBuilder(mRootWindowContainer)
                .setDisplay(newDisplay).build();
        final ActivityRecord unresizableActivity = stack.getTopNonFinishingActivity();
        VirtualDisplay virtualDisplay = createVirtualDisplay(false);
        final boolean allowed = mSupervisor.isCallerAllowedToLaunchOnDisplay(1234, 1234,
                virtualDisplay.getDisplay().getDisplayId(), unresizableActivity.info);

        assertThat(allowed).isFalse();
    }

    private VirtualDisplay createVirtualDisplay(boolean trusted) {
        final DisplayManager dm = mContext.getSystemService(DisplayManager.class);
        final DisplayInfo displayInfo = new DisplayInfo();
        final Display defaultDisplay = dm.getDisplay(Display.DEFAULT_DISPLAY);
        defaultDisplay.getDisplayInfo(displayInfo);
        int flags = DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC;
        if (trusted) {
            flags |= DisplayManager.VIRTUAL_DISPLAY_FLAG_TRUSTED;
        }

        final ImageReader imageReader = ImageReader.newInstance(
                displayInfo.logicalWidth, displayInfo.logicalHeight, PixelFormat.RGBA_8888, 2);

        return dm.createVirtualDisplay("virtualDisplay", displayInfo.logicalWidth,
                displayInfo.logicalHeight,
                displayInfo.logicalDensityDpi, imageReader.getSurface(), flags);
    }
}