Merge "Refactor virtual display creation and cleanup" into udc-dev

This commit is contained in:
Ján Sebechlebský
2023-02-24 12:19:49 +00:00
committed by Android (Google) Code Review
3 changed files with 406 additions and 322 deletions

View File

@@ -51,6 +51,10 @@ import android.content.IntentFilter;
import android.content.pm.ActivityInfo; import android.content.pm.ActivityInfo;
import android.graphics.PointF; import android.graphics.PointF;
import android.hardware.display.DisplayManager; 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.VirtualDpadConfig;
import android.hardware.input.VirtualKeyEvent; import android.hardware.input.VirtualKeyEvent;
import android.hardware.input.VirtualKeyboardConfig; import android.hardware.input.VirtualKeyboardConfig;
@@ -82,6 +86,7 @@ import android.widget.Toast;
import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.BlockedAppStreamingActivity; 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.GenericWindowPolicyController.RunningAppsChangedListener;
import com.android.server.companion.virtual.audio.VirtualAudioController; import com.android.server.companion.virtual.audio.VirtualAudioController;
@@ -109,21 +114,29 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
private final Context mContext; private final Context mContext;
private final AssociationInfo mAssociationInfo; private final AssociationInfo mAssociationInfo;
private final VirtualDeviceManagerService mService;
private final PendingTrampolineCallback mPendingTrampolineCallback; private final PendingTrampolineCallback mPendingTrampolineCallback;
private final int mOwnerUid; private final int mOwnerUid;
private final int mDeviceId; 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 InputController mInputController;
private final SensorController mSensorController; private final SensorController mSensorController;
private final CameraAccessController mCameraAccessController; private final CameraAccessController mCameraAccessController;
private VirtualAudioController mVirtualAudioController; private VirtualAudioController mVirtualAudioController;
@VisibleForTesting
final ArraySet<Integer> mVirtualDisplayIds = new ArraySet<>();
private final OnDeviceCloseListener mOnDeviceCloseListener;
private final IBinder mAppToken; private final IBinder mAppToken;
private final VirtualDeviceParams mParams; 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 IVirtualDeviceActivityListener mActivityListener;
private final IVirtualDeviceSoundEffectListener mSoundEffectListener; private final IVirtualDeviceSoundEffectListener mSoundEffectListener;
private final DisplayManagerGlobal mDisplayManager;
@GuardedBy("mVirtualDeviceLock") @GuardedBy("mVirtualDeviceLock")
private final Map<IBinder, IntentFilter> mIntentInterceptors = new ArrayMap<>(); private final Map<IBinder, IntentFilter> mIntentInterceptors = new ArrayMap<>();
@NonNull @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( VirtualDeviceImpl(
Context context, Context context,
AssociationInfo associationInfo, AssociationInfo associationInfo,
VirtualDeviceManagerService service,
IBinder token, IBinder token,
int ownerUid, int ownerUid,
int deviceId, int deviceId,
CameraAccessController cameraAccessController, CameraAccessController cameraAccessController,
OnDeviceCloseListener onDeviceCloseListener,
PendingTrampolineCallback pendingTrampolineCallback, PendingTrampolineCallback pendingTrampolineCallback,
IVirtualDeviceActivityListener activityListener, IVirtualDeviceActivityListener activityListener,
IVirtualDeviceSoundEffectListener soundEffectListener, IVirtualDeviceSoundEffectListener soundEffectListener,
@@ -197,40 +203,43 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
this( this(
context, context,
associationInfo, associationInfo,
service,
token, token,
ownerUid, ownerUid,
deviceId, deviceId,
/* inputController= */ null, /* inputController= */ null,
/* sensorController= */ null, /* sensorController= */ null,
cameraAccessController, cameraAccessController,
onDeviceCloseListener,
pendingTrampolineCallback, pendingTrampolineCallback,
activityListener, activityListener,
soundEffectListener, soundEffectListener,
runningAppsChangedCallback, runningAppsChangedCallback,
params); params,
DisplayManagerGlobal.getInstance());
} }
@VisibleForTesting @VisibleForTesting
VirtualDeviceImpl( VirtualDeviceImpl(
Context context, Context context,
AssociationInfo associationInfo, AssociationInfo associationInfo,
VirtualDeviceManagerService service,
IBinder token, IBinder token,
int ownerUid, int ownerUid,
int deviceId, int deviceId,
InputController inputController, InputController inputController,
SensorController sensorController, SensorController sensorController,
CameraAccessController cameraAccessController, CameraAccessController cameraAccessController,
OnDeviceCloseListener onDeviceCloseListener,
PendingTrampolineCallback pendingTrampolineCallback, PendingTrampolineCallback pendingTrampolineCallback,
IVirtualDeviceActivityListener activityListener, IVirtualDeviceActivityListener activityListener,
IVirtualDeviceSoundEffectListener soundEffectListener, IVirtualDeviceSoundEffectListener soundEffectListener,
Consumer<ArraySet<Integer>> runningAppsChangedCallback, Consumer<ArraySet<Integer>> runningAppsChangedCallback,
VirtualDeviceParams params) { VirtualDeviceParams params,
DisplayManagerGlobal displayManager) {
super(PermissionEnforcer.fromContext(context)); super(PermissionEnforcer.fromContext(context));
UserHandle ownerUserHandle = UserHandle.getUserHandleForUid(ownerUid); UserHandle ownerUserHandle = UserHandle.getUserHandleForUid(ownerUid);
mContext = context.createContextAsUser(ownerUserHandle, 0); mContext = context.createContextAsUser(ownerUserHandle, 0);
mAssociationInfo = associationInfo; mAssociationInfo = associationInfo;
mService = service;
mPendingTrampolineCallback = pendingTrampolineCallback; mPendingTrampolineCallback = pendingTrampolineCallback;
mActivityListener = activityListener; mActivityListener = activityListener;
mSoundEffectListener = soundEffectListener; mSoundEffectListener = soundEffectListener;
@@ -239,6 +248,7 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
mDeviceId = deviceId; mDeviceId = deviceId;
mAppToken = token; mAppToken = token;
mParams = params; mParams = params;
mDisplayManager = displayManager;
if (inputController == null) { if (inputController == null) {
mInputController = new InputController( mInputController = new InputController(
mVirtualDeviceLock, mVirtualDeviceLock,
@@ -259,7 +269,6 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
} }
mCameraAccessController = cameraAccessController; mCameraAccessController = cameraAccessController;
mCameraAccessController.startObservingIfNeeded(); mCameraAccessController.startObservingIfNeeded();
mOnDeviceCloseListener = onDeviceCloseListener;
try { try {
token.linkToDeath(this, 0); token.linkToDeath(this, 0);
} catch (RemoteException e) { } catch (RemoteException e) {
@@ -331,9 +340,11 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
@Override // Binder call @Override // Binder call
public void launchPendingIntent(int displayId, PendingIntent pendingIntent, public void launchPendingIntent(int displayId, PendingIntent pendingIntent,
ResultReceiver resultReceiver) { ResultReceiver resultReceiver) {
if (!mVirtualDisplayIds.contains(displayId)) { synchronized (mVirtualDeviceLock) {
throw new SecurityException("Display ID " + displayId if (!mVirtualDisplays.contains(displayId)) {
+ " not found for this virtual device"); throw new SecurityException("Display ID " + displayId
+ " not found for this virtual device");
}
} }
if (pendingIntent.isActivity()) { if (pendingIntent.isActivity()) {
try { try {
@@ -383,24 +394,34 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
@EnforcePermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) @EnforcePermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
public void close() { public void close() {
super.close_enforcePermission(); super.close_enforcePermission();
// Remove about-to-be-closed virtual device from the service before butchering it.
mService.removeVirtualDevice(mDeviceId);
VirtualDisplayWrapper[] virtualDisplaysToBeReleased;
synchronized (mVirtualDeviceLock) { 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) { if (mVirtualAudioController != null) {
mVirtualAudioController.stopListening(); mVirtualAudioController.stopListening();
mVirtualAudioController = null; mVirtualAudioController = null;
} }
mLocaleList = 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; mVirtualSensorList = null;
mVirtualSensors.clear(); 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); mAppToken.unlinkToDeath(this, 0);
mCameraAccessController.stopObservingIfNeeded(); mCameraAccessController.stopObservingIfNeeded();
@@ -429,11 +450,6 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
return mVirtualAudioController; return mVirtualAudioController;
} }
@VisibleForTesting
SparseArray<GenericWindowPolicyController> getWindowPolicyControllersForTesting() {
return mWindowPolicyControllers;
}
@Override // Binder call @Override // Binder call
@EnforcePermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) @EnforcePermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
public void onAudioSessionStarting(int displayId, public void onAudioSessionStarting(int displayId,
@@ -441,7 +457,7 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
@Nullable IAudioConfigChangedCallback configChangedCallback) { @Nullable IAudioConfigChangedCallback configChangedCallback) {
super.onAudioSessionStarting_enforcePermission(); super.onAudioSessionStarting_enforcePermission();
synchronized (mVirtualDeviceLock) { synchronized (mVirtualDeviceLock) {
if (!mVirtualDisplayIds.contains(displayId)) { if (!mVirtualDisplays.contains(displayId)) {
throw new SecurityException( throw new SecurityException(
"Cannot start audio session for a display not associated with this virtual " "Cannot start audio session for a display not associated with this virtual "
+ "device"); + "device");
@@ -449,7 +465,8 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
if (mVirtualAudioController == null) { if (mVirtualAudioController == null) {
mVirtualAudioController = new VirtualAudioController(mContext); mVirtualAudioController = new VirtualAudioController(mContext);
GenericWindowPolicyController gwpc = mWindowPolicyControllers.get(displayId); GenericWindowPolicyController gwpc = mVirtualDisplays.get(
displayId).getWindowPolicyController();
mVirtualAudioController.startListening(gwpc, routingCallback, mVirtualAudioController.startListening(gwpc, routingCallback,
configChangedCallback); configChangedCallback);
} }
@@ -473,7 +490,7 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
public void createVirtualDpad(VirtualDpadConfig config, @NonNull IBinder deviceToken) { public void createVirtualDpad(VirtualDpadConfig config, @NonNull IBinder deviceToken) {
super.createVirtualDpad_enforcePermission(); super.createVirtualDpad_enforcePermission();
synchronized (mVirtualDeviceLock) { synchronized (mVirtualDeviceLock) {
if (!mVirtualDisplayIds.contains(config.getAssociatedDisplayId())) { if (!mVirtualDisplays.contains(config.getAssociatedDisplayId())) {
throw new SecurityException( throw new SecurityException(
"Cannot create a virtual dpad for a display not associated with " "Cannot create a virtual dpad for a display not associated with "
+ "this virtual device"); + "this virtual device");
@@ -493,7 +510,7 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
public void createVirtualKeyboard(VirtualKeyboardConfig config, @NonNull IBinder deviceToken) { public void createVirtualKeyboard(VirtualKeyboardConfig config, @NonNull IBinder deviceToken) {
super.createVirtualKeyboard_enforcePermission(); super.createVirtualKeyboard_enforcePermission();
synchronized (mVirtualDeviceLock) { synchronized (mVirtualDeviceLock) {
if (!mVirtualDisplayIds.contains(config.getAssociatedDisplayId())) { if (!mVirtualDisplays.contains(config.getAssociatedDisplayId())) {
throw new SecurityException( throw new SecurityException(
"Cannot create a virtual keyboard for a display not associated with " "Cannot create a virtual keyboard for a display not associated with "
+ "this virtual device"); + "this virtual device");
@@ -515,7 +532,7 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
public void createVirtualMouse(VirtualMouseConfig config, @NonNull IBinder deviceToken) { public void createVirtualMouse(VirtualMouseConfig config, @NonNull IBinder deviceToken) {
super.createVirtualMouse_enforcePermission(); super.createVirtualMouse_enforcePermission();
synchronized (mVirtualDeviceLock) { synchronized (mVirtualDeviceLock) {
if (!mVirtualDisplayIds.contains(config.getAssociatedDisplayId())) { if (!mVirtualDisplays.contains(config.getAssociatedDisplayId())) {
throw new SecurityException( throw new SecurityException(
"Cannot create a virtual mouse for a display not associated with this " "Cannot create a virtual mouse for a display not associated with this "
+ "virtual device"); + "virtual device");
@@ -536,7 +553,7 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
@NonNull IBinder deviceToken) { @NonNull IBinder deviceToken) {
super.createVirtualTouchscreen_enforcePermission(); super.createVirtualTouchscreen_enforcePermission();
synchronized (mVirtualDeviceLock) { synchronized (mVirtualDeviceLock) {
if (!mVirtualDisplayIds.contains(config.getAssociatedDisplayId())) { if (!mVirtualDisplays.contains(config.getAssociatedDisplayId())) {
throw new SecurityException( throw new SecurityException(
"Cannot create a virtual touchscreen for a display not associated with " "Cannot create a virtual touchscreen for a display not associated with "
+ "this virtual device"); + "this virtual device");
@@ -566,7 +583,7 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
@NonNull IBinder deviceToken) { @NonNull IBinder deviceToken) {
super.createVirtualNavigationTouchpad_enforcePermission(); super.createVirtualNavigationTouchpad_enforcePermission();
synchronized (mVirtualDeviceLock) { synchronized (mVirtualDeviceLock) {
if (!mVirtualDisplayIds.contains(config.getAssociatedDisplayId())) { if (!mVirtualDisplays.contains(config.getAssociatedDisplayId())) {
throw new SecurityException( throw new SecurityException(
"Cannot create a virtual navigation touchpad for a display not associated " "Cannot create a virtual navigation touchpad for a display not associated "
+ "with this virtual device"); + "with this virtual device");
@@ -704,7 +721,8 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
try { try {
synchronized (mVirtualDeviceLock) { synchronized (mVirtualDeviceLock) {
mDefaultShowPointerIcon = showPointerIcon; mDefaultShowPointerIcon = showPointerIcon;
for (int displayId : mVirtualDisplayIds) { for (int i = 0; i < mVirtualDisplays.size(); i++) {
final int displayId = mVirtualDisplays.keyAt(i);
mInputController.setShowPointerIcon(mDefaultShowPointerIcon, displayId); mInputController.setShowPointerIcon(mDefaultShowPointerIcon, displayId);
} }
} }
@@ -795,8 +813,8 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
fout.println(" mParams: " + mParams); fout.println(" mParams: " + mParams);
fout.println(" mVirtualDisplayIds: "); fout.println(" mVirtualDisplayIds: ");
synchronized (mVirtualDeviceLock) { synchronized (mVirtualDeviceLock) {
for (int id : mVirtualDisplayIds) { for (int i = 0; i < mVirtualDisplays.size(); i++) {
fout.println(" " + id); fout.println(" " + mVirtualDisplays.keyAt(i));
} }
fout.println(" mDefaultShowPointerIcon: " + mDefaultShowPointerIcon); fout.println(" mDefaultShowPointerIcon: " + mDefaultShowPointerIcon);
} }
@@ -804,61 +822,75 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
mSensorController.dump(fout); mSensorController.dump(fout);
} }
GenericWindowPolicyController createWindowPolicyController( private GenericWindowPolicyController createWindowPolicyController(
@NonNull List<String> displayCategories) { @NonNull List<String> displayCategories) {
synchronized (mVirtualDeviceLock) { final GenericWindowPolicyController gwpc =
final GenericWindowPolicyController gwpc = new GenericWindowPolicyController(FLAG_SECURE,
new GenericWindowPolicyController(FLAG_SECURE, SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS,
SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS, getAllowedUserHandles(),
getAllowedUserHandles(), mParams.getAllowedCrossTaskNavigations(),
mParams.getAllowedCrossTaskNavigations(), mParams.getBlockedCrossTaskNavigations(),
mParams.getBlockedCrossTaskNavigations(), mParams.getAllowedActivities(),
mParams.getAllowedActivities(), mParams.getBlockedActivities(),
mParams.getBlockedActivities(), mParams.getDefaultActivityPolicy(),
mParams.getDefaultActivityPolicy(), createListenerAdapter(),
createListenerAdapter(), this::onEnteringPipBlocked,
this::onEnteringPipBlocked, this::onActivityBlocked,
this::onActivityBlocked, this::onSecureWindowShown,
this::onSecureWindowShown, this::shouldInterceptIntent,
this::shouldInterceptIntent, displayCategories,
displayCategories, mParams.getDefaultRecentsPolicy());
mParams.getDefaultRecentsPolicy()); gwpc.registerRunningAppsChangedListener(/* listener= */ this);
gwpc.registerRunningAppsChangedListener(/* listener= */ this); return gwpc;
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) { synchronized (mVirtualDeviceLock) {
if (displayId == Display.INVALID_DISPLAY) { if (mVirtualDisplays.contains(displayId)) {
return; gwpc.unregisterRunningAppsChangedListener(this);
}
if (mVirtualDisplayIds.contains(displayId)) {
throw new IllegalStateException( throw new IllegalStateException(
"Virtual device already has a virtual display with ID " + displayId); "Virtual device already has a virtual display with ID " + displayId);
} }
mVirtualDisplayIds.add(displayId);
gwpc.setDisplayId(displayId); PowerManager.WakeLock wakeLock = createAndAcquireWakeLockForDisplay(displayId);
mWindowPolicyControllers.put(displayId, gwpc); mVirtualDisplays.put(displayId, new VirtualDisplayWrapper(callback, gwpc, wakeLock));
}
final long token = Binder.clearCallingIdentity();
try {
mInputController.setShowPointerIcon(mDefaultShowPointerIcon, displayId); mInputController.setShowPointerIcon(mDefaultShowPointerIcon, displayId);
mInputController.setPointerAcceleration(1f, displayId); mInputController.setPointerAcceleration(1f, displayId);
mInputController.setDisplayEligibilityForPointerCapture(/* isEligible= */ false, mInputController.setDisplayEligibilityForPointerCapture(/* isEligible= */ false,
displayId); displayId);
mInputController.setLocalIme(displayId); mInputController.setLocalIme(displayId);
} finally {
Binder.restoreCallingIdentity(token);
}
return displayId;
}
if (mPerDisplayWakelocks.containsKey(displayId)) { private PowerManager.WakeLock createAndAcquireWakeLockForDisplay(int displayId) {
Slog.e(TAG, "Not creating wakelock for displayId " + displayId); final long token = Binder.clearCallingIdentity();
return; try {
}
PowerManager powerManager = mContext.getSystemService(PowerManager.class); PowerManager powerManager = mContext.getSystemService(PowerManager.class);
PowerManager.WakeLock wakeLock = powerManager.newWakeLock( PowerManager.WakeLock wakeLock = powerManager.newWakeLock(
PowerManager.SCREEN_BRIGHT_WAKE_LOCK, PowerManager.SCREEN_BRIGHT_WAKE_LOCK,
TAG + ":" + displayId, displayId); TAG + ":" + displayId, displayId);
mPerDisplayWakelocks.put(displayId, wakeLock);
wakeLock.acquire(); 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) { private void onSecureWindowShown(int displayId, int uid) {
if (!mVirtualDisplayIds.contains(displayId)) { synchronized (mVirtualDeviceLock) {
return; if (!mVirtualDisplays.contains(displayId)) {
return;
}
} }
// If a virtual display isn't secure, the screen can't be captured. Show a warning toast // 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() { private ArraySet<UserHandle> getAllowedUserHandles() {
ArraySet<UserHandle> result = new ArraySet<>(); ArraySet<UserHandle> result = new ArraySet<>();
DevicePolicyManager dpm = mContext.getSystemService(DevicePolicyManager.class); final long token = Binder.clearCallingIdentity();
UserManager userManager = mContext.getSystemService(UserManager.class); try {
for (UserHandle profile : userManager.getAllProfiles()) { DevicePolicyManager dpm = mContext.getSystemService(DevicePolicyManager.class);
int nearbyAppStreamingPolicy = dpm.getNearbyAppStreamingPolicy(profile.getIdentifier()); UserManager userManager = mContext.getSystemService(UserManager.class);
if (nearbyAppStreamingPolicy == NEARBY_STREAMING_ENABLED for (UserHandle profile : userManager.getAllProfiles()) {
|| nearbyAppStreamingPolicy == NEARBY_STREAMING_NOT_CONTROLLED_BY_POLICY) { int nearbyAppStreamingPolicy = dpm.getNearbyAppStreamingPolicy(
result.add(profile); profile.getIdentifier());
} else if (nearbyAppStreamingPolicy == NEARBY_STREAMING_SAME_MANAGED_ACCOUNT_ONLY) { if (nearbyAppStreamingPolicy == NEARBY_STREAMING_ENABLED
if (mParams.getUsersWithMatchingAccounts().contains(profile)) { || nearbyAppStreamingPolicy == NEARBY_STREAMING_NOT_CONTROLLED_BY_POLICY) {
result.add(profile); 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; 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) { synchronized (mVirtualDeviceLock) {
if (!mVirtualDisplayIds.contains(displayId)) { virtualDisplayWrapper = mVirtualDisplays.removeReturnOld(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);
} }
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() { int getOwnerUid() {
return mOwnerUid; 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 * Returns true if an app with the given {@code uid} is currently running on this virtual
* device. * device.
*/ */
boolean isAppRunningOnVirtualDevice(int uid) { boolean isAppRunningOnVirtualDevice(int uid) {
final int size = mWindowPolicyControllers.size(); synchronized (mVirtualDeviceLock) {
for (int i = 0; i < size; i++) { for (int i = 0; i < mVirtualDisplays.size(); i++) {
if (mWindowPolicyControllers.valueAt(i).containsUid(uid)) { if (mVirtualDisplays.valueAt(i).getWindowPolicyController().containsUid(uid)) {
return true; return true;
}
} }
} }
return false; return false;
@@ -957,11 +1038,9 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
Looper looper) { Looper looper) {
synchronized (mVirtualDeviceLock) { synchronized (mVirtualDeviceLock) {
DisplayManager displayManager = mContext.getSystemService(DisplayManager.class); DisplayManager displayManager = mContext.getSystemService(DisplayManager.class);
final int size = mWindowPolicyControllers.size(); for (int i = 0; i < mVirtualDisplays.size(); i++) {
for (int i = 0; i < size; i++) { if (mVirtualDisplays.valueAt(i).getWindowPolicyController().containsUid(uid)) {
if (mWindowPolicyControllers.valueAt(i).containsUid(uid)) { Display display = displayManager.getDisplay(mVirtualDisplays.keyAt(i));
int displayId = mWindowPolicyControllers.keyAt(i);
Display display = displayManager.getDisplay(displayId);
if (display != null && display.isValid()) { if (display != null && display.isValid()) {
Toast.makeText(mContext.createDisplayContext(display), looper, text, Toast.makeText(mContext.createDisplayContext(display), looper, text,
duration).show(); duration).show();
@@ -972,7 +1051,9 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
} }
boolean isDisplayOwnedByVirtualDevice(int displayId) { boolean isDisplayOwnedByVirtualDevice(int displayId) {
return mVirtualDisplayIds.contains(displayId); synchronized (mVirtualDeviceLock) {
return mVirtualDisplays.contains(displayId);
}
} }
void onEnteringPipBlocked(int uid) { void onEnteringPipBlocked(int uid) {
@@ -1016,10 +1097,6 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
} }
} }
interface OnDeviceCloseListener {
void onClose(int deviceId);
}
interface PendingTrampolineCallback { interface PendingTrampolineCallback {
/** /**
* Called when the callback should start waiting for the given pending trampoline. * Called when the callback should start waiting for the given pending trampoline.
@@ -1073,4 +1150,31 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
+ ", displayId=" + mDisplayId + "}"; + ", 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;
}
}
} }

View File

@@ -37,7 +37,6 @@ import android.companion.virtual.VirtualDeviceParams;
import android.companion.virtual.sensor.VirtualSensor; import android.companion.virtual.sensor.VirtualSensor;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.hardware.display.DisplayManagerInternal;
import android.hardware.display.IVirtualDisplayCallback; import android.hardware.display.IVirtualDisplayCallback;
import android.hardware.display.VirtualDisplayConfig; import android.hardware.display.VirtualDisplayConfig;
import android.os.Binder; import android.os.Binder;
@@ -108,26 +107,26 @@ public class VirtualDeviceManagerService extends SystemService {
private final ActivityInterceptorCallback mActivityInterceptorCallback = private final ActivityInterceptorCallback mActivityInterceptorCallback =
new ActivityInterceptorCallback() { new ActivityInterceptorCallback() {
@Nullable @Nullable
@Override @Override
public ActivityInterceptResult onInterceptActivityLaunch(@NonNull public ActivityInterceptResult onInterceptActivityLaunch(@NonNull
ActivityInterceptorInfo info) { ActivityInterceptorInfo info) {
if (info.getCallingPackage() == null) { if (info.getCallingPackage() == null) {
return null; return null;
} }
PendingTrampoline pt = mPendingTrampolines.remove(info.getCallingPackage()); PendingTrampoline pt = mPendingTrampolines.remove(info.getCallingPackage());
if (pt == null) { if (pt == null) {
return null; return null;
} }
pt.mResultReceiver.send(VirtualDeviceManager.LAUNCH_SUCCESS, null); pt.mResultReceiver.send(VirtualDeviceManager.LAUNCH_SUCCESS, null);
ActivityOptions options = info.getCheckedOptions(); ActivityOptions options = info.getCheckedOptions();
if (options == null) { if (options == null) {
options = ActivityOptions.makeBasic(); options = ActivityOptions.makeBasic();
} }
return new ActivityInterceptResult( return new ActivityInterceptResult(
info.getIntent(), options.setLaunchDisplayId(pt.mDisplayId)); info.getIntent(), options.setLaunchDisplayId(pt.mDisplayId));
} }
}; };
@Override @Override
public void onStart() { public void onStart() {
@@ -146,8 +145,8 @@ public class VirtualDeviceManagerService extends SystemService {
CharSequence deviceName = mVirtualDevices.valueAt(i).getDisplayName(); CharSequence deviceName = mVirtualDevices.valueAt(i).getDisplayName();
mVirtualDevices.valueAt(i).showToastWhereUidIsRunning(appUid, mVirtualDevices.valueAt(i).showToastWhereUidIsRunning(appUid,
getContext().getString( getContext().getString(
com.android.internal.R.string.vdm_camera_access_denied, com.android.internal.R.string.vdm_camera_access_denied,
deviceName), deviceName),
Toast.LENGTH_LONG, Looper.myLooper()); Toast.LENGTH_LONG, Looper.myLooper());
} }
} }
@@ -193,34 +192,46 @@ public class VirtualDeviceManagerService extends SystemService {
} }
} }
@VisibleForTesting
void removeVirtualDevice(int deviceId) { void removeVirtualDevice(int deviceId) {
synchronized (mVirtualDeviceManagerLock) { synchronized (mVirtualDeviceManagerLock) {
mAppsOnVirtualDevices.remove(deviceId); mAppsOnVirtualDevices.remove(deviceId);
mVirtualDevices.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 { class VirtualDeviceManagerImpl extends IVirtualDeviceManager.Stub {
private final VirtualDeviceImpl.PendingTrampolineCallback mPendingTrampolineCallback = private final VirtualDeviceImpl.PendingTrampolineCallback mPendingTrampolineCallback =
new VirtualDeviceImpl.PendingTrampolineCallback() { new VirtualDeviceImpl.PendingTrampolineCallback() {
@Override @Override
public void startWaitingForPendingTrampoline(PendingTrampoline pendingTrampoline) { public void startWaitingForPendingTrampoline(
PendingTrampoline existing = mPendingTrampolines.put( PendingTrampoline pendingTrampoline) {
pendingTrampoline.mPendingIntent.getCreatorPackage(), PendingTrampoline existing = mPendingTrampolines.put(
pendingTrampoline); pendingTrampoline.mPendingIntent.getCreatorPackage(),
if (existing != null) { pendingTrampoline);
existing.mResultReceiver.send( if (existing != null) {
VirtualDeviceManager.LAUNCH_FAILURE_NO_ACTIVITY, null); existing.mResultReceiver.send(
} VirtualDeviceManager.LAUNCH_FAILURE_NO_ACTIVITY, null);
} }
}
@Override @Override
public void stopWaitingForPendingTrampoline(PendingTrampoline pendingTrampoline) { public void stopWaitingForPendingTrampoline(
mPendingTrampolines.remove(pendingTrampoline.mPendingIntent.getCreatorPackage()); PendingTrampoline pendingTrampoline) {
} mPendingTrampolines.remove(
}; pendingTrampoline.mPendingIntent.getCreatorPackage());
}
};
@Override // Binder call @Override // Binder call
public IVirtualDevice createVirtualDevice( public IVirtualDevice createVirtualDevice(
@@ -251,8 +262,9 @@ public class VirtualDeviceManagerService extends SystemService {
final Consumer<ArraySet<Integer>> runningAppsChangedCallback = final Consumer<ArraySet<Integer>> runningAppsChangedCallback =
runningUids -> notifyRunningAppsChanged(deviceId, runningUids); runningUids -> notifyRunningAppsChanged(deviceId, runningUids);
VirtualDeviceImpl virtualDevice = new VirtualDeviceImpl(getContext(), VirtualDeviceImpl virtualDevice = new VirtualDeviceImpl(getContext(),
associationInfo, token, callingUid, deviceId, cameraAccessController, associationInfo, VirtualDeviceManagerService.this, token, callingUid,
this::onDeviceClosed, mPendingTrampolineCallback, activityListener, deviceId, cameraAccessController,
mPendingTrampolineCallback, activityListener,
soundEffectListener, runningAppsChangedCallback, params); soundEffectListener, runningAppsChangedCallback, params);
mVirtualDevices.put(deviceId, virtualDevice); mVirtualDevices.put(deviceId, virtualDevice);
return virtualDevice; return virtualDevice;
@@ -281,26 +293,9 @@ public class VirtualDeviceManagerService extends SystemService {
"uid " + callingUid "uid " + callingUid
+ " is not the owner of the supplied VirtualDevice"); + " 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( int displayId = virtualDeviceImpl.createVirtualDisplay(virtualDisplayConfig, callback,
DisplayManagerInternal.class); packageName);
int displayId = displayManager.createVirtualDisplay(virtualDisplayConfig, callback,
virtualDevice, gwpc, packageName);
final long tokenTwo = Binder.clearCallingIdentity();
try {
virtualDeviceImpl.onVirtualDisplayCreatedLocked(gwpc, displayId);
} finally {
Binder.restoreCallingIdentity(tokenTwo);
}
mLocalService.onVirtualDisplayCreated(displayId); mLocalService.onVirtualDisplayCreated(displayId);
return displayId; return displayId;
} }
@@ -412,19 +407,6 @@ public class VirtualDeviceManagerService extends SystemService {
return null; 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 @Override
public boolean onTransact(int code, Parcel data, Parcel reply, int flags) public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
throws RemoteException { throws RemoteException {
@@ -512,9 +494,14 @@ public class VirtualDeviceManagerService extends SystemService {
@Override @Override
public void onVirtualDisplayRemoved(IVirtualDevice virtualDevice, int displayId) { public void onVirtualDisplayRemoved(IVirtualDevice virtualDevice, int displayId) {
final VirtualDisplayListener[] listeners; final VirtualDisplayListener[] listeners;
VirtualDeviceImpl virtualDeviceImpl;
synchronized (mVirtualDeviceManagerLock) { synchronized (mVirtualDeviceManagerLock) {
((VirtualDeviceImpl) virtualDevice).onVirtualDisplayRemovedLocked(displayId);
listeners = mVirtualDisplayListeners.toArray(new VirtualDisplayListener[0]); listeners = mVirtualDisplayListeners.toArray(new VirtualDisplayListener[0]);
virtualDeviceImpl = mVirtualDevices.get(
((VirtualDeviceImpl) virtualDevice).getDeviceId());
}
if (virtualDeviceImpl != null) {
virtualDeviceImpl.onVirtualDisplayRemoved(displayId);
} }
mHandler.post(() -> { mHandler.post(() -> {
for (VirtualDisplayListener listener : listeners) { for (VirtualDisplayListener listener : listeners) {
@@ -599,16 +586,11 @@ public class VirtualDeviceManagerService extends SystemService {
@Override @Override
public @NonNull ArraySet<Integer> getDisplayIdsForDevice(int deviceId) { public @NonNull ArraySet<Integer> getDisplayIdsForDevice(int deviceId) {
VirtualDeviceImpl virtualDevice;
synchronized (mVirtualDeviceManagerLock) { synchronized (mVirtualDeviceManagerLock) {
int size = mVirtualDevices.size(); virtualDevice = mVirtualDevices.get(deviceId);
for (int i = 0; i < size; i++) {
VirtualDeviceImpl device = mVirtualDevices.valueAt(i);
if (device.getDeviceId() == deviceId) {
return new ArraySet<>(device.mVirtualDisplayIds);
}
}
} }
return new ArraySet<>(); return virtualDevice == null ? new ArraySet<>() : virtualDevice.getDisplayIds();
} }
@Override @Override

View File

@@ -35,6 +35,7 @@ import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.nullable; import static org.mockito.ArgumentMatchers.nullable;
import static org.mockito.Mockito.argThat; import static org.mockito.Mockito.argThat;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
@@ -67,7 +68,11 @@ import android.content.IntentFilter;
import android.content.pm.ActivityInfo; import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo; import android.content.pm.ApplicationInfo;
import android.hardware.Sensor; import android.hardware.Sensor;
import android.hardware.display.DisplayManagerGlobal;
import android.hardware.display.DisplayManagerInternal; 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.IInputManager;
import android.hardware.input.VirtualDpadConfig; import android.hardware.input.VirtualDpadConfig;
import android.hardware.input.VirtualKeyEvent; 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 String DEVICE_NAME_3 = "device name 3";
private static final int DISPLAY_ID_1 = 2; private static final int DISPLAY_ID_1 = 2;
private static final int DISPLAY_ID_2 = 3; 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_1 = 50;
private static final int DEVICE_OWNER_UID_2 = 51; private static final int DEVICE_OWNER_UID_2 = 51;
private static final int UID_1 = 0; 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 FLAG_CANNOT_DISPLAY_ON_REMOTE_DEVICES = 0x00000;
private static final int VIRTUAL_DEVICE_ID_1 = 42; private static final int VIRTUAL_DEVICE_ID_1 = 42;
private static final int VIRTUAL_DEVICE_ID_2 = 43; 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 = private static final VirtualDpadConfig DPAD_CONFIG =
new VirtualDpadConfig.Builder() new VirtualDpadConfig.Builder()
.setVendorId(VENDOR_ID) .setVendorId(VENDOR_ID)
@@ -221,6 +229,8 @@ public class VirtualDeviceManagerServiceTest {
@Mock @Mock
private DisplayManagerInternal mDisplayManagerInternalMock; private DisplayManagerInternal mDisplayManagerInternalMock;
@Mock @Mock
private IDisplayManager mIDisplayManager;
@Mock
private VirtualDeviceImpl.PendingTrampolineCallback mPendingTrampolineCallback; private VirtualDeviceImpl.PendingTrampolineCallback mPendingTrampolineCallback;
@Mock @Mock
private DevicePolicyManager mDevicePolicyManagerMock; private DevicePolicyManager mDevicePolicyManagerMock;
@@ -237,6 +247,8 @@ public class VirtualDeviceManagerServiceTest {
@Mock @Mock
private IVirtualDeviceSoundEffectListener mSoundEffectListener; private IVirtualDeviceSoundEffectListener mSoundEffectListener;
@Mock @Mock
private IVirtualDisplayCallback mVirtualDisplayCallback;
@Mock
private Consumer<ArraySet<Integer>> mRunningAppsChangedCallback; private Consumer<ArraySet<Integer>> mRunningAppsChangedCallback;
@Mock @Mock
private VirtualDeviceManagerInternal.VirtualDisplayListener mDisplayListener; private VirtualDeviceManagerInternal.VirtualDisplayListener mDisplayListener;
@@ -271,9 +283,13 @@ public class VirtualDeviceManagerServiceTest {
private Intent createRestrictedActivityBlockedIntent(List displayCategories, private Intent createRestrictedActivityBlockedIntent(List displayCategories,
String targetDisplayCategory) { String targetDisplayCategory) {
mDeviceImpl.onVirtualDisplayCreatedLocked( when(mDisplayManagerInternalMock.createVirtualDisplay(any(), any(), any(), any(),
mDeviceImpl.createWindowPolicyController(displayCategories), DISPLAY_ID_1); eq(NONBLOCKED_APP_PACKAGE_NAME))).thenReturn(DISPLAY_ID_1);
GenericWindowPolicyController gwpc = mDeviceImpl.getWindowPolicyControllersForTesting().get( 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); DISPLAY_ID_1);
doNothing().when(mContext).startActivityAsUser(any(), any(), any()); doNothing().when(mContext).startActivityAsUser(any(), any(), any());
@@ -327,6 +343,7 @@ public class VirtualDeviceManagerServiceTest {
mContext = Mockito.spy(new ContextWrapper( mContext = Mockito.spy(new ContextWrapper(
InstrumentationRegistry.getInstrumentation().getTargetContext())); InstrumentationRegistry.getInstrumentation().getTargetContext()));
doReturn(mContext).when(mContext).createContextAsUser(eq(Process.myUserHandle()), anyInt()); doReturn(mContext).when(mContext).createContextAsUser(eq(Process.myUserHandle()), anyInt());
doNothing().when(mContext).sendBroadcastAsUser(any(), any());
when(mContext.getSystemService(Context.DEVICE_POLICY_SERVICE)).thenReturn( when(mContext.getSystemService(Context.DEVICE_POLICY_SERVICE)).thenReturn(
mDevicePolicyManagerMock); mDevicePolicyManagerMock);
@@ -369,15 +386,13 @@ public class VirtualDeviceManagerServiceTest {
@Test @Test
public void getDeviceIdForDisplayId_nonExistentDisplayId_returnsDefault() { public void getDeviceIdForDisplayId_nonExistentDisplayId_returnsDefault() {
mDeviceImpl.mVirtualDisplayIds.remove(DISPLAY_ID_1); assertThat(mVdm.getDeviceIdForDisplayId(NON_EXISTENT_DISPLAY_ID))
assertThat(mVdm.getDeviceIdForDisplayId(DISPLAY_ID_1))
.isEqualTo(DEVICE_ID_DEFAULT); .isEqualTo(DEVICE_ID_DEFAULT);
} }
@Test @Test
public void getDeviceIdForDisplayId_withValidVirtualDisplayId_returnsDeviceId() { public void getDeviceIdForDisplayId_withValidVirtualDisplayId_returnsDeviceId() {
mDeviceImpl.mVirtualDisplayIds.add(DISPLAY_ID_1); addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
assertThat(mVdm.getDeviceIdForDisplayId(DISPLAY_ID_1)) assertThat(mVdm.getDeviceIdForDisplayId(DISPLAY_ID_1))
.isEqualTo(mDeviceImpl.getDeviceId()); .isEqualTo(mDeviceImpl.getDeviceId());
@@ -503,10 +518,9 @@ public class VirtualDeviceManagerServiceTest {
@Test @Test
public void getDeviceIdsForUid_differentUidOnDevice_returnsNull() { public void getDeviceIdsForUid_differentUidOnDevice_returnsNull() {
GenericWindowPolicyController gwpc = addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
mDeviceImpl.createWindowPolicyController(new ArrayList<>()); mDeviceImpl.getDisplayWindowPolicyControllerForTest(DISPLAY_ID_1).onRunningAppsChanged(
mDeviceImpl.onVirtualDisplayCreatedLocked(gwpc, DISPLAY_ID_1); Sets.newArraySet(UID_2));
gwpc.onRunningAppsChanged(Sets.newArraySet(UID_2));
Set<Integer> deviceIds = mLocalService.getDeviceIdsForUid(UID_1); Set<Integer> deviceIds = mLocalService.getDeviceIdsForUid(UID_1);
assertThat(deviceIds).isEmpty(); assertThat(deviceIds).isEmpty();
@@ -514,10 +528,9 @@ public class VirtualDeviceManagerServiceTest {
@Test @Test
public void getDeviceIdsForUid_oneUidOnDevice_returnsCorrectId() { public void getDeviceIdsForUid_oneUidOnDevice_returnsCorrectId() {
GenericWindowPolicyController gwpc = addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
mDeviceImpl.createWindowPolicyController(new ArrayList<>()); mDeviceImpl.getDisplayWindowPolicyControllerForTest(DISPLAY_ID_1).onRunningAppsChanged(
mDeviceImpl.onVirtualDisplayCreatedLocked(gwpc, DISPLAY_ID_1); Sets.newArraySet(UID_1));
gwpc.onRunningAppsChanged(Sets.newArraySet(UID_1));
Set<Integer> deviceIds = mLocalService.getDeviceIdsForUid(UID_1); Set<Integer> deviceIds = mLocalService.getDeviceIdsForUid(UID_1);
assertThat(deviceIds).containsExactly(mDeviceImpl.getDeviceId()); assertThat(deviceIds).containsExactly(mDeviceImpl.getDeviceId());
@@ -525,10 +538,10 @@ public class VirtualDeviceManagerServiceTest {
@Test @Test
public void getDeviceIdsForUid_twoUidsOnDevice_returnsCorrectId() { public void getDeviceIdsForUid_twoUidsOnDevice_returnsCorrectId() {
GenericWindowPolicyController gwpc = addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
mDeviceImpl.createWindowPolicyController(new ArrayList<>());
mDeviceImpl.onVirtualDisplayCreatedLocked(gwpc, DISPLAY_ID_1); mDeviceImpl.getDisplayWindowPolicyControllerForTest(DISPLAY_ID_1).onRunningAppsChanged(
gwpc.onRunningAppsChanged(Sets.newArraySet(UID_1, UID_2)); Sets.newArraySet(UID_1, UID_2));
Set<Integer> deviceIds = mLocalService.getDeviceIdsForUid(UID_1); Set<Integer> deviceIds = mLocalService.getDeviceIdsForUid(UID_1);
assertThat(deviceIds).containsExactly(mDeviceImpl.getDeviceId()); assertThat(deviceIds).containsExactly(mDeviceImpl.getDeviceId());
@@ -538,11 +551,10 @@ public class VirtualDeviceManagerServiceTest {
public void getDeviceIdsForUid_twoDevicesUidOnOne_returnsCorrectId() { public void getDeviceIdsForUid_twoDevicesUidOnOne_returnsCorrectId() {
VirtualDeviceImpl secondDevice = createVirtualDevice(VIRTUAL_DEVICE_ID_2, VirtualDeviceImpl secondDevice = createVirtualDevice(VIRTUAL_DEVICE_ID_2,
DEVICE_OWNER_UID_2); DEVICE_OWNER_UID_2);
addVirtualDisplay(secondDevice, DISPLAY_ID_2);
GenericWindowPolicyController gwpc = secondDevice.getDisplayWindowPolicyControllerForTest(DISPLAY_ID_2).onRunningAppsChanged(
secondDevice.createWindowPolicyController(new ArrayList<>()); Sets.newArraySet(UID_1));
secondDevice.onVirtualDisplayCreatedLocked(gwpc, DISPLAY_ID_2);
gwpc.onRunningAppsChanged(Sets.newArraySet(UID_1));
Set<Integer> deviceIds = mLocalService.getDeviceIdsForUid(UID_1); Set<Integer> deviceIds = mLocalService.getDeviceIdsForUid(UID_1);
assertThat(deviceIds).containsExactly(secondDevice.getDeviceId()); assertThat(deviceIds).containsExactly(secondDevice.getDeviceId());
@@ -550,16 +562,16 @@ public class VirtualDeviceManagerServiceTest {
@Test @Test
public void getDeviceIdsForUid_twoDevicesUidOnBoth_returnsCorrectId() { public void getDeviceIdsForUid_twoDevicesUidOnBoth_returnsCorrectId() {
addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
VirtualDeviceImpl secondDevice = createVirtualDevice(VIRTUAL_DEVICE_ID_2, VirtualDeviceImpl secondDevice = createVirtualDevice(VIRTUAL_DEVICE_ID_2,
DEVICE_OWNER_UID_2); DEVICE_OWNER_UID_2);
GenericWindowPolicyController gwpc1 = addVirtualDisplay(secondDevice, DISPLAY_ID_2);
mDeviceImpl.createWindowPolicyController(new ArrayList<>());
GenericWindowPolicyController gwpc2 =
secondDevice.createWindowPolicyController(new ArrayList<>()); mDeviceImpl.getDisplayWindowPolicyControllerForTest(DISPLAY_ID_1).onRunningAppsChanged(
mDeviceImpl.onVirtualDisplayCreatedLocked(gwpc1, DISPLAY_ID_1); Sets.newArraySet(UID_1));
secondDevice.onVirtualDisplayCreatedLocked(gwpc2, DISPLAY_ID_2); secondDevice.getDisplayWindowPolicyControllerForTest(DISPLAY_ID_2).onRunningAppsChanged(
gwpc1.onRunningAppsChanged(Sets.newArraySet(UID_1)); Sets.newArraySet(UID_1, UID_2));
gwpc2.onRunningAppsChanged(Sets.newArraySet(UID_1, UID_2));
Set<Integer> deviceIds = mLocalService.getDeviceIdsForUid(UID_1); Set<Integer> deviceIds = mLocalService.getDeviceIdsForUid(UID_1);
assertThat(deviceIds).containsExactly( assertThat(deviceIds).containsExactly(
@@ -568,8 +580,7 @@ public class VirtualDeviceManagerServiceTest {
@Test @Test
public void getPreferredLocaleListForApp_keyboardAttached_returnLocaleHints() { public void getPreferredLocaleListForApp_keyboardAttached_returnLocaleHints() {
mDeviceImpl.mVirtualDisplayIds.add(DISPLAY_ID_1); addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
mDeviceImpl.createVirtualKeyboard(KEYBOARD_CONFIG, BINDER); mDeviceImpl.createVirtualKeyboard(KEYBOARD_CONFIG, BINDER);
mVdms.notifyRunningAppsChanged(mDeviceImpl.getDeviceId(), Sets.newArraySet(UID_1)); mVdms.notifyRunningAppsChanged(mDeviceImpl.getDeviceId(), Sets.newArraySet(UID_1));
@@ -609,8 +620,8 @@ public class VirtualDeviceManagerServiceTest {
.setLanguageTag("fr-FR") .setLanguageTag("fr-FR")
.build(); .build();
mDeviceImpl.mVirtualDisplayIds.add(DISPLAY_ID_1); addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
secondDevice.mVirtualDisplayIds.add(DISPLAY_ID_2); addVirtualDisplay(secondDevice, DISPLAY_ID_2);
mDeviceImpl.createVirtualKeyboard(firstKeyboardConfig, BINDER); mDeviceImpl.createVirtualKeyboard(firstKeyboardConfig, BINDER);
secondDevice.createVirtualKeyboard(secondKeyboardConfig, secondBinder); secondDevice.createVirtualKeyboard(secondKeyboardConfig, secondBinder);
@@ -640,10 +651,9 @@ public class VirtualDeviceManagerServiceTest {
@Test @Test
public void onVirtualDisplayRemovedLocked_doesNotThrowException() { public void onVirtualDisplayRemovedLocked_doesNotThrowException() {
mDeviceImpl.onVirtualDisplayCreatedLocked( addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
mDeviceImpl.createWindowPolicyController(new ArrayList<>()), DISPLAY_ID_1);
// This call should not throw any exceptions. // This call should not throw any exceptions.
mDeviceImpl.onVirtualDisplayRemovedLocked(DISPLAY_ID_1); mDeviceImpl.onVirtualDisplayRemoved(DISPLAY_ID_1);
} }
@Test @Test
@@ -659,8 +669,8 @@ public class VirtualDeviceManagerServiceTest {
@Test @Test
public void onVirtualDisplayRemovedLocked_listenersNotified() { public void onVirtualDisplayRemovedLocked_listenersNotified() {
mLocalService.registerVirtualDisplayListener(mDisplayListener); mLocalService.registerVirtualDisplayListener(mDisplayListener);
mDeviceImpl.onVirtualDisplayCreatedLocked(
mDeviceImpl.createWindowPolicyController(new ArrayList<>()), DISPLAY_ID_1); addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
mLocalService.onVirtualDisplayRemoved(mDeviceImpl, DISPLAY_ID_1); mLocalService.onVirtualDisplayRemoved(mDeviceImpl, DISPLAY_ID_1);
TestableLooper.get(this).processAllMessages(); TestableLooper.get(this).processAllMessages();
@@ -723,8 +733,7 @@ public class VirtualDeviceManagerServiceTest {
verify(mIPowerManagerMock, never()).acquireWakeLock(any(Binder.class), anyInt(), verify(mIPowerManagerMock, never()).acquireWakeLock(any(Binder.class), anyInt(),
nullable(String.class), nullable(String.class), nullable(WorkSource.class), nullable(String.class), nullable(String.class), nullable(WorkSource.class),
nullable(String.class), anyInt(), eq(null)); nullable(String.class), anyInt(), eq(null));
mDeviceImpl.onVirtualDisplayCreatedLocked( addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
mDeviceImpl.createWindowPolicyController(new ArrayList<>()), DISPLAY_ID_1);
verify(mIPowerManagerMock).acquireWakeLock(any(Binder.class), anyInt(), verify(mIPowerManagerMock).acquireWakeLock(any(Binder.class), anyInt(),
nullable(String.class), nullable(String.class), nullable(WorkSource.class), nullable(String.class), nullable(String.class), nullable(WorkSource.class),
nullable(String.class), eq(DISPLAY_ID_1), eq(null)); nullable(String.class), eq(DISPLAY_ID_1), eq(null));
@@ -733,12 +742,9 @@ public class VirtualDeviceManagerServiceTest {
@Test @Test
public void onVirtualDisplayCreatedLocked_duplicateCalls_onlyOneWakeLockIsAcquired() public void onVirtualDisplayCreatedLocked_duplicateCalls_onlyOneWakeLockIsAcquired()
throws RemoteException { throws RemoteException {
GenericWindowPolicyController gwpc = mDeviceImpl.createWindowPolicyController( addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
new ArrayList<>());
mDeviceImpl.onVirtualDisplayCreatedLocked(
mDeviceImpl.createWindowPolicyController(new ArrayList<>()), DISPLAY_ID_1);
assertThrows(IllegalStateException.class, assertThrows(IllegalStateException.class,
() -> mDeviceImpl.onVirtualDisplayCreatedLocked(gwpc, DISPLAY_ID_1)); () -> addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1));
TestableLooper.get(this).processAllMessages(); TestableLooper.get(this).processAllMessages();
verify(mIPowerManagerMock).acquireWakeLock(any(Binder.class), anyInt(), verify(mIPowerManagerMock).acquireWakeLock(any(Binder.class), anyInt(),
nullable(String.class), nullable(String.class), nullable(WorkSource.class), nullable(String.class), nullable(String.class), nullable(WorkSource.class),
@@ -749,13 +755,12 @@ public class VirtualDeviceManagerServiceTest {
public void onVirtualDisplayRemovedLocked_unknownDisplayId_throwsException() { public void onVirtualDisplayRemovedLocked_unknownDisplayId_throwsException() {
final int unknownDisplayId = 999; final int unknownDisplayId = 999;
assertThrows(IllegalStateException.class, assertThrows(IllegalStateException.class,
() -> mDeviceImpl.onVirtualDisplayRemovedLocked(unknownDisplayId)); () -> mDeviceImpl.onVirtualDisplayRemoved(unknownDisplayId));
} }
@Test @Test
public void onVirtualDisplayRemovedLocked_wakeLockIsReleased() throws RemoteException { public void onVirtualDisplayRemovedLocked_wakeLockIsReleased() throws RemoteException {
mDeviceImpl.onVirtualDisplayCreatedLocked( addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
mDeviceImpl.createWindowPolicyController(new ArrayList<>()), DISPLAY_ID_1);
ArgumentCaptor<IBinder> wakeLockCaptor = ArgumentCaptor.forClass(IBinder.class); ArgumentCaptor<IBinder> wakeLockCaptor = ArgumentCaptor.forClass(IBinder.class);
TestableLooper.get(this).processAllMessages(); TestableLooper.get(this).processAllMessages();
verify(mIPowerManagerMock).acquireWakeLock(wakeLockCaptor.capture(), verify(mIPowerManagerMock).acquireWakeLock(wakeLockCaptor.capture(),
@@ -764,14 +769,13 @@ public class VirtualDeviceManagerServiceTest {
nullable(String.class), eq(DISPLAY_ID_1), eq(null)); nullable(String.class), eq(DISPLAY_ID_1), eq(null));
IBinder wakeLock = wakeLockCaptor.getValue(); IBinder wakeLock = wakeLockCaptor.getValue();
mDeviceImpl.onVirtualDisplayRemovedLocked(DISPLAY_ID_1); mDeviceImpl.onVirtualDisplayRemoved(DISPLAY_ID_1);
verify(mIPowerManagerMock).releaseWakeLock(eq(wakeLock), anyInt()); verify(mIPowerManagerMock).releaseWakeLock(eq(wakeLock), anyInt());
} }
@Test @Test
public void addVirtualDisplay_displayNotReleased_wakeLockIsReleased() throws RemoteException { public void addVirtualDisplay_displayNotReleased_wakeLockIsReleased() throws RemoteException {
mDeviceImpl.onVirtualDisplayCreatedLocked( addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
mDeviceImpl.createWindowPolicyController(new ArrayList<>()), DISPLAY_ID_1);
ArgumentCaptor<IBinder> wakeLockCaptor = ArgumentCaptor.forClass(IBinder.class); ArgumentCaptor<IBinder> wakeLockCaptor = ArgumentCaptor.forClass(IBinder.class);
TestableLooper.get(this).processAllMessages(); TestableLooper.get(this).processAllMessages();
verify(mIPowerManagerMock).acquireWakeLock(wakeLockCaptor.capture(), verify(mIPowerManagerMock).acquireWakeLock(wakeLockCaptor.capture(),
@@ -825,7 +829,7 @@ public class VirtualDeviceManagerServiceTest {
@Test @Test
public void createVirtualTouchscreen_positiveDisplayDimension_successful() { public void createVirtualTouchscreen_positiveDisplayDimension_successful() {
mDeviceImpl.mVirtualDisplayIds.add(DISPLAY_ID_1); addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
VirtualTouchscreenConfig positiveConfig = VirtualTouchscreenConfig positiveConfig =
new VirtualTouchscreenConfig.Builder( new VirtualTouchscreenConfig.Builder(
/* touchscrenWidth= */ 600, /* touchscreenHeight= */ 800) /* touchscrenWidth= */ 600, /* touchscreenHeight= */ 800)
@@ -863,7 +867,7 @@ public class VirtualDeviceManagerServiceTest {
@Test @Test
public void createVirtualNavigationTouchpad_positiveDisplayDimension_successful() { public void createVirtualNavigationTouchpad_positiveDisplayDimension_successful() {
mDeviceImpl.mVirtualDisplayIds.add(DISPLAY_ID_1); addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
VirtualNavigationTouchpadConfig positiveConfig = VirtualNavigationTouchpadConfig positiveConfig =
new VirtualNavigationTouchpadConfig.Builder( new VirtualNavigationTouchpadConfig.Builder(
/* touchpadHeight= */ 50, /* touchpadWidth= */ 50) /* touchpadHeight= */ 50, /* touchpadWidth= */ 50)
@@ -888,7 +892,7 @@ public class VirtualDeviceManagerServiceTest {
@Test @Test
public void createVirtualDpad_noPermission_failsSecurityException() { public void createVirtualDpad_noPermission_failsSecurityException() {
mDeviceImpl.mVirtualDisplayIds.add(DISPLAY_ID_1); addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
try (DropShellPermissionsTemporarily drop = new DropShellPermissionsTemporarily()) { try (DropShellPermissionsTemporarily drop = new DropShellPermissionsTemporarily()) {
assertThrows(SecurityException.class, assertThrows(SecurityException.class,
() -> mDeviceImpl.createVirtualDpad(DPAD_CONFIG, BINDER)); () -> mDeviceImpl.createVirtualDpad(DPAD_CONFIG, BINDER));
@@ -897,7 +901,7 @@ public class VirtualDeviceManagerServiceTest {
@Test @Test
public void createVirtualKeyboard_noPermission_failsSecurityException() { public void createVirtualKeyboard_noPermission_failsSecurityException() {
mDeviceImpl.mVirtualDisplayIds.add(DISPLAY_ID_1); addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
try (DropShellPermissionsTemporarily drop = new DropShellPermissionsTemporarily()) { try (DropShellPermissionsTemporarily drop = new DropShellPermissionsTemporarily()) {
assertThrows(SecurityException.class, assertThrows(SecurityException.class,
() -> mDeviceImpl.createVirtualKeyboard(KEYBOARD_CONFIG, BINDER)); () -> mDeviceImpl.createVirtualKeyboard(KEYBOARD_CONFIG, BINDER));
@@ -906,7 +910,7 @@ public class VirtualDeviceManagerServiceTest {
@Test @Test
public void createVirtualMouse_noPermission_failsSecurityException() { public void createVirtualMouse_noPermission_failsSecurityException() {
mDeviceImpl.mVirtualDisplayIds.add(DISPLAY_ID_1); addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
try (DropShellPermissionsTemporarily drop = new DropShellPermissionsTemporarily()) { try (DropShellPermissionsTemporarily drop = new DropShellPermissionsTemporarily()) {
assertThrows(SecurityException.class, assertThrows(SecurityException.class,
() -> mDeviceImpl.createVirtualMouse(MOUSE_CONFIG, BINDER)); () -> mDeviceImpl.createVirtualMouse(MOUSE_CONFIG, BINDER));
@@ -915,7 +919,7 @@ public class VirtualDeviceManagerServiceTest {
@Test @Test
public void createVirtualTouchscreen_noPermission_failsSecurityException() { public void createVirtualTouchscreen_noPermission_failsSecurityException() {
mDeviceImpl.mVirtualDisplayIds.add(DISPLAY_ID_1); addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
try (DropShellPermissionsTemporarily drop = new DropShellPermissionsTemporarily()) { try (DropShellPermissionsTemporarily drop = new DropShellPermissionsTemporarily()) {
assertThrows(SecurityException.class, assertThrows(SecurityException.class,
() -> mDeviceImpl.createVirtualTouchscreen(TOUCHSCREEN_CONFIG, BINDER)); () -> mDeviceImpl.createVirtualTouchscreen(TOUCHSCREEN_CONFIG, BINDER));
@@ -924,7 +928,7 @@ public class VirtualDeviceManagerServiceTest {
@Test @Test
public void createVirtualNavigationTouchpad_noPermission_failsSecurityException() { public void createVirtualNavigationTouchpad_noPermission_failsSecurityException() {
mDeviceImpl.mVirtualDisplayIds.add(DISPLAY_ID_1); addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
try (DropShellPermissionsTemporarily drop = new DropShellPermissionsTemporarily()) { try (DropShellPermissionsTemporarily drop = new DropShellPermissionsTemporarily()) {
assertThrows(SecurityException.class, assertThrows(SecurityException.class,
() -> mDeviceImpl.createVirtualNavigationTouchpad(NAVIGATION_TOUCHPAD_CONFIG, () -> mDeviceImpl.createVirtualNavigationTouchpad(NAVIGATION_TOUCHPAD_CONFIG,
@@ -934,7 +938,7 @@ public class VirtualDeviceManagerServiceTest {
@Test @Test
public void onAudioSessionStarting_noPermission_failsSecurityException() { public void onAudioSessionStarting_noPermission_failsSecurityException() {
mDeviceImpl.mVirtualDisplayIds.add(DISPLAY_ID_1); addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
try (DropShellPermissionsTemporarily drop = new DropShellPermissionsTemporarily()) { try (DropShellPermissionsTemporarily drop = new DropShellPermissionsTemporarily()) {
assertThrows(SecurityException.class, assertThrows(SecurityException.class,
() -> mDeviceImpl.onAudioSessionStarting( () -> mDeviceImpl.onAudioSessionStarting(
@@ -951,7 +955,7 @@ public class VirtualDeviceManagerServiceTest {
@Test @Test
public void createVirtualDpad_hasDisplay_obtainFileDescriptor() { public void createVirtualDpad_hasDisplay_obtainFileDescriptor() {
mDeviceImpl.mVirtualDisplayIds.add(DISPLAY_ID_1); addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
mDeviceImpl.createVirtualDpad(DPAD_CONFIG, BINDER); mDeviceImpl.createVirtualDpad(DPAD_CONFIG, BINDER);
assertWithMessage("Virtual dpad should register fd when the display matches").that( assertWithMessage("Virtual dpad should register fd when the display matches").that(
mInputController.getInputDeviceDescriptors()).isNotEmpty(); mInputController.getInputDeviceDescriptors()).isNotEmpty();
@@ -961,7 +965,7 @@ public class VirtualDeviceManagerServiceTest {
@Test @Test
public void createVirtualKeyboard_hasDisplay_obtainFileDescriptor() { public void createVirtualKeyboard_hasDisplay_obtainFileDescriptor() {
mDeviceImpl.mVirtualDisplayIds.add(DISPLAY_ID_1); addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
mDeviceImpl.createVirtualKeyboard(KEYBOARD_CONFIG, BINDER); mDeviceImpl.createVirtualKeyboard(KEYBOARD_CONFIG, BINDER);
assertWithMessage("Virtual keyboard should register fd when the display matches").that( assertWithMessage("Virtual keyboard should register fd when the display matches").that(
mInputController.getInputDeviceDescriptors()).isNotEmpty(); mInputController.getInputDeviceDescriptors()).isNotEmpty();
@@ -971,7 +975,7 @@ public class VirtualDeviceManagerServiceTest {
@Test @Test
public void createVirtualKeyboard_keyboardCreated_localeUpdated() { public void createVirtualKeyboard_keyboardCreated_localeUpdated() {
mDeviceImpl.mVirtualDisplayIds.add(DISPLAY_ID_1); addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
mDeviceImpl.createVirtualKeyboard(KEYBOARD_CONFIG, BINDER); mDeviceImpl.createVirtualKeyboard(KEYBOARD_CONFIG, BINDER);
assertWithMessage("Virtual keyboard should register fd when the display matches") assertWithMessage("Virtual keyboard should register fd when the display matches")
.that(mInputController.getInputDeviceDescriptors()) .that(mInputController.getInputDeviceDescriptors())
@@ -992,7 +996,7 @@ public class VirtualDeviceManagerServiceTest {
.setAssociatedDisplayId(DISPLAY_ID_1) .setAssociatedDisplayId(DISPLAY_ID_1)
.build(); .build();
mDeviceImpl.mVirtualDisplayIds.add(DISPLAY_ID_1); addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
mDeviceImpl.createVirtualKeyboard(configWithoutExplicitLayoutInfo, BINDER); mDeviceImpl.createVirtualKeyboard(configWithoutExplicitLayoutInfo, BINDER);
assertWithMessage("Virtual keyboard should register fd when the display matches") assertWithMessage("Virtual keyboard should register fd when the display matches")
.that(mInputController.getInputDeviceDescriptors()) .that(mInputController.getInputDeviceDescriptors())
@@ -1005,7 +1009,7 @@ public class VirtualDeviceManagerServiceTest {
@Test @Test
public void virtualDeviceWithoutKeyboard_noLocaleUpdate() { public void virtualDeviceWithoutKeyboard_noLocaleUpdate() {
mDeviceImpl.mVirtualDisplayIds.add(DISPLAY_ID_1); addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
// no preceding call to createVirtualKeyboard() // no preceding call to createVirtualKeyboard()
assertThat(mDeviceImpl.getDeviceLocaleList()).isNull(); assertThat(mDeviceImpl.getDeviceLocaleList()).isNull();
@@ -1013,7 +1017,7 @@ public class VirtualDeviceManagerServiceTest {
@Test @Test
public void createVirtualMouse_hasDisplay_obtainFileDescriptor() { public void createVirtualMouse_hasDisplay_obtainFileDescriptor() {
mDeviceImpl.mVirtualDisplayIds.add(DISPLAY_ID_1); addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
mDeviceImpl.createVirtualMouse(MOUSE_CONFIG, BINDER); mDeviceImpl.createVirtualMouse(MOUSE_CONFIG, BINDER);
assertWithMessage("Virtual mouse should register fd when the display matches").that( assertWithMessage("Virtual mouse should register fd when the display matches").that(
mInputController.getInputDeviceDescriptors()).isNotEmpty(); mInputController.getInputDeviceDescriptors()).isNotEmpty();
@@ -1023,7 +1027,7 @@ public class VirtualDeviceManagerServiceTest {
@Test @Test
public void createVirtualTouchscreen_hasDisplay_obtainFileDescriptor() { public void createVirtualTouchscreen_hasDisplay_obtainFileDescriptor() {
mDeviceImpl.mVirtualDisplayIds.add(DISPLAY_ID_1); addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
mDeviceImpl.createVirtualTouchscreen(TOUCHSCREEN_CONFIG, BINDER); mDeviceImpl.createVirtualTouchscreen(TOUCHSCREEN_CONFIG, BINDER);
assertWithMessage("Virtual touchscreen should register fd when the display matches").that( assertWithMessage("Virtual touchscreen should register fd when the display matches").that(
mInputController.getInputDeviceDescriptors()).isNotEmpty(); mInputController.getInputDeviceDescriptors()).isNotEmpty();
@@ -1033,7 +1037,7 @@ public class VirtualDeviceManagerServiceTest {
@Test @Test
public void createVirtualNavigationTouchpad_hasDisplay_obtainFileDescriptor() { public void createVirtualNavigationTouchpad_hasDisplay_obtainFileDescriptor() {
mDeviceImpl.mVirtualDisplayIds.add(DISPLAY_ID_1); addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
mDeviceImpl.createVirtualNavigationTouchpad(NAVIGATION_TOUCHPAD_CONFIG, BINDER); mDeviceImpl.createVirtualNavigationTouchpad(NAVIGATION_TOUCHPAD_CONFIG, BINDER);
assertWithMessage("Virtual navigation touchpad should register fd when the display matches") assertWithMessage("Virtual navigation touchpad should register fd when the display matches")
.that( .that(
@@ -1055,8 +1059,7 @@ public class VirtualDeviceManagerServiceTest {
@Test @Test
public void onAudioSessionStarting_hasVirtualAudioController() { public void onAudioSessionStarting_hasVirtualAudioController() {
mDeviceImpl.onVirtualDisplayCreatedLocked( addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
mDeviceImpl.createWindowPolicyController(new ArrayList<>()), DISPLAY_ID_1);
mDeviceImpl.onAudioSessionStarting(DISPLAY_ID_1, mRoutingCallback, mConfigChangedCallback); mDeviceImpl.onAudioSessionStarting(DISPLAY_ID_1, mRoutingCallback, mConfigChangedCallback);
@@ -1065,8 +1068,7 @@ public class VirtualDeviceManagerServiceTest {
@Test @Test
public void onAudioSessionEnded_noVirtualAudioController() { public void onAudioSessionEnded_noVirtualAudioController() {
mDeviceImpl.onVirtualDisplayCreatedLocked( addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
mDeviceImpl.createWindowPolicyController(new ArrayList<>()), DISPLAY_ID_1);
mDeviceImpl.onAudioSessionStarting(DISPLAY_ID_1, mRoutingCallback, mConfigChangedCallback); mDeviceImpl.onAudioSessionStarting(DISPLAY_ID_1, mRoutingCallback, mConfigChangedCallback);
mDeviceImpl.onAudioSessionEnded(); mDeviceImpl.onAudioSessionEnded();
@@ -1076,8 +1078,7 @@ public class VirtualDeviceManagerServiceTest {
@Test @Test
public void close_cleanVirtualAudioController() { public void close_cleanVirtualAudioController() {
mDeviceImpl.onVirtualDisplayCreatedLocked( addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
mDeviceImpl.createWindowPolicyController(new ArrayList<>()), DISPLAY_ID_1);
mDeviceImpl.onAudioSessionStarting(DISPLAY_ID_1, mRoutingCallback, mConfigChangedCallback); mDeviceImpl.onAudioSessionStarting(DISPLAY_ID_1, mRoutingCallback, mConfigChangedCallback);
mDeviceImpl.close(); mDeviceImpl.close();
@@ -1321,9 +1322,9 @@ public class VirtualDeviceManagerServiceTest {
@Test @Test
public void setShowPointerIcon_setsValueForAllDisplays() { public void setShowPointerIcon_setsValueForAllDisplays() {
mDeviceImpl.mVirtualDisplayIds.add(1); addVirtualDisplay(mDeviceImpl, 1);
mDeviceImpl.mVirtualDisplayIds.add(2); addVirtualDisplay(mDeviceImpl, 2);
mDeviceImpl.mVirtualDisplayIds.add(3); addVirtualDisplay(mDeviceImpl, 3);
VirtualMouseConfig config1 = new VirtualMouseConfig.Builder() VirtualMouseConfig config1 = new VirtualMouseConfig.Builder()
.setAssociatedDisplayId(1) .setAssociatedDisplayId(1)
.setInputDeviceName(DEVICE_NAME_1) .setInputDeviceName(DEVICE_NAME_1)
@@ -1346,7 +1347,9 @@ public class VirtualDeviceManagerServiceTest {
mDeviceImpl.createVirtualMouse(config1, BINDER); mDeviceImpl.createVirtualMouse(config1, BINDER);
mDeviceImpl.createVirtualMouse(config2, BINDER); mDeviceImpl.createVirtualMouse(config2, BINDER);
mDeviceImpl.createVirtualMouse(config3, BINDER); mDeviceImpl.createVirtualMouse(config3, BINDER);
clearInvocations(mInputManagerInternalMock);
mDeviceImpl.setShowPointerIcon(false); mDeviceImpl.setShowPointerIcon(false);
verify(mInputManagerInternalMock, times(3)).setPointerIconVisible(eq(false), anyInt()); verify(mInputManagerInternalMock, times(3)).setPointerIconVisible(eq(false), anyInt());
verify(mInputManagerInternalMock, never()).setPointerIconVisible(eq(true), anyInt()); verify(mInputManagerInternalMock, never()).setPointerIconVisible(eq(true), anyInt());
mDeviceImpl.setShowPointerIcon(true); mDeviceImpl.setShowPointerIcon(true);
@@ -1355,9 +1358,8 @@ public class VirtualDeviceManagerServiceTest {
@Test @Test
public void openNonBlockedAppOnVirtualDisplay_doesNotStartBlockedAlertActivity() { public void openNonBlockedAppOnVirtualDisplay_doesNotStartBlockedAlertActivity() {
mDeviceImpl.onVirtualDisplayCreatedLocked( addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
mDeviceImpl.createWindowPolicyController(new ArrayList<>()), DISPLAY_ID_1); GenericWindowPolicyController gwpc = mDeviceImpl.getDisplayWindowPolicyControllerForTest(
GenericWindowPolicyController gwpc = mDeviceImpl.getWindowPolicyControllersForTesting().get(
DISPLAY_ID_1); DISPLAY_ID_1);
doNothing().when(mContext).startActivityAsUser(any(), any(), any()); doNothing().when(mContext).startActivityAsUser(any(), any(), any());
@@ -1376,9 +1378,8 @@ public class VirtualDeviceManagerServiceTest {
@Test @Test
public void openPermissionControllerOnVirtualDisplay_startBlockedAlertActivity() { public void openPermissionControllerOnVirtualDisplay_startBlockedAlertActivity() {
mDeviceImpl.onVirtualDisplayCreatedLocked( addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
mDeviceImpl.createWindowPolicyController(new ArrayList<>()), DISPLAY_ID_1); GenericWindowPolicyController gwpc = mDeviceImpl.getDisplayWindowPolicyControllerForTest(
GenericWindowPolicyController gwpc = mDeviceImpl.getWindowPolicyControllersForTesting().get(
DISPLAY_ID_1); DISPLAY_ID_1);
doNothing().when(mContext).startActivityAsUser(any(), any(), any()); doNothing().when(mContext).startActivityAsUser(any(), any(), any());
@@ -1397,9 +1398,8 @@ public class VirtualDeviceManagerServiceTest {
@Test @Test
public void openSettingsOnVirtualDisplay_startBlockedAlertActivity() { public void openSettingsOnVirtualDisplay_startBlockedAlertActivity() {
mDeviceImpl.onVirtualDisplayCreatedLocked( addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
mDeviceImpl.createWindowPolicyController(new ArrayList<>()), DISPLAY_ID_1); GenericWindowPolicyController gwpc = mDeviceImpl.getDisplayWindowPolicyControllerForTest(
GenericWindowPolicyController gwpc = mDeviceImpl.getWindowPolicyControllersForTesting().get(
DISPLAY_ID_1); DISPLAY_ID_1);
doNothing().when(mContext).startActivityAsUser(any(), any(), any()); doNothing().when(mContext).startActivityAsUser(any(), any(), any());
@@ -1418,9 +1418,8 @@ public class VirtualDeviceManagerServiceTest {
@Test @Test
public void openVendingOnVirtualDisplay_startBlockedAlertActivity() { public void openVendingOnVirtualDisplay_startBlockedAlertActivity() {
mDeviceImpl.onVirtualDisplayCreatedLocked( addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
mDeviceImpl.createWindowPolicyController(new ArrayList<>()), DISPLAY_ID_1); GenericWindowPolicyController gwpc = mDeviceImpl.getDisplayWindowPolicyControllerForTest(
GenericWindowPolicyController gwpc = mDeviceImpl.getWindowPolicyControllersForTesting().get(
DISPLAY_ID_1); DISPLAY_ID_1);
doNothing().when(mContext).startActivityAsUser(any(), any(), any()); doNothing().when(mContext).startActivityAsUser(any(), any(), any());
@@ -1439,9 +1438,8 @@ public class VirtualDeviceManagerServiceTest {
@Test @Test
public void openGoogleDialerOnVirtualDisplay_startBlockedAlertActivity() { public void openGoogleDialerOnVirtualDisplay_startBlockedAlertActivity() {
mDeviceImpl.onVirtualDisplayCreatedLocked( addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
mDeviceImpl.createWindowPolicyController(new ArrayList<>()), DISPLAY_ID_1); GenericWindowPolicyController gwpc = mDeviceImpl.getDisplayWindowPolicyControllerForTest(
GenericWindowPolicyController gwpc = mDeviceImpl.getWindowPolicyControllersForTesting().get(
DISPLAY_ID_1); DISPLAY_ID_1);
doNothing().when(mContext).startActivityAsUser(any(), any(), any()); doNothing().when(mContext).startActivityAsUser(any(), any(), any());
@@ -1460,9 +1458,8 @@ public class VirtualDeviceManagerServiceTest {
@Test @Test
public void openGoogleMapsOnVirtualDisplay_startBlockedAlertActivity() { public void openGoogleMapsOnVirtualDisplay_startBlockedAlertActivity() {
mDeviceImpl.onVirtualDisplayCreatedLocked( addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
mDeviceImpl.createWindowPolicyController(new ArrayList<>()), DISPLAY_ID_1); GenericWindowPolicyController gwpc = mDeviceImpl.getDisplayWindowPolicyControllerForTest(
GenericWindowPolicyController gwpc = mDeviceImpl.getWindowPolicyControllersForTesting().get(
DISPLAY_ID_1); DISPLAY_ID_1);
doNothing().when(mContext).startActivityAsUser(any(), any(), any()); doNothing().when(mContext).startActivityAsUser(any(), any(), any());
@@ -1482,9 +1479,8 @@ public class VirtualDeviceManagerServiceTest {
@Test @Test
public void registerRunningAppsChangedListener_onRunningAppsChanged_listenersNotified() { public void registerRunningAppsChangedListener_onRunningAppsChanged_listenersNotified() {
ArraySet<Integer> uids = new ArraySet<>(Arrays.asList(UID_1, UID_2)); ArraySet<Integer> uids = new ArraySet<>(Arrays.asList(UID_1, UID_2));
mDeviceImpl.onVirtualDisplayCreatedLocked( addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
mDeviceImpl.createWindowPolicyController(new ArrayList<>()), DISPLAY_ID_1); GenericWindowPolicyController gwpc = mDeviceImpl.getDisplayWindowPolicyControllerForTest(
GenericWindowPolicyController gwpc = mDeviceImpl.getWindowPolicyControllersForTesting().get(
DISPLAY_ID_1); DISPLAY_ID_1);
gwpc.onRunningAppsChanged(uids); gwpc.onRunningAppsChanged(uids);
@@ -1497,11 +1493,10 @@ public class VirtualDeviceManagerServiceTest {
@Test @Test
public void noRunningAppsChangedListener_onRunningAppsChanged_doesNotThrowException() { public void noRunningAppsChangedListener_onRunningAppsChanged_doesNotThrowException() {
ArraySet<Integer> uids = new ArraySet<>(Arrays.asList(UID_1, UID_2)); ArraySet<Integer> uids = new ArraySet<>(Arrays.asList(UID_1, UID_2));
mDeviceImpl.onVirtualDisplayCreatedLocked( addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
mDeviceImpl.createWindowPolicyController(new ArrayList<>()), DISPLAY_ID_1); GenericWindowPolicyController gwpc = mDeviceImpl.getDisplayWindowPolicyControllerForTest(
GenericWindowPolicyController gwpc = mDeviceImpl.getWindowPolicyControllersForTesting().get(
DISPLAY_ID_1); DISPLAY_ID_1);
mDeviceImpl.onVirtualDisplayRemovedLocked(DISPLAY_ID_1); gwpc.unregisterRunningAppsChangedListener(mDeviceImpl);
// This call should not throw any exceptions. // This call should not throw any exceptions.
gwpc.onRunningAppsChanged(uids); gwpc.onRunningAppsChanged(uids);
@@ -1512,9 +1507,8 @@ public class VirtualDeviceManagerServiceTest {
@Test @Test
public void canActivityBeLaunched_activityCanLaunch() { public void canActivityBeLaunched_activityCanLaunch() {
Intent intent = new Intent(ACTION_VIEW, Uri.parse(TEST_SITE)); Intent intent = new Intent(ACTION_VIEW, Uri.parse(TEST_SITE));
mDeviceImpl.onVirtualDisplayCreatedLocked( addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
mDeviceImpl.createWindowPolicyController(new ArrayList<>()), DISPLAY_ID_1); GenericWindowPolicyController gwpc = mDeviceImpl.getDisplayWindowPolicyControllerForTest(
GenericWindowPolicyController gwpc = mDeviceImpl.getWindowPolicyControllersForTesting().get(
DISPLAY_ID_1); DISPLAY_ID_1);
ArrayList<ActivityInfo> activityInfos = getActivityInfoList( ArrayList<ActivityInfo> activityInfos = getActivityInfoList(
NONBLOCKED_APP_PACKAGE_NAME, NONBLOCKED_APP_PACKAGE_NAME,
@@ -1537,9 +1531,8 @@ public class VirtualDeviceManagerServiceTest {
doReturn(interceptor).when(interceptor).asBinder(); doReturn(interceptor).when(interceptor).asBinder();
doReturn(interceptor).when(interceptor).queryLocalInterface(anyString()); doReturn(interceptor).when(interceptor).queryLocalInterface(anyString());
mDeviceImpl.onVirtualDisplayCreatedLocked( addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
mDeviceImpl.createWindowPolicyController(new ArrayList<>()), DISPLAY_ID_1); GenericWindowPolicyController gwpc = mDeviceImpl.getDisplayWindowPolicyControllerForTest(
GenericWindowPolicyController gwpc = mDeviceImpl.getWindowPolicyControllersForTesting().get(
DISPLAY_ID_1); DISPLAY_ID_1);
ArrayList<ActivityInfo> activityInfos = getActivityInfoList( ArrayList<ActivityInfo> activityInfos = getActivityInfoList(
NONBLOCKED_APP_PACKAGE_NAME, NONBLOCKED_APP_PACKAGE_NAME,
@@ -1581,9 +1574,8 @@ public class VirtualDeviceManagerServiceTest {
doReturn(interceptor).when(interceptor).asBinder(); doReturn(interceptor).when(interceptor).asBinder();
doReturn(interceptor).when(interceptor).queryLocalInterface(anyString()); doReturn(interceptor).when(interceptor).queryLocalInterface(anyString());
mDeviceImpl.onVirtualDisplayCreatedLocked( addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
mDeviceImpl.createWindowPolicyController(new ArrayList<>()), DISPLAY_ID_1); GenericWindowPolicyController gwpc = mDeviceImpl.getDisplayWindowPolicyControllerForTest(
GenericWindowPolicyController gwpc = mDeviceImpl.getWindowPolicyControllersForTesting().get(
DISPLAY_ID_1); DISPLAY_ID_1);
ArrayList<ActivityInfo> activityInfos = getActivityInfoList( ArrayList<ActivityInfo> activityInfos = getActivityInfoList(
NONBLOCKED_APP_PACKAGE_NAME, NONBLOCKED_APP_PACKAGE_NAME,
@@ -1626,8 +1618,7 @@ public class VirtualDeviceManagerServiceTest {
} }
@Test @Test
public void public void restrictedActivityNonMatchingRestrictedVirtualDisplay_startBlockedAlertActivity() {
restrictedActivityOnNonMatchingRestrictedVirtualDisplay_startBlockedAlertActivity() {
Intent blockedAppIntent = createRestrictedActivityBlockedIntent(List.of("abc"), "def"); Intent blockedAppIntent = createRestrictedActivityBlockedIntent(List.of("abc"), "def");
verify(mContext).startActivityAsUser(argThat(intent -> verify(mContext).startActivityAsUser(argThat(intent ->
intent.filterEquals(blockedAppIntent)), any(), any()); intent.filterEquals(blockedAppIntent)), any(), any());
@@ -1654,15 +1645,15 @@ public class VirtualDeviceManagerServiceTest {
@Test @Test
public void getDisplayIdsForDevice_oneDisplay_resultContainsCorrectDisplayId() { 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); ArraySet<Integer> displayIds = mLocalService.getDisplayIdsForDevice(VIRTUAL_DEVICE_ID_1);
assertThat(displayIds).containsExactly(DISPLAY_ID_1); assertThat(displayIds).containsExactly(DISPLAY_ID_1);
} }
@Test @Test
public void getDisplayIdsForDevice_twoDisplays_resultContainsCorrectDisplayIds() { public void getDisplayIdsForDevice_twoDisplays_resultContainsCorrectDisplayIds() {
mDeviceImpl.mVirtualDisplayIds.add(DISPLAY_ID_1); addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
mDeviceImpl.mVirtualDisplayIds.add(DISPLAY_ID_2); addVirtualDisplay(mDeviceImpl, DISPLAY_ID_2);
ArraySet<Integer> displayIds = mLocalService.getDisplayIdsForDevice(VIRTUAL_DEVICE_ID_1); ArraySet<Integer> displayIds = mLocalService.getDisplayIdsForDevice(VIRTUAL_DEVICE_ID_1);
assertThat(displayIds).containsExactly(DISPLAY_ID_1, DISPLAY_ID_2); assertThat(displayIds).containsExactly(DISPLAY_ID_1, DISPLAY_ID_2);
} }
@@ -1677,15 +1668,22 @@ public class VirtualDeviceManagerServiceTest {
private VirtualDeviceImpl createVirtualDevice(int virtualDeviceId, int ownerUid, private VirtualDeviceImpl createVirtualDevice(int virtualDeviceId, int ownerUid,
VirtualDeviceParams params) { VirtualDeviceParams params) {
VirtualDeviceImpl virtualDeviceImpl = new VirtualDeviceImpl(mContext, VirtualDeviceImpl virtualDeviceImpl = new VirtualDeviceImpl(mContext,
mAssociationInfo, new Binder(), ownerUid, virtualDeviceId, mAssociationInfo, mVdms, new Binder(), ownerUid, virtualDeviceId,
mInputController, mSensorController, mCameraAccessController, mInputController, mSensorController, mCameraAccessController
/* onDeviceCloseListener= */ deviceId -> mVdms.removeVirtualDevice(deviceId), /* onDeviceCloseListener= */ /*deviceId -> mVdms.removeVirtualDevice(deviceId)*/,
mPendingTrampolineCallback, mActivityListener, mSoundEffectListener, mPendingTrampolineCallback, mActivityListener, mSoundEffectListener,
mRunningAppsChangedCallback, params); mRunningAppsChangedCallback, params, new DisplayManagerGlobal(mIDisplayManager));
mVdms.addVirtualDevice(virtualDeviceImpl); mVdms.addVirtualDevice(virtualDeviceImpl);
return 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. */ /** Helper class to drop permissions temporarily and restore them at the end of a test. */
static final class DropShellPermissionsTemporarily implements AutoCloseable { static final class DropShellPermissionsTemporarily implements AutoCloseable {
DropShellPermissionsTemporarily() { DropShellPermissionsTemporarily() {