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:
Zixuan Qu
2022-08-31 05:36:19 +00:00
committed by Android (Google) Code Review
3 changed files with 159 additions and 12 deletions

View File

@@ -41,6 +41,7 @@ import android.os.Looper;
import android.os.Parcel; import android.os.Parcel;
import android.os.RemoteException; import android.os.RemoteException;
import android.os.UserHandle; import android.os.UserHandle;
import android.util.ArraySet;
import android.util.ExceptionUtils; import android.util.ExceptionUtils;
import android.util.Slog; import android.util.Slog;
import android.util.SparseArray; import android.util.SparseArray;
@@ -86,6 +87,12 @@ public class VirtualDeviceManagerService extends SystemService {
@GuardedBy("mVirtualDeviceManagerLock") @GuardedBy("mVirtualDeviceManagerLock")
private final SparseArray<VirtualDeviceImpl> mVirtualDevices = new SparseArray<>(); 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 * Mapping from user ID to CDM associations. The associations come from
* {@link CompanionDeviceManager#getAllAssociations()}, which contains associations across all * {@link CompanionDeviceManager#getAllAssociations()}, which contains associations across all
@@ -213,6 +220,14 @@ public class VirtualDeviceManagerService extends SystemService {
return mLocalService; return mLocalService;
} }
@VisibleForTesting
void notifyRunningAppsChanged(int associationId, ArraySet<Integer> uids) {
synchronized (mVirtualDeviceManagerLock) {
mAppsOnVirtualDevices.put(associationId, uids);
}
mLocalService.onAppsOnVirtualDeviceChanged();
}
class VirtualDeviceManagerImpl extends IVirtualDeviceManager.Stub implements class VirtualDeviceManagerImpl extends IVirtualDeviceManager.Stub implements
VirtualDeviceImpl.PendingTrampolineCallback { VirtualDeviceImpl.PendingTrampolineCallback {
@@ -252,6 +267,7 @@ public class VirtualDeviceManagerService extends SystemService {
public void onClose(int associationId) { public void onClose(int associationId) {
synchronized (mVirtualDeviceManagerLock) { synchronized (mVirtualDeviceManagerLock) {
mVirtualDevices.remove(associationId); mVirtualDevices.remove(associationId);
mAppsOnVirtualDevices.remove(associationId);
if (cameraAccessController != null) { if (cameraAccessController != null) {
cameraAccessController.stopObservingIfNeeded(); cameraAccessController.stopObservingIfNeeded();
} else { } else {
@@ -262,8 +278,10 @@ public class VirtualDeviceManagerService extends SystemService {
} }
}, },
this, activityListener, this, activityListener,
runningUids -> cameraAccessController.blockCameraAccessIfNeeded( runningUids -> {
runningUids), cameraAccessController.blockCameraAccessIfNeeded(runningUids);
notifyRunningAppsChanged(associationInfo.getId(), runningUids);
},
params); params);
if (cameraAccessController != null) { if (cameraAccessController != null) {
cameraAccessController.startObservingIfNeeded(); cameraAccessController.startObservingIfNeeded();
@@ -385,8 +403,13 @@ public class VirtualDeviceManagerService extends SystemService {
private final class LocalService extends VirtualDeviceManagerInternal { private final class LocalService extends VirtualDeviceManagerInternal {
@GuardedBy("mVirtualDeviceManagerLock") @GuardedBy("mVirtualDeviceManagerLock")
private final ArrayList<VirtualDeviceManagerInternal.VirtualDisplayListener> private final ArrayList<VirtualDisplayListener>
mVirtualDisplayListeners = new ArrayList<>(); mVirtualDisplayListeners = new ArrayList<>();
@GuardedBy("mVirtualDeviceManagerLock")
private final ArrayList<AppsOnVirtualDeviceListener>
mAppsOnVirtualDeviceListeners = new ArrayList<>();
@GuardedBy("mVirtualDeviceManagerLock")
private final ArraySet<Integer> mAllUidsOnVirtualDevice = new ArraySet<>();
@Override @Override
public boolean isValidVirtualDevice(IVirtualDevice virtualDevice) { 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 @Override
public int getBaseVirtualDisplayFlags(IVirtualDevice virtualDevice) { public int getBaseVirtualDisplayFlags(IVirtualDevice virtualDevice) {
return ((VirtualDeviceImpl) virtualDevice).getBaseVirtualDisplayFlags(); return ((VirtualDeviceImpl) virtualDevice).getBaseVirtualDisplayFlags();
@@ -481,6 +532,22 @@ public class VirtualDeviceManagerService extends SystemService {
mVirtualDisplayListeners.remove(listener); 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 { private static final class PendingTrampolineMap {

View File

@@ -19,6 +19,8 @@ package com.android.server.companion.virtual;
import android.annotation.NonNull; import android.annotation.NonNull;
import android.companion.virtual.IVirtualDevice; import android.companion.virtual.IVirtualDevice;
import java.util.Set;
/** /**
* Virtual device manager local service interface. * Virtual device manager local service interface.
* Only for use within system server. * Only for use within system server.
@@ -34,6 +36,13 @@ public abstract class VirtualDeviceManagerInternal {
void onVirtualDisplayRemoved(int displayId); 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. */ /** Register a listener for the creation and destruction of virtual displays. */
public abstract void registerVirtualDisplayListener( public abstract void registerVirtualDisplayListener(
@NonNull VirtualDisplayListener listener); @NonNull VirtualDisplayListener listener);
@@ -42,6 +51,20 @@ public abstract class VirtualDeviceManagerInternal {
public abstract void unregisterVirtualDisplayListener( public abstract void unregisterVirtualDisplayListener(
@NonNull VirtualDisplayListener listener); @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. * Validate the virtual device.

View File

@@ -35,6 +35,7 @@ import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.never; import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times; import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import static org.testng.Assert.assertThrows; 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 GOOGLE_MAPS_PACKAGE_NAME = "com.google.android.apps.maps";
private static final String DEVICE_NAME = "device name"; private static final String DEVICE_NAME = "device name";
private static final int DISPLAY_ID = 2; 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 PRODUCT_ID = 10;
private static final int VENDOR_ID = 5; private static final int VENDOR_ID = 5;
private static final String UNIQUE_ID = "uniqueid"; private static final String UNIQUE_ID = "uniqueid";
@@ -143,6 +150,8 @@ public class VirtualDeviceManagerServiceTest {
@Mock @Mock
private VirtualDeviceManagerInternal.VirtualDisplayListener mDisplayListener; private VirtualDeviceManagerInternal.VirtualDisplayListener mDisplayListener;
@Mock @Mock
private VirtualDeviceManagerInternal.AppsOnVirtualDeviceListener mAppsOnVirtualDeviceListener;
@Mock
IPowerManager mIPowerManagerMock; IPowerManager mIPowerManagerMock;
@Mock @Mock
IThermalService mIThermalServiceMock; IThermalService mIThermalServiceMock;
@@ -242,7 +251,7 @@ public class VirtualDeviceManagerServiceTest {
} }
@Test @Test
public void onVirtualDisplayCreatedLocked_listenersNotified() throws RemoteException { public void onVirtualDisplayCreatedLocked_listenersNotified() {
mLocalService.registerVirtualDisplayListener(mDisplayListener); mLocalService.registerVirtualDisplayListener(mDisplayListener);
mLocalService.onVirtualDisplayCreated(DISPLAY_ID); mLocalService.onVirtualDisplayCreated(DISPLAY_ID);
@@ -252,7 +261,7 @@ public class VirtualDeviceManagerServiceTest {
} }
@Test @Test
public void onVirtualDisplayRemovedLocked_listenersNotified() throws RemoteException { public void onVirtualDisplayRemovedLocked_listenersNotified() {
mLocalService.registerVirtualDisplayListener(mDisplayListener); mLocalService.registerVirtualDisplayListener(mDisplayListener);
mDeviceImpl.onVirtualDisplayCreatedLocked( mDeviceImpl.onVirtualDisplayCreatedLocked(
mDeviceImpl.createWindowPolicyController(), DISPLAY_ID); mDeviceImpl.createWindowPolicyController(), DISPLAY_ID);
@@ -263,6 +272,54 @@ public class VirtualDeviceManagerServiceTest {
verify(mDisplayListener).onVirtualDisplayRemoved(DISPLAY_ID); 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 @Test
public void onVirtualDisplayCreatedLocked_wakeLockIsAcquired() throws RemoteException { public void onVirtualDisplayCreatedLocked_wakeLockIsAcquired() throws RemoteException {
verify(mIPowerManagerMock, never()).acquireWakeLock(any(Binder.class), anyInt(), verify(mIPowerManagerMock, never()).acquireWakeLock(any(Binder.class), anyInt(),
@@ -270,7 +327,7 @@ public class VirtualDeviceManagerServiceTest {
nullable(String.class), anyInt(), eq(null)); nullable(String.class), anyInt(), eq(null));
mDeviceImpl.onVirtualDisplayCreatedLocked( mDeviceImpl.onVirtualDisplayCreatedLocked(
mDeviceImpl.createWindowPolicyController(), DISPLAY_ID); 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), nullable(String.class), nullable(WorkSource.class),
nullable(String.class), eq(DISPLAY_ID), eq(null)); nullable(String.class), eq(DISPLAY_ID), eq(null));
} }
@@ -284,7 +341,7 @@ public class VirtualDeviceManagerServiceTest {
assertThrows(IllegalStateException.class, assertThrows(IllegalStateException.class,
() -> mDeviceImpl.onVirtualDisplayCreatedLocked(gwpc, DISPLAY_ID)); () -> mDeviceImpl.onVirtualDisplayCreatedLocked(gwpc, DISPLAY_ID));
TestableLooper.get(this).processAllMessages(); 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), nullable(String.class), nullable(WorkSource.class),
nullable(String.class), eq(DISPLAY_ID), eq(null)); nullable(String.class), eq(DISPLAY_ID), eq(null));
} }
@@ -302,14 +359,14 @@ public class VirtualDeviceManagerServiceTest {
mDeviceImpl.createWindowPolicyController(), DISPLAY_ID); mDeviceImpl.createWindowPolicyController(), DISPLAY_ID);
ArgumentCaptor<IBinder> wakeLockCaptor = ArgumentCaptor.forClass(IBinder.class); ArgumentCaptor<IBinder> wakeLockCaptor = ArgumentCaptor.forClass(IBinder.class);
TestableLooper.get(this).processAllMessages(); TestableLooper.get(this).processAllMessages();
verify(mIPowerManagerMock, Mockito.times(1)).acquireWakeLock(wakeLockCaptor.capture(), verify(mIPowerManagerMock).acquireWakeLock(wakeLockCaptor.capture(),
anyInt(), anyInt(),
nullable(String.class), nullable(String.class), nullable(WorkSource.class), nullable(String.class), nullable(String.class), nullable(WorkSource.class),
nullable(String.class), eq(DISPLAY_ID), eq(null)); nullable(String.class), eq(DISPLAY_ID), eq(null));
IBinder wakeLock = wakeLockCaptor.getValue(); IBinder wakeLock = wakeLockCaptor.getValue();
mDeviceImpl.onVirtualDisplayRemovedLocked(DISPLAY_ID); mDeviceImpl.onVirtualDisplayRemovedLocked(DISPLAY_ID);
verify(mIPowerManagerMock, Mockito.times(1)).releaseWakeLock(eq(wakeLock), anyInt()); verify(mIPowerManagerMock).releaseWakeLock(eq(wakeLock), anyInt());
} }
@Test @Test
@@ -318,7 +375,7 @@ public class VirtualDeviceManagerServiceTest {
mDeviceImpl.createWindowPolicyController(), DISPLAY_ID); mDeviceImpl.createWindowPolicyController(), DISPLAY_ID);
ArgumentCaptor<IBinder> wakeLockCaptor = ArgumentCaptor.forClass(IBinder.class); ArgumentCaptor<IBinder> wakeLockCaptor = ArgumentCaptor.forClass(IBinder.class);
TestableLooper.get(this).processAllMessages(); TestableLooper.get(this).processAllMessages();
verify(mIPowerManagerMock, Mockito.times(1)).acquireWakeLock(wakeLockCaptor.capture(), verify(mIPowerManagerMock).acquireWakeLock(wakeLockCaptor.capture(),
anyInt(), anyInt(),
nullable(String.class), nullable(String.class), nullable(WorkSource.class), nullable(String.class), nullable(String.class), nullable(WorkSource.class),
nullable(String.class), eq(DISPLAY_ID), eq(null)); 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. // Close the VirtualDevice without first notifying it of the VirtualDisplay removal.
mDeviceImpl.close(); mDeviceImpl.close();
verify(mIPowerManagerMock, Mockito.times(1)).releaseWakeLock(eq(wakeLock), anyInt()); verify(mIPowerManagerMock).releaseWakeLock(eq(wakeLock), anyInt());
} }
@Test @Test