diff options
| author | 2023-02-13 17:10:25 +0100 | |
|---|---|---|
| committer | 2023-02-23 14:42:00 +0100 | |
| commit | 63ba140ca3d9c080e8cfdaf8a8ebfb46ea3f060a (patch) | |
| tree | 2eb7ce37a513fe55db2aff24fd6771269560058b | |
| parent | 04b798536555f9699a902370ecc3473656007d2d (diff) | |
Refactor virtual display creation and cleanup
* Consolidate all resources tied to display in newly added
VirtualDisplayWrapper data class.
* Simplify virtual display creation logic but moving all
business logic inside VirtualDeviceImpl.createVirtualDisplay
* Release all not-yet released displays when the virtual device
is closed.
* Fix locking issues (unnecessary holding of lock, vs missing locking).
* Fix deadlock caused by lock inversion when holding mVirtualDeviceLock during calls into mInputController / InputManagerInternal.
Bug: 267747549
Bug: 266567359
Test: atest VirtualDeviceManagerServiceTest
Test: atest CtsVirtualDevicesTestCases
Test: atest VirtualDisplayTest --iterations 30
Change-Id: Ie447bd1cee9356a6343ed38c35e13c8228d2464f
3 files changed, 406 insertions, 322 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 b4dcf43c2e1a..f650560e6b22 100644 --- a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java +++ b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java @@ -51,6 +51,10 @@ import android.content.IntentFilter; import android.content.pm.ActivityInfo; import android.graphics.PointF; import android.hardware.display.DisplayManager; +import android.hardware.display.DisplayManagerGlobal; +import android.hardware.display.DisplayManagerInternal; +import android.hardware.display.IVirtualDisplayCallback; +import android.hardware.display.VirtualDisplayConfig; import android.hardware.input.VirtualDpadConfig; import android.hardware.input.VirtualKeyEvent; import android.hardware.input.VirtualKeyboardConfig; @@ -82,6 +86,7 @@ import android.widget.Toast; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.BlockedAppStreamingActivity; +import com.android.server.LocalServices; import com.android.server.companion.virtual.GenericWindowPolicyController.RunningAppsChangedListener; import com.android.server.companion.virtual.audio.VirtualAudioController; @@ -109,21 +114,29 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub private final Context mContext; private final AssociationInfo mAssociationInfo; + private final VirtualDeviceManagerService mService; private final PendingTrampolineCallback mPendingTrampolineCallback; private final int mOwnerUid; private final int mDeviceId; + // Thou shall not hold the mVirtualDeviceLock over the mInputController calls. + // Holding the lock can lead to lock inversion with GlobalWindowManagerLock. + // 1. After display is created the window manager calls into VDM during construction + // of display specific context to fetch device id corresponding to the display. + // mVirtualDeviceLock will be held while this is done. + // 2. InputController interactions result in calls to DisplayManager (to set IME, + // possibly more indirect calls), and those attempt to lock GlobalWindowManagerLock which + // creates lock inversion. private final InputController mInputController; private final SensorController mSensorController; private final CameraAccessController mCameraAccessController; private VirtualAudioController mVirtualAudioController; - @VisibleForTesting - final ArraySet<Integer> mVirtualDisplayIds = new ArraySet<>(); - private final OnDeviceCloseListener mOnDeviceCloseListener; private final IBinder mAppToken; private final VirtualDeviceParams mParams; - private final Map<Integer, PowerManager.WakeLock> mPerDisplayWakelocks = new ArrayMap<>(); + @GuardedBy("mVirtualDeviceLock") + private final SparseArray<VirtualDisplayWrapper> mVirtualDisplays = new SparseArray<>(); private final IVirtualDeviceActivityListener mActivityListener; private final IVirtualDeviceSoundEffectListener mSoundEffectListener; + private final DisplayManagerGlobal mDisplayManager; @GuardedBy("mVirtualDeviceLock") private final Map<IBinder, IntentFilter> mIntentInterceptors = new ArrayMap<>(); @NonNull @@ -174,21 +187,14 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub }; } - /** - * A mapping from the virtual display ID to its corresponding - * {@link GenericWindowPolicyController}. - */ - private final SparseArray<GenericWindowPolicyController> mWindowPolicyControllers = - new SparseArray<>(); - VirtualDeviceImpl( Context context, AssociationInfo associationInfo, + VirtualDeviceManagerService service, IBinder token, int ownerUid, int deviceId, CameraAccessController cameraAccessController, - OnDeviceCloseListener onDeviceCloseListener, PendingTrampolineCallback pendingTrampolineCallback, IVirtualDeviceActivityListener activityListener, IVirtualDeviceSoundEffectListener soundEffectListener, @@ -197,40 +203,43 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub this( context, associationInfo, + service, token, ownerUid, deviceId, /* inputController= */ null, /* sensorController= */ null, cameraAccessController, - onDeviceCloseListener, pendingTrampolineCallback, activityListener, soundEffectListener, runningAppsChangedCallback, - params); + params, + DisplayManagerGlobal.getInstance()); } @VisibleForTesting VirtualDeviceImpl( Context context, AssociationInfo associationInfo, + VirtualDeviceManagerService service, IBinder token, int ownerUid, int deviceId, InputController inputController, SensorController sensorController, CameraAccessController cameraAccessController, - OnDeviceCloseListener onDeviceCloseListener, PendingTrampolineCallback pendingTrampolineCallback, IVirtualDeviceActivityListener activityListener, IVirtualDeviceSoundEffectListener soundEffectListener, Consumer<ArraySet<Integer>> runningAppsChangedCallback, - VirtualDeviceParams params) { + VirtualDeviceParams params, + DisplayManagerGlobal displayManager) { super(PermissionEnforcer.fromContext(context)); UserHandle ownerUserHandle = UserHandle.getUserHandleForUid(ownerUid); mContext = context.createContextAsUser(ownerUserHandle, 0); mAssociationInfo = associationInfo; + mService = service; mPendingTrampolineCallback = pendingTrampolineCallback; mActivityListener = activityListener; mSoundEffectListener = soundEffectListener; @@ -239,6 +248,7 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub mDeviceId = deviceId; mAppToken = token; mParams = params; + mDisplayManager = displayManager; if (inputController == null) { mInputController = new InputController( mVirtualDeviceLock, @@ -259,7 +269,6 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub } mCameraAccessController = cameraAccessController; mCameraAccessController.startObservingIfNeeded(); - mOnDeviceCloseListener = onDeviceCloseListener; try { token.linkToDeath(this, 0); } catch (RemoteException e) { @@ -331,9 +340,11 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub @Override // Binder call public void launchPendingIntent(int displayId, PendingIntent pendingIntent, ResultReceiver resultReceiver) { - if (!mVirtualDisplayIds.contains(displayId)) { - throw new SecurityException("Display ID " + displayId - + " not found for this virtual device"); + synchronized (mVirtualDeviceLock) { + if (!mVirtualDisplays.contains(displayId)) { + throw new SecurityException("Display ID " + displayId + + " not found for this virtual device"); + } } if (pendingIntent.isActivity()) { try { @@ -383,24 +394,34 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub @EnforcePermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public void close() { super.close_enforcePermission(); + // Remove about-to-be-closed virtual device from the service before butchering it. + mService.removeVirtualDevice(mDeviceId); + + VirtualDisplayWrapper[] virtualDisplaysToBeReleased; synchronized (mVirtualDeviceLock) { - if (!mPerDisplayWakelocks.isEmpty()) { - mPerDisplayWakelocks.forEach((displayId, wakeLock) -> { - Slog.w(TAG, "VirtualDisplay " + displayId + " owned by UID " + mOwnerUid - + " was not properly released"); - wakeLock.release(); - }); - mPerDisplayWakelocks.clear(); - } if (mVirtualAudioController != null) { mVirtualAudioController.stopListening(); mVirtualAudioController = null; } mLocaleList = null; + virtualDisplaysToBeReleased = new VirtualDisplayWrapper[mVirtualDisplays.size()]; + for (int i = 0; i < mVirtualDisplays.size(); i++) { + virtualDisplaysToBeReleased[i] = mVirtualDisplays.valueAt(i); + } + mVirtualDisplays.clear(); mVirtualSensorList = null; mVirtualSensors.clear(); } - mOnDeviceCloseListener.onClose(mDeviceId); + // Destroy the display outside locked section. + for (VirtualDisplayWrapper virtualDisplayWrapper : virtualDisplaysToBeReleased) { + mDisplayManager.releaseVirtualDisplay(virtualDisplayWrapper.getToken()); + // The releaseVirtualDisplay call above won't trigger + // VirtualDeviceImpl.onVirtualDisplayRemoved callback because we already removed the + // virtual device from the service - we release the other display-tied resources here + // with the guarantee it will be done exactly once. + releaseOwnedVirtualDisplayResources(virtualDisplayWrapper); + } + mAppToken.unlinkToDeath(this, 0); mCameraAccessController.stopObservingIfNeeded(); @@ -429,11 +450,6 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub return mVirtualAudioController; } - @VisibleForTesting - SparseArray<GenericWindowPolicyController> getWindowPolicyControllersForTesting() { - return mWindowPolicyControllers; - } - @Override // Binder call @EnforcePermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public void onAudioSessionStarting(int displayId, @@ -441,7 +457,7 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub @Nullable IAudioConfigChangedCallback configChangedCallback) { super.onAudioSessionStarting_enforcePermission(); synchronized (mVirtualDeviceLock) { - if (!mVirtualDisplayIds.contains(displayId)) { + if (!mVirtualDisplays.contains(displayId)) { throw new SecurityException( "Cannot start audio session for a display not associated with this virtual " + "device"); @@ -449,7 +465,8 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub if (mVirtualAudioController == null) { mVirtualAudioController = new VirtualAudioController(mContext); - GenericWindowPolicyController gwpc = mWindowPolicyControllers.get(displayId); + GenericWindowPolicyController gwpc = mVirtualDisplays.get( + displayId).getWindowPolicyController(); mVirtualAudioController.startListening(gwpc, routingCallback, configChangedCallback); } @@ -473,7 +490,7 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub public void createVirtualDpad(VirtualDpadConfig config, @NonNull IBinder deviceToken) { super.createVirtualDpad_enforcePermission(); synchronized (mVirtualDeviceLock) { - if (!mVirtualDisplayIds.contains(config.getAssociatedDisplayId())) { + if (!mVirtualDisplays.contains(config.getAssociatedDisplayId())) { throw new SecurityException( "Cannot create a virtual dpad for a display not associated with " + "this virtual device"); @@ -493,7 +510,7 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub public void createVirtualKeyboard(VirtualKeyboardConfig config, @NonNull IBinder deviceToken) { super.createVirtualKeyboard_enforcePermission(); synchronized (mVirtualDeviceLock) { - if (!mVirtualDisplayIds.contains(config.getAssociatedDisplayId())) { + if (!mVirtualDisplays.contains(config.getAssociatedDisplayId())) { throw new SecurityException( "Cannot create a virtual keyboard for a display not associated with " + "this virtual device"); @@ -515,7 +532,7 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub public void createVirtualMouse(VirtualMouseConfig config, @NonNull IBinder deviceToken) { super.createVirtualMouse_enforcePermission(); synchronized (mVirtualDeviceLock) { - if (!mVirtualDisplayIds.contains(config.getAssociatedDisplayId())) { + if (!mVirtualDisplays.contains(config.getAssociatedDisplayId())) { throw new SecurityException( "Cannot create a virtual mouse for a display not associated with this " + "virtual device"); @@ -536,7 +553,7 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub @NonNull IBinder deviceToken) { super.createVirtualTouchscreen_enforcePermission(); synchronized (mVirtualDeviceLock) { - if (!mVirtualDisplayIds.contains(config.getAssociatedDisplayId())) { + if (!mVirtualDisplays.contains(config.getAssociatedDisplayId())) { throw new SecurityException( "Cannot create a virtual touchscreen for a display not associated with " + "this virtual device"); @@ -566,7 +583,7 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub @NonNull IBinder deviceToken) { super.createVirtualNavigationTouchpad_enforcePermission(); synchronized (mVirtualDeviceLock) { - if (!mVirtualDisplayIds.contains(config.getAssociatedDisplayId())) { + if (!mVirtualDisplays.contains(config.getAssociatedDisplayId())) { throw new SecurityException( "Cannot create a virtual navigation touchpad for a display not associated " + "with this virtual device"); @@ -704,7 +721,8 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub try { synchronized (mVirtualDeviceLock) { mDefaultShowPointerIcon = showPointerIcon; - for (int displayId : mVirtualDisplayIds) { + for (int i = 0; i < mVirtualDisplays.size(); i++) { + final int displayId = mVirtualDisplays.keyAt(i); mInputController.setShowPointerIcon(mDefaultShowPointerIcon, displayId); } } @@ -795,8 +813,8 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub fout.println(" mParams: " + mParams); fout.println(" mVirtualDisplayIds: "); synchronized (mVirtualDeviceLock) { - for (int id : mVirtualDisplayIds) { - fout.println(" " + id); + for (int i = 0; i < mVirtualDisplays.size(); i++) { + fout.println(" " + mVirtualDisplays.keyAt(i)); } fout.println(" mDefaultShowPointerIcon: " + mDefaultShowPointerIcon); } @@ -804,61 +822,75 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub mSensorController.dump(fout); } - GenericWindowPolicyController createWindowPolicyController( + private GenericWindowPolicyController createWindowPolicyController( @NonNull List<String> displayCategories) { - synchronized (mVirtualDeviceLock) { - final GenericWindowPolicyController gwpc = - new GenericWindowPolicyController(FLAG_SECURE, - SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS, - getAllowedUserHandles(), - mParams.getAllowedCrossTaskNavigations(), - mParams.getBlockedCrossTaskNavigations(), - mParams.getAllowedActivities(), - mParams.getBlockedActivities(), - mParams.getDefaultActivityPolicy(), - createListenerAdapter(), - this::onEnteringPipBlocked, - this::onActivityBlocked, - this::onSecureWindowShown, - this::shouldInterceptIntent, - displayCategories, - mParams.getDefaultRecentsPolicy()); - gwpc.registerRunningAppsChangedListener(/* listener= */ this); - return gwpc; - } + final GenericWindowPolicyController gwpc = + new GenericWindowPolicyController(FLAG_SECURE, + SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS, + getAllowedUserHandles(), + mParams.getAllowedCrossTaskNavigations(), + mParams.getBlockedCrossTaskNavigations(), + mParams.getAllowedActivities(), + mParams.getBlockedActivities(), + mParams.getDefaultActivityPolicy(), + createListenerAdapter(), + this::onEnteringPipBlocked, + this::onActivityBlocked, + this::onSecureWindowShown, + this::shouldInterceptIntent, + displayCategories, + mParams.getDefaultRecentsPolicy()); + gwpc.registerRunningAppsChangedListener(/* listener= */ this); + return gwpc; } - void onVirtualDisplayCreatedLocked(GenericWindowPolicyController gwpc, int displayId) { + int createVirtualDisplay(@NonNull VirtualDisplayConfig virtualDisplayConfig, + @NonNull IVirtualDisplayCallback callback, String packageName) { + GenericWindowPolicyController gwpc = createWindowPolicyController( + virtualDisplayConfig.getDisplayCategories()); + DisplayManagerInternal displayManager = LocalServices.getService( + DisplayManagerInternal.class); + int displayId; + displayId = displayManager.createVirtualDisplay(virtualDisplayConfig, callback, + this, gwpc, packageName); + gwpc.setDisplayId(displayId); + synchronized (mVirtualDeviceLock) { - if (displayId == Display.INVALID_DISPLAY) { - return; - } - if (mVirtualDisplayIds.contains(displayId)) { + if (mVirtualDisplays.contains(displayId)) { + gwpc.unregisterRunningAppsChangedListener(this); throw new IllegalStateException( "Virtual device already has a virtual display with ID " + displayId); } - mVirtualDisplayIds.add(displayId); - gwpc.setDisplayId(displayId); - mWindowPolicyControllers.put(displayId, gwpc); + PowerManager.WakeLock wakeLock = createAndAcquireWakeLockForDisplay(displayId); + mVirtualDisplays.put(displayId, new VirtualDisplayWrapper(callback, gwpc, wakeLock)); + } + final long token = Binder.clearCallingIdentity(); + try { mInputController.setShowPointerIcon(mDefaultShowPointerIcon, displayId); mInputController.setPointerAcceleration(1f, displayId); mInputController.setDisplayEligibilityForPointerCapture(/* isEligible= */ false, displayId); mInputController.setLocalIme(displayId); + } finally { + Binder.restoreCallingIdentity(token); + } + return displayId; + } - if (mPerDisplayWakelocks.containsKey(displayId)) { - Slog.e(TAG, "Not creating wakelock for displayId " + displayId); - return; - } + private PowerManager.WakeLock createAndAcquireWakeLockForDisplay(int displayId) { + final long token = Binder.clearCallingIdentity(); + try { PowerManager powerManager = mContext.getSystemService(PowerManager.class); PowerManager.WakeLock wakeLock = powerManager.newWakeLock( PowerManager.SCREEN_BRIGHT_WAKE_LOCK, TAG + ":" + displayId, displayId); - mPerDisplayWakelocks.put(displayId, wakeLock); wakeLock.acquire(); + return wakeLock; + } finally { + Binder.restoreCallingIdentity(token); } } @@ -872,8 +904,10 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub } private void onSecureWindowShown(int displayId, int uid) { - if (!mVirtualDisplayIds.contains(displayId)) { - return; + synchronized (mVirtualDeviceLock) { + if (!mVirtualDisplays.contains(displayId)) { + return; + } } // If a virtual display isn't secure, the screen can't be captured. Show a warning toast @@ -888,55 +922,102 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub private ArraySet<UserHandle> getAllowedUserHandles() { ArraySet<UserHandle> result = new ArraySet<>(); - DevicePolicyManager dpm = mContext.getSystemService(DevicePolicyManager.class); - UserManager userManager = mContext.getSystemService(UserManager.class); - for (UserHandle profile : userManager.getAllProfiles()) { - int nearbyAppStreamingPolicy = dpm.getNearbyAppStreamingPolicy(profile.getIdentifier()); - if (nearbyAppStreamingPolicy == NEARBY_STREAMING_ENABLED - || nearbyAppStreamingPolicy == NEARBY_STREAMING_NOT_CONTROLLED_BY_POLICY) { - result.add(profile); - } else if (nearbyAppStreamingPolicy == NEARBY_STREAMING_SAME_MANAGED_ACCOUNT_ONLY) { - if (mParams.getUsersWithMatchingAccounts().contains(profile)) { + final long token = Binder.clearCallingIdentity(); + try { + DevicePolicyManager dpm = mContext.getSystemService(DevicePolicyManager.class); + UserManager userManager = mContext.getSystemService(UserManager.class); + for (UserHandle profile : userManager.getAllProfiles()) { + int nearbyAppStreamingPolicy = dpm.getNearbyAppStreamingPolicy( + profile.getIdentifier()); + if (nearbyAppStreamingPolicy == NEARBY_STREAMING_ENABLED + || nearbyAppStreamingPolicy == NEARBY_STREAMING_NOT_CONTROLLED_BY_POLICY) { result.add(profile); + } else if (nearbyAppStreamingPolicy == NEARBY_STREAMING_SAME_MANAGED_ACCOUNT_ONLY) { + if (mParams.getUsersWithMatchingAccounts().contains(profile)) { + result.add(profile); + } } } + } finally { + Binder.restoreCallingIdentity(token); } return result; } - void onVirtualDisplayRemovedLocked(int displayId) { + + 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) { - if (!mVirtualDisplayIds.contains(displayId)) { - throw new IllegalStateException( - "Virtual device doesn't have a virtual display with ID " + displayId); - } - PowerManager.WakeLock wakeLock = mPerDisplayWakelocks.get(displayId); - if (wakeLock != null) { - wakeLock.release(); - mPerDisplayWakelocks.remove(displayId); - } - GenericWindowPolicyController gwpc = mWindowPolicyControllers.get(displayId); - if (gwpc != null) { - gwpc.unregisterRunningAppsChangedListener(/* listener= */ this); - } - mVirtualDisplayIds.remove(displayId); - mWindowPolicyControllers.remove(displayId); + virtualDisplayWrapper = mVirtualDisplays.removeReturnOld(displayId); + } + + if (virtualDisplayWrapper == null) { + throw new IllegalStateException( + "Virtual device doesn't have a virtual display with ID " + displayId); } + + releaseOwnedVirtualDisplayResources(virtualDisplayWrapper); + + } + + /** + * Release resources tied to virtual display owned by this VirtualDevice instance. + * + * Note that this method won't release the virtual display itself. + * + * @param virtualDisplayWrapper - VirtualDisplayWrapper to release resources for. + */ + private void releaseOwnedVirtualDisplayResources(VirtualDisplayWrapper virtualDisplayWrapper) { + virtualDisplayWrapper.getWakeLock().release(); + virtualDisplayWrapper.getWindowPolicyController().unregisterRunningAppsChangedListener( + this); } int getOwnerUid() { return mOwnerUid; } + ArraySet<Integer> getDisplayIds() { + synchronized (mVirtualDeviceLock) { + final int size = mVirtualDisplays.size(); + ArraySet<Integer> arraySet = new ArraySet<>(size); + for (int i = 0; i < size; i++) { + arraySet.append(mVirtualDisplays.keyAt(i)); + } + return arraySet; + } + } + + @VisibleForTesting + GenericWindowPolicyController getDisplayWindowPolicyControllerForTest(int displayId) { + VirtualDisplayWrapper virtualDisplayWrapper; + synchronized (mVirtualDeviceLock) { + virtualDisplayWrapper = mVirtualDisplays.get(displayId); + } + return virtualDisplayWrapper != null ? virtualDisplayWrapper.getWindowPolicyController() + : null; + } + /** * Returns true if an app with the given {@code uid} is currently running on this virtual * device. */ boolean isAppRunningOnVirtualDevice(int uid) { - final int size = mWindowPolicyControllers.size(); - for (int i = 0; i < size; i++) { - if (mWindowPolicyControllers.valueAt(i).containsUid(uid)) { - return true; + synchronized (mVirtualDeviceLock) { + for (int i = 0; i < mVirtualDisplays.size(); i++) { + if (mVirtualDisplays.valueAt(i).getWindowPolicyController().containsUid(uid)) { + return true; + } } } return false; @@ -957,11 +1038,9 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub Looper looper) { synchronized (mVirtualDeviceLock) { DisplayManager displayManager = mContext.getSystemService(DisplayManager.class); - final int size = mWindowPolicyControllers.size(); - for (int i = 0; i < size; i++) { - if (mWindowPolicyControllers.valueAt(i).containsUid(uid)) { - int displayId = mWindowPolicyControllers.keyAt(i); - Display display = displayManager.getDisplay(displayId); + for (int i = 0; i < mVirtualDisplays.size(); i++) { + if (mVirtualDisplays.valueAt(i).getWindowPolicyController().containsUid(uid)) { + Display display = displayManager.getDisplay(mVirtualDisplays.keyAt(i)); if (display != null && display.isValid()) { Toast.makeText(mContext.createDisplayContext(display), looper, text, duration).show(); @@ -972,7 +1051,9 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub } boolean isDisplayOwnedByVirtualDevice(int displayId) { - return mVirtualDisplayIds.contains(displayId); + synchronized (mVirtualDeviceLock) { + return mVirtualDisplays.contains(displayId); + } } void onEnteringPipBlocked(int uid) { @@ -1016,10 +1097,6 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub } } - interface OnDeviceCloseListener { - void onClose(int deviceId); - } - interface PendingTrampolineCallback { /** * Called when the callback should start waiting for the given pending trampoline. @@ -1073,4 +1150,31 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub + ", displayId=" + mDisplayId + "}"; } } + + /** Data class wrapping resources tied to single virtual display. */ + private static final class VirtualDisplayWrapper { + private final IVirtualDisplayCallback mToken; + private final GenericWindowPolicyController mWindowPolicyController; + private final PowerManager.WakeLock mWakeLock; + + VirtualDisplayWrapper(@NonNull IVirtualDisplayCallback token, + @NonNull GenericWindowPolicyController windowPolicyController, + @NonNull PowerManager.WakeLock wakeLock) { + mToken = Objects.requireNonNull(token); + mWindowPolicyController = Objects.requireNonNull(windowPolicyController); + mWakeLock = Objects.requireNonNull(wakeLock); + } + + GenericWindowPolicyController getWindowPolicyController() { + return mWindowPolicyController; + } + + PowerManager.WakeLock getWakeLock() { + return mWakeLock; + } + + IVirtualDisplayCallback getToken() { + return mToken; + } + } } 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 9bb05a6bfe5d..ed5b858da27a 100644 --- a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java +++ b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java @@ -37,7 +37,6 @@ import android.companion.virtual.VirtualDeviceParams; import android.companion.virtual.sensor.VirtualSensor; import android.content.Context; import android.content.Intent; -import android.hardware.display.DisplayManagerInternal; import android.hardware.display.IVirtualDisplayCallback; import android.hardware.display.VirtualDisplayConfig; import android.os.Binder; @@ -108,26 +107,26 @@ public class VirtualDeviceManagerService extends SystemService { private final ActivityInterceptorCallback mActivityInterceptorCallback = new ActivityInterceptorCallback() { - @Nullable - @Override - public ActivityInterceptResult onInterceptActivityLaunch(@NonNull - ActivityInterceptorInfo info) { - if (info.getCallingPackage() == null) { - return null; - } - PendingTrampoline pt = mPendingTrampolines.remove(info.getCallingPackage()); - if (pt == null) { - return null; - } - pt.mResultReceiver.send(VirtualDeviceManager.LAUNCH_SUCCESS, null); - ActivityOptions options = info.getCheckedOptions(); - if (options == null) { - options = ActivityOptions.makeBasic(); - } - return new ActivityInterceptResult( - info.getIntent(), options.setLaunchDisplayId(pt.mDisplayId)); - } - }; + @Nullable + @Override + public ActivityInterceptResult onInterceptActivityLaunch(@NonNull + ActivityInterceptorInfo info) { + if (info.getCallingPackage() == null) { + return null; + } + PendingTrampoline pt = mPendingTrampolines.remove(info.getCallingPackage()); + if (pt == null) { + return null; + } + pt.mResultReceiver.send(VirtualDeviceManager.LAUNCH_SUCCESS, null); + ActivityOptions options = info.getCheckedOptions(); + if (options == null) { + options = ActivityOptions.makeBasic(); + } + return new ActivityInterceptResult( + info.getIntent(), options.setLaunchDisplayId(pt.mDisplayId)); + } + }; @Override public void onStart() { @@ -146,8 +145,8 @@ public class VirtualDeviceManagerService extends SystemService { CharSequence deviceName = mVirtualDevices.valueAt(i).getDisplayName(); mVirtualDevices.valueAt(i).showToastWhereUidIsRunning(appUid, getContext().getString( - com.android.internal.R.string.vdm_camera_access_denied, - deviceName), + com.android.internal.R.string.vdm_camera_access_denied, + deviceName), Toast.LENGTH_LONG, Looper.myLooper()); } } @@ -193,34 +192,46 @@ public class VirtualDeviceManagerService extends SystemService { } } - @VisibleForTesting void removeVirtualDevice(int deviceId) { synchronized (mVirtualDeviceManagerLock) { mAppsOnVirtualDevices.remove(deviceId); mVirtualDevices.remove(deviceId); } + + Intent i = new Intent(VirtualDeviceManager.ACTION_VIRTUAL_DEVICE_REMOVED); + i.putExtra(VirtualDeviceManager.EXTRA_VIRTUAL_DEVICE_ID, deviceId); + i.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); + final long identity = Binder.clearCallingIdentity(); + try { + getContext().sendBroadcastAsUser(i, UserHandle.ALL); + } finally { + Binder.restoreCallingIdentity(identity); + } } class VirtualDeviceManagerImpl extends IVirtualDeviceManager.Stub { private final VirtualDeviceImpl.PendingTrampolineCallback mPendingTrampolineCallback = new VirtualDeviceImpl.PendingTrampolineCallback() { - @Override - public void startWaitingForPendingTrampoline(PendingTrampoline pendingTrampoline) { - PendingTrampoline existing = mPendingTrampolines.put( - pendingTrampoline.mPendingIntent.getCreatorPackage(), - pendingTrampoline); - if (existing != null) { - existing.mResultReceiver.send( - VirtualDeviceManager.LAUNCH_FAILURE_NO_ACTIVITY, null); - } - } + @Override + public void startWaitingForPendingTrampoline( + PendingTrampoline pendingTrampoline) { + PendingTrampoline existing = mPendingTrampolines.put( + pendingTrampoline.mPendingIntent.getCreatorPackage(), + pendingTrampoline); + if (existing != null) { + existing.mResultReceiver.send( + VirtualDeviceManager.LAUNCH_FAILURE_NO_ACTIVITY, null); + } + } - @Override - public void stopWaitingForPendingTrampoline(PendingTrampoline pendingTrampoline) { - mPendingTrampolines.remove(pendingTrampoline.mPendingIntent.getCreatorPackage()); - } - }; + @Override + public void stopWaitingForPendingTrampoline( + PendingTrampoline pendingTrampoline) { + mPendingTrampolines.remove( + pendingTrampoline.mPendingIntent.getCreatorPackage()); + } + }; @Override // Binder call public IVirtualDevice createVirtualDevice( @@ -251,8 +262,9 @@ public class VirtualDeviceManagerService extends SystemService { final Consumer<ArraySet<Integer>> runningAppsChangedCallback = runningUids -> notifyRunningAppsChanged(deviceId, runningUids); VirtualDeviceImpl virtualDevice = new VirtualDeviceImpl(getContext(), - associationInfo, token, callingUid, deviceId, cameraAccessController, - this::onDeviceClosed, mPendingTrampolineCallback, activityListener, + associationInfo, VirtualDeviceManagerService.this, token, callingUid, + deviceId, cameraAccessController, + mPendingTrampolineCallback, activityListener, soundEffectListener, runningAppsChangedCallback, params); mVirtualDevices.put(deviceId, virtualDevice); return virtualDevice; @@ -281,26 +293,9 @@ public class VirtualDeviceManagerService extends SystemService { "uid " + callingUid + " is not the owner of the supplied VirtualDevice"); } - GenericWindowPolicyController gwpc; - final long token = Binder.clearCallingIdentity(); - try { - gwpc = virtualDeviceImpl.createWindowPolicyController( - virtualDisplayConfig.getDisplayCategories()); - } finally { - Binder.restoreCallingIdentity(token); - } - - DisplayManagerInternal displayManager = getLocalService( - DisplayManagerInternal.class); - int displayId = displayManager.createVirtualDisplay(virtualDisplayConfig, callback, - virtualDevice, gwpc, packageName); - final long tokenTwo = Binder.clearCallingIdentity(); - try { - virtualDeviceImpl.onVirtualDisplayCreatedLocked(gwpc, displayId); - } finally { - Binder.restoreCallingIdentity(tokenTwo); - } + int displayId = virtualDeviceImpl.createVirtualDisplay(virtualDisplayConfig, callback, + packageName); mLocalService.onVirtualDisplayCreated(displayId); return displayId; } @@ -412,19 +407,6 @@ public class VirtualDeviceManagerService extends SystemService { return null; } - private void onDeviceClosed(int deviceId) { - removeVirtualDevice(deviceId); - Intent i = new Intent(VirtualDeviceManager.ACTION_VIRTUAL_DEVICE_REMOVED); - i.putExtra(VirtualDeviceManager.EXTRA_VIRTUAL_DEVICE_ID, deviceId); - i.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); - final long identity = Binder.clearCallingIdentity(); - try { - getContext().sendBroadcastAsUser(i, UserHandle.ALL); - } finally { - Binder.restoreCallingIdentity(identity); - } - } - @Override public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException { @@ -512,9 +494,14 @@ public class VirtualDeviceManagerService extends SystemService { @Override public void onVirtualDisplayRemoved(IVirtualDevice virtualDevice, int displayId) { final VirtualDisplayListener[] listeners; + VirtualDeviceImpl virtualDeviceImpl; synchronized (mVirtualDeviceManagerLock) { - ((VirtualDeviceImpl) virtualDevice).onVirtualDisplayRemovedLocked(displayId); listeners = mVirtualDisplayListeners.toArray(new VirtualDisplayListener[0]); + virtualDeviceImpl = mVirtualDevices.get( + ((VirtualDeviceImpl) virtualDevice).getDeviceId()); + } + if (virtualDeviceImpl != null) { + virtualDeviceImpl.onVirtualDisplayRemoved(displayId); } mHandler.post(() -> { for (VirtualDisplayListener listener : listeners) { @@ -599,16 +586,11 @@ public class VirtualDeviceManagerService extends SystemService { @Override public @NonNull ArraySet<Integer> getDisplayIdsForDevice(int deviceId) { + VirtualDeviceImpl virtualDevice; synchronized (mVirtualDeviceManagerLock) { - int size = mVirtualDevices.size(); - for (int i = 0; i < size; i++) { - VirtualDeviceImpl device = mVirtualDevices.valueAt(i); - if (device.getDeviceId() == deviceId) { - return new ArraySet<>(device.mVirtualDisplayIds); - } - } + virtualDevice = mVirtualDevices.get(deviceId); } - return new ArraySet<>(); + return virtualDevice == null ? new ArraySet<>() : virtualDevice.getDisplayIds(); } @Override 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 0cd50f03fbfa..cc6f7c27b01d 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 @@ -35,6 +35,7 @@ import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.nullable; import static org.mockito.Mockito.argThat; +import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; @@ -67,7 +68,11 @@ import android.content.IntentFilter; import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; import android.hardware.Sensor; +import android.hardware.display.DisplayManagerGlobal; import android.hardware.display.DisplayManagerInternal; +import android.hardware.display.IDisplayManager; +import android.hardware.display.IVirtualDisplayCallback; +import android.hardware.display.VirtualDisplayConfig; import android.hardware.input.IInputManager; import android.hardware.input.VirtualDpadConfig; import android.hardware.input.VirtualKeyEvent; @@ -144,6 +149,7 @@ public class VirtualDeviceManagerServiceTest { private static final String DEVICE_NAME_3 = "device name 3"; private static final int DISPLAY_ID_1 = 2; private static final int DISPLAY_ID_2 = 3; + private static final int NON_EXISTENT_DISPLAY_ID = 42; private static final int DEVICE_OWNER_UID_1 = 50; private static final int DEVICE_OWNER_UID_2 = 51; private static final int UID_1 = 0; @@ -162,6 +168,8 @@ 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) @@ -221,6 +229,8 @@ public class VirtualDeviceManagerServiceTest { @Mock private DisplayManagerInternal mDisplayManagerInternalMock; @Mock + private IDisplayManager mIDisplayManager; + @Mock private VirtualDeviceImpl.PendingTrampolineCallback mPendingTrampolineCallback; @Mock private DevicePolicyManager mDevicePolicyManagerMock; @@ -237,6 +247,8 @@ public class VirtualDeviceManagerServiceTest { @Mock private IVirtualDeviceSoundEffectListener mSoundEffectListener; @Mock + private IVirtualDisplayCallback mVirtualDisplayCallback; + @Mock private Consumer<ArraySet<Integer>> mRunningAppsChangedCallback; @Mock private VirtualDeviceManagerInternal.VirtualDisplayListener mDisplayListener; @@ -271,9 +283,13 @@ public class VirtualDeviceManagerServiceTest { private Intent createRestrictedActivityBlockedIntent(List displayCategories, String targetDisplayCategory) { - mDeviceImpl.onVirtualDisplayCreatedLocked( - mDeviceImpl.createWindowPolicyController(displayCategories), DISPLAY_ID_1); - GenericWindowPolicyController gwpc = mDeviceImpl.getWindowPolicyControllersForTesting().get( + when(mDisplayManagerInternalMock.createVirtualDisplay(any(), any(), any(), any(), + eq(NONBLOCKED_APP_PACKAGE_NAME))).thenReturn(DISPLAY_ID_1); + VirtualDisplayConfig config = new VirtualDisplayConfig.Builder("display", 640, 480, + 420).setDisplayCategories(displayCategories).build(); + mDeviceImpl.createVirtualDisplay(config, mVirtualDisplayCallback, + NONBLOCKED_APP_PACKAGE_NAME); + GenericWindowPolicyController gwpc = mDeviceImpl.getDisplayWindowPolicyControllerForTest( DISPLAY_ID_1); doNothing().when(mContext).startActivityAsUser(any(), any(), any()); @@ -327,6 +343,7 @@ public class VirtualDeviceManagerServiceTest { mContext = Mockito.spy(new ContextWrapper( InstrumentationRegistry.getInstrumentation().getTargetContext())); doReturn(mContext).when(mContext).createContextAsUser(eq(Process.myUserHandle()), anyInt()); + doNothing().when(mContext).sendBroadcastAsUser(any(), any()); when(mContext.getSystemService(Context.DEVICE_POLICY_SERVICE)).thenReturn( mDevicePolicyManagerMock); @@ -369,15 +386,13 @@ public class VirtualDeviceManagerServiceTest { @Test public void getDeviceIdForDisplayId_nonExistentDisplayId_returnsDefault() { - mDeviceImpl.mVirtualDisplayIds.remove(DISPLAY_ID_1); - - assertThat(mVdm.getDeviceIdForDisplayId(DISPLAY_ID_1)) + assertThat(mVdm.getDeviceIdForDisplayId(NON_EXISTENT_DISPLAY_ID)) .isEqualTo(DEVICE_ID_DEFAULT); } @Test public void getDeviceIdForDisplayId_withValidVirtualDisplayId_returnsDeviceId() { - mDeviceImpl.mVirtualDisplayIds.add(DISPLAY_ID_1); + addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1); assertThat(mVdm.getDeviceIdForDisplayId(DISPLAY_ID_1)) .isEqualTo(mDeviceImpl.getDeviceId()); @@ -503,10 +518,9 @@ public class VirtualDeviceManagerServiceTest { @Test public void getDeviceIdsForUid_differentUidOnDevice_returnsNull() { - GenericWindowPolicyController gwpc = - mDeviceImpl.createWindowPolicyController(new ArrayList<>()); - mDeviceImpl.onVirtualDisplayCreatedLocked(gwpc, DISPLAY_ID_1); - gwpc.onRunningAppsChanged(Sets.newArraySet(UID_2)); + addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1); + mDeviceImpl.getDisplayWindowPolicyControllerForTest(DISPLAY_ID_1).onRunningAppsChanged( + Sets.newArraySet(UID_2)); Set<Integer> deviceIds = mLocalService.getDeviceIdsForUid(UID_1); assertThat(deviceIds).isEmpty(); @@ -514,10 +528,9 @@ public class VirtualDeviceManagerServiceTest { @Test public void getDeviceIdsForUid_oneUidOnDevice_returnsCorrectId() { - GenericWindowPolicyController gwpc = - mDeviceImpl.createWindowPolicyController(new ArrayList<>()); - mDeviceImpl.onVirtualDisplayCreatedLocked(gwpc, DISPLAY_ID_1); - gwpc.onRunningAppsChanged(Sets.newArraySet(UID_1)); + addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1); + mDeviceImpl.getDisplayWindowPolicyControllerForTest(DISPLAY_ID_1).onRunningAppsChanged( + Sets.newArraySet(UID_1)); Set<Integer> deviceIds = mLocalService.getDeviceIdsForUid(UID_1); assertThat(deviceIds).containsExactly(mDeviceImpl.getDeviceId()); @@ -525,10 +538,10 @@ public class VirtualDeviceManagerServiceTest { @Test public void getDeviceIdsForUid_twoUidsOnDevice_returnsCorrectId() { - GenericWindowPolicyController gwpc = - mDeviceImpl.createWindowPolicyController(new ArrayList<>()); - mDeviceImpl.onVirtualDisplayCreatedLocked(gwpc, DISPLAY_ID_1); - gwpc.onRunningAppsChanged(Sets.newArraySet(UID_1, UID_2)); + addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1); + + mDeviceImpl.getDisplayWindowPolicyControllerForTest(DISPLAY_ID_1).onRunningAppsChanged( + Sets.newArraySet(UID_1, UID_2)); Set<Integer> deviceIds = mLocalService.getDeviceIdsForUid(UID_1); assertThat(deviceIds).containsExactly(mDeviceImpl.getDeviceId()); @@ -538,11 +551,10 @@ public class VirtualDeviceManagerServiceTest { public void getDeviceIdsForUid_twoDevicesUidOnOne_returnsCorrectId() { VirtualDeviceImpl secondDevice = createVirtualDevice(VIRTUAL_DEVICE_ID_2, DEVICE_OWNER_UID_2); + addVirtualDisplay(secondDevice, DISPLAY_ID_2); - GenericWindowPolicyController gwpc = - secondDevice.createWindowPolicyController(new ArrayList<>()); - secondDevice.onVirtualDisplayCreatedLocked(gwpc, DISPLAY_ID_2); - gwpc.onRunningAppsChanged(Sets.newArraySet(UID_1)); + secondDevice.getDisplayWindowPolicyControllerForTest(DISPLAY_ID_2).onRunningAppsChanged( + Sets.newArraySet(UID_1)); Set<Integer> deviceIds = mLocalService.getDeviceIdsForUid(UID_1); assertThat(deviceIds).containsExactly(secondDevice.getDeviceId()); @@ -550,16 +562,16 @@ public class VirtualDeviceManagerServiceTest { @Test public void getDeviceIdsForUid_twoDevicesUidOnBoth_returnsCorrectId() { + addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1); VirtualDeviceImpl secondDevice = createVirtualDevice(VIRTUAL_DEVICE_ID_2, DEVICE_OWNER_UID_2); - GenericWindowPolicyController gwpc1 = - mDeviceImpl.createWindowPolicyController(new ArrayList<>()); - GenericWindowPolicyController gwpc2 = - secondDevice.createWindowPolicyController(new ArrayList<>()); - mDeviceImpl.onVirtualDisplayCreatedLocked(gwpc1, DISPLAY_ID_1); - secondDevice.onVirtualDisplayCreatedLocked(gwpc2, DISPLAY_ID_2); - gwpc1.onRunningAppsChanged(Sets.newArraySet(UID_1)); - gwpc2.onRunningAppsChanged(Sets.newArraySet(UID_1, UID_2)); + addVirtualDisplay(secondDevice, DISPLAY_ID_2); + + + mDeviceImpl.getDisplayWindowPolicyControllerForTest(DISPLAY_ID_1).onRunningAppsChanged( + Sets.newArraySet(UID_1)); + secondDevice.getDisplayWindowPolicyControllerForTest(DISPLAY_ID_2).onRunningAppsChanged( + Sets.newArraySet(UID_1, UID_2)); Set<Integer> deviceIds = mLocalService.getDeviceIdsForUid(UID_1); assertThat(deviceIds).containsExactly( @@ -568,8 +580,7 @@ public class VirtualDeviceManagerServiceTest { @Test public void getPreferredLocaleListForApp_keyboardAttached_returnLocaleHints() { - mDeviceImpl.mVirtualDisplayIds.add(DISPLAY_ID_1); - + addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1); mDeviceImpl.createVirtualKeyboard(KEYBOARD_CONFIG, BINDER); mVdms.notifyRunningAppsChanged(mDeviceImpl.getDeviceId(), Sets.newArraySet(UID_1)); @@ -609,8 +620,8 @@ public class VirtualDeviceManagerServiceTest { .setLanguageTag("fr-FR") .build(); - mDeviceImpl.mVirtualDisplayIds.add(DISPLAY_ID_1); - secondDevice.mVirtualDisplayIds.add(DISPLAY_ID_2); + addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1); + addVirtualDisplay(secondDevice, DISPLAY_ID_2); mDeviceImpl.createVirtualKeyboard(firstKeyboardConfig, BINDER); secondDevice.createVirtualKeyboard(secondKeyboardConfig, secondBinder); @@ -640,10 +651,9 @@ public class VirtualDeviceManagerServiceTest { @Test public void onVirtualDisplayRemovedLocked_doesNotThrowException() { - mDeviceImpl.onVirtualDisplayCreatedLocked( - mDeviceImpl.createWindowPolicyController(new ArrayList<>()), DISPLAY_ID_1); + addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1); // This call should not throw any exceptions. - mDeviceImpl.onVirtualDisplayRemovedLocked(DISPLAY_ID_1); + mDeviceImpl.onVirtualDisplayRemoved(DISPLAY_ID_1); } @Test @@ -659,8 +669,8 @@ public class VirtualDeviceManagerServiceTest { @Test public void onVirtualDisplayRemovedLocked_listenersNotified() { mLocalService.registerVirtualDisplayListener(mDisplayListener); - mDeviceImpl.onVirtualDisplayCreatedLocked( - mDeviceImpl.createWindowPolicyController(new ArrayList<>()), DISPLAY_ID_1); + + addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1); mLocalService.onVirtualDisplayRemoved(mDeviceImpl, DISPLAY_ID_1); TestableLooper.get(this).processAllMessages(); @@ -723,8 +733,7 @@ public class VirtualDeviceManagerServiceTest { verify(mIPowerManagerMock, never()).acquireWakeLock(any(Binder.class), anyInt(), nullable(String.class), nullable(String.class), nullable(WorkSource.class), nullable(String.class), anyInt(), eq(null)); - mDeviceImpl.onVirtualDisplayCreatedLocked( - mDeviceImpl.createWindowPolicyController(new ArrayList<>()), DISPLAY_ID_1); + addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1); verify(mIPowerManagerMock).acquireWakeLock(any(Binder.class), anyInt(), nullable(String.class), nullable(String.class), nullable(WorkSource.class), nullable(String.class), eq(DISPLAY_ID_1), eq(null)); @@ -733,12 +742,9 @@ public class VirtualDeviceManagerServiceTest { @Test public void onVirtualDisplayCreatedLocked_duplicateCalls_onlyOneWakeLockIsAcquired() throws RemoteException { - GenericWindowPolicyController gwpc = mDeviceImpl.createWindowPolicyController( - new ArrayList<>()); - mDeviceImpl.onVirtualDisplayCreatedLocked( - mDeviceImpl.createWindowPolicyController(new ArrayList<>()), DISPLAY_ID_1); + addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1); assertThrows(IllegalStateException.class, - () -> mDeviceImpl.onVirtualDisplayCreatedLocked(gwpc, DISPLAY_ID_1)); + () -> addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1)); TestableLooper.get(this).processAllMessages(); verify(mIPowerManagerMock).acquireWakeLock(any(Binder.class), anyInt(), nullable(String.class), nullable(String.class), nullable(WorkSource.class), @@ -749,13 +755,12 @@ public class VirtualDeviceManagerServiceTest { public void onVirtualDisplayRemovedLocked_unknownDisplayId_throwsException() { final int unknownDisplayId = 999; assertThrows(IllegalStateException.class, - () -> mDeviceImpl.onVirtualDisplayRemovedLocked(unknownDisplayId)); + () -> mDeviceImpl.onVirtualDisplayRemoved(unknownDisplayId)); } @Test public void onVirtualDisplayRemovedLocked_wakeLockIsReleased() throws RemoteException { - mDeviceImpl.onVirtualDisplayCreatedLocked( - mDeviceImpl.createWindowPolicyController(new ArrayList<>()), DISPLAY_ID_1); + addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1); ArgumentCaptor<IBinder> wakeLockCaptor = ArgumentCaptor.forClass(IBinder.class); TestableLooper.get(this).processAllMessages(); verify(mIPowerManagerMock).acquireWakeLock(wakeLockCaptor.capture(), @@ -764,14 +769,13 @@ public class VirtualDeviceManagerServiceTest { nullable(String.class), eq(DISPLAY_ID_1), eq(null)); IBinder wakeLock = wakeLockCaptor.getValue(); - mDeviceImpl.onVirtualDisplayRemovedLocked(DISPLAY_ID_1); + mDeviceImpl.onVirtualDisplayRemoved(DISPLAY_ID_1); verify(mIPowerManagerMock).releaseWakeLock(eq(wakeLock), anyInt()); } @Test public void addVirtualDisplay_displayNotReleased_wakeLockIsReleased() throws RemoteException { - mDeviceImpl.onVirtualDisplayCreatedLocked( - mDeviceImpl.createWindowPolicyController(new ArrayList<>()), DISPLAY_ID_1); + addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1); ArgumentCaptor<IBinder> wakeLockCaptor = ArgumentCaptor.forClass(IBinder.class); TestableLooper.get(this).processAllMessages(); verify(mIPowerManagerMock).acquireWakeLock(wakeLockCaptor.capture(), @@ -825,7 +829,7 @@ public class VirtualDeviceManagerServiceTest { @Test public void createVirtualTouchscreen_positiveDisplayDimension_successful() { - mDeviceImpl.mVirtualDisplayIds.add(DISPLAY_ID_1); + addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1); VirtualTouchscreenConfig positiveConfig = new VirtualTouchscreenConfig.Builder( /* touchscrenWidth= */ 600, /* touchscreenHeight= */ 800) @@ -863,7 +867,7 @@ public class VirtualDeviceManagerServiceTest { @Test public void createVirtualNavigationTouchpad_positiveDisplayDimension_successful() { - mDeviceImpl.mVirtualDisplayIds.add(DISPLAY_ID_1); + addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1); VirtualNavigationTouchpadConfig positiveConfig = new VirtualNavigationTouchpadConfig.Builder( /* touchpadHeight= */ 50, /* touchpadWidth= */ 50) @@ -888,7 +892,7 @@ public class VirtualDeviceManagerServiceTest { @Test public void createVirtualDpad_noPermission_failsSecurityException() { - mDeviceImpl.mVirtualDisplayIds.add(DISPLAY_ID_1); + addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1); try (DropShellPermissionsTemporarily drop = new DropShellPermissionsTemporarily()) { assertThrows(SecurityException.class, () -> mDeviceImpl.createVirtualDpad(DPAD_CONFIG, BINDER)); @@ -897,7 +901,7 @@ public class VirtualDeviceManagerServiceTest { @Test public void createVirtualKeyboard_noPermission_failsSecurityException() { - mDeviceImpl.mVirtualDisplayIds.add(DISPLAY_ID_1); + addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1); try (DropShellPermissionsTemporarily drop = new DropShellPermissionsTemporarily()) { assertThrows(SecurityException.class, () -> mDeviceImpl.createVirtualKeyboard(KEYBOARD_CONFIG, BINDER)); @@ -906,7 +910,7 @@ public class VirtualDeviceManagerServiceTest { @Test public void createVirtualMouse_noPermission_failsSecurityException() { - mDeviceImpl.mVirtualDisplayIds.add(DISPLAY_ID_1); + addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1); try (DropShellPermissionsTemporarily drop = new DropShellPermissionsTemporarily()) { assertThrows(SecurityException.class, () -> mDeviceImpl.createVirtualMouse(MOUSE_CONFIG, BINDER)); @@ -915,7 +919,7 @@ public class VirtualDeviceManagerServiceTest { @Test public void createVirtualTouchscreen_noPermission_failsSecurityException() { - mDeviceImpl.mVirtualDisplayIds.add(DISPLAY_ID_1); + addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1); try (DropShellPermissionsTemporarily drop = new DropShellPermissionsTemporarily()) { assertThrows(SecurityException.class, () -> mDeviceImpl.createVirtualTouchscreen(TOUCHSCREEN_CONFIG, BINDER)); @@ -924,7 +928,7 @@ public class VirtualDeviceManagerServiceTest { @Test public void createVirtualNavigationTouchpad_noPermission_failsSecurityException() { - mDeviceImpl.mVirtualDisplayIds.add(DISPLAY_ID_1); + addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1); try (DropShellPermissionsTemporarily drop = new DropShellPermissionsTemporarily()) { assertThrows(SecurityException.class, () -> mDeviceImpl.createVirtualNavigationTouchpad(NAVIGATION_TOUCHPAD_CONFIG, @@ -934,7 +938,7 @@ public class VirtualDeviceManagerServiceTest { @Test public void onAudioSessionStarting_noPermission_failsSecurityException() { - mDeviceImpl.mVirtualDisplayIds.add(DISPLAY_ID_1); + addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1); try (DropShellPermissionsTemporarily drop = new DropShellPermissionsTemporarily()) { assertThrows(SecurityException.class, () -> mDeviceImpl.onAudioSessionStarting( @@ -951,7 +955,7 @@ public class VirtualDeviceManagerServiceTest { @Test public void createVirtualDpad_hasDisplay_obtainFileDescriptor() { - mDeviceImpl.mVirtualDisplayIds.add(DISPLAY_ID_1); + addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1); mDeviceImpl.createVirtualDpad(DPAD_CONFIG, BINDER); assertWithMessage("Virtual dpad should register fd when the display matches").that( mInputController.getInputDeviceDescriptors()).isNotEmpty(); @@ -961,7 +965,7 @@ public class VirtualDeviceManagerServiceTest { @Test public void createVirtualKeyboard_hasDisplay_obtainFileDescriptor() { - mDeviceImpl.mVirtualDisplayIds.add(DISPLAY_ID_1); + addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1); mDeviceImpl.createVirtualKeyboard(KEYBOARD_CONFIG, BINDER); assertWithMessage("Virtual keyboard should register fd when the display matches").that( mInputController.getInputDeviceDescriptors()).isNotEmpty(); @@ -971,7 +975,7 @@ public class VirtualDeviceManagerServiceTest { @Test public void createVirtualKeyboard_keyboardCreated_localeUpdated() { - mDeviceImpl.mVirtualDisplayIds.add(DISPLAY_ID_1); + addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1); mDeviceImpl.createVirtualKeyboard(KEYBOARD_CONFIG, BINDER); assertWithMessage("Virtual keyboard should register fd when the display matches") .that(mInputController.getInputDeviceDescriptors()) @@ -992,7 +996,7 @@ public class VirtualDeviceManagerServiceTest { .setAssociatedDisplayId(DISPLAY_ID_1) .build(); - mDeviceImpl.mVirtualDisplayIds.add(DISPLAY_ID_1); + addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1); mDeviceImpl.createVirtualKeyboard(configWithoutExplicitLayoutInfo, BINDER); assertWithMessage("Virtual keyboard should register fd when the display matches") .that(mInputController.getInputDeviceDescriptors()) @@ -1005,7 +1009,7 @@ public class VirtualDeviceManagerServiceTest { @Test public void virtualDeviceWithoutKeyboard_noLocaleUpdate() { - mDeviceImpl.mVirtualDisplayIds.add(DISPLAY_ID_1); + addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1); // no preceding call to createVirtualKeyboard() assertThat(mDeviceImpl.getDeviceLocaleList()).isNull(); @@ -1013,7 +1017,7 @@ public class VirtualDeviceManagerServiceTest { @Test public void createVirtualMouse_hasDisplay_obtainFileDescriptor() { - mDeviceImpl.mVirtualDisplayIds.add(DISPLAY_ID_1); + addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1); mDeviceImpl.createVirtualMouse(MOUSE_CONFIG, BINDER); assertWithMessage("Virtual mouse should register fd when the display matches").that( mInputController.getInputDeviceDescriptors()).isNotEmpty(); @@ -1023,7 +1027,7 @@ public class VirtualDeviceManagerServiceTest { @Test public void createVirtualTouchscreen_hasDisplay_obtainFileDescriptor() { - mDeviceImpl.mVirtualDisplayIds.add(DISPLAY_ID_1); + addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1); mDeviceImpl.createVirtualTouchscreen(TOUCHSCREEN_CONFIG, BINDER); assertWithMessage("Virtual touchscreen should register fd when the display matches").that( mInputController.getInputDeviceDescriptors()).isNotEmpty(); @@ -1033,7 +1037,7 @@ public class VirtualDeviceManagerServiceTest { @Test public void createVirtualNavigationTouchpad_hasDisplay_obtainFileDescriptor() { - mDeviceImpl.mVirtualDisplayIds.add(DISPLAY_ID_1); + addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1); mDeviceImpl.createVirtualNavigationTouchpad(NAVIGATION_TOUCHPAD_CONFIG, BINDER); assertWithMessage("Virtual navigation touchpad should register fd when the display matches") .that( @@ -1055,8 +1059,7 @@ public class VirtualDeviceManagerServiceTest { @Test public void onAudioSessionStarting_hasVirtualAudioController() { - mDeviceImpl.onVirtualDisplayCreatedLocked( - mDeviceImpl.createWindowPolicyController(new ArrayList<>()), DISPLAY_ID_1); + addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1); mDeviceImpl.onAudioSessionStarting(DISPLAY_ID_1, mRoutingCallback, mConfigChangedCallback); @@ -1065,8 +1068,7 @@ public class VirtualDeviceManagerServiceTest { @Test public void onAudioSessionEnded_noVirtualAudioController() { - mDeviceImpl.onVirtualDisplayCreatedLocked( - mDeviceImpl.createWindowPolicyController(new ArrayList<>()), DISPLAY_ID_1); + addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1); mDeviceImpl.onAudioSessionStarting(DISPLAY_ID_1, mRoutingCallback, mConfigChangedCallback); mDeviceImpl.onAudioSessionEnded(); @@ -1076,8 +1078,7 @@ public class VirtualDeviceManagerServiceTest { @Test public void close_cleanVirtualAudioController() { - mDeviceImpl.onVirtualDisplayCreatedLocked( - mDeviceImpl.createWindowPolicyController(new ArrayList<>()), DISPLAY_ID_1); + addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1); mDeviceImpl.onAudioSessionStarting(DISPLAY_ID_1, mRoutingCallback, mConfigChangedCallback); mDeviceImpl.close(); @@ -1321,9 +1322,9 @@ public class VirtualDeviceManagerServiceTest { @Test public void setShowPointerIcon_setsValueForAllDisplays() { - mDeviceImpl.mVirtualDisplayIds.add(1); - mDeviceImpl.mVirtualDisplayIds.add(2); - mDeviceImpl.mVirtualDisplayIds.add(3); + addVirtualDisplay(mDeviceImpl, 1); + addVirtualDisplay(mDeviceImpl, 2); + addVirtualDisplay(mDeviceImpl, 3); VirtualMouseConfig config1 = new VirtualMouseConfig.Builder() .setAssociatedDisplayId(1) .setInputDeviceName(DEVICE_NAME_1) @@ -1346,7 +1347,9 @@ public class VirtualDeviceManagerServiceTest { mDeviceImpl.createVirtualMouse(config1, BINDER); mDeviceImpl.createVirtualMouse(config2, BINDER); mDeviceImpl.createVirtualMouse(config3, BINDER); + clearInvocations(mInputManagerInternalMock); mDeviceImpl.setShowPointerIcon(false); + verify(mInputManagerInternalMock, times(3)).setPointerIconVisible(eq(false), anyInt()); verify(mInputManagerInternalMock, never()).setPointerIconVisible(eq(true), anyInt()); mDeviceImpl.setShowPointerIcon(true); @@ -1355,9 +1358,8 @@ public class VirtualDeviceManagerServiceTest { @Test public void openNonBlockedAppOnVirtualDisplay_doesNotStartBlockedAlertActivity() { - mDeviceImpl.onVirtualDisplayCreatedLocked( - mDeviceImpl.createWindowPolicyController(new ArrayList<>()), DISPLAY_ID_1); - GenericWindowPolicyController gwpc = mDeviceImpl.getWindowPolicyControllersForTesting().get( + addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1); + GenericWindowPolicyController gwpc = mDeviceImpl.getDisplayWindowPolicyControllerForTest( DISPLAY_ID_1); doNothing().when(mContext).startActivityAsUser(any(), any(), any()); @@ -1376,9 +1378,8 @@ public class VirtualDeviceManagerServiceTest { @Test public void openPermissionControllerOnVirtualDisplay_startBlockedAlertActivity() { - mDeviceImpl.onVirtualDisplayCreatedLocked( - mDeviceImpl.createWindowPolicyController(new ArrayList<>()), DISPLAY_ID_1); - GenericWindowPolicyController gwpc = mDeviceImpl.getWindowPolicyControllersForTesting().get( + addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1); + GenericWindowPolicyController gwpc = mDeviceImpl.getDisplayWindowPolicyControllerForTest( DISPLAY_ID_1); doNothing().when(mContext).startActivityAsUser(any(), any(), any()); @@ -1397,9 +1398,8 @@ public class VirtualDeviceManagerServiceTest { @Test public void openSettingsOnVirtualDisplay_startBlockedAlertActivity() { - mDeviceImpl.onVirtualDisplayCreatedLocked( - mDeviceImpl.createWindowPolicyController(new ArrayList<>()), DISPLAY_ID_1); - GenericWindowPolicyController gwpc = mDeviceImpl.getWindowPolicyControllersForTesting().get( + addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1); + GenericWindowPolicyController gwpc = mDeviceImpl.getDisplayWindowPolicyControllerForTest( DISPLAY_ID_1); doNothing().when(mContext).startActivityAsUser(any(), any(), any()); @@ -1418,9 +1418,8 @@ public class VirtualDeviceManagerServiceTest { @Test public void openVendingOnVirtualDisplay_startBlockedAlertActivity() { - mDeviceImpl.onVirtualDisplayCreatedLocked( - mDeviceImpl.createWindowPolicyController(new ArrayList<>()), DISPLAY_ID_1); - GenericWindowPolicyController gwpc = mDeviceImpl.getWindowPolicyControllersForTesting().get( + addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1); + GenericWindowPolicyController gwpc = mDeviceImpl.getDisplayWindowPolicyControllerForTest( DISPLAY_ID_1); doNothing().when(mContext).startActivityAsUser(any(), any(), any()); @@ -1439,9 +1438,8 @@ public class VirtualDeviceManagerServiceTest { @Test public void openGoogleDialerOnVirtualDisplay_startBlockedAlertActivity() { - mDeviceImpl.onVirtualDisplayCreatedLocked( - mDeviceImpl.createWindowPolicyController(new ArrayList<>()), DISPLAY_ID_1); - GenericWindowPolicyController gwpc = mDeviceImpl.getWindowPolicyControllersForTesting().get( + addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1); + GenericWindowPolicyController gwpc = mDeviceImpl.getDisplayWindowPolicyControllerForTest( DISPLAY_ID_1); doNothing().when(mContext).startActivityAsUser(any(), any(), any()); @@ -1460,9 +1458,8 @@ public class VirtualDeviceManagerServiceTest { @Test public void openGoogleMapsOnVirtualDisplay_startBlockedAlertActivity() { - mDeviceImpl.onVirtualDisplayCreatedLocked( - mDeviceImpl.createWindowPolicyController(new ArrayList<>()), DISPLAY_ID_1); - GenericWindowPolicyController gwpc = mDeviceImpl.getWindowPolicyControllersForTesting().get( + addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1); + GenericWindowPolicyController gwpc = mDeviceImpl.getDisplayWindowPolicyControllerForTest( DISPLAY_ID_1); doNothing().when(mContext).startActivityAsUser(any(), any(), any()); @@ -1482,9 +1479,8 @@ public class VirtualDeviceManagerServiceTest { @Test public void registerRunningAppsChangedListener_onRunningAppsChanged_listenersNotified() { ArraySet<Integer> uids = new ArraySet<>(Arrays.asList(UID_1, UID_2)); - mDeviceImpl.onVirtualDisplayCreatedLocked( - mDeviceImpl.createWindowPolicyController(new ArrayList<>()), DISPLAY_ID_1); - GenericWindowPolicyController gwpc = mDeviceImpl.getWindowPolicyControllersForTesting().get( + addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1); + GenericWindowPolicyController gwpc = mDeviceImpl.getDisplayWindowPolicyControllerForTest( DISPLAY_ID_1); gwpc.onRunningAppsChanged(uids); @@ -1497,11 +1493,10 @@ public class VirtualDeviceManagerServiceTest { @Test public void noRunningAppsChangedListener_onRunningAppsChanged_doesNotThrowException() { ArraySet<Integer> uids = new ArraySet<>(Arrays.asList(UID_1, UID_2)); - mDeviceImpl.onVirtualDisplayCreatedLocked( - mDeviceImpl.createWindowPolicyController(new ArrayList<>()), DISPLAY_ID_1); - GenericWindowPolicyController gwpc = mDeviceImpl.getWindowPolicyControllersForTesting().get( + addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1); + GenericWindowPolicyController gwpc = mDeviceImpl.getDisplayWindowPolicyControllerForTest( DISPLAY_ID_1); - mDeviceImpl.onVirtualDisplayRemovedLocked(DISPLAY_ID_1); + gwpc.unregisterRunningAppsChangedListener(mDeviceImpl); // This call should not throw any exceptions. gwpc.onRunningAppsChanged(uids); @@ -1512,9 +1507,8 @@ public class VirtualDeviceManagerServiceTest { @Test public void canActivityBeLaunched_activityCanLaunch() { Intent intent = new Intent(ACTION_VIEW, Uri.parse(TEST_SITE)); - mDeviceImpl.onVirtualDisplayCreatedLocked( - mDeviceImpl.createWindowPolicyController(new ArrayList<>()), DISPLAY_ID_1); - GenericWindowPolicyController gwpc = mDeviceImpl.getWindowPolicyControllersForTesting().get( + addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1); + GenericWindowPolicyController gwpc = mDeviceImpl.getDisplayWindowPolicyControllerForTest( DISPLAY_ID_1); ArrayList<ActivityInfo> activityInfos = getActivityInfoList( NONBLOCKED_APP_PACKAGE_NAME, @@ -1537,9 +1531,8 @@ public class VirtualDeviceManagerServiceTest { doReturn(interceptor).when(interceptor).asBinder(); doReturn(interceptor).when(interceptor).queryLocalInterface(anyString()); - mDeviceImpl.onVirtualDisplayCreatedLocked( - mDeviceImpl.createWindowPolicyController(new ArrayList<>()), DISPLAY_ID_1); - GenericWindowPolicyController gwpc = mDeviceImpl.getWindowPolicyControllersForTesting().get( + addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1); + GenericWindowPolicyController gwpc = mDeviceImpl.getDisplayWindowPolicyControllerForTest( DISPLAY_ID_1); ArrayList<ActivityInfo> activityInfos = getActivityInfoList( NONBLOCKED_APP_PACKAGE_NAME, @@ -1581,9 +1574,8 @@ public class VirtualDeviceManagerServiceTest { doReturn(interceptor).when(interceptor).asBinder(); doReturn(interceptor).when(interceptor).queryLocalInterface(anyString()); - mDeviceImpl.onVirtualDisplayCreatedLocked( - mDeviceImpl.createWindowPolicyController(new ArrayList<>()), DISPLAY_ID_1); - GenericWindowPolicyController gwpc = mDeviceImpl.getWindowPolicyControllersForTesting().get( + addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1); + GenericWindowPolicyController gwpc = mDeviceImpl.getDisplayWindowPolicyControllerForTest( DISPLAY_ID_1); ArrayList<ActivityInfo> activityInfos = getActivityInfoList( NONBLOCKED_APP_PACKAGE_NAME, @@ -1626,8 +1618,7 @@ public class VirtualDeviceManagerServiceTest { } @Test - public void - restrictedActivityOnNonMatchingRestrictedVirtualDisplay_startBlockedAlertActivity() { + public void restrictedActivityNonMatchingRestrictedVirtualDisplay_startBlockedAlertActivity() { Intent blockedAppIntent = createRestrictedActivityBlockedIntent(List.of("abc"), "def"); verify(mContext).startActivityAsUser(argThat(intent -> intent.filterEquals(blockedAppIntent)), any(), any()); @@ -1654,15 +1645,15 @@ public class VirtualDeviceManagerServiceTest { @Test public void getDisplayIdsForDevice_oneDisplay_resultContainsCorrectDisplayId() { - mDeviceImpl.mVirtualDisplayIds.add(DISPLAY_ID_1); + addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1); ArraySet<Integer> displayIds = mLocalService.getDisplayIdsForDevice(VIRTUAL_DEVICE_ID_1); assertThat(displayIds).containsExactly(DISPLAY_ID_1); } @Test public void getDisplayIdsForDevice_twoDisplays_resultContainsCorrectDisplayIds() { - mDeviceImpl.mVirtualDisplayIds.add(DISPLAY_ID_1); - mDeviceImpl.mVirtualDisplayIds.add(DISPLAY_ID_2); + addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1); + addVirtualDisplay(mDeviceImpl, DISPLAY_ID_2); ArraySet<Integer> displayIds = mLocalService.getDisplayIdsForDevice(VIRTUAL_DEVICE_ID_1); assertThat(displayIds).containsExactly(DISPLAY_ID_1, DISPLAY_ID_2); } @@ -1677,15 +1668,22 @@ public class VirtualDeviceManagerServiceTest { private VirtualDeviceImpl createVirtualDevice(int virtualDeviceId, int ownerUid, VirtualDeviceParams params) { VirtualDeviceImpl virtualDeviceImpl = new VirtualDeviceImpl(mContext, - mAssociationInfo, new Binder(), ownerUid, virtualDeviceId, - mInputController, mSensorController, mCameraAccessController, - /* onDeviceCloseListener= */ deviceId -> mVdms.removeVirtualDevice(deviceId), + mAssociationInfo, mVdms, new Binder(), ownerUid, virtualDeviceId, + mInputController, mSensorController, mCameraAccessController + /* onDeviceCloseListener= */ /*deviceId -> mVdms.removeVirtualDevice(deviceId)*/, mPendingTrampolineCallback, mActivityListener, mSoundEffectListener, - mRunningAppsChangedCallback, params); + mRunningAppsChangedCallback, params, new DisplayManagerGlobal(mIDisplayManager)); mVdms.addVirtualDevice(virtualDeviceImpl); return virtualDeviceImpl; } + private void addVirtualDisplay(VirtualDeviceImpl virtualDevice, int displayId) { + when(mDisplayManagerInternalMock.createVirtualDisplay(any(), eq(mVirtualDisplayCallback), + eq(virtualDevice), any(), any())).thenReturn(displayId); + virtualDevice.createVirtualDisplay(VIRTUAL_DISPLAY_CONFIG, mVirtualDisplayCallback, + NONBLOCKED_APP_PACKAGE_NAME); + } + /** Helper class to drop permissions temporarily and restore them at the end of a test. */ static final class DropShellPermissionsTemporarily implements AutoCloseable { DropShellPermissionsTemporarily() { |