diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java
index 4c81f9cd38081..00374644d72c1 100644
--- a/core/java/android/hardware/display/DisplayManager.java
+++ b/core/java/android/hardware/display/DisplayManager.java
@@ -30,6 +30,7 @@ import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.annotation.TestApi;
import android.app.KeyguardManager;
+import android.companion.virtual.IVirtualDevice;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.content.res.Resources;
@@ -902,8 +903,16 @@ public final class DisplayManager {
@NonNull VirtualDisplayConfig virtualDisplayConfig,
@Nullable VirtualDisplay.Callback callback, @Nullable Handler handler,
@Nullable Context windowContext) {
- return mGlobal.createVirtualDisplay(mContext, projection, virtualDisplayConfig, callback,
- handler, windowContext);
+ return mGlobal.createVirtualDisplay(mContext, projection, null /* virtualDevice */,
+ virtualDisplayConfig, callback, handler, windowContext);
+ }
+
+ /** @hide */
+ public VirtualDisplay createVirtualDisplay(@Nullable IVirtualDevice virtualDevice,
+ @NonNull VirtualDisplayConfig virtualDisplayConfig,
+ @Nullable VirtualDisplay.Callback callback, @Nullable Handler handler) {
+ return mGlobal.createVirtualDisplay(mContext, null /* projection */, virtualDevice,
+ virtualDisplayConfig, callback, handler, null);
}
/**
diff --git a/core/java/android/hardware/display/DisplayManagerGlobal.java b/core/java/android/hardware/display/DisplayManagerGlobal.java
index 75155bbab0c88..01833fda5b95f 100644
--- a/core/java/android/hardware/display/DisplayManagerGlobal.java
+++ b/core/java/android/hardware/display/DisplayManagerGlobal.java
@@ -24,6 +24,7 @@ import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.PropertyInvalidatedCache;
+import android.companion.virtual.IVirtualDevice;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.content.pm.ParceledListSlice;
@@ -582,14 +583,14 @@ public final class DisplayManagerGlobal {
}
public VirtualDisplay createVirtualDisplay(@NonNull Context context, MediaProjection projection,
- @NonNull VirtualDisplayConfig virtualDisplayConfig, VirtualDisplay.Callback callback,
- Handler handler, @Nullable Context windowContext) {
+ IVirtualDevice virtualDevice, @NonNull VirtualDisplayConfig virtualDisplayConfig,
+ VirtualDisplay.Callback callback, Handler handler, @Nullable Context windowContext) {
VirtualDisplayCallback callbackWrapper = new VirtualDisplayCallback(callback, handler);
IMediaProjection projectionToken = projection != null ? projection.getProjection() : null;
int displayId;
try {
displayId = mDm.createVirtualDisplay(virtualDisplayConfig, callbackWrapper,
- projectionToken, context.getPackageName());
+ projectionToken, virtualDevice, context.getPackageName());
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
diff --git a/core/java/android/hardware/display/DisplayManagerInternal.java b/core/java/android/hardware/display/DisplayManagerInternal.java
index 2985c754ac45f..83e1061d81436 100644
--- a/core/java/android/hardware/display/DisplayManagerInternal.java
+++ b/core/java/android/hardware/display/DisplayManagerInternal.java
@@ -20,7 +20,6 @@ import android.annotation.IntDef;
import android.annotation.Nullable;
import android.graphics.Point;
import android.hardware.SensorManager;
-import android.media.projection.IMediaProjection;
import android.os.Handler;
import android.os.IBinder;
import android.os.PowerManager;
@@ -380,31 +379,6 @@ public abstract class DisplayManagerInternal {
*/
public abstract void onEarlyInteractivityChange(boolean interactive);
- /**
- * A special API for creates a virtual display with a DisplayPolicyController in system_server.
- *
- * If this method is called without original calling uid, the caller must enforce the
- * corresponding permissions according to the flags.
- * {@link android.Manifest.permission#CAPTURE_VIDEO_OUTPUT}
- * {@link android.Manifest.permission#CAPTURE_SECURE_VIDEO_OUTPUT}
- * {@link android.Manifest.permission#ADD_TRUSTED_DISPLAY}
- * {@link android.Manifest.permission#INTERNAL_SYSTEM_WINDOW}
- *
- *
- * @param virtualDisplayConfig The arguments for the virtual display configuration. See
- * {@link VirtualDisplayConfig} for using it.
- * @param callback Callback to call when the virtual display's state changes, or null if none.
- * @param projection MediaProjection token.
- * @param packageName The package name of the app.
- * @param controller The DisplayWindowPolicyControl that can control what contents are
- * allowed to be displayed.
- * @return The newly created virtual display id , or {@link Display#INVALID_DISPLAY} if the
- * virtual display cannot be created.
- */
- public abstract int createVirtualDisplay(VirtualDisplayConfig virtualDisplayConfig,
- IVirtualDisplayCallback callback, IMediaProjection projection, String packageName,
- DisplayWindowPolicyController controller);
-
/**
* Get {@link DisplayWindowPolicyController} associated to the {@link DisplayInfo#displayId}
*
diff --git a/core/java/android/hardware/display/IDisplayManager.aidl b/core/java/android/hardware/display/IDisplayManager.aidl
index 0d5f1af727ae8..82b31d48d5feb 100644
--- a/core/java/android/hardware/display/IDisplayManager.aidl
+++ b/core/java/android/hardware/display/IDisplayManager.aidl
@@ -16,6 +16,7 @@
package android.hardware.display;
+import android.companion.virtual.IVirtualDevice;
import android.content.pm.ParceledListSlice;
import android.graphics.Point;
import android.hardware.display.BrightnessConfiguration;
@@ -86,10 +87,10 @@ interface IDisplayManager {
void requestColorMode(int displayId, int colorMode);
// Requires CAPTURE_VIDEO_OUTPUT, CAPTURE_SECURE_VIDEO_OUTPUT, or an appropriate
- // MediaProjection token for certain combinations of flags.
+ // MediaProjection token or VirtualDevice for certain combinations of flags.
int createVirtualDisplay(in VirtualDisplayConfig virtualDisplayConfig,
in IVirtualDisplayCallback callback, in IMediaProjection projectionToken,
- String packageName);
+ in IVirtualDevice virtualDevice, String packageName);
// No permissions required, but must be same Uid as the creator.
void resizeVirtualDisplay(in IVirtualDisplayCallback token,
diff --git a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java
index 8592c05d9ea57..020d08f77642b 100644
--- a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java
@@ -31,6 +31,7 @@ import android.os.RemoteException;
import android.util.ExceptionUtils;
import android.util.Slog;
import android.util.SparseArray;
+import android.window.DisplayWindowPolicyController;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.DumpUtils;
@@ -38,11 +39,11 @@ import com.android.server.SystemService;
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
-/** @hide */
@SuppressLint("LongLogTag")
public class VirtualDeviceManagerService extends SystemService {
@@ -84,6 +85,15 @@ public class VirtualDeviceManagerService extends SystemService {
publishLocalService(VirtualDeviceManagerInternal.class, new LocalService());
}
+ @GuardedBy("mVirtualDeviceManagerLock")
+ private boolean isValidVirtualDeviceLocked(IVirtualDevice virtualDevice) {
+ try {
+ return mVirtualDevices.contains(virtualDevice.getAssociationId());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
@Override
public void onUserStarting(@NonNull TargetUser user) {
super.onUserStarting(user);
@@ -121,6 +131,7 @@ public class VirtualDeviceManagerService extends SystemService {
private final AssociationInfo mAssociationInfo;
private final int mOwnerUid;
+ private final ArrayList mDisplayIds = new ArrayList<>();
private VirtualDeviceImpl(int ownerUid, IBinder token, AssociationInfo associationInfo) {
mOwnerUid = ownerUid;
@@ -149,6 +160,24 @@ public class VirtualDeviceManagerService extends SystemService {
public void binderDied() {
close();
}
+
+ DisplayWindowPolicyController onVirtualDisplayCreatedLocked(int displayId) {
+ if (mDisplayIds.contains(displayId)) {
+ throw new IllegalStateException(
+ "Virtual device already have a virtual display with ID " + displayId);
+ }
+ mDisplayIds.add(displayId);
+ // TODO(b/201712607): Return the corresponding DisplayWindowPolicyController.
+ return null;
+ }
+
+ void onVirtualDisplayRemovedLocked(int displayId) {
+ if (!mDisplayIds.contains(displayId)) {
+ throw new IllegalStateException(
+ "Virtual device doesn't have a virtual display with ID " + displayId);
+ }
+ mDisplayIds.remove(displayId);
+ }
}
class VirtualDeviceManagerImpl extends IVirtualDeviceManager.Stub {
@@ -229,6 +258,28 @@ public class VirtualDeviceManagerService extends SystemService {
private final class LocalService extends VirtualDeviceManagerInternal {
+ @Override
+ public boolean isValidVirtualDevice(IVirtualDevice virtualDevice) {
+ synchronized (mVirtualDeviceManagerLock) {
+ return isValidVirtualDeviceLocked(virtualDevice);
+ }
+ }
+
+ @Override
+ public DisplayWindowPolicyController onVirtualDisplayCreated(IVirtualDevice virtualDevice,
+ int displayId) {
+ synchronized (mVirtualDeviceManagerLock) {
+ return ((VirtualDeviceImpl) virtualDevice).onVirtualDisplayCreatedLocked(displayId);
+ }
+ }
+
+ @Override
+ public void onVirtualDisplayRemoved(IVirtualDevice virtualDevice, int displayId) {
+ synchronized (mVirtualDeviceManagerLock) {
+ ((VirtualDeviceImpl) virtualDevice).onVirtualDisplayRemovedLocked(displayId);
+ }
+ }
+
@Override
public boolean isAppOwnerOfAnyVirtualDevice(int uid) {
synchronized (mVirtualDeviceManagerLock) {
diff --git a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerInternal.java b/services/core/java/com/android/server/companion/virtual/VirtualDeviceManagerInternal.java
similarity index 55%
rename from services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerInternal.java
rename to services/core/java/com/android/server/companion/virtual/VirtualDeviceManagerInternal.java
index ee09832dc7e23..39fa3f200aab0 100644
--- a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerInternal.java
+++ b/services/core/java/com/android/server/companion/virtual/VirtualDeviceManagerInternal.java
@@ -16,11 +16,39 @@
package com.android.server.companion.virtual;
+import android.companion.virtual.IVirtualDevice;
+import android.window.DisplayWindowPolicyController;
+
/**
* Virtual device manager local service interface.
+ * Only for use within system server.
*/
public abstract class VirtualDeviceManagerInternal {
+ /**
+ * Validate the virtual device.
+ */
+ public abstract boolean isValidVirtualDevice(IVirtualDevice virtualDevice);
+
+ /**
+ * Notify a virtual display is created.
+ *
+ * @param virtualDevice The virtual device where the virtual display located.
+ * @param displayId The display id of the created virtual display.
+ *
+ * @return The {@link DisplayWindowPolicyController} of the virtual device.
+ */
+ public abstract DisplayWindowPolicyController onVirtualDisplayCreated(
+ IVirtualDevice virtualDevice, int displayId);
+
+ /**
+ * Notify a virtual display is removed.
+ *
+ * @param virtualDevice The virtual device where the virtual display located.
+ * @param displayId The display id of the removed virtual display.
+ */
+ public abstract void onVirtualDisplayRemoved(IVirtualDevice virtualDevice, int displayId);
+
/**
* Returns true if the given {@code uid} is the owner of any virtual devices that are
* currently active.
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index 77ab81301059e..3f55848e26a85 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -42,6 +42,7 @@ import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.app.AppOpsManager;
import android.app.compat.CompatChanges;
+import android.companion.virtual.IVirtualDevice;
import android.compat.annotation.ChangeId;
import android.compat.annotation.EnabledSince;
import android.content.Context;
@@ -126,6 +127,7 @@ import com.android.server.DisplayThread;
import com.android.server.LocalServices;
import com.android.server.SystemService;
import com.android.server.UiThread;
+import com.android.server.companion.virtual.VirtualDeviceManagerInternal;
import com.android.server.display.DisplayDeviceConfig.SensorData;
import com.android.server.display.utils.SensorUtils;
import com.android.server.wm.SurfaceAnimationThread;
@@ -244,9 +246,12 @@ public final class DisplayManagerService extends SystemService {
public final SparseArray mCallbacks =
new SparseArray();
- /** All {@link DisplayWindowPolicyController}s indexed by {@link DisplayInfo#displayId}. */
- final SparseArray mDisplayWindowPolicyController =
- new SparseArray<>();
+ /**
+ * All {@link IVirtualDevice} and {@link DisplayWindowPolicyController}s indexed by
+ * {@link DisplayInfo#displayId}.
+ */
+ final SparseArray>
+ mDisplayWindowPolicyControllers = new SparseArray<>();
// List of all currently registered display adapters.
private final ArrayList mDisplayAdapters = new ArrayList();
@@ -1180,8 +1185,8 @@ public final class DisplayManagerService extends SystemService {
}
private int createVirtualDisplayInternal(VirtualDisplayConfig virtualDisplayConfig,
- IVirtualDisplayCallback callback, IMediaProjection projection, String packageName,
- DisplayWindowPolicyController controller) {
+ IVirtualDisplayCallback callback, IMediaProjection projection,
+ IVirtualDevice virtualDevice, String packageName) {
final int callingUid = Binder.getCallingUid();
if (!validatePackageName(callingUid, packageName)) {
throw new SecurityException("packageName must match the calling uid");
@@ -1226,6 +1231,14 @@ public final class DisplayManagerService extends SystemService {
}
}
+ if (virtualDevice != null) {
+ final VirtualDeviceManagerInternal vdm =
+ getLocalService(VirtualDeviceManagerInternal.class);
+ if (!vdm.isValidVirtualDevice(virtualDevice)) {
+ throw new SecurityException("Invalid virtual device");
+ }
+ }
+
if (callingUid != Process.SYSTEM_UID
&& (flags & VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR) != 0) {
if (!canProjectVideo(projection)) {
@@ -1306,8 +1319,8 @@ public final class DisplayManagerService extends SystemService {
final long token = Binder.clearCallingIdentity();
try {
synchronized (mSyncRoot) {
- return createVirtualDisplayLocked(callback, projection, callingUid, packageName,
- surface, flags, virtualDisplayConfig, controller);
+ return createVirtualDisplayLocked(callback, projection, virtualDevice, callingUid,
+ packageName, surface, flags, virtualDisplayConfig);
}
} finally {
Binder.restoreCallingIdentity(token);
@@ -1315,9 +1328,9 @@ public final class DisplayManagerService extends SystemService {
}
private int createVirtualDisplayLocked(IVirtualDisplayCallback callback,
- IMediaProjection projection, int callingUid, String packageName, Surface surface,
- int flags, VirtualDisplayConfig virtualDisplayConfig,
- DisplayWindowPolicyController controller) {
+ IMediaProjection projection, IVirtualDevice virtualDevice,
+ int callingUid, String packageName, Surface surface,
+ int flags, VirtualDisplayConfig virtualDisplayConfig) {
if (mVirtualDisplayAdapter == null) {
Slog.w(TAG, "Rejecting request to create private virtual display "
+ "because the virtual display adapter is not available.");
@@ -1344,10 +1357,16 @@ public final class DisplayManagerService extends SystemService {
final LogicalDisplay display = mLogicalDisplayMapper.getDisplayLocked(device);
if (display != null) {
- if (controller != null) {
- mDisplayWindowPolicyController.put(display.getDisplayIdLocked(), controller);
+ final int displayId = display.getDisplayIdLocked();
+ if (virtualDevice != null) {
+ final VirtualDeviceManagerInternal vdm =
+ getLocalService(VirtualDeviceManagerInternal.class);
+ final DisplayWindowPolicyController controller =
+ vdm.onVirtualDisplayCreated(virtualDevice, displayId);
+ mDisplayWindowPolicyControllers.put(displayId,
+ Pair.create(virtualDevice, controller));
}
- return display.getDisplayIdLocked();
+ return displayId;
}
// Something weird happened and the logical display was not created.
@@ -1391,7 +1410,13 @@ public final class DisplayManagerService extends SystemService {
if (device != null) {
final LogicalDisplay display = mLogicalDisplayMapper.getDisplayLocked(device);
if (display != null) {
- mDisplayWindowPolicyController.delete(display.getDisplayIdLocked());
+ final int displayId = display.getDisplayIdLocked();
+ if (mDisplayWindowPolicyControllers.contains(displayId)) {
+ Pair pair =
+ mDisplayWindowPolicyControllers.removeReturnOld(displayId);
+ getLocalService(VirtualDeviceManagerInternal.class)
+ .onVirtualDisplayRemoved(pair.first, displayId);
+ }
}
// TODO: multi-display - handle virtual displays the same as other display adapters.
mDisplayDeviceRepo.onDisplayDeviceEvent(device,
@@ -2345,13 +2370,13 @@ public final class DisplayManagerService extends SystemService {
pw.println();
mPersistentDataStore.dump(pw);
- final int displayWindowPolicyControllerCount = mDisplayWindowPolicyController.size();
+ final int displayWindowPolicyControllerCount = mDisplayWindowPolicyControllers.size();
pw.println();
pw.println("Display Window Policy Controllers: size="
+ displayWindowPolicyControllerCount);
for (int i = 0; i < displayWindowPolicyControllerCount; i++) {
- pw.print("Display " + mDisplayWindowPolicyController.keyAt(i) + ":");
- mDisplayWindowPolicyController.valueAt(i).dump(" ", pw);
+ pw.print("Display " + mDisplayWindowPolicyControllers.keyAt(i) + ":");
+ mDisplayWindowPolicyControllers.valueAt(i).second.dump(" ", pw);
}
}
pw.println();
@@ -2922,9 +2947,10 @@ public final class DisplayManagerService extends SystemService {
@Override // Binder call
public int createVirtualDisplay(VirtualDisplayConfig virtualDisplayConfig,
- IVirtualDisplayCallback callback, IMediaProjection projection, String packageName) {
+ IVirtualDisplayCallback callback, IMediaProjection projection,
+ IVirtualDevice virtualDeviceToken, String packageName) {
return createVirtualDisplayInternal(virtualDisplayConfig, callback, projection,
- packageName, null /* controller */);
+ virtualDeviceToken, packageName);
}
@Override // Binder call
@@ -3689,18 +3715,13 @@ public final class DisplayManagerService extends SystemService {
mLogicalDisplayMapper.onEarlyInteractivityChange(interactive);
}
- @Override
- public int createVirtualDisplay(VirtualDisplayConfig virtualDisplayConfig,
- IVirtualDisplayCallback callback, IMediaProjection projection, String packageName,
- DisplayWindowPolicyController controller) {
- return createVirtualDisplayInternal(virtualDisplayConfig, callback, projection,
- packageName, controller);
- }
-
@Override
public DisplayWindowPolicyController getDisplayWindowPolicyController(int displayId) {
synchronized (mSyncRoot) {
- return mDisplayWindowPolicyController.get(displayId);
+ if (mDisplayWindowPolicyControllers.contains(displayId)) {
+ return mDisplayWindowPolicyControllers.get(displayId).second;
+ }
+ return null;
}
}
}
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 68e90fbadd0c3..eaa271a22725d 100644
--- a/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java
@@ -219,7 +219,7 @@ public class DisplayManagerServiceTest {
builder.setUniqueId(uniqueId);
builder.setFlags(flags);
int displayId = bs.createVirtualDisplay(builder.build(), mMockAppToken /* callback */,
- null /* projection */, PACKAGE_NAME);
+ null /* projection */, null /* virtualDeviceToken */, PACKAGE_NAME);
displayManager.performTraversalInternal(mock(SurfaceControl.Transaction.class));
@@ -341,7 +341,7 @@ public class DisplayManagerServiceTest {
builder.setFlags(flags);
builder.setUniqueId(uniqueId);
int displayId = bs.createVirtualDisplay(builder.build(), mMockAppToken /* callback */,
- null /* projection */, PACKAGE_NAME);
+ null /* projection */, null /* virtualDeviceToken */, PACKAGE_NAME);
displayManager.performTraversalInternal(mock(SurfaceControl.Transaction.class));
@@ -580,7 +580,8 @@ public class DisplayManagerServiceTest {
VIRTUAL_DISPLAY_NAME, width, height, dpi);
builder.setUniqueId(uniqueId);
final int firstDisplayId = binderService.createVirtualDisplay(builder.build(),
- mMockAppToken /* callback */, null /* projection */, PACKAGE_NAME);
+ mMockAppToken /* callback */, null /* projection */, null /* virtualDeviceToken */,
+ PACKAGE_NAME);
// The second virtual display requests to mirror the first virtual display.
final String uniqueId2 = "uniqueId --- displayIdToMirrorTest #2";
@@ -590,7 +591,8 @@ public class DisplayManagerServiceTest {
builder2.setUniqueId(uniqueId2);
builder2.setDisplayIdToMirror(firstDisplayId);
final int secondDisplayId = binderService.createVirtualDisplay(builder2.build(),
- mMockAppToken2 /* callback */, null /* projection */, PACKAGE_NAME);
+ mMockAppToken2 /* callback */, null /* projection */,
+ null /* virtualDeviceToken */, PACKAGE_NAME);
displayManager.performTraversalInternal(mock(SurfaceControl.Transaction.class));
// flush the handler
@@ -628,7 +630,8 @@ public class DisplayManagerServiceTest {
builder.setSurface(surface);
builder.setUniqueId(uniqueId);
final int displayId = binderService.createVirtualDisplay(builder.build(),
- mMockAppToken /* callback */, null /* projection */, PACKAGE_NAME);
+ mMockAppToken /* callback */, null /* projection */, null /* virtualDeviceToken */,
+ PACKAGE_NAME);
displayManager.performTraversalInternal(mock(SurfaceControl.Transaction.class));
@@ -1108,7 +1111,7 @@ public class DisplayManagerServiceTest {
builder.setUniqueId(uniqueId);
int displayId = bs.createVirtualDisplay(builder.build(), mMockAppToken /* callback */,
- null /* projection */, PACKAGE_NAME);
+ null /* projection */, null /* virtualDeviceToken */, PACKAGE_NAME);
displayManager.performTraversalInternal(mock(SurfaceControl.Transaction.class));
displayManager.getDisplayHandler().runWithScissors(() -> {}, 0 /* now */);
DisplayDeviceInfo ddi = displayManager.getDisplayDeviceInfoInternal(displayId);