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

Commit 1cba31c3 authored by Andrii Kulian's avatar Andrii Kulian
Browse files

Restrict launching activities on virtual displays

If an app creates a Surface and a virtual display backed by that
Surface, it can then launch activities and hijack their content.
This CL restrict activities that can be launched to virtual displays
created by apps only to those who set "allowEmbedded" attribute.
If a virtual display was created by system, apps won't get access to
the surface, so we're not limiting in this case.

Bug: 63094482
Test: android.server.cts.ActivityManagerDisplayTests
Test: #testLaunchNotEmbeddedOnVirtualDisplay
Change-Id: Ied216bdf33df4b5a6cc8cac0e006a4883a36f94f
parent f36a9954
Loading
Loading
Loading
Loading
+25 −11
Original line number Diff line number Diff line
@@ -38,11 +38,13 @@ import static android.app.ITaskStackListener.FORCED_RESIZEABLE_REASON_SPLIT_SCRE
import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.os.Process.SYSTEM_UID;
import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.FLAG_PRIVATE;
import static android.view.Display.INVALID_DISPLAY;
import static android.view.Display.REMOVE_MODE_DESTROY_CONTENT;
import static android.view.Display.TYPE_VIRTUAL;

import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.ACTION_PICTURE_IN_PICTURE_EXPANDED_TO_FULLSCREEN;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ALL;
@@ -1654,7 +1656,8 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
            // owner.
            final int launchDisplayId = options.getLaunchDisplayId();
            if (launchDisplayId != INVALID_DISPLAY
                    && !isCallerAllowedToLaunchOnDisplay(callingPid, callingUid, launchDisplayId)) {
                    && !isCallerAllowedToLaunchOnDisplay(callingPid, callingUid, launchDisplayId,
                    aInfo)) {
                final String msg = "Permission Denial: starting " + intent.toString()
                        + " from " + callerApp + " (pid=" + callingPid
                        + ", uid=" + callingUid + ") with launchDisplayId="
@@ -1668,7 +1671,8 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
    }

    /** Check if caller is allowed to launch activities on specified display. */
    boolean isCallerAllowedToLaunchOnDisplay(int callingPid, int callingUid, int launchDisplayId) {
    boolean isCallerAllowedToLaunchOnDisplay(int callingPid, int callingUid, int launchDisplayId,
            ActivityInfo aInfo) {
        if (DEBUG_TASKS) Slog.d(TAG, "Launch on display check: displayId=" + launchDisplayId
                + " callingPid=" + callingPid + " callingUid=" + callingUid);

@@ -1678,6 +1682,25 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
            return false;
        }

        // Check if the caller can manage activity stacks.
        final int startAnyPerm = mService.checkPermission(MANAGE_ACTIVITY_STACKS, callingPid,
                callingUid);
        if (startAnyPerm == PERMISSION_GRANTED) {
            if (DEBUG_TASKS) Slog.d(TAG, "Launch on display check:"
                    + " allow launch any on display");
            return true;
        }

        if (activityDisplay.mDisplay.getType() == TYPE_VIRTUAL
                && activityDisplay.mDisplay.getOwnerUid() != SYSTEM_UID
                && (aInfo.flags & ActivityInfo.FLAG_ALLOW_EMBEDDED) == 0) {
            // Limit launching on virtual displays, because their contents can be read from Surface
            // by apps that created them.
            if (DEBUG_TASKS) Slog.d(TAG, "Launch on display check:"
                    + " disallow launch on virtual display for not-embedded activity");
            return false;
        }

        if (!activityDisplay.isPrivate()) {
            // Anyone can launch on a public display.
            if (DEBUG_TASKS) Slog.d(TAG, "Launch on display check:"
@@ -1699,15 +1722,6 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
            return true;
        }

        // Check if the caller can manage activity stacks.
        final int startAnyPerm = mService.checkPermission(MANAGE_ACTIVITY_STACKS, callingPid,
                callingUid);
        if (startAnyPerm == PERMISSION_GRANTED) {
            if (DEBUG_TASKS) Slog.d(TAG, "Launch on display check:"
                    + " allow launch any on display");
            return true;
        }

        Slog.w(TAG, "Launch on display check: denied");
        return false;
    }