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

Commit 29112c97 authored by Bernardo Rufino's avatar Bernardo Rufino Committed by Automerger Merge Worker
Browse files

Merge "Make SnapshotStartingWindow and its child surface trusted" am: a15ff93e

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/12986397

Change-Id: I2e62d1925ac249313dc576c93909e1cef76826fe
parents b52d0411 a15ff93e
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);