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
This commit is contained in:
Jan Sebechlebsky
2023-02-13 17:10:25 +01:00
parent 04b7985365
commit 63ba140ca3
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.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;
}
}
}

View File

@@ -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

View File

@@ -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() {