Merge "[automerger skipped] Merge "switch TelecomManager List getters to ParceledListSlice" into rvc-dev am: 2f287743a4 am: b680cef434 -s ours am: 3247344939 -s ours am: 1ef8802d73 -s ours am: 36f6dd18e3 -s ours am: 31a632835d -s ours"
diff --git a/core/java/android/hardware/display/DisplayManagerInternal.java b/core/java/android/hardware/display/DisplayManagerInternal.java
index b0b3e9e..52cef0f 100644
--- a/core/java/android/hardware/display/DisplayManagerInternal.java
+++ b/core/java/android/hardware/display/DisplayManagerInternal.java
@@ -374,6 +374,15 @@
public abstract Point getDisplaySurfaceDefaultSize(int displayId);
/**
+ * Get a new displayId which represents the display you want to mirror. If mirroring is not
+ * enabled on the display, {@link Display#INVALID_DISPLAY} will be returned.
+ *
+ * @param displayId The id of the display.
+ * @return The displayId that should be mirrored or INVALID_DISPLAY if mirroring is not enabled.
+ */
+ public abstract int getDisplayIdToMirror(int displayId);
+
+ /**
* Receives early interactivity changes from power manager.
*
* @param interactive The interactive state that the device is moving into.
diff --git a/core/java/com/android/internal/protolog/ProtoLogGroup.java b/core/java/com/android/internal/protolog/ProtoLogGroup.java
index 7f36c79..0e8dc07 100644
--- a/core/java/com/android/internal/protolog/ProtoLogGroup.java
+++ b/core/java/com/android/internal/protolog/ProtoLogGroup.java
@@ -83,7 +83,7 @@
Consts.TAG_WM),
WM_DEBUG_WINDOW_INSETS(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false,
Consts.TAG_WM),
- WM_DEBUG_CONTENT_RECORDING(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, true,
+ WM_DEBUG_CONTENT_RECORDING(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false,
Consts.TAG_WM),
WM_DEBUG_WALLPAPER(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false, Consts.TAG_WM),
WM_DEBUG_BACK_PREVIEW(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, true,
diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index 505d2a3..e0ec33e 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -13,12 +13,24 @@
"group": "WM_DEBUG_STARTING_WINDOW",
"at": "com\/android\/server\/wm\/ActivityRecord.java"
},
+ "-2123789565": {
+ "message": "Found no matching mirror display for id=%d for DEFAULT_DISPLAY. Nothing to mirror.",
+ "level": "WARN",
+ "group": "WM_DEBUG_CONTENT_RECORDING",
+ "at": "com\/android\/server\/wm\/DisplayContent.java"
+ },
"-2121056984": {
"message": "%s",
"level": "WARN",
"group": "WM_DEBUG_LOCKTASK",
"at": "com\/android\/server\/wm\/LockTaskController.java"
},
+ "-2113780196": {
+ "message": "Successfully created a ContentRecordingSession for displayId=%d to mirror content from displayId=%d",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_CONTENT_RECORDING",
+ "at": "com\/android\/server\/wm\/DisplayContent.java"
+ },
"-2111539867": {
"message": "remove IME snapshot, caller=%s",
"level": "INFO",
@@ -1303,6 +1315,12 @@
"group": "WM_DEBUG_CONFIGURATION",
"at": "com\/android\/server\/wm\/ActivityRecord.java"
},
+ "-838378223": {
+ "message": "Attempting to mirror self on %d",
+ "level": "WARN",
+ "group": "WM_DEBUG_CONTENT_RECORDING",
+ "at": "com\/android\/server\/wm\/DisplayContent.java"
+ },
"-814760297": {
"message": "Looking for task of %s in %s",
"level": "DEBUG",
@@ -1411,6 +1429,12 @@
"group": "WM_DEBUG_CONTENT_RECORDING",
"at": "com\/android\/server\/wm\/ContentRecorder.java"
},
+ "-729864558": {
+ "message": "Attempting to mirror %d from %d but no DisplayContent associated. Changing to mirror default display.",
+ "level": "WARN",
+ "group": "WM_DEBUG_CONTENT_RECORDING",
+ "at": "com\/android\/server\/wm\/DisplayContent.java"
+ },
"-729530161": {
"message": "Moving to DESTROYED: %s (no app)",
"level": "VERBOSE",
diff --git a/services/core/java/com/android/server/display/DisplayDevice.java b/services/core/java/com/android/server/display/DisplayDevice.java
index e53aef7..99e709e 100644
--- a/services/core/java/com/android/server/display/DisplayDevice.java
+++ b/services/core/java/com/android/server/display/DisplayDevice.java
@@ -127,12 +127,13 @@
/**
* Returns the default size of the surface associated with the display, or null if the surface
- * is not provided for layer mirroring by SurfaceFlinger.
- * Only used for mirroring started from MediaProjection.
+ * is not provided for layer mirroring by SurfaceFlinger. For non virtual displays, this will
+ * be the actual display device's size.
*/
@Nullable
public Point getDisplaySurfaceDefaultSizeLocked() {
- return null;
+ DisplayDeviceInfo displayDeviceInfo = getDisplayDeviceInfoLocked();
+ return new Point(displayDeviceInfo.width, displayDeviceInfo.height);
}
/**
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index 2dd3864..67f64a99 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -2214,24 +2214,10 @@
private void configureDisplayLocked(SurfaceControl.Transaction t, DisplayDevice device) {
final DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked();
- final boolean ownContent = (info.flags & DisplayDeviceInfo.FLAG_OWN_CONTENT_ONLY) != 0;
// Find the logical display that the display device is showing.
// Certain displays only ever show their own content.
LogicalDisplay display = mLogicalDisplayMapper.getDisplayLocked(device);
- // Proceed with display-managed mirroring only if window manager will not be handling it.
- if (!ownContent && !device.isWindowManagerMirroringLocked()) {
- // Only mirror the display if content recording is not taking place in WM.
- if (display != null && !display.hasContentLocked()) {
- // If the display does not have any content of its own, then
- // automatically mirror the requested logical display contents if possible.
- display = mLogicalDisplayMapper.getDisplayLocked(
- device.getDisplayIdToMirrorLocked());
- }
- if (display == null) {
- display = mLogicalDisplayMapper.getDisplayLocked(Display.DEFAULT_DISPLAY);
- }
- }
// Apply the logical display configuration to the display device.
if (display == null) {
@@ -2546,18 +2532,6 @@
}
@VisibleForTesting
- int getDisplayIdToMirrorInternal(int displayId) {
- synchronized (mSyncRoot) {
- final LogicalDisplay display = mLogicalDisplayMapper.getDisplayLocked(displayId);
- if (display != null) {
- final DisplayDevice displayDevice = display.getPrimaryDisplayDeviceLocked();
- return displayDevice.getDisplayIdToMirrorLocked();
- }
- return Display.INVALID_DISPLAY;
- }
- }
-
- @VisibleForTesting
Surface getVirtualDisplaySurfaceInternal(IBinder appToken) {
synchronized (mSyncRoot) {
if (mVirtualDisplayAdapter == null) {
@@ -3853,6 +3827,37 @@
return null;
}
}
+
+ @Override
+ public int getDisplayIdToMirror(int displayId) {
+ synchronized (mSyncRoot) {
+ final LogicalDisplay display = mLogicalDisplayMapper.getDisplayLocked(displayId);
+ if (display == null) {
+ return Display.INVALID_DISPLAY;
+ }
+
+ final DisplayDevice displayDevice = display.getPrimaryDisplayDeviceLocked();
+ final boolean ownContent = (displayDevice.getDisplayDeviceInfoLocked().flags
+ & DisplayDeviceInfo.FLAG_OWN_CONTENT_ONLY) != 0;
+ // If the display has enabled mirroring, but specified that it will be managed by
+ // WindowManager, return an invalid display id. This is to ensure we don't
+ // accidentally select the display id to mirror based on DM logic and instead allow
+ // the caller to specify what area to mirror.
+ if (ownContent || displayDevice.isWindowManagerMirroringLocked()) {
+ return Display.INVALID_DISPLAY;
+ }
+
+ int displayIdToMirror = displayDevice.getDisplayIdToMirrorLocked();
+ LogicalDisplay displayToMirror = mLogicalDisplayMapper.getDisplayLocked(
+ displayIdToMirror);
+ // If the displayId for the requested mirror doesn't exist, fallback to mirroring
+ // default display.
+ if (displayToMirror == null) {
+ displayIdToMirror = Display.DEFAULT_DISPLAY;
+ }
+ return displayIdToMirror;
+ }
+ }
}
class DesiredDisplayModeSpecsObserver
diff --git a/services/core/java/com/android/server/wm/ContentRecorder.java b/services/core/java/com/android/server/wm/ContentRecorder.java
index 5d2d582..7731f28 100644
--- a/services/core/java/com/android/server/wm/ContentRecorder.java
+++ b/services/core/java/com/android/server/wm/ContentRecorder.java
@@ -87,6 +87,10 @@
mContentRecordingSession = session;
}
+ boolean isContentRecordingSessionSet() {
+ return mContentRecordingSession != null;
+ }
+
/**
* Returns {@code true} if this DisplayContent is currently recording.
*/
@@ -299,8 +303,7 @@
mDisplayContent.mWmService.mWindowContextListenerController.getContainer(
tokenToRecord);
if (wc == null) {
- // Un-set the window token to record for this VirtualDisplay. Fall back to
- // Display stack capture for the entire display.
+ // Fall back to screenrecording using the data sent to DisplayManager
mDisplayContent.mWmService.mDisplayManagerInternal.setWindowManagerMirroring(
mDisplayContent.getDisplayId(), false);
handleStartRecordingFailed();
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index b54cd41..cb486d4 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -6366,11 +6366,73 @@
}
/**
+ * This is to enable mirroring on virtual displays that specify the
+ * {@link android.hardware.display.DisplayManager#VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR} but don't
+ * mirror using MediaProjection. When done through MediaProjection API, the
+ * ContentRecordingSession will be created automatically.
+ *
+ * This should only be called when there's no ContentRecordingSession already set for this
+ * display. The code will ask DMS if this display should enable display mirroring and which
+ * displayId to mirror from.
+ *
+ * @return true if the {@link ContentRecordingSession} was set for display mirroring using data
+ * from DMS, false if there was no ContentRecordingSession created.
+ */
+ boolean setDisplayMirroring() {
+ int mirrorDisplayId = mWmService.mDisplayManagerInternal.getDisplayIdToMirror(mDisplayId);
+ if (mirrorDisplayId == INVALID_DISPLAY) {
+ return false;
+ }
+
+ if (mirrorDisplayId == mDisplayId) {
+ if (mDisplayId != DEFAULT_DISPLAY) {
+ ProtoLog.w(WM_DEBUG_CONTENT_RECORDING,
+ "Attempting to mirror self on %d", mirrorDisplayId);
+ }
+ return false;
+ }
+
+ // This is very unlikely, and probably impossible, but if the current display is
+ // DEFAULT_DISPLAY and the displayId to mirror results in an invalid display, we don't want
+ // to mirror the DEFAULT_DISPLAY so instead we just return
+ DisplayContent mirrorDc = mRootWindowContainer.getDisplayContentOrCreate(mirrorDisplayId);
+ if (mirrorDc == null && mDisplayId == DEFAULT_DISPLAY) {
+ ProtoLog.w(WM_DEBUG_CONTENT_RECORDING, "Found no matching mirror display for id=%d for"
+ + " DEFAULT_DISPLAY. Nothing to mirror.", mirrorDisplayId);
+ return false;
+ }
+
+ if (mirrorDc == null) {
+ mirrorDc = mRootWindowContainer.getDefaultDisplay();
+ ProtoLog.w(WM_DEBUG_CONTENT_RECORDING,
+ "Attempting to mirror %d from %d but no DisplayContent associated. Changing "
+ + "to mirror default display.",
+ mirrorDisplayId, mDisplayId);
+ }
+
+ ContentRecordingSession session = ContentRecordingSession
+ .createDisplaySession(mirrorDc.getDisplayUiContext().getWindowContextToken())
+ .setDisplayId(mDisplayId);
+ setContentRecordingSession(session);
+ ProtoLog.v(WM_DEBUG_CONTENT_RECORDING,
+ "Successfully created a ContentRecordingSession for displayId=%d to mirror "
+ + "content from displayId=%d",
+ mDisplayId, mirrorDisplayId);
+ return true;
+ }
+
+ /**
* Start recording if this DisplayContent no longer has content. Stop recording if it now
* has content or the display is not on.
*/
@VisibleForTesting void updateRecording() {
- getContentRecorder().updateRecording();
+ if (mContentRecorder == null || !mContentRecorder.isContentRecordingSessionSet()) {
+ if (!setDisplayMirroring()) {
+ return;
+ }
+ }
+
+ mContentRecorder.updateRecording();
}
/**
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 c11e2b0..3eb1dea 100644
--- a/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java
@@ -17,6 +17,7 @@
package com.android.server.display;
import static android.Manifest.permission.ADD_TRUSTED_DISPLAY;
+import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY;
import static com.android.server.display.VirtualDisplayAdapter.UNIQUE_ID_PREFIX;
@@ -577,6 +578,7 @@
// This is effectively the DisplayManager service published to ServiceManager.
DisplayManagerService.BinderService binderService = displayManager.new BinderService();
+ DisplayManagerService.LocalService localDisplayManager = displayManager.new LocalService();
final String uniqueId = "uniqueId --- displayIdToMirrorTest";
final int width = 600;
@@ -606,12 +608,58 @@
displayManager.getDisplayHandler().runWithScissors(() -> {}, 0 /* now */);
// The displayId to mirror should be a default display if there is none initially.
- assertEquals(displayManager.getDisplayIdToMirrorInternal(firstDisplayId),
+ assertEquals(localDisplayManager.getDisplayIdToMirror(firstDisplayId),
Display.DEFAULT_DISPLAY);
- assertEquals(displayManager.getDisplayIdToMirrorInternal(secondDisplayId),
+ assertEquals(localDisplayManager.getDisplayIdToMirror(secondDisplayId),
firstDisplayId);
}
+ @Test
+ public void testGetDisplayIdToMirror() throws Exception {
+ DisplayManagerService displayManager = new DisplayManagerService(mContext, mBasicInjector);
+ registerDefaultDisplays(displayManager);
+
+ // This is effectively the DisplayManager service published to ServiceManager.
+ DisplayManagerService.BinderService binderService = displayManager.new BinderService();
+ DisplayManagerService.LocalService localDisplayManager = displayManager.new LocalService();
+
+ final String uniqueId = "uniqueId --- displayIdToMirrorTest";
+ final int width = 600;
+ final int height = 800;
+ final int dpi = 320;
+
+ when(mMockAppToken.asBinder()).thenReturn(mMockAppToken);
+ final VirtualDisplayConfig.Builder builder = new VirtualDisplayConfig.Builder(
+ VIRTUAL_DISPLAY_NAME, width, height, dpi)
+ .setUniqueId(uniqueId)
+ .setFlags(VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY);
+ final int firstDisplayId = binderService.createVirtualDisplay(builder.build(),
+ mMockAppToken /* callback */, null /* projection */, PACKAGE_NAME);
+
+ // The second virtual display requests to mirror the first virtual display.
+ final String uniqueId2 = "uniqueId --- displayIdToMirrorTest #2";
+ when(mMockAppToken2.asBinder()).thenReturn(mMockAppToken2);
+ final VirtualDisplayConfig.Builder builder2 = new VirtualDisplayConfig.Builder(
+ VIRTUAL_DISPLAY_NAME, width, height, dpi)
+ .setUniqueId(uniqueId2)
+ .setWindowManagerMirroring(true);
+ final int secondDisplayId = binderService.createVirtualDisplay(builder2.build(),
+ mMockAppToken2 /* callback */, null /* projection */,
+ PACKAGE_NAME);
+ displayManager.performTraversalInternal(mock(SurfaceControl.Transaction.class));
+
+ // flush the handler
+ displayManager.getDisplayHandler().runWithScissors(() -> {}, 0 /* now */);
+
+ // The displayId to mirror should be a invalid since the display had flag OWN_CONTENT_ONLY
+ assertEquals(localDisplayManager.getDisplayIdToMirror(firstDisplayId),
+ Display.INVALID_DISPLAY);
+ // The second display has mirroring managed by WindowManager so the mirror displayId should
+ // be invalid.
+ assertEquals(localDisplayManager.getDisplayIdToMirror(secondDisplayId),
+ Display.INVALID_DISPLAY);
+ }
+
/**
* Tests that the virtual display is created with
* {@link VirtualDisplayConfig.Builder#setSurface(Surface)}
diff --git a/services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java b/services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java
index c5117bb..69ba8ad 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java
@@ -19,6 +19,7 @@
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR;
+import static android.view.Display.INVALID_DISPLAY;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
@@ -85,6 +86,8 @@
mDefaultDisplay.getDefaultTaskDisplayArea().getBounds().height());
mRecordedSurface = surfaceControlMirrors(sSurfaceSize);
+ doReturn(INVALID_DISPLAY).when(mWm.mDisplayManagerInternal).getDisplayIdToMirror(anyInt());
+
// GIVEN the VirtualDisplay associated with the session (so the display has state ON).
VirtualDisplay virtualDisplay = mWm.mDisplayManager.createVirtualDisplay("VirtualDisplay",
sSurfaceSize.x, sSurfaceSize.y,
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
index 641a3ad..2cf9c01 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -31,6 +31,7 @@
import static android.os.Build.VERSION_CODES.Q;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.FLAG_PRIVATE;
+import static android.view.Display.INVALID_DISPLAY;
import static android.view.DisplayCutout.BOUNDS_POSITION_TOP;
import static android.view.DisplayCutout.fromBoundingRect;
import static android.view.InsetsState.ITYPE_IME;
@@ -2588,6 +2589,43 @@
display.release();
}
+ @Test
+ public void testVirtualDisplayContent_displayMirroring() {
+ // 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);
+ // Initially disable getDisplayIdToMirror since the DMS may create the DC outside the direct
+ // call in the test. We need to spy on the DC before updateRecording is called or we can't
+ // verify setDisplayMirroring is called
+ doReturn(INVALID_DISPLAY).when(mWm.mDisplayManagerInternal).getDisplayIdToMirror(anyInt());
+
+ // GIVEN a new VirtualDisplay with an associated surface.
+ final VirtualDisplay display = createVirtualDisplay(surfaceSize, new Surface());
+ final int displayId = display.getDisplay().getDisplayId();
+
+ // GIVEN a session for this display.
+ mWm.mRoot.onDisplayAdded(displayId);
+
+ // WHEN getting the DisplayContent for the new virtual display.
+ DisplayContent actualDC = mWm.mRoot.getDisplayContent(displayId);
+ spyOn(actualDC);
+ // Return the default display as the value to mirror to ensure the VD with flag mirroring
+ // creates a ContentRecordingSession automatically.
+ doReturn(DEFAULT_DISPLAY).when(mWm.mDisplayManagerInternal).getDisplayIdToMirror(anyInt());
+ actualDC.updateRecording();
+
+ // THEN mirroring is initiated for the default display's DisplayArea.
+ verify(actualDC).setDisplayMirroring();
+ assertThat(actualDC.isCurrentlyRecording()).isTrue();
+ display.release();
+ }
+
private static class MirroringTestToken extends Binder {
}