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

Commit bf2c373d authored by Lingyu Feng's avatar Lingyu Feng
Browse files

Revert^2 "Prevent activity being launched on a display where canHostTasks()"

This reverts commit 395a6636.

Reason for revert: Reapply the change with test failure fixes

This fixes the test failures in ActivityStarterTests and
ActivityStarterTests by ensuring the Display object created in
TestDisplayContent class has canHostTasks is true by default.

Note that Display.canHostTasks should be false only for virtual displays
that should always be mirroring (i.e., MediaProjection is not null), or
for a display that can dynamically switch its content mode and has the
mirroring switch enabled. Since the mirroring switch is disabled by
default, the Display object created in TestDisplayContent should have
canHostTasks being true by default.

Bug: 424049071
Test: ActivityStarterTests
Test: RootWindowContainerTests
Change-Id: I8586f8f0b9840891388c811d3b4c574f7a9e2341
parent 59f36d3e
Loading
Loading
Loading
Loading
+4 −2
Original line number Diff line number Diff line
@@ -1793,8 +1793,10 @@ public class ActivityOptions extends ComponentOptions {
    /**
     * Sets the id of the display where the activity should be launched.
     * An app can launch activities on public displays or displays where the app already has
     * activities. Otherwise, trying to launch on a private display or providing an invalid display
     * id will result in an exception.
     * activities. Otherwise, trying to launch on a display for which
     * {@link android.app.ActivityManager#isActivityStartAllowedOnDisplay(Context, int, Intent)}
     * returns {@code false} (such as a private display or providing an invalid display id) will
     * result in an exception.
     * <p>
     * Setting launch display id will be ignored on devices that don't have
     * {@link android.content.pm.PackageManager#FEATURE_ACTIVITIES_ON_SECONDARY_DISPLAYS}.
+8 −0
Original line number Diff line number Diff line
@@ -1280,6 +1280,14 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks {
            return false;
        }

        if (DesktopExperienceFlags.ENABLE_MIRROR_DISPLAY_NO_ACTIVITY.isTrue()) {
            if (!displayContent.mDisplay.canHostTasks()) {
                Slog.w(TAG, "Launch on display check: activity launch is not allowed on a "
                        + "display that cannot host tasks");
                return false;
            }
        }

        // Check if the caller has enough privileges to embed activities and launch to private
        // displays.
        final int startAnyPerm = mService.checkPermission(INTERNAL_SYSTEM_WINDOW, callingPid,
+27 −0
Original line number Diff line number Diff line
@@ -70,6 +70,7 @@ import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
@@ -1069,6 +1070,32 @@ public class ActivityStarterTests extends WindowTestsBase {
        verify(secondaryTaskContainer, times(1)).createRootTask(anyInt(), anyInt(), anyBoolean());
    }

    /**
     * This test ensures that activity launch on a secondary display that cannot host tasks is
     * disallowed, and a SecurityException should be thrown.
     */
    @Test
    public void testStartActivityOnDisplayCannotHostTasks() {
        final ActivityStarter starter = prepareStarter(0);

        // Create a display that cannot host tasks.
        final TestDisplayContent secondaryDisplay =
                new TestDisplayContent.Builder(mAtm, 1000, 1500)
                        .setCanHostTasks(false).build();

        final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true).build();

        final ActivityOptions options = ActivityOptions.makeBasic()
                .setLaunchDisplayId(secondaryDisplay.mDisplayId);

        assertThrows(SecurityException.class,
                () -> starter.setReason("testStartActivityOnDisplayCannotHostTasks")
                        .setIntent(activity.intent)
                        .setActivityOptions(options.toBundle(), Binder.getCallingPid(),
                                Binder.getCallingUid())
                        .execute());
    }

    @Test
    public void testWasVisibleInRestartAttempt() {
        final ActivityStarter starter = prepareStarter(
+26 −1
Original line number Diff line number Diff line
@@ -334,7 +334,7 @@ public class ActivityTaskSupervisorTests extends WindowTestsBase {
     * Ensures that a trusted display can launch arbitrary activity and an untrusted display can't.
     */
    @Test
    public void testDisplayCanLaunchActivities() {
    public void testDisplayCanLaunchActivities_trustedDisplay() {
        final Display display = mDisplayContent.mDisplay;
        // An empty info without FLAG_ALLOW_EMBEDDED.
        final ActivityInfo activityInfo = new ActivityInfo();
@@ -355,6 +355,31 @@ public class ActivityTaskSupervisorTests extends WindowTestsBase {
        assertThat(allowedOnUntrusted).isFalse();
    }

    /**
     * Ensures that an arbitrary activity can be launched on a display the can host tasks, and
     * cannot be launched on a display that cannot host tasks.
     */
    @EnableFlags(Flags.FLAG_ENABLE_MIRROR_DISPLAY_NO_ACTIVITY)
    @Test
    public void testDisplayCanLaunchActivities_canHostTasksDisplay() {
        final Display display = mDisplayContent.mDisplay;
        // An empty info without FLAG_ALLOW_EMBEDDED.
        final ActivityInfo activityInfo = new ActivityInfo();
        final int callingPid = 12345;
        final int callingUid = 12345;
        spyOn(display);

        doReturn(true).when(display).canHostTasks();
        final boolean allowedOnCanHostTasks = mSupervisor.isCallerAllowedToLaunchOnDisplay(
                callingPid, callingUid, display.getDisplayId(), activityInfo);
        assertThat(allowedOnCanHostTasks).isTrue();

        doReturn(false).when(display).canHostTasks();
        final boolean allowedOnCannotHostTasks = mSupervisor.isCallerAllowedToLaunchOnDisplay(
                callingPid, callingUid, display.getDisplayId(), activityInfo);
        assertThat(allowedOnCannotHostTasks).isFalse();
    }

    /**
     * Verifies that process state will be updated with pending top without activity state change.
     * E.g. switch focus between resumed activities in multi-window mode.
+9 −0
Original line number Diff line number Diff line
@@ -105,6 +105,7 @@ class TestDisplayContent extends DisplayContent {
        private SettingsEntry mOverrideSettings;
        @NonNull
        private DeviceStateController mDeviceStateController = mock(DeviceStateController.class);
        private boolean mCanHostTasks = true;

        Builder(ActivityTaskManagerService service, int width, int height) {
            mService = service;
@@ -160,6 +161,10 @@ class TestDisplayContent extends DisplayContent {
            mInfo.ownerUid = ownerUid;
            return this;
        }
        Builder setCanHostTasks(boolean canHostTasks) {
            mCanHostTasks = canHostTasks;
            return this;
        }
        Builder setCutout(int left, int top, int right, int bottom) {
            final int cutoutFillerSize = 80;
            Rect boundLeft = left != 0 ? new Rect(0, 0, left, cutoutFillerSize) : null;
@@ -215,6 +220,10 @@ class TestDisplayContent extends DisplayContent {
            mInfo.displayId = displayId;
            final Display display = new Display(DisplayManagerGlobal.getInstance(), displayId,
                    mInfo, DEFAULT_DISPLAY_ADJUSTMENTS);
            spyOn(display);
            if (mCanHostTasks) {
                doReturn(true).when(display).canHostTasks();
            }
            final TestDisplayContent newDisplay = createInternal(display);
            // disable the normal system decorations
            final DisplayPolicy displayPolicy = newDisplay.getDisplayPolicy();