diff options
author | 2023-03-07 22:47:47 +0000 | |
---|---|---|
committer | 2023-03-07 22:47:47 +0000 | |
commit | c722618ac84987e944fbce2a002295830af488ab (patch) | |
tree | 0dbdeb786c442431a71267a5da5e23d3752f48e4 | |
parent | 2f0523ee9c6d5b987811de2ce96bc3b7e152a35f (diff) | |
parent | 17469b9ac364a47296707c04016a602091a0ebbe (diff) |
Merge "VirtualDisplay: Merge AIDL calls to stop race condition" into udc-dev
6 files changed, 210 insertions, 38 deletions
diff --git a/core/java/android/hardware/display/VirtualDisplayConfig.java b/core/java/android/hardware/display/VirtualDisplayConfig.java index 067ae4d438cc..490e55ba260f 100644 --- a/core/java/android/hardware/display/VirtualDisplayConfig.java +++ b/core/java/android/hardware/display/VirtualDisplayConfig.java @@ -28,6 +28,7 @@ import android.os.Handler; import android.os.Parcel; import android.os.Parcelable; import android.util.ArraySet; +import android.view.ContentRecordingSession; import android.view.Display; import android.view.Surface; @@ -53,6 +54,8 @@ public final class VirtualDisplayConfig implements Parcelable { private final int mDisplayIdToMirror; private final boolean mWindowManagerMirroringEnabled; private ArraySet<String> mDisplayCategories = null; + @Nullable + private ContentRecordingSession mContentRecordingSession; private final float mRequestedRefreshRate; private VirtualDisplayConfig( @@ -65,6 +68,7 @@ public final class VirtualDisplayConfig implements Parcelable { @Nullable String uniqueId, int displayIdToMirror, boolean windowManagerMirroringEnabled, + ContentRecordingSession session, @NonNull ArraySet<String> displayCategories, float requestedRefreshRate) { mName = name; @@ -76,6 +80,7 @@ public final class VirtualDisplayConfig implements Parcelable { mUniqueId = uniqueId; mDisplayIdToMirror = displayIdToMirror; mWindowManagerMirroringEnabled = windowManagerMirroringEnabled; + mContentRecordingSession = session; mDisplayCategories = displayCategories; mRequestedRefreshRate = requestedRefreshRate; } @@ -156,6 +161,17 @@ public final class VirtualDisplayConfig implements Parcelable { } /** + * Returns the recording session associated with this VirtualDisplay. Only used for + * recording via {@link MediaProjection}. + * + * @hide + */ + @Nullable + public ContentRecordingSession getContentRecordingSession() { + return mContentRecordingSession; + } + + /** * Returns the display categories. * * @see Builder#setDisplayCategories @@ -186,6 +202,7 @@ public final class VirtualDisplayConfig implements Parcelable { dest.writeString8(mUniqueId); dest.writeInt(mDisplayIdToMirror); dest.writeBoolean(mWindowManagerMirroringEnabled); + dest.writeTypedObject(mContentRecordingSession, flags); dest.writeArraySet(mDisplayCategories); dest.writeFloat(mRequestedRefreshRate); } @@ -211,6 +228,7 @@ public final class VirtualDisplayConfig implements Parcelable { && Objects.equals(mUniqueId, that.mUniqueId) && mDisplayIdToMirror == that.mDisplayIdToMirror && mWindowManagerMirroringEnabled == that.mWindowManagerMirroringEnabled + && Objects.equals(mContentRecordingSession, that.mContentRecordingSession) && Objects.equals(mDisplayCategories, that.mDisplayCategories) && mRequestedRefreshRate == that.mRequestedRefreshRate; } @@ -219,8 +237,8 @@ public final class VirtualDisplayConfig implements Parcelable { public int hashCode() { int hashCode = Objects.hash( mName, mWidth, mHeight, mDensityDpi, mFlags, mSurface, mUniqueId, - mDisplayIdToMirror, mWindowManagerMirroringEnabled, mDisplayCategories, - mRequestedRefreshRate); + mDisplayIdToMirror, mWindowManagerMirroringEnabled, mContentRecordingSession, + mDisplayCategories, mRequestedRefreshRate); return hashCode; } @@ -237,6 +255,7 @@ public final class VirtualDisplayConfig implements Parcelable { + " mUniqueId=" + mUniqueId + " mDisplayIdToMirror=" + mDisplayIdToMirror + " mWindowManagerMirroringEnabled=" + mWindowManagerMirroringEnabled + + " mContentRecordingSession=" + mContentRecordingSession + " mDisplayCategories=" + mDisplayCategories + " mRequestedRefreshRate=" + mRequestedRefreshRate + ")"; @@ -252,6 +271,7 @@ public final class VirtualDisplayConfig implements Parcelable { mUniqueId = in.readString8(); mDisplayIdToMirror = in.readInt(); mWindowManagerMirroringEnabled = in.readBoolean(); + mContentRecordingSession = in.readTypedObject(ContentRecordingSession.CREATOR); mDisplayCategories = (ArraySet<String>) in.readArraySet(null); mRequestedRefreshRate = in.readFloat(); } @@ -283,6 +303,8 @@ public final class VirtualDisplayConfig implements Parcelable { private String mUniqueId = null; private int mDisplayIdToMirror = DEFAULT_DISPLAY; private boolean mWindowManagerMirroringEnabled = false; + @Nullable + private ContentRecordingSession mContentRecordingSession; private ArraySet<String> mDisplayCategories = new ArraySet<>(); private float mRequestedRefreshRate = 0.0f; @@ -375,6 +397,18 @@ public final class VirtualDisplayConfig implements Parcelable { } /** + * Sets the recording session associated with this {@link VirtualDisplay}. Only used for + * recording via {@link MediaProjection}. + * + * @hide + */ + @NonNull + public Builder setContentRecordingSession(@Nullable ContentRecordingSession session) { + mContentRecordingSession = session; + return this; + } + + /** * Sets the display categories. * * <p>The categories of the display indicate the type of activities allowed to run on that @@ -435,6 +469,7 @@ public final class VirtualDisplayConfig implements Parcelable { mUniqueId, mDisplayIdToMirror, mWindowManagerMirroringEnabled, + mContentRecordingSession, mDisplayCategories, mRequestedRefreshRate); } diff --git a/media/java/android/media/projection/MediaProjection.java b/media/java/android/media/projection/MediaProjection.java index d70e8b36afdb..178a6d97dff8 100644 --- a/media/java/android/media/projection/MediaProjection.java +++ b/media/java/android/media/projection/MediaProjection.java @@ -191,20 +191,13 @@ public final class MediaProjection { } else { session = ContentRecordingSession.createTaskSession(launchCookie); } + // Pass in the current session details, so they are guaranteed to only be set in WMS + // AFTER a VirtualDisplay is constructed (assuming there are no errors during set-up). + virtualDisplayConfig.setContentRecordingSession(session); virtualDisplayConfig.setWindowManagerMirroringEnabled(true); final DisplayManager dm = mContext.getSystemService(DisplayManager.class); final VirtualDisplay virtualDisplay = dm.createVirtualDisplay(this, virtualDisplayConfig.build(), callback, handler, windowContext); - if (virtualDisplay == null) { - // Since WM handling a new display and DM creating a new VirtualDisplay is async, - // WM may have tried to start task recording and encountered an error that required - // stopping recording entirely. The VirtualDisplay would then be null when the - // MediaProjection is no longer active. - return null; - } - session.setDisplayId(virtualDisplay.getDisplay().getDisplayId()); - // Successfully set up, so save the current session details. - getProjectionService().setContentRecordingSession(session, mImpl); return virtualDisplay; } catch (RemoteException e) { // Can not capture if WMS is not accessible, so bail out. diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java index 55d2921b2878..ea157c89f675 100644 --- a/services/core/java/com/android/server/display/DisplayManagerService.java +++ b/services/core/java/com/android/server/display/DisplayManagerService.java @@ -128,6 +128,7 @@ import android.util.Slog; import android.util.SparseArray; import android.util.SparseIntArray; import android.util.Spline; +import android.view.ContentRecordingSession; import android.view.Display; import android.view.DisplayEventReceiver; import android.view.DisplayInfo; @@ -250,6 +251,7 @@ public final class DisplayManagerService extends SystemService { private ActivityManagerInternal mActivityManagerInternal; private ActivityManager mActivityManager; private UidImportanceListener mUidImportanceListener = new UidImportanceListener(); + @Nullable private IMediaProjectionManager mProjectionService; private DeviceStateManagerInternal mDeviceStateManager; @GuardedBy("mSyncRoot") @@ -1494,8 +1496,9 @@ public final class DisplayManagerService extends SystemService { final long token = Binder.clearCallingIdentity(); try { + final int displayId; synchronized (mSyncRoot) { - final int displayId = + displayId = createVirtualDisplayLocked( callback, projection, @@ -1509,8 +1512,39 @@ public final class DisplayManagerService extends SystemService { mDisplayWindowPolicyControllers.put( displayId, Pair.create(virtualDevice, dwpc)); } - return displayId; } + + // When calling setContentRecordingSession into the WindowManagerService, the WMS + // attempts to acquire a lock before executing its main body. Due to this, we need + // to be sure that it isn't called while the DisplayManagerService is also holding + // a lock, to avoid a deadlock scenario. + final ContentRecordingSession session = + virtualDisplayConfig.getContentRecordingSession(); + + if (displayId != Display.INVALID_DISPLAY && session != null) { + // Only attempt to set content recording session if there are details to set and a + // VirtualDisplay has been successfully constructed. + session.setDisplayId(displayId); + + // We set the content recording session here on the server side instead of using + // a second AIDL call in MediaProjection. By ensuring that a virtual display has + // been constructed before calling setContentRecordingSession, we avoid a race + // condition between the DMS & WMS which could lead to the MediaProjection + // being pre-emptively torn down. + if (!mWindowManagerInternal.setContentRecordingSession(session)) { + // Unable to start mirroring, so tear down projection & release VirtualDisplay. + try { + getProjectionService().stopActiveProjection(); + } catch (RemoteException e) { + Slog.e(TAG, "Unable to tell MediaProjectionManagerService to stop the " + + "active projection", e); + } + releaseVirtualDisplayInternal(callback.asBinder()); + return Display.INVALID_DISPLAY; + } + } + + return displayId; } finally { Binder.restoreCallingIdentity(token); } @@ -2804,8 +2838,7 @@ public final class DisplayManagerService extends SystemService { private IMediaProjectionManager getProjectionService() { if (mProjectionService == null) { - IBinder b = ServiceManager.getService(Context.MEDIA_PROJECTION_SERVICE); - mProjectionService = IMediaProjectionManager.Stub.asInterface(b); + mProjectionService = mInjector.getProjectionService(); } return mProjectionService; } @@ -2964,6 +2997,11 @@ public final class DisplayManagerService extends SystemService { boolean getHdrOutputConversionSupport() { return DisplayControl.getHdrOutputConversionSupport(); } + + IMediaProjectionManager getProjectionService() { + IBinder b = ServiceManager.getService(Context.MEDIA_PROJECTION_SERVICE); + return IMediaProjectionManager.Stub.asInterface(b); + } } @VisibleForTesting diff --git a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java index eda15ae32c8b..4f7a2ba58570 100644 --- a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java +++ b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java @@ -88,7 +88,17 @@ public class VirtualDisplayAdapter extends DisplayAdapter { // Called with SyncRoot lock held. public VirtualDisplayAdapter(DisplayManagerService.SyncRoot syncRoot, Context context, Handler handler, Listener listener) { - this(syncRoot, context, handler, listener, DisplayControl::createDisplay); + this(syncRoot, context, handler, listener, new SurfaceControlDisplayFactory() { + @Override + public IBinder createDisplay(String name, boolean secure, float requestedRefreshRate) { + return DisplayControl.createDisplay(name, secure, requestedRefreshRate); + } + + @Override + public void destroyDisplay(IBinder displayToken) { + DisplayControl.destroyDisplay(displayToken); + } + }); } @VisibleForTesting @@ -311,7 +321,7 @@ public class VirtualDisplayAdapter extends DisplayAdapter { mSurface.release(); mSurface = null; } - DisplayControl.destroyDisplay(getDisplayTokenLocked()); + mSurfaceControlDisplayFactory.destroyDisplay(getDisplayTokenLocked()); if (mProjection != null && mMediaProjectionCallback != null) { try { mProjection.unregisterCallback(mMediaProjectionCallback); @@ -653,5 +663,12 @@ public class VirtualDisplayAdapter extends DisplayAdapter { * @return The token reference for the display in SurfaceFlinger. */ IBinder createDisplay(String name, boolean secure, float requestedRefreshRate); + + /** + * Destroy a display in SurfaceFlinger. + * + * @param displayToken The display token for the display to be destroyed. + */ + void destroyDisplay(IBinder displayToken); } } diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml index 71492656913b..6861c2f049fb 100644 --- a/services/tests/servicestests/AndroidManifest.xml +++ b/services/tests/servicestests/AndroidManifest.xml @@ -108,6 +108,7 @@ <uses-permission android:name="android.permission.UPDATE_LOCK_TASK_PACKAGES" /> <uses-permission android:name="android.permission.ACCESS_CONTEXT_HUB" /> <uses-permission android:name="android.permission.USE_BIOMETRIC_INTERNAL" /> + <uses-permission android:name="android.permission.MANAGE_MEDIA_PROJECTION" /> <queries> <package android:name="com.android.servicestests.apps.suspendtestapp" /> diff --git a/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java index de1c2195fcdb..94d30bb4440b 100644 --- a/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java @@ -24,6 +24,8 @@ import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_D import static com.android.server.display.VirtualDisplayAdapter.UNIQUE_ID_PREFIX; +import static com.google.common.truth.Truth.assertThat; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotEquals; @@ -32,8 +34,10 @@ import static org.junit.Assert.assertThrows; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.Mockito.any; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -61,10 +65,13 @@ import android.hardware.display.HdrConversionMode; import android.hardware.display.IDisplayManagerCallback; import android.hardware.display.IVirtualDisplayCallback; import android.hardware.display.VirtualDisplayConfig; +import android.media.projection.IMediaProjectionManager; +import android.os.Binder; import android.os.Handler; import android.os.IBinder; import android.os.MessageQueue; import android.os.Process; +import android.view.ContentRecordingSession; import android.view.Display; import android.view.DisplayCutout; import android.view.DisplayEventReceiver; @@ -158,25 +165,40 @@ public class DisplayManagerServiceTest { } }; - class BasicInjector extends DisplayManagerService.Injector { - @Override - VirtualDisplayAdapter getVirtualDisplayAdapter(SyncRoot syncRoot, Context context, - Handler handler, DisplayAdapter.Listener displayAdapterListener) { - return new VirtualDisplayAdapter(syncRoot, context, handler, displayAdapterListener, - (String name, boolean secure, float refreshRate) -> mMockDisplayToken); - } - - @Override - LocalDisplayAdapter getLocalDisplayAdapter(SyncRoot syncRoot, Context context, - Handler handler, DisplayAdapter.Listener displayAdapterListener) { - return new LocalDisplayAdapter(syncRoot, context, handler, - displayAdapterListener, new LocalDisplayAdapter.Injector() { - @Override - public LocalDisplayAdapter.SurfaceControlProxy getSurfaceControlProxy() { - return mSurfaceControlProxy; - } - }); - } + class BasicInjector extends DisplayManagerService.Injector { + @Override + IMediaProjectionManager getProjectionService() { + return mMockProjectionService; + } + + @Override + VirtualDisplayAdapter getVirtualDisplayAdapter(SyncRoot syncRoot, Context context, + Handler handler, DisplayAdapter.Listener displayAdapterListener) { + return new VirtualDisplayAdapter(syncRoot, context, handler, displayAdapterListener, + new VirtualDisplayAdapter.SurfaceControlDisplayFactory() { + @Override + public IBinder createDisplay(String name, boolean secure, + float requestedRefreshRate) { + return mMockDisplayToken; + } + + @Override + public void destroyDisplay(IBinder displayToken) { + } + }); + } + + @Override + LocalDisplayAdapter getLocalDisplayAdapter(SyncRoot syncRoot, Context context, + Handler handler, DisplayAdapter.Listener displayAdapterListener) { + return new LocalDisplayAdapter(syncRoot, context, handler, + displayAdapterListener, new LocalDisplayAdapter.Injector() { + @Override + public LocalDisplayAdapter.SurfaceControlProxy getSurfaceControlProxy() { + return mSurfaceControlProxy; + } + }); + } @Override int setHdrConversionMode(int conversionMode, int preferredHdrOutputType, @@ -198,6 +220,7 @@ public class DisplayManagerServiceTest { private final DisplayManagerService.Injector mBasicInjector = new BasicInjector(); + @Mock IMediaProjectionManager mMockProjectionService; @Mock IVirtualDeviceManager mIVirtualDeviceManager; @Mock InputManagerInternal mMockInputManagerInternal; @Mock VirtualDeviceManagerInternal mMockVirtualDeviceManagerInternal; @@ -285,6 +308,7 @@ public class DisplayManagerServiceTest { builder.setFlags(flags); int displayId = bs.createVirtualDisplay(builder.build(), mMockAppToken /* callback */, null /* projection */, PACKAGE_NAME); + verify(mMockWindowManagerInternal, never()).setContentRecordingSession(Mockito.any()); displayManager.performTraversalInternal(mock(SurfaceControl.Transaction.class)); @@ -410,6 +434,7 @@ public class DisplayManagerServiceTest { builder.setUniqueId(uniqueId); int displayId = bs.createVirtualDisplay(builder.build(), mMockAppToken /* callback */, null /* projection */, PACKAGE_NAME); + verify(mMockWindowManagerInternal, never()).setContentRecordingSession(Mockito.any()); displayManager.performTraversalInternal(mock(SurfaceControl.Transaction.class)); @@ -446,6 +471,7 @@ public class DisplayManagerServiceTest { builder.setUniqueId(uniqueId); int displayId = bs.createVirtualDisplay(builder.build(), /* callback= */ mMockAppToken, /* projection= */ null, PACKAGE_NAME); + verify(mMockWindowManagerInternal, never()).setContentRecordingSession(Mockito.any()); displayManager.performTraversalInternal(mock(SurfaceControl.Transaction.class)); @@ -479,6 +505,7 @@ public class DisplayManagerServiceTest { builder.setUniqueId(uniqueId); int displayId = bs.createVirtualDisplay(builder.build(), /* callback= */ mMockAppToken, /* projection= */ null, PACKAGE_NAME); + verify(mMockWindowManagerInternal, never()).setContentRecordingSession(Mockito.any()); displayManager.performTraversalInternal(mock(SurfaceControl.Transaction.class)); @@ -720,6 +747,7 @@ public class DisplayManagerServiceTest { builder.setUniqueId(uniqueId); final int firstDisplayId = binderService.createVirtualDisplay(builder.build(), mMockAppToken /* callback */, null /* projection */, PACKAGE_NAME); + verify(mMockWindowManagerInternal, never()).setContentRecordingSession(Mockito.any()); // The second virtual display requests to mirror the first virtual display. final String uniqueId2 = "uniqueId --- displayIdToMirrorTest #2"; @@ -731,6 +759,7 @@ public class DisplayManagerServiceTest { final int secondDisplayId = binderService.createVirtualDisplay(builder2.build(), mMockAppToken2 /* callback */, null /* projection */, PACKAGE_NAME); + verify(mMockWindowManagerInternal, never()).setContentRecordingSession(Mockito.any()); displayManager.performTraversalInternal(mock(SurfaceControl.Transaction.class)); // flush the handler @@ -768,6 +797,7 @@ public class DisplayManagerServiceTest { virtualDevice /* virtualDeviceToken */, mock(DisplayWindowPolicyController.class), PACKAGE_NAME); + verify(mMockWindowManagerInternal, never()).setContentRecordingSession(Mockito.any()); int displayGroupId1 = localService.getDisplayInfo(displayId1).displayGroupId; // Create a second virtual display. This should be added to the previously created display @@ -783,6 +813,7 @@ public class DisplayManagerServiceTest { virtualDevice /* virtualDeviceToken */, mock(DisplayWindowPolicyController.class), PACKAGE_NAME); + verify(mMockWindowManagerInternal, never()).setContentRecordingSession(Mockito.any()); int displayGroupId2 = localService.getDisplayInfo(displayId2).displayGroupId; assertEquals( @@ -820,6 +851,7 @@ public class DisplayManagerServiceTest { virtualDevice /* virtualDeviceToken */, mock(DisplayWindowPolicyController.class), PACKAGE_NAME); + verify(mMockWindowManagerInternal, never()).setContentRecordingSession(Mockito.any()); int displayGroupId1 = localService.getDisplayInfo(displayId1).displayGroupId; // Create a second virtual display. With the flag VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP, @@ -838,6 +870,7 @@ public class DisplayManagerServiceTest { virtualDevice /* virtualDeviceToken */, mock(DisplayWindowPolicyController.class), PACKAGE_NAME); + verify(mMockWindowManagerInternal, never()).setContentRecordingSession(Mockito.any()); int displayGroupId2 = localService.getDisplayInfo(displayId2).displayGroupId; assertNotEquals( @@ -881,6 +914,7 @@ public class DisplayManagerServiceTest { virtualDevice /* virtualDeviceToken */, mock(DisplayWindowPolicyController.class), PACKAGE_NAME); + verify(mMockWindowManagerInternal, never()).setContentRecordingSession(Mockito.any()); // Check that FLAG_ALWAYS_UNLOCKED is set. assertNotEquals( @@ -906,6 +940,7 @@ public class DisplayManagerServiceTest { virtualDevice /* virtualDeviceToken */, mock(DisplayWindowPolicyController.class), PACKAGE_NAME); + verify(mMockWindowManagerInternal, never()).setContentRecordingSession(Mockito.any()); // Check that FLAG_ALWAYS_UNLOCKED is set. assertNotEquals( @@ -929,6 +964,7 @@ public class DisplayManagerServiceTest { null /* virtualDeviceToken */, mock(DisplayWindowPolicyController.class), PACKAGE_NAME); + verify(mMockWindowManagerInternal, never()).setContentRecordingSession(Mockito.any()); // Check that FLAG_ALWAYS_UNLOCKED is not set. assertEquals( @@ -960,6 +996,7 @@ public class DisplayManagerServiceTest { .setFlags(VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY); final int firstDisplayId = binderService.createVirtualDisplay(builder.build(), mMockAppToken /* callback */, null /* projection */, PACKAGE_NAME); + verify(mMockWindowManagerInternal, never()).setContentRecordingSession(Mockito.any()); // The second virtual display requests to mirror the first virtual display. final String uniqueId2 = "uniqueId --- displayIdToMirrorTest #2"; @@ -971,6 +1008,7 @@ public class DisplayManagerServiceTest { final int secondDisplayId = binderService.createVirtualDisplay(builder2.build(), mMockAppToken2 /* callback */, null /* projection */, PACKAGE_NAME); + verify(mMockWindowManagerInternal, never()).setContentRecordingSession(Mockito.any()); displayManager.performTraversalInternal(mock(SurfaceControl.Transaction.class)); // flush the handler @@ -985,6 +1023,54 @@ public class DisplayManagerServiceTest { Display.INVALID_DISPLAY); } + @Test + public void testCreateVirtualDisplay_setContentRecordingSessionSuccess() throws Exception { + when(mMockAppToken.asBinder()).thenReturn(mMockAppToken); + when(mMockWindowManagerInternal + .setContentRecordingSession(any(ContentRecordingSession.class))) + .thenReturn(true); + + final VirtualDisplayConfig.Builder builder = new VirtualDisplayConfig.Builder( + VIRTUAL_DISPLAY_NAME, 600, 800, 320); + builder.setUniqueId("uniqueId --- setContentRecordingSession true"); + builder.setContentRecordingSession( + ContentRecordingSession.createDisplaySession(new Binder(""))); + + DisplayManagerService displayManager = new DisplayManagerService(mContext, mBasicInjector); + registerDefaultDisplays(displayManager); + displayManager.windowManagerAndInputReady(); + + DisplayManagerService.BinderService binderService = displayManager.new BinderService(); + final int displayId = binderService.createVirtualDisplay(builder.build(), + mMockAppToken /* callback */, null /* projection */, PACKAGE_NAME); + + assertThat(displayId).isNotEqualTo(Display.INVALID_DISPLAY); + } + + @Test + public void testCreateVirtualDisplay_setContentRecordingSessionFail() throws Exception { + when(mMockAppToken.asBinder()).thenReturn(mMockAppToken); + when(mMockWindowManagerInternal + .setContentRecordingSession(any(ContentRecordingSession.class))) + .thenReturn(false); + + final VirtualDisplayConfig.Builder builder = new VirtualDisplayConfig.Builder( + VIRTUAL_DISPLAY_NAME, 600, 800, 320); + builder.setUniqueId("uniqueId --- setContentRecordingSession false"); + builder.setContentRecordingSession( + ContentRecordingSession.createDisplaySession(new Binder(""))); + + DisplayManagerService displayManager = new DisplayManagerService(mContext, mBasicInjector); + registerDefaultDisplays(displayManager); + displayManager.windowManagerAndInputReady(); + + DisplayManagerService.BinderService binderService = displayManager.new BinderService(); + final int displayId = binderService.createVirtualDisplay(builder.build(), + mMockAppToken /* callback */, null /* projection */, PACKAGE_NAME); + + assertThat(displayId).isEqualTo(Display.INVALID_DISPLAY); + } + /** * Tests that the virtual display is created with * {@link VirtualDisplayConfig.Builder#setSurface(Surface)} @@ -1011,6 +1097,7 @@ public class DisplayManagerServiceTest { builder.setUniqueId(uniqueId); final int displayId = binderService.createVirtualDisplay(builder.build(), mMockAppToken /* callback */, null /* projection */, PACKAGE_NAME); + verify(mMockWindowManagerInternal, never()).setContentRecordingSession(Mockito.any()); displayManager.performTraversalInternal(mock(SurfaceControl.Transaction.class)); @@ -1043,6 +1130,7 @@ public class DisplayManagerServiceTest { int displayId = bs.createVirtualDisplay(builder.build(), mMockAppToken /* callback */, null /* projection */, PACKAGE_NAME); + verify(mMockWindowManagerInternal, never()).setContentRecordingSession(Mockito.any()); displayManager.performTraversalInternal(mock(SurfaceControl.Transaction.class)); displayManager.getDisplayHandler().runWithScissors(() -> {}, 0 /* now */); DisplayDeviceInfo ddi = displayManager.getDisplayDeviceInfoInternal(displayId); @@ -1093,7 +1181,6 @@ public class DisplayManagerServiceTest { registerDefaultDisplays(displayManager); - DisplayManagerService.BinderService bs = displayManager.new BinderService(); when(mMockAppToken.asBinder()).thenReturn(mMockAppToken); when(mContext.checkCallingPermission(ADD_TRUSTED_DISPLAY)).thenReturn( @@ -1111,6 +1198,7 @@ public class DisplayManagerServiceTest { int displayId = localService.createVirtualDisplay(builder.build(), mMockAppToken /* callback */, virtualDevice /* virtualDeviceToken */, mock(DisplayWindowPolicyController.class), PACKAGE_NAME); + verify(mMockWindowManagerInternal, never()).setContentRecordingSession(Mockito.any()); displayManager.performTraversalInternal(mock(SurfaceControl.Transaction.class)); displayManager.getDisplayHandler().runWithScissors(() -> {}, 0 /* now */); DisplayDeviceInfo ddi = displayManager.getDisplayDeviceInfoInternal(displayId); |