From 8048d256c2ad86d4e1dacabd6041a6f03a5fbe32 Mon Sep 17 00:00:00 2001 From: Jacky Kao Date: Wed, 7 Apr 2021 10:41:52 +0800 Subject: [PATCH] Fix the crash due to multi-register callbacks For multi-display device, like pixel_jumbojack, when this device is folded, the secondary display is removed. The A11y framework stops tracking windows on the removed display by un-registering its callback. When the A11y framework un-registers a callback, it checks if the display is embedded. If it is, the observer is not removed since the same observer will be observing the parent display. When the display disappears entirely, however, its context disappears and there's no way to know if it was embedded or not. The observer was therefore not removed. When the device is unfolded and the display reappears, the attempt to register an observer causes an exception because the previous one is still there. Due to there's no multi-display device for android S now, so we adopt simple solution as below to fix it: 1. Throws the exception for debug builds only. 2. Adds this exception into the error log. 3. Recovers by unregistering the current observer and proceeding to register the new one The fully solution will phase in the master. Bug: 182963008 Test: a11y CTS & unit tests Change-Id: Iff9776ac6e054c0198c0d8739d9446a785716612 --- .../server/wm/AccessibilityController.java | 30 ++++++++++++------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java index d23579a1da89f..3c0ef6e779545 100644 --- a/services/core/java/com/android/server/wm/AccessibilityController.java +++ b/services/core/java/com/android/server/wm/AccessibilityController.java @@ -59,6 +59,7 @@ import android.graphics.Rect; import android.graphics.RectF; import android.graphics.Region; import android.os.Binder; +import android.os.Build; import android.os.Handler; import android.os.HandlerThread; import android.os.IBinder; @@ -188,22 +189,28 @@ final class AccessibilityController { } if (callback != null) { + WindowsForAccessibilityObserver observer = + mWindowsForAccessibilityObserver.get(displayId); if (isEmbeddedDisplay(dc)) { // If this display is an embedded one, its window observer should have been set from // window manager after setting its parent window. But if its window observer is // empty, that means this mapping didn't be set, and needs to do this again. // This happened when accessibility window observer is disabled and enabled again. - if (mWindowsForAccessibilityObserver.get(displayId) == null) { + if (observer == null) { handleWindowObserverOfEmbeddedDisplay(displayId, dc.getParentWindow()); } return false; - } else if (mWindowsForAccessibilityObserver.get(displayId) != null) { - throw new IllegalStateException( - "Windows for accessibility callback of display " - + displayId + " already set!"); + } else if (observer != null) { + final String errorMessage = "Windows for accessibility callback of display " + + displayId + " already set!"; + Slog.e(TAG, errorMessage); + if (Build.IS_DEBUGGABLE) { + throw new IllegalStateException(errorMessage); + } + removeObserverOfEmbeddedDisplay(observer); + mWindowsForAccessibilityObserver.remove(displayId); } - final WindowsForAccessibilityObserver observer = - new WindowsForAccessibilityObserver(mService, displayId, callback); + observer = new WindowsForAccessibilityObserver(mService, displayId, callback); mWindowsForAccessibilityObserver.put(displayId, observer); mAllObserversInitialized &= observer.mInitialized; } else { @@ -218,9 +225,12 @@ final class AccessibilityController { final WindowsForAccessibilityObserver windowsForA11yObserver = mWindowsForAccessibilityObserver.get(displayId); if (windowsForA11yObserver == null) { - throw new IllegalStateException( - "Windows for accessibility callback of display " + displayId - + " already cleared!"); + final String errorMessage = "Windows for accessibility callback of display " + + displayId + " already cleared!"; + Slog.e(TAG, errorMessage); + if (Build.IS_DEBUGGABLE) { + throw new IllegalStateException(errorMessage); + } } removeObserverOfEmbeddedDisplay(windowsForA11yObserver); mWindowsForAccessibilityObserver.remove(displayId);