Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c2b616af authored by Zixuan Qu's avatar Zixuan Qu Committed by Android (Google) Code Review
Browse files

Merge "Add listeners for the changes of App UIDs running on virtual displays....

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."
parents b91e5ebd 0880191a
Loading
Loading
Loading
Loading
+70 −3
Original line number Diff line number Diff line
@@ -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 {
+24 −1
Original line number Diff line number Diff line
@@ -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,6 +36,13 @@ 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);
@@ -42,6 +51,20 @@ public abstract class VirtualDeviceManagerInternal {
    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.
+65 −8
Original line number Diff line number Diff line
@@ -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