From af769b1e0bf09e9a8a4a6bc45914d17cd4f6b799 Mon Sep 17 00:00:00 2001 From: Antony Sargent Date: Fri, 8 Apr 2022 07:00:51 -0700 Subject: [PATCH] Prevent deadlock when releasing VirtualDisplays When releasing a VirtualDisplay owned by a VirtualDevice, the VirtualDeviceManagerService needs to release a WakeLock it holds on behalf of the display. This needs to happen outside of the synchronized block in DisplayManagerService, because releasing the WakeLock ends up calling back into the DisplayManagerService. Fixes: 224775363 Test: atest StreamedAppBehaviorTest Change-Id: Ie831fcad7105d51c64717c3e00d332c543de3b47 --- .../server/display/DisplayManagerService.java | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java index 5fcdc8a08b5d4..f3b2738012a19 100644 --- a/services/core/java/com/android/server/display/DisplayManagerService.java +++ b/services/core/java/com/android/server/display/DisplayManagerService.java @@ -1459,16 +1459,6 @@ public final class DisplayManagerService extends SystemService { DisplayDevice device = mVirtualDisplayAdapter.releaseVirtualDisplayLocked(appToken); if (device != null) { - final LogicalDisplay display = mLogicalDisplayMapper.getDisplayLocked(device); - if (display != null) { - final int displayId = display.getDisplayIdLocked(); - if (mDisplayWindowPolicyControllers.contains(displayId)) { - Pair pair = - mDisplayWindowPolicyControllers.removeReturnOld(displayId); - getLocalService(VirtualDeviceManagerInternal.class) - .onVirtualDisplayRemoved(pair.first, displayId); - } - } // TODO: multi-display - handle virtual displays the same as other display adapters. mDisplayDeviceRepo.onDisplayDeviceEvent(device, DisplayAdapter.DISPLAY_DEVICE_EVENT_REMOVED); @@ -1628,6 +1618,17 @@ public final class DisplayManagerService extends SystemService { DisplayManagerGlobal.invalidateLocalDisplayInfoCaches(); sendDisplayEventLocked(displayId, DisplayManagerGlobal.EVENT_DISPLAY_REMOVED); scheduleTraversalLocked(false); + + if (mDisplayWindowPolicyControllers.contains(displayId)) { + final IVirtualDevice virtualDevice = mDisplayWindowPolicyControllers.removeReturnOld( + displayId).first; + if (virtualDevice != null) { + mHandler.post(() -> { + getLocalService(VirtualDeviceManagerInternal.class) + .onVirtualDisplayRemoved(virtualDevice, displayId); + }); + } + } } private void handleLogicalDisplaySwappedLocked(@NonNull LogicalDisplay display) {