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

Commit a15ff93e authored by Bernardo Rufino's avatar Bernardo Rufino Committed by Android (Google) Code Review
Browse files

Merge "Make SnapshotStartingWindow and its child surface trusted"

parents da674f57 a03b86f3
Loading
Loading
Loading
Loading
+32 −14
Original line number Diff line number Diff line
@@ -36,6 +36,7 @@ import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATIO
import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
import static android.view.WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;

import static com.android.internal.policy.DecorView.NAVIGATION_BAR_COLOR_VIEW_ATTRIBUTES;
@@ -129,6 +130,7 @@ class TaskSnapshotSurface implements StartingSurface {
    private SurfaceControl mChildSurfaceControl;
    private final IWindowSession mSession;
    private final WindowManagerService mService;
    private final int mDisplayId;
    private final Rect mTaskBounds;
    private final Rect mFrame = new Rect();
    private final Rect mSystemBarInsets = new Rect();
@@ -151,10 +153,15 @@ class TaskSnapshotSurface implements StartingSurface {

    static TaskSnapshotSurface create(WindowManagerService service, ActivityRecord activity,
            TaskSnapshot snapshot) {
        return create(service, activity, snapshot, WindowManagerGlobal.getWindowSession());
    }

    @VisibleForTesting
    static TaskSnapshotSurface create(WindowManagerService service, ActivityRecord activity,
            TaskSnapshot snapshot, IWindowSession session) {

        final WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams();
        final Window window = new Window();
        final IWindowSession session = WindowManagerGlobal.getWindowSession();
        window.setSession(session);
        final SurfaceControl surfaceControl = new SurfaceControl();
        final ClientWindowFrames tmpFrames = new ClientWindowFrames();
@@ -215,7 +222,10 @@ class TaskSnapshotSurface implements StartingSurface {
            layoutParams.flags = (windowFlags & ~FLAG_INHERIT_EXCLUDES)
                    | FLAG_NOT_FOCUSABLE
                    | FLAG_NOT_TOUCHABLE;
            layoutParams.privateFlags = windowPrivateFlags & PRIVATE_FLAG_INHERITS;
            // Setting as trusted overlay to let touches pass through. This is safe because this
            // window is controlled by the system.
            layoutParams.privateFlags = (windowPrivateFlags & PRIVATE_FLAG_INHERITS)
                    | PRIVATE_FLAG_TRUSTED_OVERLAY;
            layoutParams.token = activity.token;
            layoutParams.width = LayoutParams.MATCH_PARENT;
            layoutParams.height = LayoutParams.MATCH_PARENT;
@@ -239,11 +249,11 @@ class TaskSnapshotSurface implements StartingSurface {
            insetsState = getInsetsStateWithVisibilityOverride(topFullscreenOpaqueWindow);

        }
        int displayId = activity.getDisplayContent().getDisplayId();
        try {
            final int res = session.addToDisplay(window, layoutParams,
                    View.GONE, activity.getDisplayContent().getDisplayId(), mTmpInsetsState,
                    tmpFrames.frame, tmpFrames.displayCutout, null /* outInputChannel */,
                    mTmpInsetsState, mTempControls);
                    View.GONE, displayId, mTmpInsetsState, tmpFrames.frame, tmpFrames.displayCutout,
                    null /* outInputChannel */, mTmpInsetsState, mTempControls);
            if (res < 0) {
                Slog.w(TAG, "Failed to add snapshot starting window res=" + res);
                return null;
@@ -251,10 +261,10 @@ class TaskSnapshotSurface implements StartingSurface {
        } catch (RemoteException e) {
            // Local call.
        }
        final TaskSnapshotSurface snapshotSurface = new TaskSnapshotSurface(service, window,
                surfaceControl, snapshot, layoutParams.getTitle(), taskDescription, appearance,
                windowFlags, windowPrivateFlags, taskBounds, currentOrientation, activityType,
                insetsState);
        final TaskSnapshotSurface snapshotSurface = new TaskSnapshotSurface(service, displayId,
                window, surfaceControl, snapshot, layoutParams.getTitle(), taskDescription,
                appearance, windowFlags, windowPrivateFlags, taskBounds, currentOrientation,
                activityType, insetsState);
        window.setOuter(snapshotSurface);
        try {
            session.relayout(window, layoutParams, -1, -1, View.VISIBLE, 0, -1,
@@ -271,11 +281,13 @@ class TaskSnapshotSurface implements StartingSurface {
    }

    @VisibleForTesting
    TaskSnapshotSurface(WindowManagerService service, Window window, SurfaceControl surfaceControl,
            TaskSnapshot snapshot, CharSequence title, TaskDescription taskDescription,
            int appearance, int windowFlags, int windowPrivateFlags, Rect taskBounds,
            int currentOrientation, int activityType, InsetsState insetsState) {
    TaskSnapshotSurface(WindowManagerService service, int displayId, Window window,
            SurfaceControl surfaceControl, TaskSnapshot snapshot, CharSequence title,
            TaskDescription taskDescription, int appearance, int windowFlags,
            int windowPrivateFlags, Rect taskBounds, int currentOrientation, int activityType,
            InsetsState insetsState) {
        mService = service;
        mDisplayId = displayId;
        mSurface = service.mSurfaceFactory.get();
        mHandler = new Handler(mService.mH.getLooper());
        mSession = WindowManagerGlobal.getWindowSession();
@@ -368,8 +380,9 @@ class TaskSnapshotSurface implements StartingSurface {
                - ((float) mFrame.width() / mFrame.height())) > 0.01f;

        // Keep a reference to it such that it doesn't get destroyed when finalized.
        final String name = mTitle + " - task-snapshot-surface";
        mChildSurfaceControl = mService.mSurfaceControlFactory.apply(session)
                .setName(mTitle + " - task-snapshot-surface")
                .setName(name)
                .setBufferSize(buffer.getWidth(), buffer.getHeight())
                .setFormat(buffer.getFormat())
                .setParent(mSurfaceControl)
@@ -401,6 +414,11 @@ class TaskSnapshotSurface implements StartingSurface {
        mSnapshotMatrix.setRectToRect(mTmpSnapshotSize, mTmpDstFrame, Matrix.ScaleToFit.FILL);
        mTransaction.setMatrix(mChildSurfaceControl, mSnapshotMatrix, mTmpFloat9);

        // This is the way to tell the input system to exclude this surface from occlusion
        // detection since we don't have a window for it. We do this because this window is
        // generated by the system as well as its content (the snapshot of the app).
        InputMonitor.setTrustedOverlayInputInfo(mChildSurfaceControl, mTransaction, mDisplayId,
                name);
        mTransaction.apply();
        surface.attachAndQueueBufferWithColorSpace(buffer, mSnapshot.getColorSpace());
        surface.release();
+7 −1
Original line number Diff line number Diff line
@@ -88,6 +88,7 @@ import org.mockito.quality.Strictness;

import java.io.File;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Supplier;

/**
 * JUnit test rule to correctly setting up system services like {@link WindowManagerService}
@@ -112,6 +113,7 @@ public class SystemServicesTestRule implements TestRule {
    private WindowState.PowerManagerWrapper mPowerManagerWrapper;
    private InputManagerService mImService;
    private InputChannel mInputChannel;
    private Supplier<Surface> mSurfaceFactory = () -> mock(Surface.class);
    /**
     * Spied {@link SurfaceControl.Transaction} class than can be used to verify calls.
     */
@@ -286,7 +288,7 @@ public class SystemServicesTestRule implements TestRule {
        DisplayThread.getHandler().post(StrictMode::allowThreadDiskWritesMask);
        mWmService = WindowManagerService.main(
                mContext, mImService, false, false, mWMPolicy, mAtmService, StubTransaction::new,
                () -> mock(Surface.class), (unused) -> new MockSurfaceControlBuilder());
                () -> mSurfaceFactory.get(), (unused) -> new MockSurfaceControlBuilder());
        spyOn(mWmService);
        spyOn(mWmService.mRoot);
        // Invoked during {@link ActivityStack} creation.
@@ -396,6 +398,10 @@ public class SystemServicesTestRule implements TestRule {
        return mPowerManagerWrapper;
    }

    void setSurfaceFactory(Supplier<Surface> factory) {
        mSurfaceFactory = factory;
    }

    void cleanupWindowManagerHandlers() {
        final WindowManagerService wm = getWindowManagerService();
        if (wm == null) {
+51 −7
Original line number Diff line number Diff line
@@ -20,17 +20,23 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;

import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.never;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;

import static com.google.common.truth.Truth.assertThat;

import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.eq;

import android.app.ActivityManager;
import android.app.ActivityManager.TaskDescription;
import android.app.ActivityManager.TaskSnapshot;
import android.content.ComponentName;
@@ -41,14 +47,18 @@ import android.graphics.Point;
import android.graphics.Rect;
import android.hardware.HardwareBuffer;
import android.platform.test.annotations.Presubmit;
import android.view.Display;
import android.view.IWindowSession;
import android.view.InsetsState;
import android.view.Surface;
import android.view.SurfaceControl;
import android.view.WindowManager;

import androidx.test.filters.SmallTest;

import com.android.server.wm.TaskSnapshotSurface.Window;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;

@@ -67,9 +77,6 @@ public class TaskSnapshotSurfaceTest extends WindowTestsBase {

    private void setupSurface(int width, int height, Rect contentInsets, int sysuiVis,
            int windowFlags, Rect taskBounds) {
        final HardwareBuffer buffer = HardwareBuffer.create(width, height, HardwareBuffer.RGBA_8888,
                1, HardwareBuffer.USAGE_CPU_READ_RARELY);

        // Previously when constructing TaskSnapshots for this test, scale was 1.0f, so to mimic
        // this behavior set the taskSize to be the same as the taskBounds width and height. The
        // taskBounds passed here are assumed to be the same task bounds as when the snapshot was
@@ -79,16 +86,24 @@ public class TaskSnapshotSurfaceTest extends WindowTestsBase {
        assertEquals(height, taskBounds.height());
        Point taskSize = new Point(taskBounds.width(), taskBounds.height());

        final TaskSnapshot snapshot = new TaskSnapshot(
        final TaskSnapshot snapshot = createTaskSnapshot(width, height, taskSize, contentInsets);
        mSurface = new TaskSnapshotSurface(mWm, Display.DEFAULT_DISPLAY, new Window(),
                new SurfaceControl(), snapshot, "Test", createTaskDescription(Color.WHITE,
                Color.RED, Color.BLUE), sysuiVis, windowFlags, 0, taskBounds, ORIENTATION_PORTRAIT,
                ACTIVITY_TYPE_STANDARD, new InsetsState());
    }

    private ActivityManager.TaskSnapshot createTaskSnapshot(int width, int height, Point taskSize,
            Rect contentInsets) {
        final HardwareBuffer buffer = HardwareBuffer.create(width, height, HardwareBuffer.RGBA_8888,
                1, HardwareBuffer.USAGE_CPU_READ_RARELY);
        return new TaskSnapshot(
                System.currentTimeMillis(),
                new ComponentName("", ""), buffer,
                ColorSpace.get(ColorSpace.Named.SRGB), ORIENTATION_PORTRAIT,
                Surface.ROTATION_0, taskSize, contentInsets, false,
                true /* isRealSnapshot */, WINDOWING_MODE_FULLSCREEN,
                0 /* systemUiVisibility */, false /* isTranslucent */);
        mSurface = new TaskSnapshotSurface(mWm, new Window(), new SurfaceControl(), snapshot, "Test",
                createTaskDescription(Color.WHITE, Color.RED, Color.BLUE), sysuiVis, windowFlags, 0,
                taskBounds, ORIENTATION_PORTRAIT, ACTIVITY_TYPE_STANDARD, new InsetsState());
    }

    private static TaskDescription createTaskDescription(int background, int statusBar,
@@ -105,6 +120,35 @@ public class TaskSnapshotSurfaceTest extends WindowTestsBase {
                new Rect(0, 0, width, height));
    }

    private boolean isTrustedOverlay(WindowManager.LayoutParams params) {
        return (params.privateFlags & PRIVATE_FLAG_TRUSTED_OVERLAY) != 0;
    }

    @Before
    public void setUp() throws Exception {
        mSystemServicesTestRule.setSurfaceFactory(() -> {
            Surface surface = mock(Surface.class);
            when(surface.isValid()).thenReturn(true);
            return surface;
        });
    }

    @Test
    public void createSurface_asTrustedOverlay() throws Exception {
        Point task = new Point(200, 100);
        ActivityRecord activityRecord = createActivityRecord(mDisplayContent);
        createWindow(null, TYPE_BASE_APPLICATION, activityRecord, "window");
        TaskSnapshot taskSnapshot = createTaskSnapshot(task.x, task.y, task, new Rect());
        IWindowSession session = mock(IWindowSession.class);

        TaskSnapshotSurface surface = TaskSnapshotSurface.create(mWm, activityRecord, taskSnapshot,
                session);

        assertThat(surface).isNotNull();
        verify(session).addToDisplay(any(), argThat(this::isTrustedOverlay), anyInt(), anyInt(),
                any(), any(), any(), any(), any(), any());
    }

    @Test
    public void fillEmptyBackground_fillHorizontally() {
        setupSurface(200, 100);