Merge "VirtualDisplay: Merge AIDL calls to stop race condition" into udc-dev am: c722618ac8

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

Change-Id: I7de91aa11fad1439e78f59459a45262d3918c14e
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
TreeHugger Robot
2023-03-07 23:03:27 +00:00
committed by Automerger Merge Worker
6 changed files with 209 additions and 37 deletions

View File

@@ -28,6 +28,7 @@ import android.os.Handler;
import android.os.Parcel; import android.os.Parcel;
import android.os.Parcelable; import android.os.Parcelable;
import android.util.ArraySet; import android.util.ArraySet;
import android.view.ContentRecordingSession;
import android.view.Display; import android.view.Display;
import android.view.Surface; import android.view.Surface;
@@ -53,6 +54,8 @@ public final class VirtualDisplayConfig implements Parcelable {
private final int mDisplayIdToMirror; private final int mDisplayIdToMirror;
private final boolean mWindowManagerMirroringEnabled; private final boolean mWindowManagerMirroringEnabled;
private ArraySet<String> mDisplayCategories = null; private ArraySet<String> mDisplayCategories = null;
@Nullable
private ContentRecordingSession mContentRecordingSession;
private final float mRequestedRefreshRate; private final float mRequestedRefreshRate;
private VirtualDisplayConfig( private VirtualDisplayConfig(
@@ -65,6 +68,7 @@ public final class VirtualDisplayConfig implements Parcelable {
@Nullable String uniqueId, @Nullable String uniqueId,
int displayIdToMirror, int displayIdToMirror,
boolean windowManagerMirroringEnabled, boolean windowManagerMirroringEnabled,
ContentRecordingSession session,
@NonNull ArraySet<String> displayCategories, @NonNull ArraySet<String> displayCategories,
float requestedRefreshRate) { float requestedRefreshRate) {
mName = name; mName = name;
@@ -76,6 +80,7 @@ public final class VirtualDisplayConfig implements Parcelable {
mUniqueId = uniqueId; mUniqueId = uniqueId;
mDisplayIdToMirror = displayIdToMirror; mDisplayIdToMirror = displayIdToMirror;
mWindowManagerMirroringEnabled = windowManagerMirroringEnabled; mWindowManagerMirroringEnabled = windowManagerMirroringEnabled;
mContentRecordingSession = session;
mDisplayCategories = displayCategories; mDisplayCategories = displayCategories;
mRequestedRefreshRate = requestedRefreshRate; mRequestedRefreshRate = requestedRefreshRate;
} }
@@ -155,6 +160,17 @@ public final class VirtualDisplayConfig implements Parcelable {
return mWindowManagerMirroringEnabled; return mWindowManagerMirroringEnabled;
} }
/**
* 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. * Returns the display categories.
* *
@@ -186,6 +202,7 @@ public final class VirtualDisplayConfig implements Parcelable {
dest.writeString8(mUniqueId); dest.writeString8(mUniqueId);
dest.writeInt(mDisplayIdToMirror); dest.writeInt(mDisplayIdToMirror);
dest.writeBoolean(mWindowManagerMirroringEnabled); dest.writeBoolean(mWindowManagerMirroringEnabled);
dest.writeTypedObject(mContentRecordingSession, flags);
dest.writeArraySet(mDisplayCategories); dest.writeArraySet(mDisplayCategories);
dest.writeFloat(mRequestedRefreshRate); dest.writeFloat(mRequestedRefreshRate);
} }
@@ -211,6 +228,7 @@ public final class VirtualDisplayConfig implements Parcelable {
&& Objects.equals(mUniqueId, that.mUniqueId) && Objects.equals(mUniqueId, that.mUniqueId)
&& mDisplayIdToMirror == that.mDisplayIdToMirror && mDisplayIdToMirror == that.mDisplayIdToMirror
&& mWindowManagerMirroringEnabled == that.mWindowManagerMirroringEnabled && mWindowManagerMirroringEnabled == that.mWindowManagerMirroringEnabled
&& Objects.equals(mContentRecordingSession, that.mContentRecordingSession)
&& Objects.equals(mDisplayCategories, that.mDisplayCategories) && Objects.equals(mDisplayCategories, that.mDisplayCategories)
&& mRequestedRefreshRate == that.mRequestedRefreshRate; && mRequestedRefreshRate == that.mRequestedRefreshRate;
} }
@@ -219,8 +237,8 @@ public final class VirtualDisplayConfig implements Parcelable {
public int hashCode() { public int hashCode() {
int hashCode = Objects.hash( int hashCode = Objects.hash(
mName, mWidth, mHeight, mDensityDpi, mFlags, mSurface, mUniqueId, mName, mWidth, mHeight, mDensityDpi, mFlags, mSurface, mUniqueId,
mDisplayIdToMirror, mWindowManagerMirroringEnabled, mDisplayCategories, mDisplayIdToMirror, mWindowManagerMirroringEnabled, mContentRecordingSession,
mRequestedRefreshRate); mDisplayCategories, mRequestedRefreshRate);
return hashCode; return hashCode;
} }
@@ -237,6 +255,7 @@ public final class VirtualDisplayConfig implements Parcelable {
+ " mUniqueId=" + mUniqueId + " mUniqueId=" + mUniqueId
+ " mDisplayIdToMirror=" + mDisplayIdToMirror + " mDisplayIdToMirror=" + mDisplayIdToMirror
+ " mWindowManagerMirroringEnabled=" + mWindowManagerMirroringEnabled + " mWindowManagerMirroringEnabled=" + mWindowManagerMirroringEnabled
+ " mContentRecordingSession=" + mContentRecordingSession
+ " mDisplayCategories=" + mDisplayCategories + " mDisplayCategories=" + mDisplayCategories
+ " mRequestedRefreshRate=" + mRequestedRefreshRate + " mRequestedRefreshRate=" + mRequestedRefreshRate
+ ")"; + ")";
@@ -252,6 +271,7 @@ public final class VirtualDisplayConfig implements Parcelable {
mUniqueId = in.readString8(); mUniqueId = in.readString8();
mDisplayIdToMirror = in.readInt(); mDisplayIdToMirror = in.readInt();
mWindowManagerMirroringEnabled = in.readBoolean(); mWindowManagerMirroringEnabled = in.readBoolean();
mContentRecordingSession = in.readTypedObject(ContentRecordingSession.CREATOR);
mDisplayCategories = (ArraySet<String>) in.readArraySet(null); mDisplayCategories = (ArraySet<String>) in.readArraySet(null);
mRequestedRefreshRate = in.readFloat(); mRequestedRefreshRate = in.readFloat();
} }
@@ -283,6 +303,8 @@ public final class VirtualDisplayConfig implements Parcelable {
private String mUniqueId = null; private String mUniqueId = null;
private int mDisplayIdToMirror = DEFAULT_DISPLAY; private int mDisplayIdToMirror = DEFAULT_DISPLAY;
private boolean mWindowManagerMirroringEnabled = false; private boolean mWindowManagerMirroringEnabled = false;
@Nullable
private ContentRecordingSession mContentRecordingSession;
private ArraySet<String> mDisplayCategories = new ArraySet<>(); private ArraySet<String> mDisplayCategories = new ArraySet<>();
private float mRequestedRefreshRate = 0.0f; private float mRequestedRefreshRate = 0.0f;
@@ -374,6 +396,18 @@ public final class VirtualDisplayConfig implements Parcelable {
return this; return this;
} }
/**
* 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. * Sets the display categories.
* *
@@ -435,6 +469,7 @@ public final class VirtualDisplayConfig implements Parcelable {
mUniqueId, mUniqueId,
mDisplayIdToMirror, mDisplayIdToMirror,
mWindowManagerMirroringEnabled, mWindowManagerMirroringEnabled,
mContentRecordingSession,
mDisplayCategories, mDisplayCategories,
mRequestedRefreshRate); mRequestedRefreshRate);
} }

View File

@@ -191,20 +191,13 @@ public final class MediaProjection {
} else { } else {
session = ContentRecordingSession.createTaskSession(launchCookie); 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); virtualDisplayConfig.setWindowManagerMirroringEnabled(true);
final DisplayManager dm = mContext.getSystemService(DisplayManager.class); final DisplayManager dm = mContext.getSystemService(DisplayManager.class);
final VirtualDisplay virtualDisplay = dm.createVirtualDisplay(this, final VirtualDisplay virtualDisplay = dm.createVirtualDisplay(this,
virtualDisplayConfig.build(), callback, handler, windowContext); 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; return virtualDisplay;
} catch (RemoteException e) { } catch (RemoteException e) {
// Can not capture if WMS is not accessible, so bail out. // Can not capture if WMS is not accessible, so bail out.

View File

@@ -128,6 +128,7 @@ import android.util.Slog;
import android.util.SparseArray; import android.util.SparseArray;
import android.util.SparseIntArray; import android.util.SparseIntArray;
import android.util.Spline; import android.util.Spline;
import android.view.ContentRecordingSession;
import android.view.Display; import android.view.Display;
import android.view.DisplayEventReceiver; import android.view.DisplayEventReceiver;
import android.view.DisplayInfo; import android.view.DisplayInfo;
@@ -250,6 +251,7 @@ public final class DisplayManagerService extends SystemService {
private ActivityManagerInternal mActivityManagerInternal; private ActivityManagerInternal mActivityManagerInternal;
private ActivityManager mActivityManager; private ActivityManager mActivityManager;
private UidImportanceListener mUidImportanceListener = new UidImportanceListener(); private UidImportanceListener mUidImportanceListener = new UidImportanceListener();
@Nullable
private IMediaProjectionManager mProjectionService; private IMediaProjectionManager mProjectionService;
private DeviceStateManagerInternal mDeviceStateManager; private DeviceStateManagerInternal mDeviceStateManager;
@GuardedBy("mSyncRoot") @GuardedBy("mSyncRoot")
@@ -1494,8 +1496,9 @@ public final class DisplayManagerService extends SystemService {
final long token = Binder.clearCallingIdentity(); final long token = Binder.clearCallingIdentity();
try { try {
final int displayId;
synchronized (mSyncRoot) { synchronized (mSyncRoot) {
final int displayId = displayId =
createVirtualDisplayLocked( createVirtualDisplayLocked(
callback, callback,
projection, projection,
@@ -1509,8 +1512,39 @@ public final class DisplayManagerService extends SystemService {
mDisplayWindowPolicyControllers.put( mDisplayWindowPolicyControllers.put(
displayId, Pair.create(virtualDevice, dwpc)); 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 { } finally {
Binder.restoreCallingIdentity(token); Binder.restoreCallingIdentity(token);
} }
@@ -2804,8 +2838,7 @@ public final class DisplayManagerService extends SystemService {
private IMediaProjectionManager getProjectionService() { private IMediaProjectionManager getProjectionService() {
if (mProjectionService == null) { if (mProjectionService == null) {
IBinder b = ServiceManager.getService(Context.MEDIA_PROJECTION_SERVICE); mProjectionService = mInjector.getProjectionService();
mProjectionService = IMediaProjectionManager.Stub.asInterface(b);
} }
return mProjectionService; return mProjectionService;
} }
@@ -2964,6 +2997,11 @@ public final class DisplayManagerService extends SystemService {
boolean getHdrOutputConversionSupport() { boolean getHdrOutputConversionSupport() {
return DisplayControl.getHdrOutputConversionSupport(); return DisplayControl.getHdrOutputConversionSupport();
} }
IMediaProjectionManager getProjectionService() {
IBinder b = ServiceManager.getService(Context.MEDIA_PROJECTION_SERVICE);
return IMediaProjectionManager.Stub.asInterface(b);
}
} }
@VisibleForTesting @VisibleForTesting

View File

@@ -88,7 +88,17 @@ public class VirtualDisplayAdapter extends DisplayAdapter {
// Called with SyncRoot lock held. // Called with SyncRoot lock held.
public VirtualDisplayAdapter(DisplayManagerService.SyncRoot syncRoot, public VirtualDisplayAdapter(DisplayManagerService.SyncRoot syncRoot,
Context context, Handler handler, Listener listener) { 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 @VisibleForTesting
@@ -311,7 +321,7 @@ public class VirtualDisplayAdapter extends DisplayAdapter {
mSurface.release(); mSurface.release();
mSurface = null; mSurface = null;
} }
DisplayControl.destroyDisplay(getDisplayTokenLocked()); mSurfaceControlDisplayFactory.destroyDisplay(getDisplayTokenLocked());
if (mProjection != null && mMediaProjectionCallback != null) { if (mProjection != null && mMediaProjectionCallback != null) {
try { try {
mProjection.unregisterCallback(mMediaProjectionCallback); mProjection.unregisterCallback(mMediaProjectionCallback);
@@ -653,5 +663,12 @@ public class VirtualDisplayAdapter extends DisplayAdapter {
* @return The token reference for the display in SurfaceFlinger. * @return The token reference for the display in SurfaceFlinger.
*/ */
IBinder createDisplay(String name, boolean secure, float requestedRefreshRate); 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);
} }
} }

