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

Commit 052c311b authored by Naomi Musgrave's avatar Naomi Musgrave Committed by Android (Google) Code Review
Browse files

Merge "[MediaProjection] Do not start layer mirroring without a surface" into sc-v2-dev

parents 506fa0be fcef7825
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -82,6 +82,8 @@ public enum ProtoLogGroup implements IProtoLogGroup {
            Consts.TAG_WM),
    WM_DEBUG_WINDOW_INSETS(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false,
            Consts.TAG_WM),
    WM_DEBUG_LAYER_MIRRORING(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, true,
            Consts.TAG_WM),
    TEST_GROUP(true, true, false, "WindowManagerProtoLogTest");

    private final boolean mEnabled;
+63 −0
Original line number Diff line number Diff line
@@ -211,6 +211,12 @@
      "group": "WM_DEBUG_SYNC_ENGINE",
      "at": "com\/android\/server\/wm\/BLASTSyncEngine.java"
    },
    "-1898316768": {
      "message": "Unable to retrieve window container to start layer mirroring for display %d",
      "level": "VERBOSE",
      "group": "WM_DEBUG_LAYER_MIRRORING",
      "at": "com\/android\/server\/wm\/DisplayContent.java"
    },
    "-1895337367": {
      "message": "Delete root task display=%d winMode=%d",
      "level": "VERBOSE",
@@ -1093,6 +1099,12 @@
      "group": "WM_ERROR",
      "at": "com\/android\/server\/wm\/WindowManagerService.java"
    },
    "-904499590": {
      "message": "Provided surface for layer mirroring on display %d is not present, so do not update the surface",
      "level": "VERBOSE",
      "group": "WM_DEBUG_LAYER_MIRRORING",
      "at": "com\/android\/server\/wm\/DisplayContent.java"
    },
    "-883738232": {
      "message": "Adding more than one toast window for UID at a time.",
      "level": "WARN",
@@ -1303,6 +1315,12 @@
      "group": "WM_DEBUG_ORIENTATION",
      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
    },
    "-663411559": {
      "message": "Going ahead with updating layer mirroring for display %d to new bounds %s and\/or orientation %d.",
      "level": "VERBOSE",
      "group": "WM_DEBUG_LAYER_MIRRORING",
      "at": "com\/android\/server\/wm\/DisplayContent.java"
    },
    "-655104359": {
      "message": "Frontmost changed immersion: %s",
      "level": "DEBUG",
@@ -1561,6 +1579,12 @@
      "group": "WM_ERROR",
      "at": "com\/android\/server\/wm\/WindowManagerService.java"
    },
    "-384564722": {
      "message": "Unable to start layer mirroring for display %d since the surface is not available.",
      "level": "VERBOSE",
      "group": "WM_DEBUG_LAYER_MIRRORING",
      "at": "com\/android\/server\/wm\/DisplayContent.java"
    },
    "-381475323": {
      "message": "DisplayContent: boot is waiting for window of type %d to be drawn",
      "level": "DEBUG",
@@ -1633,6 +1657,12 @@
      "group": "WM_DEBUG_STATES",
      "at": "com\/android\/server\/wm\/TaskFragment.java"
    },
    "-309399422": {
      "message": "Display %d state is now (%d), so update layer mirroring?",
      "level": "VERBOSE",
      "group": "WM_DEBUG_LAYER_MIRRORING",
      "at": "com\/android\/server\/wm\/DisplayContent.java"
    },
    "-302468788": {
      "message": "Expected target rootTask=%s to be top most but found rootTask=%s",
      "level": "WARN",
@@ -1699,6 +1729,12 @@
      "group": "WM_DEBUG_WINDOW_MOVEMENT",
      "at": "com\/android\/server\/wm\/WindowManagerService.java"
    },
    "-190034097": {
      "message": "Unable to retrieve window container to update layer mirroring for display %d",
      "level": "VERBOSE",
      "group": "WM_DEBUG_LAYER_MIRRORING",
      "at": "com\/android\/server\/wm\/DisplayContent.java"
    },
    "-177040661": {
      "message": "Start rotation animation. customAnim=%s, mCurRotation=%s, mOriginalRotation=%s",
      "level": "DEBUG",
@@ -1795,6 +1831,12 @@
      "group": "WM_DEBUG_STATES",
      "at": "com\/android\/server\/wm\/TaskFragment.java"
    },
    "-79877120": {
      "message": "Display %d has content (%b) so disable layer mirroring",
      "level": "VERBOSE",
      "group": "WM_DEBUG_LAYER_MIRRORING",
      "at": "com\/android\/server\/wm\/DisplayContent.java"
    },
    "-70719599": {
      "message": "Unregister remote animations for organizer=%s uid=%d pid=%d",
      "level": "VERBOSE",
@@ -2347,6 +2389,12 @@
      "group": "WM_DEBUG_WINDOW_ORGANIZER",
      "at": "com\/android\/server\/wm\/DisplayAreaOrganizerController.java"
    },
    "504397469": {
      "message": "Unable to update layer mirroring for display %d to new bounds %s and\/or orientation %d, since the surface is not available.",
      "level": "VERBOSE",
      "group": "WM_DEBUG_LAYER_MIRRORING",
      "at": "com\/android\/server\/wm\/DisplayContent.java"
    },
    "508887531": {
      "message": "applyAnimation voice: anim=%s transit=%s isEntrance=%b Callers=%s",
      "level": "VERBOSE",
@@ -3103,6 +3151,12 @@
      "group": "WM_DEBUG_SCREEN_ON",
      "at": "com\/android\/server\/wm\/WindowManagerService.java"
    },
    "1407569006": {
      "message": "Display %d was already layer mirroring, so apply transformations if necessary",
      "level": "VERBOSE",
      "group": "WM_DEBUG_LAYER_MIRRORING",
      "at": "com\/android\/server\/wm\/DisplayContent.java"
    },
    "1417601133": {
      "message": "Enqueueing ADD_STARTING",
      "level": "VERBOSE",
@@ -3349,6 +3403,12 @@
      "group": "WM_DEBUG_CONFIGURATION",
      "at": "com\/android\/server\/wm\/ActivityRecord.java"
    },
    "1687376052": {
      "message": "Display %d has no content and is on, so start layer mirroring for state %d",
      "level": "VERBOSE",
      "group": "WM_DEBUG_LAYER_MIRRORING",
      "at": "com\/android\/server\/wm\/DisplayContent.java"
    },
    "1689989893": {
      "message": "SyncGroup %d: Set ready",
      "level": "VERBOSE",
@@ -3753,6 +3813,9 @@
    "WM_DEBUG_KEEP_SCREEN_ON": {
      "tag": "WindowManager"
    },
    "WM_DEBUG_LAYER_MIRRORING": {
      "tag": "WindowManager"
    },
    "WM_DEBUG_LOCKTASK": {
      "tag": "WindowManager"
    },
+3 −0
Original line number Diff line number Diff line
@@ -303,6 +303,9 @@ public class VirtualDisplayAdapter extends DisplayAdapter {

        @Override
        public Point getDisplaySurfaceDefaultSize() {
            if (mSurface == null) {
                return null;
            }
            return mSurface.getDefaultSize();
        }

+123 −38
Original line number Diff line number Diff line
@@ -88,6 +88,7 @@ import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_BOOT;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_FOCUS;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_FOCUS_LIGHT;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_IME;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_LAYER_MIRRORING;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ORIENTATION;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_SCREEN_ON;
import static com.android.internal.protolog.ProtoLogGroup.WM_SHOW_TRANSACTIONS;
@@ -305,7 +306,8 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
    @VisibleForTesting IBinder mTokenToMirror = null;

    /**
     * The surface for mirroring the contents of this hierarchy.
     * The surface for mirroring the contents of this hierarchy, or null if layer mirroring is
     * temporarily disabled.
     */
    private SurfaceControl mMirroredSurface = null;

@@ -314,6 +316,11 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
     */
    private Rect mLastMirroredDisplayAreaBounds = null;

    /**
     * The last state of the display.
     */
    private int mLastDisplayState;

    // Contains all IME window containers. Note that the z-ordering of the IME windows will depend
    // on the IME target. We mainly have this container grouping so we can keep track of all the IME
    // window containers together and move them in-sync if/when needed. We use a subclass of
@@ -1142,10 +1149,6 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
        if (DEBUG_DISPLAY) Slog.v(TAG_WM, "Creating display=" + display);

        mWmService.mDisplayWindowSettings.applySettingsToDisplayLocked(this);

        // Check if this DisplayContent is for a new VirtualDisplay, that should use layer mirroring
        // to capture the contents of a DisplayArea.
        startMirrorIfNeeded();
    }

    boolean isReady() {
@@ -2504,19 +2507,42 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp

        // Update mirroring surface for MediaProjection, if this DisplayContent is being used
        // for layer mirroring.
        if (mMirroredSurface != null) {
            // Retrieve the size of the DisplayArea to mirror, and continue with the update if the
            // bounds have changed.
        if (isCurrentlyMirroring() && mLastMirroredDisplayAreaBounds != null) {
            // Mirroring has already begun, but update mirroring since the display is now on.
            final WindowContainer wc = mWmService.mWindowContextListenerController.getContainer(
                    mTokenToMirror);
            if (wc != null && mLastMirroredDisplayAreaBounds != null) {
            if (wc == null) {
                ProtoLog.v(WM_DEBUG_LAYER_MIRRORING,
                        "Unable to retrieve window container to update layer mirroring for "
                                + "display %d",
                        mDisplayId);
                return;
            }

            ProtoLog.v(WM_DEBUG_LAYER_MIRRORING,
                    "Display %d was already layer mirroring, so apply transformations if necessary",
                    mDisplayId);
            // Retrieve the size of the DisplayArea to mirror, and continue with the update
            // if the bounds or orientation has changed.
            final Rect displayAreaBounds = wc.getDisplayContent().getBounds();
            int displayAreaOrientation = wc.getDisplayContent().getOrientation();
            if (!mLastMirroredDisplayAreaBounds.equals(displayAreaBounds)
                    || lastOrientation != displayAreaOrientation) {
                    updateMirroredSurface(mWmService.mTransactionFactory.get(), displayAreaBounds);
                Point surfaceSize = fetchSurfaceSizeIfPresent();
                if (surfaceSize != null) {
                    ProtoLog.v(WM_DEBUG_LAYER_MIRRORING,
                            "Going ahead with updating layer mirroring for display %d to new "
                                    + "bounds %s and/or orientation %d.",
                            mDisplayId, displayAreaBounds, displayAreaOrientation);
                    updateMirroredSurface(mWmService.mTransactionFactory.get(),
                            displayAreaBounds, surfaceSize);
                } else {
                    // If the surface removed, do nothing. We will handle this via onDisplayChanged
                    // (the display will be off if the surface is removed).
                    ProtoLog.v(WM_DEBUG_LAYER_MIRRORING,
                            "Unable to update layer mirroring for display %d to new bounds %s"
                            + " and/or orientation %d, since the surface is not available.",
                            mDisplayId, displayAreaBounds, displayAreaOrientation);
                }
            }
        }
@@ -4405,6 +4431,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
                    mTmpApplySurfaceChangesTransactionState.preferMinimalPostProcessing,
                    true /* inTraversal, must call performTraversalInTrans... below */);
        }
        // If the display now has content, or no longer has content, update layer mirroring.
        updateMirroring();

        final boolean wallpaperVisible = mWallpaperController.isWallpaperVisible();
@@ -5504,6 +5531,15 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
            } else if (displayState == Display.STATE_ON) {
                mOffTokenAcquirer.release(mDisplayId);
            }
            ProtoLog.v(WM_DEBUG_LAYER_MIRRORING,
                    "Display %d state is now (%d), so update layer mirroring?",
                    mDisplayId, displayState);
            if (mLastDisplayState != displayState) {
                // If state is on due to surface being added, then start layer mirroring.
                // If state is off due to surface being removed, then stop layer mirroring.
                updateMirroring();
            }
            mLastDisplayState = displayState;
        }
        mWmService.requestTraversal();
    }
