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

Commit 3888e425 authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Fix the VDM<->WM deadlock when creating a display." into main

parents 1d883bc1 594db036
Loading
Loading
Loading
Loading
+104 −70
Original line number Diff line number Diff line
@@ -110,6 +110,7 @@ import android.util.SparseIntArray;
import android.view.Display;
import android.view.WindowManager;
import android.widget.Toast;
import android.window.DisplayWindowPolicyController;

import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
@@ -1411,8 +1412,7 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
        return mirroredDisplayId == Display.INVALID_DISPLAY ? displayId : mirroredDisplayId;
    }

    @GuardedBy("mVirtualDeviceLock")
    private GenericWindowPolicyController createWindowPolicyControllerLocked(
    private GenericWindowPolicyController createWindowPolicyController(
            @NonNull Set<String> displayCategories) {
        final boolean activityLaunchAllowedByDefault =
                getDevicePolicy(POLICY_TYPE_ACTIVITY) == DEVICE_POLICY_DEFAULT;
@@ -1421,11 +1421,12 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
        final boolean showTasksInHostDeviceRecents =
                getDevicePolicy(POLICY_TYPE_RECENTS) == DEVICE_POLICY_DEFAULT;

        synchronized (mVirtualDeviceLock) {
            if (mActivityListenerAdapter == null) {
                mActivityListenerAdapter = new GwpcActivityListener();
            }

        final GenericWindowPolicyController gwpc = new GenericWindowPolicyController(
            return new GenericWindowPolicyController(
                    WindowManager.LayoutParams.FLAG_SECURE,
                    WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS,
                    mAttributionSource,
@@ -1441,8 +1442,7 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
                    displayCategories,
                    showTasksInHostDeviceRecents,
                    mParams.getHomeComponent());
        gwpc.registerRunningAppsChangedListener(/* listener= */ this);
        return gwpc;
        }
    }

    @Override // Binder call
@@ -1450,55 +1450,54 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
            @NonNull IVirtualDisplayCallback callback) {
        checkCallerIsDeviceOwner();

        int displayId;
        boolean showPointer;
        boolean isTrustedDisplay;
        GenericWindowPolicyController gwpc;
        synchronized (mVirtualDeviceLock) {
            gwpc = createWindowPolicyControllerLocked(virtualDisplayConfig.getDisplayCategories());
            displayId = mDisplayManagerInternal.createVirtualDisplay(virtualDisplayConfig,
                    callback, this, gwpc, mOwnerPackageName);
            boolean isMirrorDisplay =
                    mDisplayManagerInternal.getDisplayIdToMirror(displayId)
                            != Display.INVALID_DISPLAY;
            gwpc.setDisplayId(displayId, isMirrorDisplay);
            isTrustedDisplay =
                    (mDisplayManagerInternal.getDisplayInfo(displayId).flags & Display.FLAG_TRUSTED)
                            == Display.FLAG_TRUSTED;
            if (!isTrustedDisplay
                    && getDevicePolicy(POLICY_TYPE_CLIPBOARD) != DEVICE_POLICY_DEFAULT) {
                throw new SecurityException("All displays must be trusted for devices with "
                        + "custom clipboard policy.");
        final boolean isTrustedDisplay =
                (virtualDisplayConfig.getFlags() & DisplayManager.VIRTUAL_DISPLAY_FLAG_TRUSTED)
                        == DisplayManager.VIRTUAL_DISPLAY_FLAG_TRUSTED;
        if (!isTrustedDisplay && getDevicePolicy(POLICY_TYPE_CLIPBOARD) != DEVICE_POLICY_DEFAULT) {
            throw new SecurityException(
                "All displays must be trusted for devices with custom clipboard policy.");
        }

            if (mVirtualDisplays.contains(displayId)) {
                gwpc.unregisterRunningAppsChangedListener(this);
                throw new IllegalStateException(
                        "Virtual device already has a virtual display with ID " + displayId);
        GenericWindowPolicyController gwpc =
                createWindowPolicyController(virtualDisplayConfig.getDisplayCategories());

        // Create the display outside of the lock to avoid deadlock. DisplayManagerService will
        // acquire the global WM lock while creating the display. At the same time, WM may query
        // VDM and this virtual device to get policies, display ownership, etc.
        int displayId = mDisplayManagerInternal.createVirtualDisplay(virtualDisplayConfig,
                    callback, this, gwpc, mOwnerPackageName);
        if (displayId == Display.INVALID_DISPLAY) {
            return displayId;
        }

            PowerManager.WakeLock wakeLock =
                    isTrustedDisplay ? createAndAcquireWakeLockForDisplay(displayId) : null;
            mVirtualDisplays.put(displayId, new VirtualDisplayWrapper(callback, gwpc, wakeLock,
                    isTrustedDisplay, isMirrorDisplay));
        // DisplayManagerService will call onVirtualDisplayCreated() after the display is created,
        // while holding its own lock to ensure that this device knows about the display before any
        // other display listeners are notified about the display creation.
        VirtualDisplayWrapper displayWrapper;
        boolean showPointer;
        synchronized (mVirtualDeviceLock) {
            if (!mVirtualDisplays.contains(displayId)) {
                throw new IllegalStateException("Virtual device was not notified about the "
                        + "creation of display with ID " + displayId);
            }
            displayWrapper = mVirtualDisplays.get(displayId);
            showPointer = mDefaultShowPointerIcon;
        }
        displayWrapper.acquireWakeLock();
        gwpc.registerRunningAppsChangedListener(/* listener= */ this);

        final long token = Binder.clearCallingIdentity();
        try {
        Binder.withCleanCallingIdentity(() -> {
            mInputController.setMouseScalingEnabled(false, displayId);
            mInputController.setDisplayEligibilityForPointerCapture(/* isEligible= */ false,
                    displayId);
            if (isTrustedDisplay) {
            if (displayWrapper.isTrusted()) {
                mInputController.setShowPointerIcon(showPointer, displayId);
                mInputController.setDisplayImePolicy(displayId,
                        WindowManager.DISPLAY_IME_POLICY_LOCAL);
            } else {
                gwpc.setShowInHostDeviceRecents(true);
            }
        } finally {
            Binder.restoreCallingIdentity(token);
        }
        });

        Counter.logIncrementWithUid(
                "virtual_devices.value_virtual_display_created_count",
@@ -1506,7 +1505,7 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
        return displayId;
    }

    private PowerManager.WakeLock createAndAcquireWakeLockForDisplay(int displayId) {
    private PowerManager.WakeLock createWakeLockForDisplay(int displayId) {
        if (Flags.deviceAwareDisplayPower()) {
            return null;
        }
@@ -1516,7 +1515,6 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
            PowerManager.WakeLock wakeLock = powerManager.newWakeLock(
                    PowerManager.SCREEN_BRIGHT_WAKE_LOCK,
                    TAG + ":" + displayId, displayId);
            wakeLock.acquire();
            return wakeLock;
        } finally {
            Binder.restoreCallingIdentity(token);
@@ -1561,8 +1559,37 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
        return result;
    }

    void onVirtualDisplayRemoved(int displayId) {
        /* This is callback invoked by VirtualDeviceManagerService when VirtualDisplay was released
    /**
     * DisplayManagerService is notifying this virtual device about the display creation. This
     * should happen before the DisplayManagerInternal#createVirtualDisplay() call above
     * returns.
     * This is called while holding the DisplayManagerService lock, so no heavy-weight work must
     * be done here and especially *** no calls to WindowManager! ***
     */
    public void onVirtualDisplayCreated(int displayId, IVirtualDisplayCallback callback,
            DisplayWindowPolicyController dwpc) {
        final boolean isMirrorDisplay =
                mDisplayManagerInternal.getDisplayIdToMirror(displayId) != Display.INVALID_DISPLAY;
        final boolean isTrustedDisplay =
                (mDisplayManagerInternal.getDisplayInfo(displayId).flags & Display.FLAG_TRUSTED)
                        == Display.FLAG_TRUSTED;

        GenericWindowPolicyController gwpc = (GenericWindowPolicyController) dwpc;
        gwpc.setDisplayId(displayId, isMirrorDisplay);
        PowerManager.WakeLock wakeLock =
                isTrustedDisplay ? createWakeLockForDisplay(displayId) : null;
        synchronized (mVirtualDeviceLock) {
            if (mVirtualDisplays.contains(displayId)) {
                Slog.wtf(TAG, "Virtual device already has a virtual display with ID " + displayId);
                return;
            }
            mVirtualDisplays.put(displayId, new VirtualDisplayWrapper(callback, gwpc, wakeLock,
                    isTrustedDisplay, isMirrorDisplay));
        }
    }

    /**
     * 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
@@ -1572,6 +1599,7 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
     * this callback won't be invoked because the display is removed from
     * VirtualDeviceManagerService before any resources are released.
     */
    void onVirtualDisplayRemoved(int displayId) {
        VirtualDisplayWrapper virtualDisplayWrapper;
        synchronized (mVirtualDeviceLock) {
            virtualDisplayWrapper = mVirtualDisplays.removeReturnOld(displayId);
@@ -1847,6 +1875,12 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
            return mWindowPolicyController;
        }

        void acquireWakeLock() {
            if (mWakeLock != null && !mWakeLock.isHeld()) {
                mWakeLock.acquire();
            }
        }

        void releaseWakeLock() {
            if (mWakeLock != null && mWakeLock.isHeld()) {
                mWakeLock.release();
+12 −1
Original line number Diff line number Diff line
@@ -40,7 +40,6 @@ import android.companion.virtual.IVirtualDeviceSoundEffectListener;
import android.companion.virtual.VirtualDevice;
import android.companion.virtual.VirtualDeviceManager;
import android.companion.virtual.VirtualDeviceParams;
import android.companion.virtual.flags.Flags;
import android.companion.virtual.sensor.VirtualSensor;
import android.companion.virtualnative.IVirtualDeviceManagerNative;
import android.compat.annotation.ChangeId;
@@ -49,6 +48,7 @@ import android.content.AttributionSource;
import android.content.Context;
import android.content.Intent;
import android.hardware.display.DisplayManagerInternal;
import android.hardware.display.IVirtualDisplayCallback;
import android.os.Binder;
import android.os.Build;
import android.os.Handler;
@@ -67,6 +67,7 @@ import android.util.Slog;
import android.util.SparseArray;
import android.view.Display;
import android.widget.Toast;
import android.window.DisplayWindowPolicyController;

import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
@@ -750,6 +751,16 @@ public class VirtualDeviceManagerService extends SystemService {
            return result;
        }

        @Override
        public void onVirtualDisplayCreated(IVirtualDevice virtualDevice, int displayId,
                IVirtualDisplayCallback callback, DisplayWindowPolicyController dwpc) {
            VirtualDeviceImpl virtualDeviceImpl = getVirtualDeviceForId(
                    ((VirtualDeviceImpl) virtualDevice).getDeviceId());
            if (virtualDeviceImpl != null) {
                virtualDeviceImpl.onVirtualDisplayCreated(displayId, callback, dwpc);
            }
        }

        @Override
        public void onVirtualDisplayRemoved(IVirtualDevice virtualDevice, int displayId) {
            VirtualDeviceImpl virtualDeviceImpl = getVirtualDeviceForId(
+13 −0
Original line number Diff line number Diff line
@@ -24,8 +24,10 @@ import android.companion.virtual.VirtualDeviceManager;
import android.companion.virtual.VirtualDeviceParams;
import android.companion.virtual.sensor.VirtualSensor;
import android.content.Context;
import android.hardware.display.IVirtualDisplayCallback;
import android.os.LocaleList;
import android.util.ArraySet;
import android.window.DisplayWindowPolicyController;

import java.util.Set;
import java.util.function.Consumer;
@@ -103,6 +105,17 @@ public abstract class VirtualDeviceManagerInternal {
     */
    public abstract @NonNull ArraySet<Integer> getDeviceIdsForUid(int uid);

    /**
     * Notifies that a virtual display was created.
     *
     * @param virtualDevice The virtual device that owns the virtual display.
     * @param displayId     The display id of the created virtual display.
     * @param callback      The callback of the virtual display.
     * @param dwpc          The DisplayWindowPolicyController of the created virtual display.
     */
    public abstract void onVirtualDisplayCreated(IVirtualDevice virtualDevice, int displayId,
            IVirtualDisplayCallback callback, DisplayWindowPolicyController dwpc);

    /**
     * Notifies that a virtual display is removed.
     *
+12 −0
Original line number Diff line number Diff line
@@ -2041,6 +2041,7 @@ public final class DisplayManagerService extends SystemService {
                                packageName,
                                displayUniqueId,
                                virtualDevice,
                                dwpc,
                                surface,
                                flags,
                                virtualDisplayConfig);
@@ -2135,6 +2136,7 @@ public final class DisplayManagerService extends SystemService {
            String packageName,
            String uniqueId,
            IVirtualDevice virtualDevice,
            DisplayWindowPolicyController dwpc,
            Surface surface,
            int flags,
            VirtualDisplayConfig virtualDisplayConfig) {
@@ -2188,6 +2190,16 @@ public final class DisplayManagerService extends SystemService {

        final LogicalDisplay display = mLogicalDisplayMapper.getDisplayLocked(device);
        if (display != null) {
            // Notify the virtual device that the display has been created. This needs to be called
            // in this locked section before the repository had the chance to notify any listeners
            // to ensure that the device is aware of the new display before others know about it.
            if (virtualDevice != null) {
                final VirtualDeviceManagerInternal vdm =
                        getLocalService(VirtualDeviceManagerInternal.class);
                vdm.onVirtualDisplayCreated(
                        virtualDevice, display.getDisplayIdLocked(), callback, dwpc);
            }

            return display.getDisplayIdLocked();
        }

+25 −8
Original line number Diff line number Diff line
@@ -73,6 +73,7 @@ import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.hardware.Sensor;
import android.hardware.display.DisplayManager;
import android.hardware.display.DisplayManagerGlobal;
import android.hardware.display.DisplayManagerInternal;
import android.hardware.display.IDisplayManager;
@@ -173,8 +174,7 @@ 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)
@@ -284,7 +284,12 @@ public class VirtualDeviceManagerServiceTest {
    private Intent createRestrictedActivityBlockedIntent(Set<String> displayCategories,
            String targetDisplayCategory) {
        when(mDisplayManagerInternalMock.createVirtualDisplay(any(), any(), any(), any(),
                eq(VIRTUAL_DEVICE_OWNER_PACKAGE))).thenReturn(DISPLAY_ID_1);
                eq(VIRTUAL_DEVICE_OWNER_PACKAGE)))
                .thenAnswer(inv -> {
                    mLocalService.onVirtualDisplayCreated(
                            mDeviceImpl, DISPLAY_ID_1, inv.getArgument(1), inv.getArgument(3));
                    return DISPLAY_ID_1;
                });
        VirtualDisplayConfig config = new VirtualDisplayConfig.Builder("display", 640, 480,
                420).setDisplayCategories(displayCategories).build();
        mDeviceImpl.createVirtualDisplay(config, mVirtualDisplayCallback);
@@ -997,8 +1002,7 @@ public class VirtualDeviceManagerServiceTest {
    public void onVirtualDisplayCreatedLocked_duplicateCalls_onlyOneWakeLockIsAcquired()
            throws RemoteException {
        addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1, Display.FLAG_TRUSTED);
        assertThrows(IllegalStateException.class,
                () -> addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1));
        addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1, Display.FLAG_TRUSTED);
        TestableLooper.get(this).processAllMessages();
        verify(mIPowerManagerMock).acquireWakeLock(any(Binder.class), anyInt(),
                nullable(String.class), nullable(String.class), nullable(WorkSource.class),
@@ -1871,8 +1875,6 @@ public class VirtualDeviceManagerServiceTest {
    }

    private void addVirtualDisplay(VirtualDeviceImpl virtualDevice, int displayId, int flags) {
        when(mDisplayManagerInternalMock.createVirtualDisplay(any(), eq(mVirtualDisplayCallback),
                eq(virtualDevice), any(), any())).thenReturn(displayId);
        final String uniqueId = UNIQUE_ID + displayId;
        doAnswer(inv -> {
            final DisplayInfo displayInfo = new DisplayInfo();
@@ -1880,7 +1882,22 @@ public class VirtualDeviceManagerServiceTest {
            displayInfo.flags = flags;
            return displayInfo;
        }).when(mDisplayManagerInternalMock).getDisplayInfo(eq(displayId));
        virtualDevice.createVirtualDisplay(VIRTUAL_DISPLAY_CONFIG, mVirtualDisplayCallback);

        when(mDisplayManagerInternalMock.createVirtualDisplay(any(), eq(mVirtualDisplayCallback),
                eq(virtualDevice), any(), any())).thenAnswer(inv -> {
                    mLocalService.onVirtualDisplayCreated(
                            virtualDevice, displayId, mVirtualDisplayCallback, inv.getArgument(3));
                    return displayId;
                });

        final int virtualDisplayFlags = (flags & Display.FLAG_TRUSTED) == 0
                ? 0
                : DisplayManager.VIRTUAL_DISPLAY_FLAG_TRUSTED;
        VirtualDisplayConfig virtualDisplayConfig =
                new VirtualDisplayConfig.Builder("virtual_display", 640, 480, 400)
                        .setFlags(virtualDisplayFlags)
                        .build();
        virtualDevice.createVirtualDisplay(virtualDisplayConfig, mVirtualDisplayCallback);
        mInputManagerMockHelper.addDisplayIdMapping(uniqueId, displayId);
    }