Merge "Add listeners for the changes of App UIDs running on virtual displays. This will be used later by VibrationSettings to keep record of apps currently on virtual displays." into tm-qpr-dev
This commit is contained in:
@@ -41,6 +41,7 @@ import android.os.Looper;
|
||||
import android.os.Parcel;
|
||||
import android.os.RemoteException;
|
||||
import android.os.UserHandle;
|
||||
import android.util.ArraySet;
|
||||
import android.util.ExceptionUtils;
|
||||
import android.util.Slog;
|
||||
import android.util.SparseArray;
|
||||
@@ -86,6 +87,12 @@ public class VirtualDeviceManagerService extends SystemService {
|
||||
@GuardedBy("mVirtualDeviceManagerLock")
|
||||
private final SparseArray<VirtualDeviceImpl> mVirtualDevices = new SparseArray<>();
|
||||
|
||||
/**
|
||||
* Mapping from CDM association IDs to app UIDs running on the corresponding virtual device.
|
||||
*/
|
||||
@GuardedBy("mVirtualDeviceManagerLock")
|
||||
private final SparseArray<ArraySet<Integer>> mAppsOnVirtualDevices = new SparseArray<>();
|
||||
|
||||
/**
|
||||
* Mapping from user ID to CDM associations. The associations come from
|
||||
* {@link CompanionDeviceManager#getAllAssociations()}, which contains associations across all
|
||||
@@ -213,6 +220,14 @@ public class VirtualDeviceManagerService extends SystemService {
|
||||
return mLocalService;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void notifyRunningAppsChanged(int associationId, ArraySet<Integer> uids) {
|
||||
synchronized (mVirtualDeviceManagerLock) {
|
||||
mAppsOnVirtualDevices.put(associationId, uids);
|
||||
}
|
||||
mLocalService.onAppsOnVirtualDeviceChanged();
|
||||
}
|
||||
|
||||
class VirtualDeviceManagerImpl extends IVirtualDeviceManager.Stub implements
|
||||
VirtualDeviceImpl.PendingTrampolineCallback {
|
||||
|
||||
@@ -252,6 +267,7 @@ public class VirtualDeviceManagerService extends SystemService {
|
||||
public void onClose(int associationId) {
|
||||
synchronized (mVirtualDeviceManagerLock) {
|
||||
mVirtualDevices.remove(associationId);
|
||||
mAppsOnVirtualDevices.remove(associationId);
|
||||
if (cameraAccessController != null) {
|
||||
cameraAccessController.stopObservingIfNeeded();
|
||||
} else {
|
||||
@@ -262,8 +278,10 @@ public class VirtualDeviceManagerService extends SystemService {
|
||||
}
|
||||
},
|
||||
this, activityListener,
|
||||
runningUids -> cameraAccessController.blockCameraAccessIfNeeded(
|
||||
runningUids),
|
||||
runningUids -> {
|
||||
cameraAccessController.blockCameraAccessIfNeeded(runningUids);
|
||||
notifyRunningAppsChanged(associationInfo.getId(), runningUids);
|
||||
},
|
||||
params);
|
||||
if (cameraAccessController != null) {
|
||||
cameraAccessController.startObservingIfNeeded();
|
||||
@@ -385,8 +403,13 @@ public class VirtualDeviceManagerService extends SystemService {
|
||||
|
||||
private final class LocalService extends VirtualDeviceManagerInternal {
|
||||
@GuardedBy("mVirtualDeviceManagerLock")
|
||||
private final ArrayList<VirtualDeviceManagerInternal.VirtualDisplayListener>
|
||||
private final ArrayList<VirtualDisplayListener>
|
||||
mVirtualDisplayListeners = new ArrayList<>();
|
||||
@GuardedBy("mVirtualDeviceManagerLock")
|
||||
private final ArrayList<AppsOnVirtualDeviceListener>
|
||||
mAppsOnVirtualDeviceListeners = new ArrayList<>();
|
||||
@GuardedBy("mVirtualDeviceManagerLock")
|
||||
private final ArraySet<Integer> mAllUidsOnVirtualDevice = new ArraySet<>();
|
||||
|
||||
@Override
|
||||
public boolean isValidVirtualDevice(IVirtualDevice virtualDevice) {
|
||||
@@ -422,6 +445,34 @@ public class VirtualDeviceManagerService extends SystemService {
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAppsOnVirtualDeviceChanged() {
|
||||
ArraySet<Integer> latestRunningUids = new ArraySet<>();
|
||||
final AppsOnVirtualDeviceListener[] listeners;
|
||||
synchronized (mVirtualDeviceManagerLock) {
|
||||
int size = mAppsOnVirtualDevices.size();
|
||||
for (int i = 0; i < size; i++) {
|
||||
latestRunningUids.addAll(mAppsOnVirtualDevices.valueAt(i));
|
||||
}
|
||||
if (!mAllUidsOnVirtualDevice.equals(latestRunningUids)) {
|
||||
mAllUidsOnVirtualDevice.clear();
|
||||
mAllUidsOnVirtualDevice.addAll(latestRunningUids);
|
||||
listeners =
|
||||
mAppsOnVirtualDeviceListeners.toArray(
|
||||
new AppsOnVirtualDeviceListener[0]);
|
||||
} else {
|
||||
listeners = null;
|
||||
}
|
||||
}
|
||||
if (listeners != null) {
|
||||
mHandler.post(() -> {
|
||||
for (AppsOnVirtualDeviceListener listener : listeners) {
|
||||
listener.onAppsOnAnyVirtualDeviceChanged(latestRunningUids);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBaseVirtualDisplayFlags(IVirtualDevice virtualDevice) {
|
||||
return ((VirtualDeviceImpl) virtualDevice).getBaseVirtualDisplayFlags();
|
||||
@@ -481,6 +532,22 @@ public class VirtualDeviceManagerService extends SystemService {
|
||||
mVirtualDisplayListeners.remove(listener);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerAppsOnVirtualDeviceListener(
|
||||
@NonNull AppsOnVirtualDeviceListener listener) {
|
||||
synchronized (mVirtualDeviceManagerLock) {
|
||||
mAppsOnVirtualDeviceListeners.add(listener);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterAppsOnVirtualDeviceListener(
|
||||
@NonNull AppsOnVirtualDeviceListener listener) {
|
||||
synchronized (mVirtualDeviceManagerLock) {
|
||||
mAppsOnVirtualDeviceListeners.remove(listener);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static final class PendingTrampolineMap {
|
||||
|
||||
@@ -19,6 +19,8 @@ package com.android.server.companion.virtual;
|
||||
import android.annotation.NonNull;
|
||||
import android.companion.virtual.IVirtualDevice;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Virtual device manager local service interface.
|
||||
* Only for use within system server.
|
||||
@@ -34,14 +36,35 @@ public abstract class VirtualDeviceManagerInternal {
|
||||
void onVirtualDisplayRemoved(int displayId);
|
||||
}
|
||||
|
||||
|
||||
/** Interface to listen to the changes on the list of app UIDs running on any virtual device. */
|
||||
public interface AppsOnVirtualDeviceListener {
|
||||
/** Notifies that running apps on any virtual device has changed */
|
||||
void onAppsOnAnyVirtualDeviceChanged(Set<Integer> allRunningUids);
|
||||
}
|
||||
|
||||
/** Register a listener for the creation and destruction of virtual displays. */
|
||||
public abstract void registerVirtualDisplayListener(
|
||||
@NonNull VirtualDisplayListener listener);
|
||||
|
||||
/** Unregister a listener for the creation and destruction of virtual displays. */
|
||||
/** Unregister a listener for the creation and destruction of virtual displays. */
|
||||
public abstract void unregisterVirtualDisplayListener(
|
||||
@NonNull VirtualDisplayListener listener);
|
||||
|
||||
/** Register a listener for changes of running app UIDs on any virtual device. */
|
||||
public abstract void registerAppsOnVirtualDeviceListener(
|
||||
@NonNull AppsOnVirtualDeviceListener listener);
|
||||
|
||||
/** Unregister a listener for changes of running app UIDs on any virtual device. */
|
||||
public abstract void unregisterAppsOnVirtualDeviceListener(
|
||||
@NonNull AppsOnVirtualDeviceListener listener);
|
||||
|
||||
/**
|
||||
* Notifies that the set of apps running on virtual devices has changed.
|
||||
* This method only notifies the listeners when the union of running UIDs on all virtual devices
|
||||
* has changed.
|
||||
*/
|
||||
public abstract void onAppsOnVirtualDeviceChanged();
|
||||
|
||||
/**
|
||||
* Validate the virtual device.
|
||||
|
||||
@@ -35,6 +35,7 @@ import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.testng.Assert.assertThrows;
|
||||
|
||||
@@ -110,6 +111,12 @@ public class VirtualDeviceManagerServiceTest {
|
||||
private static final String GOOGLE_MAPS_PACKAGE_NAME = "com.google.android.apps.maps";
|
||||
private static final String DEVICE_NAME = "device name";
|
||||
private static final int DISPLAY_ID = 2;
|
||||
private static final int UID_1 = 0;
|
||||
private static final int UID_2 = 10;
|
||||
private static final int UID_3 = 10000;
|
||||
private static final int UID_4 = 10001;
|
||||
private static final int ASSOCIATION_ID_1 = 1;
|
||||
private static final int ASSOCIATION_ID_2 = 2;
|
||||
private static final int PRODUCT_ID = 10;
|
||||
private static final int VENDOR_ID = 5;
|
||||
private static final String UNIQUE_ID = "uniqueid";
|
||||
@@ -143,6 +150,8 @@ public class VirtualDeviceManagerServiceTest {
|
||||
@Mock
|
||||
private VirtualDeviceManagerInternal.VirtualDisplayListener mDisplayListener;
|
||||
@Mock
|
||||
private VirtualDeviceManagerInternal.AppsOnVirtualDeviceListener mAppsOnVirtualDeviceListener;
|
||||
@Mock
|
||||
IPowerManager mIPowerManagerMock;
|
||||
@Mock
|
||||
IThermalService mIThermalServiceMock;
|
||||
@@ -242,7 +251,7 @@ public class VirtualDeviceManagerServiceTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onVirtualDisplayCreatedLocked_listenersNotified() throws RemoteException {
|
||||
public void onVirtualDisplayCreatedLocked_listenersNotified() {
|
||||
mLocalService.registerVirtualDisplayListener(mDisplayListener);
|
||||
|
||||
mLocalService.onVirtualDisplayCreated(DISPLAY_ID);
|
||||
@@ -252,7 +261,7 @@ public class VirtualDeviceManagerServiceTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onVirtualDisplayRemovedLocked_listenersNotified() throws RemoteException {
|
||||
public void onVirtualDisplayRemovedLocked_listenersNotified() {
|
||||
mLocalService.registerVirtualDisplayListener(mDisplayListener);
|
||||
mDeviceImpl.onVirtualDisplayCreatedLocked(
|
||||
mDeviceImpl.createWindowPolicyController(), DISPLAY_ID);
|
||||
@@ -263,6 +272,54 @@ public class VirtualDeviceManagerServiceTest {
|
||||
verify(mDisplayListener).onVirtualDisplayRemoved(DISPLAY_ID);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onAppsOnVirtualDeviceChanged_singleVirtualDevice_listenersNotified() {
|
||||
ArraySet<Integer> uids = new ArraySet<>(Arrays.asList(UID_1, UID_2));
|
||||
mLocalService.registerAppsOnVirtualDeviceListener(mAppsOnVirtualDeviceListener);
|
||||
|
||||
mVdms.notifyRunningAppsChanged(ASSOCIATION_ID_1, uids);
|
||||
TestableLooper.get(this).processAllMessages();
|
||||
|
||||
verify(mAppsOnVirtualDeviceListener).onAppsOnAnyVirtualDeviceChanged(uids);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onAppsOnVirtualDeviceChanged_multipleVirtualDevices_listenersNotified() {
|
||||
ArraySet<Integer> uidsOnDevice1 = new ArraySet<>(Arrays.asList(UID_1, UID_2));
|
||||
ArraySet<Integer> uidsOnDevice2 = new ArraySet<>(Arrays.asList(UID_3, UID_4));
|
||||
mLocalService.registerAppsOnVirtualDeviceListener(mAppsOnVirtualDeviceListener);
|
||||
|
||||
// Notifies that the running apps on the first virtual device has changed.
|
||||
mVdms.notifyRunningAppsChanged(ASSOCIATION_ID_1, uidsOnDevice1);
|
||||
TestableLooper.get(this).processAllMessages();
|
||||
verify(mAppsOnVirtualDeviceListener).onAppsOnAnyVirtualDeviceChanged(
|
||||
new ArraySet<>(Arrays.asList(UID_1, UID_2)));
|
||||
|
||||
// Notifies that the running apps on the second virtual device has changed.
|
||||
mVdms.notifyRunningAppsChanged(ASSOCIATION_ID_2, uidsOnDevice2);
|
||||
TestableLooper.get(this).processAllMessages();
|
||||
// The union of the apps running on both virtual devices are sent to the listeners.
|
||||
verify(mAppsOnVirtualDeviceListener).onAppsOnAnyVirtualDeviceChanged(
|
||||
new ArraySet<>(Arrays.asList(UID_1, UID_2, UID_3, UID_4)));
|
||||
|
||||
// Notifies that the running apps on the first virtual device has changed again.
|
||||
uidsOnDevice1.remove(UID_2);
|
||||
mVdms.notifyRunningAppsChanged(ASSOCIATION_ID_1, uidsOnDevice1);
|
||||
mLocalService.onAppsOnVirtualDeviceChanged();
|
||||
TestableLooper.get(this).processAllMessages();
|
||||
// The union of the apps running on both virtual devices are sent to the listeners.
|
||||
verify(mAppsOnVirtualDeviceListener).onAppsOnAnyVirtualDeviceChanged(
|
||||
new ArraySet<>(Arrays.asList(UID_1, UID_3, UID_4)));
|
||||
|
||||
// Notifies that the running apps on the first virtual device has changed but with the same
|
||||
// set of UIDs.
|
||||
mVdms.notifyRunningAppsChanged(ASSOCIATION_ID_1, uidsOnDevice1);
|
||||
mLocalService.onAppsOnVirtualDeviceChanged();
|
||||
TestableLooper.get(this).processAllMessages();
|
||||
// Listeners should not be notified.
|
||||
verifyNoMoreInteractions(mAppsOnVirtualDeviceListener);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onVirtualDisplayCreatedLocked_wakeLockIsAcquired() throws RemoteException {
|
||||
verify(mIPowerManagerMock, never()).acquireWakeLock(any(Binder.class), anyInt(),
|
||||
@@ -270,7 +327,7 @@ public class VirtualDeviceManagerServiceTest {
|
||||
nullable(String.class), anyInt(), eq(null));
|
||||
mDeviceImpl.onVirtualDisplayCreatedLocked(
|
||||
mDeviceImpl.createWindowPolicyController(), DISPLAY_ID);
|
||||
verify(mIPowerManagerMock, Mockito.times(1)).acquireWakeLock(any(Binder.class), anyInt(),
|
||||
verify(mIPowerManagerMock).acquireWakeLock(any(Binder.class), anyInt(),
|
||||
nullable(String.class), nullable(String.class), nullable(WorkSource.class),
|
||||
nullable(String.class), eq(DISPLAY_ID), eq(null));
|
||||
}
|
||||
@@ -284,7 +341,7 @@ public class VirtualDeviceManagerServiceTest {
|
||||
assertThrows(IllegalStateException.class,
|
||||
() -> mDeviceImpl.onVirtualDisplayCreatedLocked(gwpc, DISPLAY_ID));
|
||||
TestableLooper.get(this).processAllMessages();
|
||||
verify(mIPowerManagerMock, Mockito.times(1)).acquireWakeLock(any(Binder.class), anyInt(),
|
||||
verify(mIPowerManagerMock).acquireWakeLock(any(Binder.class), anyInt(),
|
||||
nullable(String.class), nullable(String.class), nullable(WorkSource.class),
|
||||
nullable(String.class), eq(DISPLAY_ID), eq(null));
|
||||
}
|
||||
@@ -302,14 +359,14 @@ public class VirtualDeviceManagerServiceTest {
|
||||
mDeviceImpl.createWindowPolicyController(), DISPLAY_ID);
|
||||
ArgumentCaptor<IBinder> wakeLockCaptor = ArgumentCaptor.forClass(IBinder.class);
|
||||
TestableLooper.get(this).processAllMessages();
|
||||
verify(mIPowerManagerMock, Mockito.times(1)).acquireWakeLock(wakeLockCaptor.capture(),
|
||||
verify(mIPowerManagerMock).acquireWakeLock(wakeLockCaptor.capture(),
|
||||
anyInt(),
|
||||
nullable(String.class), nullable(String.class), nullable(WorkSource.class),
|
||||
nullable(String.class), eq(DISPLAY_ID), eq(null));
|
||||
|
||||
IBinder wakeLock = wakeLockCaptor.getValue();
|
||||
mDeviceImpl.onVirtualDisplayRemovedLocked(DISPLAY_ID);
|
||||
verify(mIPowerManagerMock, Mockito.times(1)).releaseWakeLock(eq(wakeLock), anyInt());
|
||||
verify(mIPowerManagerMock).releaseWakeLock(eq(wakeLock), anyInt());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -318,7 +375,7 @@ public class VirtualDeviceManagerServiceTest {
|
||||
mDeviceImpl.createWindowPolicyController(), DISPLAY_ID);
|
||||
ArgumentCaptor<IBinder> wakeLockCaptor = ArgumentCaptor.forClass(IBinder.class);
|
||||
TestableLooper.get(this).processAllMessages();
|
||||
verify(mIPowerManagerMock, Mockito.times(1)).acquireWakeLock(wakeLockCaptor.capture(),
|
||||
verify(mIPowerManagerMock).acquireWakeLock(wakeLockCaptor.capture(),
|
||||
anyInt(),
|
||||
nullable(String.class), nullable(String.class), nullable(WorkSource.class),
|
||||
nullable(String.class), eq(DISPLAY_ID), eq(null));
|
||||
@@ -326,7 +383,7 @@ public class VirtualDeviceManagerServiceTest {
|
||||
|
||||
// Close the VirtualDevice without first notifying it of the VirtualDisplay removal.
|
||||
mDeviceImpl.close();
|
||||
verify(mIPowerManagerMock, Mockito.times(1)).releaseWakeLock(eq(wakeLock), anyInt());
|
||||
verify(mIPowerManagerMock).releaseWakeLock(eq(wakeLock), anyInt());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
Reference in New Issue
Block a user