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

Commit c0ccf9b0 authored by Chris Li's avatar Chris Li Committed by Android (Google) Code Review
Browse files

Merge "Make activities in untrusted embedding mode invisible behind overlay" into tm-dev

parents 6a2b312a ff3321d1
Loading
Loading
Loading
Loading
+83 −0
Original line number Diff line number Diff line
@@ -278,6 +278,7 @@ import android.graphics.PixelFormat;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.gui.DropInputMode;
import android.hardware.HardwareBuffer;
import android.net.Uri;
import android.os.Binder;
@@ -782,6 +783,10 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
    boolean startingDisplayed;
    boolean startingMoved;

    /** The last set {@link DropInputMode} for this activity surface. */
    @DropInputMode
    private int mLastDropInputMode = DropInputMode.NONE;

    /**
     * If it is non-null, it requires all activities who have the same starting data to be drawn
     * to remove the starting window.
@@ -1548,6 +1553,60 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
                rootTask.setHasBeenVisible(true);
            }
        }

        // Update the input mode if the embedded mode is changed.
        updateUntrustedEmbeddingInputProtection();
    }

    @Override
    void setSurfaceControl(SurfaceControl sc) {
        super.setSurfaceControl(sc);
        if (sc != null) {
            mLastDropInputMode = DropInputMode.NONE;
            updateUntrustedEmbeddingInputProtection();
        }
    }

    /**
     * Sets to drop input when obscured to activity if it is embedded in untrusted mode.
     *
     * Although the untrusted embedded activity should be invisible when behind other overlay,
     * theoretically even if this activity is the top most, app can still move surface of activity
     * below it to the top. As a result, we want to update the input mode to drop when obscured for
     * all untrusted activities.
     */
    private void updateUntrustedEmbeddingInputProtection() {
        final SurfaceControl sc = getSurfaceControl();
        if (sc == null) {
            return;
        }
        if (isEmbeddedInUntrustedMode()) {
            // Set drop input to OBSCURED when untrusted embedded.
            setDropInputMode(DropInputMode.OBSCURED);
        } else {
            // Reset drop input mode when this activity is not embedded in untrusted mode.
            setDropInputMode(DropInputMode.NONE);
        }
    }

    @VisibleForTesting
    void setDropInputMode(@DropInputMode int mode) {
        if (mLastDropInputMode != mode && getSurfaceControl() != null) {
            mLastDropInputMode = mode;
            mWmService.mTransactionFactory.get()
                    .setDropInputMode(getSurfaceControl(), mode)
                    .apply();
        }
    }

    private boolean isEmbeddedInUntrustedMode() {
        final TaskFragment organizedTaskFragment = getOrganizedTaskFragment();
        if (organizedTaskFragment == null) {
            // Not embedded.
            return false;
        }
        // Check if trusted.
        return !organizedTaskFragment.isAllowedToEmbedActivityInTrustedMode(this);
    }

    void updateAnimatingActivityRegistry() {
@@ -5443,6 +5502,11 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
            return false;
        }

        // Untrusted embedded activity can be visible only if there is no other overlay window.
        if (hasOverlayOverUntrustedModeEmbedded()) {
            return false;
        }

        // Check if the activity is on a sleeping display, canTurnScreenOn will also check
        // keyguard visibility
        if (mDisplayContent.isSleeping()) {
@@ -5452,6 +5516,25 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
        }
    }

    /**
     * Checks if there are any activities or other containers that belong to the same task on top of
     * this activity when embedded in untrusted mode.
     */
    boolean hasOverlayOverUntrustedModeEmbedded() {
        if (!isEmbeddedInUntrustedMode() || getRootTask() == null) {
            // The activity is not embedded in untrusted mode.
            return false;
        }

        // Check if there are any activities with different UID over the activity that is embedded
        // in untrusted mode. Traverse bottom to top with boundary so that it will only check
        // activities above this activity.
        final ActivityRecord differentUidOverlayActivity = getRootTask().getActivity(
                a -> a.getUid() != getUid(), this /* boundary */, false /* includeBoundary */,
                false /* traverseTopToBottom */);
        return differentUidOverlayActivity != null;
    }

    void updateVisibilityIgnoringKeyguard(boolean behindFullscreenActivity) {
        visibleIgnoringKeyguard = (!behindFullscreenActivity || mLaunchTaskBehind)
                && showToCurrentUser();
+7 −6
Original line number Diff line number Diff line
@@ -516,12 +516,13 @@ class TaskFragment extends WindowContainer<WindowContainer> {
     * @see #isAllowedToEmbedActivityInTrustedMode(ActivityRecord)
     */
    boolean isAllowedToEmbedActivity(@NonNull ActivityRecord a) {
        if ((a.info.flags & FLAG_ALLOW_UNTRUSTED_ACTIVITY_EMBEDDING)
                == FLAG_ALLOW_UNTRUSTED_ACTIVITY_EMBEDDING) {
            return true;
        return isAllowedToEmbedActivityInUntrustedMode(a)
                || isAllowedToEmbedActivityInTrustedMode(a);
    }

        return isAllowedToEmbedActivityInTrustedMode(a);
    boolean isAllowedToEmbedActivityInUntrustedMode(@NonNull ActivityRecord a) {
        return (a.info.flags & FLAG_ALLOW_UNTRUSTED_ACTIVITY_EMBEDDING)
                == FLAG_ALLOW_UNTRUSTED_ACTIVITY_EMBEDDING;
    }

    /**
@@ -531,7 +532,7 @@ class TaskFragment extends WindowContainer<WindowContainer> {
     * <li>the activity has declared the organizer host as trusted explicitly via known
     * certificate.</li>
     */
    private boolean isAllowedToEmbedActivityInTrustedMode(@NonNull ActivityRecord a) {
    boolean isAllowedToEmbedActivityInTrustedMode(@NonNull ActivityRecord a) {
        if (UserHandle.getAppId(mTaskFragmentOrganizerUid) == SYSTEM_UID) {
            // The system is trusted to embed other apps securely and for all users.
            return true;
+2 −0
Original line number Diff line number Diff line
@@ -701,6 +701,8 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
                    sendTaskFragmentOperationFailure(tf.getTaskFragmentOrganizer(),
                            errorCallbackToken,
                            convertStartFailureToThrowable(result, activityIntent));
                } else {
                    effects |= TRANSACT_EFFECTS_LIFECYCLE;
                }
                break;
            }
+2 −0
Original line number Diff line number Diff line
@@ -36,6 +36,7 @@ import static android.view.WindowManager.TRANSIT_OPEN;

import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;

import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyInt;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
@@ -422,6 +423,7 @@ public class AppTransitionTests extends WindowTestsBase {
    public void testActivityRecordReparentToTaskFragment() {
        final ActivityRecord activity = createActivityRecord(mDc);
        final SurfaceControl activityLeash = mock(SurfaceControl.class);
        doNothing().when(activity).setDropInputMode(anyInt());
        activity.setVisibility(true);
        activity.setSurfaceControl(activityLeash);
        final Task task = activity.getTask();