diff options
| author | 2023-03-21 13:53:40 +0000 | |
|---|---|---|
| committer | 2023-03-21 13:53:40 +0000 | |
| commit | df60ec392518a7c63be5ab3d060ab465dfccae48 (patch) | |
| tree | 0a007891a83ebc871aeaed261642d549532a993f | |
| parent | eaa4f5129e408cd7c527a0e481b2e78168f3fa6a (diff) | |
| parent | c5c96700af5638fde26d1d71c9d95457fa3f0770 (diff) | |
Merge "Only allow mirroring on a VirtualDisplay with a mirroring flag or MediaProjection instance." into udc-dev
| -rw-r--r-- | services/core/java/com/android/server/display/DisplayManagerService.java | 13 | ||||
| -rw-r--r-- | services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java | 102 |
2 files changed, 106 insertions, 9 deletions
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java index ea157c89f675..e01aa9b33784 100644 --- a/services/core/java/com/android/server/display/DisplayManagerService.java +++ b/services/core/java/com/android/server/display/DisplayManagerService.java @@ -1514,14 +1514,17 @@ public final class DisplayManagerService extends SystemService { } } - // When calling setContentRecordingSession into the WindowManagerService, the WMS + // When calling WindowManagerService#setContentRecordingSession, WindowManagerService // 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) { + // Ensure session details are only set when mirroring (through VirtualDisplay flags or + // MediaProjection). + final boolean shouldMirror = + projection != null || (flags & VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR) != 0; + if (shouldMirror && 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); @@ -1529,8 +1532,8 @@ public final class DisplayManagerService extends SystemService { // 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. + // condition between the DisplayManagerService & WindowManagerService 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 { 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 94d30bb4440b..6d2ce7fbe68d 100644 --- a/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java @@ -34,7 +34,9 @@ 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.ArgumentMatchers.eq; import static org.mockito.Mockito.any; +import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; @@ -65,12 +67,14 @@ import android.hardware.display.HdrConversionMode; import android.hardware.display.IDisplayManagerCallback; import android.hardware.display.IVirtualDisplayCallback; import android.hardware.display.VirtualDisplayConfig; +import android.media.projection.IMediaProjection; 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.os.RemoteException; import android.view.ContentRecordingSession; import android.view.Display; import android.view.DisplayCutout; @@ -1024,11 +1028,14 @@ public class DisplayManagerServiceTest { } @Test - public void testCreateVirtualDisplay_setContentRecordingSessionSuccess() throws Exception { + public void testCreateVirtualDisplay_setContentRecordingSessionSuccess() + throws RemoteException { when(mMockAppToken.asBinder()).thenReturn(mMockAppToken); when(mMockWindowManagerInternal .setContentRecordingSession(any(ContentRecordingSession.class))) .thenReturn(true); + IMediaProjection projection = mock(IMediaProjection.class); + doReturn(true).when(mMockProjectionService).isCurrentProjection(eq(projection)); final VirtualDisplayConfig.Builder builder = new VirtualDisplayConfig.Builder( VIRTUAL_DISPLAY_NAME, 600, 800, 320); @@ -1042,17 +1049,19 @@ public class DisplayManagerServiceTest { DisplayManagerService.BinderService binderService = displayManager.new BinderService(); final int displayId = binderService.createVirtualDisplay(builder.build(), - mMockAppToken /* callback */, null /* projection */, PACKAGE_NAME); + mMockAppToken /* callback */, projection, PACKAGE_NAME); assertThat(displayId).isNotEqualTo(Display.INVALID_DISPLAY); } @Test - public void testCreateVirtualDisplay_setContentRecordingSessionFail() throws Exception { + public void testCreateVirtualDisplay_setContentRecordingSessionFail() throws RemoteException { when(mMockAppToken.asBinder()).thenReturn(mMockAppToken); when(mMockWindowManagerInternal .setContentRecordingSession(any(ContentRecordingSession.class))) .thenReturn(false); + IMediaProjection projection = mock(IMediaProjection.class); + doReturn(true).when(mMockProjectionService).isCurrentProjection(eq(projection)); final VirtualDisplayConfig.Builder builder = new VirtualDisplayConfig.Builder( VIRTUAL_DISPLAY_NAME, 600, 800, 320); @@ -1066,11 +1075,96 @@ public class DisplayManagerServiceTest { DisplayManagerService.BinderService binderService = displayManager.new BinderService(); final int displayId = binderService.createVirtualDisplay(builder.build(), - mMockAppToken /* callback */, null /* projection */, PACKAGE_NAME); + mMockAppToken /* callback */, projection, PACKAGE_NAME); assertThat(displayId).isEqualTo(Display.INVALID_DISPLAY); } + @Test + public void testCreateVirtualDisplay_setContentRecordingSession_noProjection_noFlags() { + when(mMockAppToken.asBinder()).thenReturn(mMockAppToken); + + // Set no flags for the VirtualDisplay. + 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(); + + // Pass in a null projection. + DisplayManagerService.BinderService binderService = displayManager.new BinderService(); + final int displayId = binderService.createVirtualDisplay(builder.build(), + mMockAppToken /* callback */, null /* projection */, PACKAGE_NAME); + + // VirtualDisplay is created but not for mirroring. + assertThat(displayId).isNotEqualTo(Display.INVALID_DISPLAY); + verify(mMockWindowManagerInternal, never()).setContentRecordingSession( + any(ContentRecordingSession.class)); + } + + @Test + public void testCreateVirtualDisplay_setContentRecordingSession_noProjection_noMirroringFlag() { + when(mMockAppToken.asBinder()).thenReturn(mMockAppToken); + + // Set a non-mirroring flag for the VirtualDisplay. + final VirtualDisplayConfig.Builder builder = new VirtualDisplayConfig.Builder( + VIRTUAL_DISPLAY_NAME, 600, 800, 320); + builder.setUniqueId("uniqueId --- setContentRecordingSession false"); + builder.setFlags(VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY); + builder.setContentRecordingSession( + ContentRecordingSession.createDisplaySession(new Binder(""))); + + DisplayManagerService displayManager = new DisplayManagerService(mContext, mBasicInjector); + registerDefaultDisplays(displayManager); + displayManager.windowManagerAndInputReady(); + + // Pass in a null projection. + DisplayManagerService.BinderService binderService = displayManager.new BinderService(); + final int displayId = binderService.createVirtualDisplay(builder.build(), + mMockAppToken /* callback */, null /* projection */, PACKAGE_NAME); + + // VirtualDisplay is created but not for mirroring. + assertThat(displayId).isNotEqualTo(Display.INVALID_DISPLAY); + verify(mMockWindowManagerInternal, never()).setContentRecordingSession( + any(ContentRecordingSession.class)); + } + + @Test + public void testCreateVirtualDisplay_setContentRecordingSession_projection_noMirroringFlag() + throws RemoteException { + when(mMockAppToken.asBinder()).thenReturn(mMockAppToken); + when(mMockWindowManagerInternal + .setContentRecordingSession(any(ContentRecordingSession.class))) + .thenReturn(true); + IMediaProjection projection = mock(IMediaProjection.class); + doReturn(true).when(mMockProjectionService).isCurrentProjection(eq(projection)); + + // Set no flags for the VirtualDisplay. + 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(); + + // Pass in a non-null projection. + DisplayManagerService.BinderService binderService = displayManager.new BinderService(); + final int displayId = binderService.createVirtualDisplay(builder.build(), + mMockAppToken /* callback */, projection, PACKAGE_NAME); + + // VirtualDisplay is created for mirroring. + assertThat(displayId).isNotEqualTo(Display.INVALID_DISPLAY); + verify(mMockWindowManagerInternal, atLeastOnce()).setContentRecordingSession( + any(ContentRecordingSession.class)); + } + /** * Tests that the virtual display is created with * {@link VirtualDisplayConfig.Builder#setSurface(Surface)} |