View File

@@ -108,6 +108,7 @@
<uses-permission android:name="android.permission.UPDATE_LOCK_TASK_PACKAGES" /> <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.ACCESS_CONTEXT_HUB" />
<uses-permission android:name="android.permission.USE_BIOMETRIC_INTERNAL" /> <uses-permission android:name="android.permission.USE_BIOMETRIC_INTERNAL" />
<uses-permission android:name="android.permission.MANAGE_MEDIA_PROJECTION" />
<queries> <queries>
<package android:name="com.android.servicestests.apps.suspendtestapp" /> <package android:name="com.android.servicestests.apps.suspendtestapp" />

View File

@@ -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.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.assertEquals;
import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals; 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.assertTrue;
import static org.junit.Assert.fail; import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy; import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
@@ -61,10 +65,13 @@ import android.hardware.display.HdrConversionMode;
import android.hardware.display.IDisplayManagerCallback; import android.hardware.display.IDisplayManagerCallback;
import android.hardware.display.IVirtualDisplayCallback; import android.hardware.display.IVirtualDisplayCallback;
import android.hardware.display.VirtualDisplayConfig; import android.hardware.display.VirtualDisplayConfig;
import android.media.projection.IMediaProjectionManager;
import android.os.Binder;
import android.os.Handler; import android.os.Handler;
import android.os.IBinder; import android.os.IBinder;
import android.os.MessageQueue; import android.os.MessageQueue;
import android.os.Process; import android.os.Process;
import android.view.ContentRecordingSession;
import android.view.Display; import android.view.Display;
import android.view.DisplayCutout; import android.view.DisplayCutout;
import android.view.DisplayEventReceiver; import android.view.DisplayEventReceiver;
@@ -158,25 +165,40 @@ public class DisplayManagerServiceTest {
} }
}; };
class BasicInjector extends DisplayManagerService.Injector { class BasicInjector extends DisplayManagerService.Injector {
@Override @Override
VirtualDisplayAdapter getVirtualDisplayAdapter(SyncRoot syncRoot, Context context, IMediaProjectionManager getProjectionService() {
Handler handler, DisplayAdapter.Listener displayAdapterListener) { return mMockProjectionService;
return new VirtualDisplayAdapter(syncRoot, context, handler, displayAdapterListener, }
(String name, boolean secure, float refreshRate) -> mMockDisplayToken);
}
@Override @Override
LocalDisplayAdapter getLocalDisplayAdapter(SyncRoot syncRoot, Context context, VirtualDisplayAdapter getVirtualDisplayAdapter(SyncRoot syncRoot, Context context,
Handler handler, DisplayAdapter.Listener displayAdapterListener) { Handler handler, DisplayAdapter.Listener displayAdapterListener) {
return new LocalDisplayAdapter(syncRoot, context, handler, return new VirtualDisplayAdapter(syncRoot, context, handler, displayAdapterListener,
displayAdapterListener, new LocalDisplayAdapter.Injector() { new VirtualDisplayAdapter.SurfaceControlDisplayFactory() {
@Override @Override
public LocalDisplayAdapter.SurfaceControlProxy getSurfaceControlProxy() { public IBinder createDisplay(String name, boolean secure,
return mSurfaceControlProxy; 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 @Override
int setHdrConversionMode(int conversionMode, int preferredHdrOutputType, int setHdrConversionMode(int conversionMode, int preferredHdrOutputType,
@@ -198,6 +220,7 @@ public class DisplayManagerServiceTest {
private final DisplayManagerService.Injector mBasicInjector = new BasicInjector(); private final DisplayManagerService.Injector mBasicInjector = new BasicInjector();
@Mock IMediaProjectionManager mMockProjectionService;
@Mock IVirtualDeviceManager mIVirtualDeviceManager; @Mock IVirtualDeviceManager mIVirtualDeviceManager;
@Mock InputManagerInternal mMockInputManagerInternal; @Mock InputManagerInternal mMockInputManagerInternal;
@Mock VirtualDeviceManagerInternal mMockVirtualDeviceManagerInternal; @Mock VirtualDeviceManagerInternal mMockVirtualDeviceManagerInternal;
@@ -285,6 +308,7 @@ public class DisplayManagerServiceTest {
builder.setFlags(flags); builder.setFlags(flags);
int displayId = bs.createVirtualDisplay(builder.build(), mMockAppToken /* callback */, int displayId = bs.createVirtualDisplay(builder.build(), mMockAppToken /* callback */,
null /* projection */, PACKAGE_NAME); null /* projection */, PACKAGE_NAME);
verify(mMockWindowManagerInternal, never()).setContentRecordingSession(Mockito.any());
displayManager.performTraversalInternal(mock(SurfaceControl.Transaction.class)); displayManager.performTraversalInternal(mock(SurfaceControl.Transaction.class));
@@ -410,6 +434,7 @@ public class DisplayManagerServiceTest {
builder.setUniqueId(uniqueId); builder.setUniqueId(uniqueId);
int displayId = bs.createVirtualDisplay(builder.build(), mMockAppToken /* callback */, int displayId = bs.createVirtualDisplay(builder.build(), mMockAppToken /* callback */,
null /* projection */, PACKAGE_NAME); null /* projection */, PACKAGE_NAME);
verify(mMockWindowManagerInternal, never()).setContentRecordingSession(Mockito.any());
displayManager.performTraversalInternal(mock(SurfaceControl.Transaction.class)); displayManager.performTraversalInternal(mock(SurfaceControl.Transaction.class));
@@ -446,6 +471,7 @@ public class DisplayManagerServiceTest {
builder.setUniqueId(uniqueId); builder.setUniqueId(uniqueId);
int displayId = bs.createVirtualDisplay(builder.build(), /* callback= */ mMockAppToken, int displayId = bs.createVirtualDisplay(builder.build(), /* callback= */ mMockAppToken,
/* projection= */ null, PACKAGE_NAME); /* projection= */ null, PACKAGE_NAME);
verify(mMockWindowManagerInternal, never()).setContentRecordingSession(Mockito.any());
displayManager.performTraversalInternal(mock(SurfaceControl.Transaction.class)); displayManager.performTraversalInternal(mock(SurfaceControl.Transaction.class));
@@ -479,6 +505,7 @@ public class DisplayManagerServiceTest {
builder.setUniqueId(uniqueId); builder.setUniqueId(uniqueId);
int displayId = bs.createVirtualDisplay(builder.build(), /* callback= */ mMockAppToken, int displayId = bs.createVirtualDisplay(builder.build(), /* callback= */ mMockAppToken,
/* projection= */ null, PACKAGE_NAME); /* projection= */ null, PACKAGE_NAME);
verify(mMockWindowManagerInternal, never()).setContentRecordingSession(Mockito.any());
displayManager.performTraversalInternal(mock(SurfaceControl.Transaction.class)); displayManager.performTraversalInternal(mock(SurfaceControl.Transaction.class));
@@ -720,6 +747,7 @@ public class DisplayManagerServiceTest {
builder.setUniqueId(uniqueId); builder.setUniqueId(uniqueId);
final int firstDisplayId = binderService.createVirtualDisplay(builder.build(), final int firstDisplayId = binderService.createVirtualDisplay(builder.build(),
mMockAppToken /* callback */, null /* projection */, PACKAGE_NAME); mMockAppToken /* callback */, null /* projection */, PACKAGE_NAME);
verify(mMockWindowManagerInternal, never()).setContentRecordingSession(Mockito.any());
// The second virtual display requests to mirror the first virtual display. // The second virtual display requests to mirror the first virtual display.
final String uniqueId2 = "uniqueId --- displayIdToMirrorTest #2"; final String uniqueId2 = "uniqueId --- displayIdToMirrorTest #2";
@@ -731,6 +759,7 @@ public class DisplayManagerServiceTest {
final int secondDisplayId = binderService.createVirtualDisplay(builder2.build(), final int secondDisplayId = binderService.createVirtualDisplay(builder2.build(),
mMockAppToken2 /* callback */, null /* projection */, mMockAppToken2 /* callback */, null /* projection */,
PACKAGE_NAME); PACKAGE_NAME);
verify(mMockWindowManagerInternal, never()).setContentRecordingSession(Mockito.any());
displayManager.performTraversalInternal(mock(SurfaceControl.Transaction.class)); displayManager.performTraversalInternal(mock(SurfaceControl.Transaction.class));
// flush the handler // flush the handler
@@ -768,6 +797,7 @@ public class DisplayManagerServiceTest {
virtualDevice /* virtualDeviceToken */, virtualDevice /* virtualDeviceToken */,
mock(DisplayWindowPolicyController.class), mock(DisplayWindowPolicyController.class),
PACKAGE_NAME); PACKAGE_NAME);
verify(mMockWindowManagerInternal, never()).setContentRecordingSession(Mockito.any());
int displayGroupId1 = localService.getDisplayInfo(displayId1).displayGroupId; int displayGroupId1 = localService.getDisplayInfo(displayId1).displayGroupId;
// Create a second virtual display. This should be added to the previously created display // Create a second virtual display. This should be added to the previously created display
@@ -783,6 +813,7 @@ public class DisplayManagerServiceTest {
virtualDevice /* virtualDeviceToken */, virtualDevice /* virtualDeviceToken */,
mock(DisplayWindowPolicyController.class), mock(DisplayWindowPolicyController.class),
PACKAGE_NAME); PACKAGE_NAME);
verify(mMockWindowManagerInternal, never()).setContentRecordingSession(Mockito.any());
int displayGroupId2 = localService.getDisplayInfo(displayId2).displayGroupId; int displayGroupId2 = localService.getDisplayInfo(displayId2).displayGroupId;
assertEquals( assertEquals(
@@ -820,6 +851,7 @@ public class DisplayManagerServiceTest {
virtualDevice /* virtualDeviceToken */, virtualDevice /* virtualDeviceToken */,
mock(DisplayWindowPolicyController.class), mock(DisplayWindowPolicyController.class),
PACKAGE_NAME); PACKAGE_NAME);
verify(mMockWindowManagerInternal, never()).setContentRecordingSession(Mockito.any());
int displayGroupId1 = localService.getDisplayInfo(displayId1).displayGroupId; int displayGroupId1 = localService.getDisplayInfo(displayId1).displayGroupId;
// Create a second virtual display. With the flag VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP, // Create a second virtual display. With the flag VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP,
@@ -838,6 +870,7 @@ public class DisplayManagerServiceTest {
virtualDevice /* virtualDeviceToken */, virtualDevice /* virtualDeviceToken */,
mock(DisplayWindowPolicyController.class), mock(DisplayWindowPolicyController.class),
PACKAGE_NAME); PACKAGE_NAME);
verify(mMockWindowManagerInternal, never()).setContentRecordingSession(Mockito.any());
int displayGroupId2 = localService.getDisplayInfo(displayId2).displayGroupId; int displayGroupId2 = localService.getDisplayInfo(displayId2).displayGroupId;
assertNotEquals( assertNotEquals(
@@ -881,6 +914,7 @@ public class DisplayManagerServiceTest {
virtualDevice /* virtualDeviceToken */, virtualDevice /* virtualDeviceToken */,
mock(DisplayWindowPolicyController.class), mock(DisplayWindowPolicyController.class),
PACKAGE_NAME); PACKAGE_NAME);
verify(mMockWindowManagerInternal, never()).setContentRecordingSession(Mockito.any());
// Check that FLAG_ALWAYS_UNLOCKED is set. // Check that FLAG_ALWAYS_UNLOCKED is set.
assertNotEquals( assertNotEquals(
@@ -906,6 +940,7 @@ public class DisplayManagerServiceTest {
virtualDevice /* virtualDeviceToken */, virtualDevice /* virtualDeviceToken */,
mock(DisplayWindowPolicyController.class), mock(DisplayWindowPolicyController.class),
PACKAGE_NAME); PACKAGE_NAME);
verify(mMockWindowManagerInternal, never()).setContentRecordingSession(Mockito.any());
// Check that FLAG_ALWAYS_UNLOCKED is set. // Check that FLAG_ALWAYS_UNLOCKED is set.
assertNotEquals( assertNotEquals(
@@ -929,6 +964,7 @@ public class DisplayManagerServiceTest {
null /* virtualDeviceToken */, null /* virtualDeviceToken */,
mock(DisplayWindowPolicyController.class), mock(DisplayWindowPolicyController.class),
PACKAGE_NAME); PACKAGE_NAME);
verify(mMockWindowManagerInternal, never()).setContentRecordingSession(Mockito.any());
// Check that FLAG_ALWAYS_UNLOCKED is not set. // Check that FLAG_ALWAYS_UNLOCKED is not set.
assertEquals( assertEquals(
@@ -960,6 +996,7 @@ public class DisplayManagerServiceTest {
.setFlags(VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY); .setFlags(VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY);
final int firstDisplayId = binderService.createVirtualDisplay(builder.build(), final int firstDisplayId = binderService.createVirtualDisplay(builder.build(),
mMockAppToken /* callback */, null /* projection */, PACKAGE_NAME); mMockAppToken /* callback */, null /* projection */, PACKAGE_NAME);
verify(mMockWindowManagerInternal, never()).setContentRecordingSession(Mockito.any());
// The second virtual display requests to mirror the first virtual display. // The second virtual display requests to mirror the first virtual display.
final String uniqueId2 = "uniqueId --- displayIdToMirrorTest #2"; final String uniqueId2 = "uniqueId --- displayIdToMirrorTest #2";
@@ -971,6 +1008,7 @@ public class DisplayManagerServiceTest {
final int secondDisplayId = binderService.createVirtualDisplay(builder2.build(), final int secondDisplayId = binderService.createVirtualDisplay(builder2.build(),
mMockAppToken2 /* callback */, null /* projection */, mMockAppToken2 /* callback */, null /* projection */,
PACKAGE_NAME); PACKAGE_NAME);
verify(mMockWindowManagerInternal, never()).setContentRecordingSession(Mockito.any());
displayManager.performTraversalInternal(mock(SurfaceControl.Transaction.class)); displayManager.performTraversalInternal(mock(SurfaceControl.Transaction.class));
// flush the handler // flush the handler
@@ -985,6 +1023,54 @@ public class DisplayManagerServiceTest {
Display.INVALID_DISPLAY); 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 * Tests that the virtual display is created with
* {@link VirtualDisplayConfig.Builder#setSurface(Surface)} * {@link VirtualDisplayConfig.Builder#setSurface(Surface)}
@@ -1011,6 +1097,7 @@ public class DisplayManagerServiceTest {
builder.setUniqueId(uniqueId); builder.setUniqueId(uniqueId);
final int displayId = binderService.createVirtualDisplay(builder.build(), final int displayId = binderService.createVirtualDisplay(builder.build(),
mMockAppToken /* callback */, null /* projection */, PACKAGE_NAME); mMockAppToken /* callback */, null /* projection */, PACKAGE_NAME);
verify(mMockWindowManagerInternal, never()).setContentRecordingSession(Mockito.any());
displayManager.performTraversalInternal(mock(SurfaceControl.Transaction.class)); displayManager.performTraversalInternal(mock(SurfaceControl.Transaction.class));
@@ -1043,6 +1130,7 @@ public class DisplayManagerServiceTest {
int displayId = bs.createVirtualDisplay(builder.build(), mMockAppToken /* callback */, int displayId = bs.createVirtualDisplay(builder.build(), mMockAppToken /* callback */,
null /* projection */, PACKAGE_NAME); null /* projection */, PACKAGE_NAME);
verify(mMockWindowManagerInternal, never()).setContentRecordingSession(Mockito.any());
displayManager.performTraversalInternal(mock(SurfaceControl.Transaction.class)); displayManager.performTraversalInternal(mock(SurfaceControl.Transaction.class));
displayManager.getDisplayHandler().runWithScissors(() -> {}, 0 /* now */); displayManager.getDisplayHandler().runWithScissors(() -> {}, 0 /* now */);
DisplayDeviceInfo ddi = displayManager.getDisplayDeviceInfoInternal(displayId); DisplayDeviceInfo ddi = displayManager.getDisplayDeviceInfoInternal(displayId);
@@ -1093,7 +1181,6 @@ public class DisplayManagerServiceTest {
registerDefaultDisplays(displayManager); registerDefaultDisplays(displayManager);
DisplayManagerService.BinderService bs = displayManager.new BinderService();
when(mMockAppToken.asBinder()).thenReturn(mMockAppToken); when(mMockAppToken.asBinder()).thenReturn(mMockAppToken);
when(mContext.checkCallingPermission(ADD_TRUSTED_DISPLAY)).thenReturn( when(mContext.checkCallingPermission(ADD_TRUSTED_DISPLAY)).thenReturn(
@@ -1111,6 +1198,7 @@ public class DisplayManagerServiceTest {
int displayId = localService.createVirtualDisplay(builder.build(), int displayId = localService.createVirtualDisplay(builder.build(),
mMockAppToken /* callback */, virtualDevice /* virtualDeviceToken */, mMockAppToken /* callback */, virtualDevice /* virtualDeviceToken */,
mock(DisplayWindowPolicyController.class), PACKAGE_NAME); mock(DisplayWindowPolicyController.class), PACKAGE_NAME);
verify(mMockWindowManagerInternal, never()).setContentRecordingSession(Mockito.any());
displayManager.performTraversalInternal(mock(SurfaceControl.Transaction.class)); displayManager.performTraversalInternal(mock(SurfaceControl.Transaction.class));
displayManager.getDisplayHandler().runWithScissors(() -> {}, 0 /* now */); displayManager.getDisplayHandler().runWithScissors(() -> {}, 0 /* now */);
DisplayDeviceInfo ddi = displayManager.getDisplayDeviceInfoInternal(displayId); DisplayDeviceInfo ddi = displayManager.getDisplayDeviceInfoInternal(displayId);