summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java174
-rw-r--r--services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java13
-rw-r--r--services/core/java/com/android/server/companion/virtual/VirtualDeviceManagerInternal.java13
-rw-r--r--services/core/java/com/android/server/display/DisplayManagerService.java12
-rw-r--r--services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java33
5 files changed, 166 insertions, 79 deletions
diff --git a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
index b75728e9f97c..f03e8c713228 100644
--- a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
+++ b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
@@ -110,6 +110,7 @@ import android.util.SparseIntArray;
import android.view.Display;
import android.view.WindowManager;
import android.widget.Toast;
+import android.window.DisplayWindowPolicyController;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
@@ -1411,8 +1412,7 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
return mirroredDisplayId == Display.INVALID_DISPLAY ? displayId : mirroredDisplayId;
}
- @GuardedBy("mVirtualDeviceLock")
- private GenericWindowPolicyController createWindowPolicyControllerLocked(
+ private GenericWindowPolicyController createWindowPolicyController(
@NonNull Set<String> displayCategories) {
final boolean activityLaunchAllowedByDefault =
getDevicePolicy(POLICY_TYPE_ACTIVITY) == DEVICE_POLICY_DEFAULT;
@@ -1421,28 +1421,28 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
final boolean showTasksInHostDeviceRecents =
getDevicePolicy(POLICY_TYPE_RECENTS) == DEVICE_POLICY_DEFAULT;
- if (mActivityListenerAdapter == null) {
- mActivityListenerAdapter = new GwpcActivityListener();
- }
-
- final GenericWindowPolicyController gwpc = new GenericWindowPolicyController(
- WindowManager.LayoutParams.FLAG_SECURE,
- WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS,
- mAttributionSource,
- getAllowedUserHandles(),
- activityLaunchAllowedByDefault,
- mActivityPolicyExemptions,
- mActivityPolicyPackageExemptions,
- crossTaskNavigationAllowedByDefault,
- /* crossTaskNavigationExemptions= */crossTaskNavigationAllowedByDefault
- ? mParams.getBlockedCrossTaskNavigations()
- : mParams.getAllowedCrossTaskNavigations(),
- mActivityListenerAdapter,
- displayCategories,
- showTasksInHostDeviceRecents,
- mParams.getHomeComponent());
- gwpc.registerRunningAppsChangedListener(/* listener= */ this);
- return gwpc;
+ synchronized (mVirtualDeviceLock) {
+ if (mActivityListenerAdapter == null) {
+ mActivityListenerAdapter = new GwpcActivityListener();
+ }
+
+ return new GenericWindowPolicyController(
+ WindowManager.LayoutParams.FLAG_SECURE,
+ WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS,
+ mAttributionSource,
+ getAllowedUserHandles(),
+ activityLaunchAllowedByDefault,
+ mActivityPolicyExemptions,
+ mActivityPolicyPackageExemptions,
+ crossTaskNavigationAllowedByDefault,
+ /* crossTaskNavigationExemptions= */crossTaskNavigationAllowedByDefault
+ ? mParams.getBlockedCrossTaskNavigations()
+ : mParams.getAllowedCrossTaskNavigations(),
+ mActivityListenerAdapter,
+ displayCategories,
+ showTasksInHostDeviceRecents,
+ mParams.getHomeComponent());
+ }
}
@Override // Binder call
@@ -1450,55 +1450,54 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
@NonNull IVirtualDisplayCallback callback) {
checkCallerIsDeviceOwner();
- int displayId;
- boolean showPointer;
- boolean isTrustedDisplay;
- GenericWindowPolicyController gwpc;
- synchronized (mVirtualDeviceLock) {
- gwpc = createWindowPolicyControllerLocked(virtualDisplayConfig.getDisplayCategories());
- displayId = mDisplayManagerInternal.createVirtualDisplay(virtualDisplayConfig,
+ final boolean isTrustedDisplay =
+ (virtualDisplayConfig.getFlags() & DisplayManager.VIRTUAL_DISPLAY_FLAG_TRUSTED)
+ == DisplayManager.VIRTUAL_DISPLAY_FLAG_TRUSTED;
+ if (!isTrustedDisplay && getDevicePolicy(POLICY_TYPE_CLIPBOARD) != DEVICE_POLICY_DEFAULT) {
+ throw new SecurityException(
+ "All displays must be trusted for devices with custom clipboard policy.");
+ }
+
+ GenericWindowPolicyController gwpc =
+ createWindowPolicyController(virtualDisplayConfig.getDisplayCategories());
+
+ // Create the display outside of the lock to avoid deadlock. DisplayManagerService will
+ // acquire the global WM lock while creating the display. At the same time, WM may query
+ // VDM and this virtual device to get policies, display ownership, etc.
+ int displayId = mDisplayManagerInternal.createVirtualDisplay(virtualDisplayConfig,
callback, this, gwpc, mOwnerPackageName);
- boolean isMirrorDisplay =
- mDisplayManagerInternal.getDisplayIdToMirror(displayId)
- != Display.INVALID_DISPLAY;
- gwpc.setDisplayId(displayId, isMirrorDisplay);
- isTrustedDisplay =
- (mDisplayManagerInternal.getDisplayInfo(displayId).flags & Display.FLAG_TRUSTED)
- == Display.FLAG_TRUSTED;
- if (!isTrustedDisplay
- && getDevicePolicy(POLICY_TYPE_CLIPBOARD) != DEVICE_POLICY_DEFAULT) {
- throw new SecurityException("All displays must be trusted for devices with "
- + "custom clipboard policy.");
- }
+ if (displayId == Display.INVALID_DISPLAY) {
+ return displayId;
+ }
- if (mVirtualDisplays.contains(displayId)) {
- gwpc.unregisterRunningAppsChangedListener(this);
- throw new IllegalStateException(
- "Virtual device already has a virtual display with ID " + displayId);
+ // DisplayManagerService will call onVirtualDisplayCreated() after the display is created,
+ // while holding its own lock to ensure that this device knows about the display before any
+ // other display listeners are notified about the display creation.
+ VirtualDisplayWrapper displayWrapper;
+ boolean showPointer;
+ synchronized (mVirtualDeviceLock) {
+ if (!mVirtualDisplays.contains(displayId)) {
+ throw new IllegalStateException("Virtual device was not notified about the "
+ + "creation of display with ID " + displayId);
}
-
- PowerManager.WakeLock wakeLock =
- isTrustedDisplay ? createAndAcquireWakeLockForDisplay(displayId) : null;
- mVirtualDisplays.put(displayId, new VirtualDisplayWrapper(callback, gwpc, wakeLock,
- isTrustedDisplay, isMirrorDisplay));
+ displayWrapper = mVirtualDisplays.get(displayId);
showPointer = mDefaultShowPointerIcon;
}
+ displayWrapper.acquireWakeLock();
+ gwpc.registerRunningAppsChangedListener(/* listener= */ this);
- final long token = Binder.clearCallingIdentity();
- try {
+ Binder.withCleanCallingIdentity(() -> {
mInputController.setMouseScalingEnabled(false, displayId);
mInputController.setDisplayEligibilityForPointerCapture(/* isEligible= */ false,
displayId);
- if (isTrustedDisplay) {
+ if (displayWrapper.isTrusted()) {
mInputController.setShowPointerIcon(showPointer, displayId);
mInputController.setDisplayImePolicy(displayId,
WindowManager.DISPLAY_IME_POLICY_LOCAL);
} else {
gwpc.setShowInHostDeviceRecents(true);
}
- } finally {
- Binder.restoreCallingIdentity(token);
- }
+ });
Counter.logIncrementWithUid(
"virtual_devices.value_virtual_display_created_count",
@@ -1506,7 +1505,7 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
return displayId;
}
- private PowerManager.WakeLock createAndAcquireWakeLockForDisplay(int displayId) {
+ private PowerManager.WakeLock createWakeLockForDisplay(int displayId) {
if (Flags.deviceAwareDisplayPower()) {
return null;
}
@@ -1516,7 +1515,6 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
PowerManager.WakeLock wakeLock = powerManager.newWakeLock(
PowerManager.SCREEN_BRIGHT_WAKE_LOCK,
TAG + ":" + displayId, displayId);
- wakeLock.acquire();
return wakeLock;
} finally {
Binder.restoreCallingIdentity(token);
@@ -1561,17 +1559,47 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
return result;
}
+ /**
+ * DisplayManagerService is notifying this virtual device about the display creation. This
+ * should happen before the DisplayManagerInternal#createVirtualDisplay() call above
+ * returns.
+ * This is called while holding the DisplayManagerService lock, so no heavy-weight work must
+ * be done here and especially *** no calls to WindowManager! ***
+ */
+ public void onVirtualDisplayCreated(int displayId, IVirtualDisplayCallback callback,
+ DisplayWindowPolicyController dwpc) {
+ final boolean isMirrorDisplay =
+ mDisplayManagerInternal.getDisplayIdToMirror(displayId) != Display.INVALID_DISPLAY;
+ final boolean isTrustedDisplay =
+ (mDisplayManagerInternal.getDisplayInfo(displayId).flags & Display.FLAG_TRUSTED)
+ == Display.FLAG_TRUSTED;
+
+ GenericWindowPolicyController gwpc = (GenericWindowPolicyController) dwpc;
+ gwpc.setDisplayId(displayId, isMirrorDisplay);
+ PowerManager.WakeLock wakeLock =
+ isTrustedDisplay ? createWakeLockForDisplay(displayId) : null;
+ synchronized (mVirtualDeviceLock) {
+ if (mVirtualDisplays.contains(displayId)) {
+ Slog.wtf(TAG, "Virtual device already has a virtual display with ID " + displayId);
+ return;
+ }
+ mVirtualDisplays.put(displayId, new VirtualDisplayWrapper(callback, gwpc, wakeLock,
+ isTrustedDisplay, isMirrorDisplay));
+ }
+ }
+
+ /**
+ * This is callback invoked by VirtualDeviceManagerService when VirtualDisplay was released
+ * by DisplayManager (most probably caused by someone calling VirtualDisplay.close()).
+ * At this point, the display is already released, but we still need to release the
+ * corresponding wakeLock and unregister the RunningAppsChangedListener from corresponding
+ * WindowPolicyController.
+ *
+ * Note that when the display is destroyed during VirtualDeviceImpl.close() call,
+ * this callback won't be invoked because the display is removed from
+ * VirtualDeviceManagerService before any resources are released.
+ */
void onVirtualDisplayRemoved(int displayId) {
- /* This is callback invoked by VirtualDeviceManagerService when VirtualDisplay was released
- * by DisplayManager (most probably caused by someone calling VirtualDisplay.close()).
- * At this point, the display is already released, but we still need to release the
- * corresponding wakeLock and unregister the RunningAppsChangedListener from corresponding
- * WindowPolicyController.
- *
- * Note that when the display is destroyed during VirtualDeviceImpl.close() call,
- * this callback won't be invoked because the display is removed from
- * VirtualDeviceManagerService before any resources are released.
- */
VirtualDisplayWrapper virtualDisplayWrapper;
synchronized (mVirtualDeviceLock) {
virtualDisplayWrapper = mVirtualDisplays.removeReturnOld(displayId);
@@ -1847,6 +1875,12 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
return mWindowPolicyController;
}
+ void acquireWakeLock() {
+ if (mWakeLock != null && !mWakeLock.isHeld()) {
+ mWakeLock.acquire();
+ }
+ }
+
void releaseWakeLock() {
if (mWakeLock != null && mWakeLock.isHeld()) {
mWakeLock.release();
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 8a0b85859b66..ff82ca00b840 100644
--- a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java
@@ -40,7 +40,6 @@ import android.companion.virtual.IVirtualDeviceSoundEffectListener;
import android.companion.virtual.VirtualDevice;
import android.companion.virtual.VirtualDeviceManager;
import android.companion.virtual.VirtualDeviceParams;
-import android.companion.virtual.flags.Flags;
import android.companion.virtual.sensor.VirtualSensor;
import android.companion.virtualnative.IVirtualDeviceManagerNative;
import android.compat.annotation.ChangeId;
@@ -49,6 +48,7 @@ import android.content.AttributionSource;
import android.content.Context;
import android.content.Intent;
import android.hardware.display.DisplayManagerInternal;
+import android.hardware.display.IVirtualDisplayCallback;
import android.os.Binder;
import android.os.Build;
import android.os.Handler;
@@ -67,6 +67,7 @@ import android.util.Slog;
import android.util.SparseArray;
import android.view.Display;
import android.widget.Toast;
+import android.window.DisplayWindowPolicyController;
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
@@ -751,6 +752,16 @@ public class VirtualDeviceManagerService extends SystemService {
}
@Override
+ public void onVirtualDisplayCreated(IVirtualDevice virtualDevice, int displayId,
+ IVirtualDisplayCallback callback, DisplayWindowPolicyController dwpc) {
+ VirtualDeviceImpl virtualDeviceImpl = getVirtualDeviceForId(
+ ((VirtualDeviceImpl) virtualDevice).getDeviceId());
+ if (virtualDeviceImpl != null) {
+ virtualDeviceImpl.onVirtualDisplayCreated(displayId, callback, dwpc);
+ }
+ }
+
+ @Override
public void onVirtualDisplayRemoved(IVirtualDevice virtualDevice, int displayId) {
VirtualDeviceImpl virtualDeviceImpl = getVirtualDeviceForId(
((VirtualDeviceImpl) virtualDevice).getDeviceId());
diff --git a/services/core/java/com/android/server/companion/virtual/VirtualDeviceManagerInternal.java b/services/core/java/com/android/server/companion/virtual/VirtualDeviceManagerInternal.java
index 471b7b4ddfc8..d412277d2605 100644
--- a/services/core/java/com/android/server/companion/virtual/VirtualDeviceManagerInternal.java
+++ b/services/core/java/com/android/server/companion/virtual/VirtualDeviceManagerInternal.java
@@ -24,8 +24,10 @@ import android.companion.virtual.VirtualDeviceManager;
import android.companion.virtual.VirtualDeviceParams;
import android.companion.virtual.sensor.VirtualSensor;
import android.content.Context;
+import android.hardware.display.IVirtualDisplayCallback;
import android.os.LocaleList;
import android.util.ArraySet;
+import android.window.DisplayWindowPolicyController;
import java.util.Set;
import java.util.function.Consumer;
@@ -104,6 +106,17 @@ public abstract class VirtualDeviceManagerInternal {
public abstract @NonNull ArraySet<Integer> getDeviceIdsForUid(int uid);
/**
+ * Notifies that a virtual display was created.
+ *
+ * @param virtualDevice The virtual device that owns the virtual display.
+ * @param displayId The display id of the created virtual display.
+ * @param callback The callback of the virtual display.
+ * @param dwpc The DisplayWindowPolicyController of the created virtual display.
+ */
+ public abstract void onVirtualDisplayCreated(IVirtualDevice virtualDevice, int displayId,
+ IVirtualDisplayCallback callback, DisplayWindowPolicyController dwpc);
+
+ /**
* Notifies that a virtual display is removed.
*
* @param virtualDevice The virtual device where the virtual display located.
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index e83efc573ea8..854b0dd7676b 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -2041,6 +2041,7 @@ public final class DisplayManagerService extends SystemService {
packageName,
displayUniqueId,
virtualDevice,
+ dwpc,
surface,
flags,
virtualDisplayConfig);
@@ -2135,6 +2136,7 @@ public final class DisplayManagerService extends SystemService {
String packageName,
String uniqueId,
IVirtualDevice virtualDevice,
+ DisplayWindowPolicyController dwpc,
Surface surface,
int flags,
VirtualDisplayConfig virtualDisplayConfig) {
@@ -2188,6 +2190,16 @@ public final class DisplayManagerService extends SystemService {
final LogicalDisplay display = mLogicalDisplayMapper.getDisplayLocked(device);
if (display != null) {
+ // Notify the virtual device that the display has been created. This needs to be called
+ // in this locked section before the repository had the chance to notify any listeners
+ // to ensure that the device is aware of the new display before others know about it.
+ if (virtualDevice != null) {
+ final VirtualDeviceManagerInternal vdm =
+ getLocalService(VirtualDeviceManagerInternal.class);
+ vdm.onVirtualDisplayCreated(
+ virtualDevice, display.getDisplayIdLocked(), callback, dwpc);
+ }
+
return display.getDisplayIdLocked();
}
diff --git a/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java
index ffcb96120b19..ab7b4da269db 100644
--- a/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java
@@ -73,6 +73,7 @@ import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.hardware.Sensor;
+import android.hardware.display.DisplayManager;
import android.hardware.display.DisplayManagerGlobal;
import android.hardware.display.DisplayManagerInternal;
import android.hardware.display.IDisplayManager;
@@ -173,8 +174,7 @@ public class VirtualDeviceManagerServiceTest {
private static final int FLAG_CANNOT_DISPLAY_ON_REMOTE_DEVICES = 0x00000;
private static final int VIRTUAL_DEVICE_ID_1 = 42;
private static final int VIRTUAL_DEVICE_ID_2 = 43;
- private static final VirtualDisplayConfig VIRTUAL_DISPLAY_CONFIG =
- new VirtualDisplayConfig.Builder("virtual_display", 640, 480, 400).build();
+
private static final VirtualDpadConfig DPAD_CONFIG =
new VirtualDpadConfig.Builder()
.setVendorId(VENDOR_ID)
@@ -284,7 +284,12 @@ public class VirtualDeviceManagerServiceTest {
private Intent createRestrictedActivityBlockedIntent(Set<String> displayCategories,
String targetDisplayCategory) {
when(mDisplayManagerInternalMock.createVirtualDisplay(any(), any(), any(), any(),
- eq(VIRTUAL_DEVICE_OWNER_PACKAGE))).thenReturn(DISPLAY_ID_1);
+ eq(VIRTUAL_DEVICE_OWNER_PACKAGE)))
+ .thenAnswer(inv -> {
+ mLocalService.onVirtualDisplayCreated(
+ mDeviceImpl, DISPLAY_ID_1, inv.getArgument(1), inv.getArgument(3));
+ return DISPLAY_ID_1;
+ });
VirtualDisplayConfig config = new VirtualDisplayConfig.Builder("display", 640, 480,
420).setDisplayCategories(displayCategories).build();
mDeviceImpl.createVirtualDisplay(config, mVirtualDisplayCallback);
@@ -997,8 +1002,7 @@ public class VirtualDeviceManagerServiceTest {
public void onVirtualDisplayCreatedLocked_duplicateCalls_onlyOneWakeLockIsAcquired()
throws RemoteException {
addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1, Display.FLAG_TRUSTED);
- assertThrows(IllegalStateException.class,
- () -> addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1));
+ addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1, Display.FLAG_TRUSTED);
TestableLooper.get(this).processAllMessages();
verify(mIPowerManagerMock).acquireWakeLock(any(Binder.class), anyInt(),
nullable(String.class), nullable(String.class), nullable(WorkSource.class),
@@ -1871,8 +1875,6 @@ public class VirtualDeviceManagerServiceTest {
}
private void addVirtualDisplay(VirtualDeviceImpl virtualDevice, int displayId, int flags) {
- when(mDisplayManagerInternalMock.createVirtualDisplay(any(), eq(mVirtualDisplayCallback),
- eq(virtualDevice), any(), any())).thenReturn(displayId);
final String uniqueId = UNIQUE_ID + displayId;
doAnswer(inv -> {
final DisplayInfo displayInfo = new DisplayInfo();
@@ -1880,7 +1882,22 @@ public class VirtualDeviceManagerServiceTest {
displayInfo.flags = flags;
return displayInfo;
}).when(mDisplayManagerInternalMock).getDisplayInfo(eq(displayId));
- virtualDevice.createVirtualDisplay(VIRTUAL_DISPLAY_CONFIG, mVirtualDisplayCallback);
+
+ when(mDisplayManagerInternalMock.createVirtualDisplay(any(), eq(mVirtualDisplayCallback),
+ eq(virtualDevice), any(), any())).thenAnswer(inv -> {
+ mLocalService.onVirtualDisplayCreated(
+ virtualDevice, displayId, mVirtualDisplayCallback, inv.getArgument(3));
+ return displayId;
+ });
+
+ final int virtualDisplayFlags = (flags & Display.FLAG_TRUSTED) == 0
+ ? 0
+ : DisplayManager.VIRTUAL_DISPLAY_FLAG_TRUSTED;
+ VirtualDisplayConfig virtualDisplayConfig =
+ new VirtualDisplayConfig.Builder("virtual_display", 640, 480, 400)
+ .setFlags(virtualDisplayFlags)
+ .build();
+ virtualDevice.createVirtualDisplay(virtualDisplayConfig, mVirtualDisplayCallback);
mInputManagerMockHelper.addDisplayIdMapping(uniqueId, displayId);
}