@@ -5982,31 +6018,48 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
     * back to original MediaProjection approach.
     */
    private void startMirrorIfNeeded() {
        // Only mirror if this display does not have its own content.
        if (mLastHasContent) {
        // Only mirror if this display does not have its own content, is not mirroring already,
        // and if this display is on (it has a surface to write output to).
        if (mLastHasContent || isCurrentlyMirroring() || mDisplay.getState() == Display.STATE_OFF) {
            return;
        }

        // Given the WindowToken of the DisplayArea to mirror, retrieve the associated
        // SurfaceControl.
        IBinder tokenToMirror = mWmService.mDisplayManagerInternal.getWindowTokenClientToMirror(
                mDisplayId);

        if (tokenToMirror == null) {
            // This DisplayContent instance is not involved in layer mirroring. If the display
            // has been created for capturing, fall back to prior MediaProjection approach.
            return;
        }

        final WindowContainer wc = mWmService.mWindowContextListenerController.getContainer(
                tokenToMirror);
        if (wc == null) {
            // Un-set the window token to mirror for this VirtualDisplay, to fall back to the
            // original MediaProjection approach.
            mWmService.mDisplayManagerInternal.setWindowTokenClientToMirror(mDisplayId, null);
            ProtoLog.v(WM_DEBUG_LAYER_MIRRORING,
                    "Unable to retrieve window container to start layer mirroring for display %d",
                    mDisplayId);
            return;
        }
        SurfaceControl sc = wc.getDisplayContent().getSurfaceControl();

        Point surfaceSize = fetchSurfaceSizeIfPresent();
        if (surfaceSize == null) {
            ProtoLog.v(WM_DEBUG_LAYER_MIRRORING,
                    "Unable to start layer mirroring for display %d since the surface is not "
                            + "available.",
                    mDisplayId);
            return;
        }
        ProtoLog.v(WM_DEBUG_LAYER_MIRRORING,
                "Display %d has no content and is on, so start layer mirroring for state %d",
                mDisplayId, mDisplay.getState());

        // Create a mirrored hierarchy for the SurfaceControl of the DisplayArea to capture.
        SurfaceControl sc = wc.getDisplayContent().getSurfaceControl();
        mMirroredSurface = SurfaceControl.mirrorSurface(sc);
        SurfaceControl.Transaction transaction = mWmService.mTransactionFactory.get()
                // Set the mMirroredSurface's parent to the root SurfaceControl for this
@@ -6019,7 +6072,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
                // VirtualDisplay will show up as part of the mirrored content.
                .reparent(mWindowingLayer, null);
        // Retrieve the size of the DisplayArea to mirror.
        updateMirroredSurface(transaction, wc.getDisplayContent().getBounds());
        updateMirroredSurface(transaction, wc.getDisplayContent().getBounds(), surfaceSize);
        mTokenToMirror = tokenToMirror;

        // No need to clean up. In SurfaceFlinger, parents hold references to their children. The
@@ -6029,11 +6082,18 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
    }

    /**
     * Start or stop mirroring if this DisplayContent now has content, or no longer has content.
     * Start mirroring if this DisplayContent no longer has content. Stop mirroring if it now
     * has content or the display is not on.
     */
    private void updateMirroring() {
        if (mLastHasContent && mMirroredSurface != null) {
            // Display now has content, so stop mirroring to it.
        if (isCurrentlyMirroring() && (mLastHasContent
                || mDisplay.getState() == Display.STATE_OFF)) {
            ProtoLog.v(WM_DEBUG_LAYER_MIRRORING,
                    "Display %d has content (%b) so disable layer mirroring", mDisplayId,
                    mLastHasContent);
            // If the display is not on and it is a virtual display, then it no longer has an
            // associated surface to write output to.
            // If the display now has content, stop mirroring to it.
            mWmService.mTransactionFactory.get()
                    // Remove the reference to mMirroredSurface, to clean up associated memory.
                    .remove(mMirroredSurface)
@@ -6044,8 +6104,9 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
            // Stop mirroring by destroying the reference to the mirrored layer.
            mMirroredSurface = null;
            // Do not un-set the token, in case content is removed and mirroring should begin again.
        } else if (!mLastHasContent && mMirroredSurface == null) {
            // Display no longer has content, so start mirroring to it.
        } else {
            // Display no longer has content, or now has a surface to write to, so try to start
            // mirroring to it.
            startMirrorIfNeeded();
        }
    }
@@ -6058,17 +6119,11 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
     *                          to. Transaction is not applied before returning.
     * @param displayAreaBounds bounds of the DisplayArea to mirror to the surface provided by
     *                          the app.
     * @param surfaceSize       the default size of the surface to write the display area content to
     */
    @VisibleForTesting
    void updateMirroredSurface(SurfaceControl.Transaction transaction,
            Rect displayAreaBounds) {
        // Retrieve the default size of the surface the app provided to
        // MediaProjection#createVirtualDisplay. Note the app is the consumer of the surface,
        // since it reads out buffers from the surface, and SurfaceFlinger is the producer since
        // it writes the mirrored layers to the buffers.
        final Point surfaceSize = mWmService.mDisplayManagerInternal.getDisplaySurfaceDefaultSize(
                mDisplayId);

            Rect displayAreaBounds, Point surfaceSize) {
        // Calculate the scale to apply to the root mirror SurfaceControl to fit the size of the
        // output surface.
        float scaleX = surfaceSize.x / (float) displayAreaBounds.width();
@@ -6103,6 +6158,36 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
        mLastMirroredDisplayAreaBounds = new Rect(displayAreaBounds);
    }

    /**
     * Returns a non-null {@link Point} if the surface is present, or null otherwise
     */
    Point fetchSurfaceSizeIfPresent() {
        // Retrieve the default size of the surface the app provided to
        // MediaProjection#createVirtualDisplay. Note the app is the consumer of the surface,
        // since it reads out buffers from the surface, and SurfaceFlinger is the producer since
        // it writes the mirrored layers to the buffers.
        Point surfaceSize = mWmService.mDisplayManagerInternal.getDisplaySurfaceDefaultSize(
                mDisplayId);
        if (surfaceSize == null) {
            // Layer mirroring started with a null surface, so do not apply any transformations yet.
            // State of virtual display will change to 'ON' when the surface is set.
            // will get event DISPLAY_DEVICE_EVENT_CHANGED
            ProtoLog.v(WM_DEBUG_LAYER_MIRRORING,
                    "Provided surface for layer mirroring on display %d is not present, so do not"
                            + " update the surface",
                    mDisplayId);
            return null;
        }
        return surfaceSize;
    }

    /**
     * Returns {@code true} if this DisplayContent is currently layer mirroring.
     */
    boolean isCurrentlyMirroring() {
        return mTokenToMirror != null && mMirroredSurface != null;
    }

    /** The entry for proceeding to handle {@link #mFixedRotationLaunchingApp}. */
    class FixedRotationTransitionListener extends WindowManagerInternal.AppTransitionListener {

+74 −1
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@ import static android.content.pm.ActivityInfo.FLAG_SHOW_WHEN_LOCKED;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR;
import static android.os.Build.VERSION_CODES.P;
import static android.os.Build.VERSION_CODES.Q;
import static android.view.Display.DEFAULT_DISPLAY;
@@ -111,6 +112,7 @@ import android.graphics.Insets;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.Region;
import android.hardware.display.VirtualDisplay;
import android.metrics.LogMaker;
import android.os.Binder;
import android.os.IBinder;
@@ -2292,7 +2294,7 @@ public class DisplayContentTests extends WindowTestsBase {
        float yScale = 2f;
        Rect displayAreaBounds = new Rect(0, 0, Math.round(surfaceSize.x * xScale),
                Math.round(surfaceSize.y * yScale));
        virtualDisplay.updateMirroredSurface(mTransaction, displayAreaBounds);
        virtualDisplay.updateMirroredSurface(mTransaction, displayAreaBounds, surfaceSize);

        // THEN content in the captured DisplayArea is scaled to fit the surface size.
        verify(mTransaction, atLeastOnce()).setMatrix(mirroredSurface, 1.0f / yScale, 0, 0,
@@ -2305,6 +2307,72 @@ public class DisplayContentTests extends WindowTestsBase {
        mockSession.finishMocking();
    }

    @Test
    public void testVirtualDisplayContent_withoutSurface() {
        MockitoSession mockSession = mockitoSession()
                .initMocks(this)
                .spyStatic(SurfaceControl.class)
                .strictness(Strictness.LENIENT)
                .startMocking();

        // GIVEN MediaProjection has already initialized the WindowToken of the DisplayArea to
        // mirror.
        setUpDefaultTaskDisplayAreaWindowToken();

        // GIVEN SurfaceControl can successfully mirror the provided surface.
        Point surfaceSize = new Point(
                mDefaultDisplay.getDefaultTaskDisplayArea().getBounds().width(),
                mDefaultDisplay.getDefaultTaskDisplayArea().getBounds().height());
        surfaceControlMirrors(surfaceSize);

        // GIVEN a new VirtualDisplay with an associated surface.
        final VirtualDisplay display = createVirtualDisplay(surfaceSize, null /* surface */);
        final int displayId = display.getDisplay().getDisplayId();
        mWm.mRoot.onDisplayAdded(displayId);

        // WHEN getting the DisplayContent for the new virtual display.
        DisplayContent actualDC = mWm.mRoot.getDisplayContent(displayId);

        // THEN mirroring is not started, since a null surface indicates the VirtualDisplay is off.
        assertThat(actualDC.mTokenToMirror).isNull();

        display.release();
        mockSession.finishMocking();
    }

    @Test
    public void testVirtualDisplayContent_withSurface() {
        MockitoSession mockSession = mockitoSession()
                .initMocks(this)
                .spyStatic(SurfaceControl.class)
                .strictness(Strictness.LENIENT)
                .startMocking();

        // GIVEN MediaProjection has already initialized the WindowToken of the DisplayArea to
        // mirror.
        final IBinder tokenToMirror = setUpDefaultTaskDisplayAreaWindowToken();

        // GIVEN SurfaceControl can successfully mirror the provided surface.
        Point surfaceSize = new Point(
                mDefaultDisplay.getDefaultTaskDisplayArea().getBounds().width(),
                mDefaultDisplay.getDefaultTaskDisplayArea().getBounds().height());
        surfaceControlMirrors(surfaceSize);

        // GIVEN a new VirtualDisplay with an associated surface.
        final VirtualDisplay display = createVirtualDisplay(surfaceSize, new Surface());
        final int displayId = display.getDisplay().getDisplayId();
        mWm.mRoot.onDisplayAdded(displayId);

        // WHEN getting the DisplayContent for the new virtual display.
        DisplayContent actualDC = mWm.mRoot.getDisplayContent(displayId);

        // THEN mirroring is initiated for the default display's DisplayArea.
        assertThat(actualDC.mTokenToMirror).isEqualTo(tokenToMirror);

        display.release();
        mockSession.finishMocking();
    }

    private class TestToken extends Binder {
    }

@@ -2342,6 +2410,11 @@ public class DisplayContentTests extends WindowTestsBase {
        return mirroredSurface;
    }

    private VirtualDisplay createVirtualDisplay(Point size, Surface surface) {
        return mWm.mDisplayManager.createVirtualDisplay("VirtualDisplay", size.x, size.y,
                DisplayMetrics.DENSITY_140, surface, VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR);
    }

    private void removeRootTaskTests(Runnable runnable) {
        final TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea();
        final Task rootTask1 = taskDisplayArea.createRootTask(WINDOWING_MODE_FULLSCREEN,