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:
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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() {
|
||||
|
||||
Reference in New Issue
Block a user