diff options
| author | 2021-06-16 03:14:27 +0000 | |
|---|---|---|
| committer | 2021-06-16 03:14:27 +0000 | |
| commit | e6510baf3bd6b948dff25aae1c997670a68ae392 (patch) | |
| tree | 50ccf1d4ab032bbdc7a182e594a8d0f99d0400bb | |
| parent | e19a7da47f79a4ca8ed199171865e8084aad21a5 (diff) | |
| parent | fed928bb1fb63e27dc1373ce2aec8caf90415d67 (diff) | |
Merge "Eliminate potential deadlock in AccessibilityCache"
| -rw-r--r-- | core/java/android/view/accessibility/AccessibilityCache.java | 77 | ||||
| -rw-r--r-- | core/tests/coretests/src/android/view/accessibility/AccessibilityCacheTest.java | 17 |
2 files changed, 34 insertions, 60 deletions
diff --git a/core/java/android/view/accessibility/AccessibilityCache.java b/core/java/android/view/accessibility/AccessibilityCache.java index 9ab2c2b8bcb1..d14dc6e71c00 100644 --- a/core/java/android/view/accessibility/AccessibilityCache.java +++ b/core/java/android/view/accessibility/AccessibilityCache.java @@ -158,6 +158,7 @@ public class AccessibilityCache { * @param event An event. */ public void onAccessibilityEvent(AccessibilityEvent event) { + AccessibilityNodeInfo nodeToRefresh = null; synchronized (mLock) { if (DEBUG) { Log.i(LOG_TAG, "onAccessibilityEvent(" + event + ")"); @@ -166,17 +167,19 @@ public class AccessibilityCache { switch (eventType) { case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED: { if (mAccessibilityFocus != AccessibilityNodeInfo.UNDEFINED_ITEM_ID) { - refreshCachedNodeLocked(mAccessibilityFocusedWindow, mAccessibilityFocus); + removeCachedNodeLocked(mAccessibilityFocusedWindow, mAccessibilityFocus); } mAccessibilityFocus = event.getSourceNodeId(); mAccessibilityFocusedWindow = event.getWindowId(); - refreshCachedNodeLocked(mAccessibilityFocusedWindow, mAccessibilityFocus); + nodeToRefresh = removeCachedNodeLocked(mAccessibilityFocusedWindow, + mAccessibilityFocus); } break; case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED: { if (mAccessibilityFocus == event.getSourceNodeId() && mAccessibilityFocusedWindow == event.getWindowId()) { - refreshCachedNodeLocked(mAccessibilityFocusedWindow, mAccessibilityFocus); + nodeToRefresh = removeCachedNodeLocked(mAccessibilityFocusedWindow, + mAccessibilityFocus); mAccessibilityFocus = AccessibilityNodeInfo.UNDEFINED_ITEM_ID; mAccessibilityFocusedWindow = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID; } @@ -184,17 +187,18 @@ public class AccessibilityCache { case AccessibilityEvent.TYPE_VIEW_FOCUSED: { if (mInputFocus != AccessibilityNodeInfo.UNDEFINED_ITEM_ID) { - refreshCachedNodeLocked(event.getWindowId(), mInputFocus); + removeCachedNodeLocked(event.getWindowId(), mInputFocus); } mInputFocus = event.getSourceNodeId(); - refreshCachedNodeLocked(event.getWindowId(), mInputFocus); + nodeToRefresh = removeCachedNodeLocked(event.getWindowId(), mInputFocus); } break; case AccessibilityEvent.TYPE_VIEW_SELECTED: case AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED: case AccessibilityEvent.TYPE_VIEW_CLICKED: case AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED: { - refreshCachedNodeLocked(event.getWindowId(), event.getSourceNodeId()); + nodeToRefresh = removeCachedNodeLocked(event.getWindowId(), + event.getSourceNodeId()); } break; case AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED: { @@ -205,7 +209,7 @@ public class AccessibilityCache { & AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE) != 0) { clearSubTreeLocked(windowId, sourceId); } else { - refreshCachedNodeLocked(windowId, sourceId); + nodeToRefresh = removeCachedNodeLocked(windowId, sourceId); } } } break; @@ -218,8 +222,8 @@ public class AccessibilityCache { if (event.getWindowChanges() == AccessibilityEvent.WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED) { // Don't need to clear all cache. Unless the changes are related to - // content, we won't clear all cache here. - refreshCachedWindowLocked(event.getWindowId()); + // content, we won't clear all cache here with clear(). + clearWindowCacheLocked(); break; } case AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED: { @@ -228,59 +232,34 @@ public class AccessibilityCache { } } + if (nodeToRefresh != null) { + if (DEBUG) { + Log.i(LOG_TAG, "Refreshing and re-adding cached node."); + } + if (mAccessibilityNodeRefresher.refreshNode(nodeToRefresh, true)) { + add(nodeToRefresh); + } + } if (CHECK_INTEGRITY) { checkIntegrity(); } } - private void refreshCachedNodeLocked(int windowId, long sourceId) { + private AccessibilityNodeInfo removeCachedNodeLocked(int windowId, long sourceId) { if (DEBUG) { - Log.i(LOG_TAG, "Refreshing cached node."); + Log.i(LOG_TAG, "Removing cached node."); } - LongSparseArray<AccessibilityNodeInfo> nodes = mNodeCache.get(windowId); if (nodes == null) { - return; + return null; } AccessibilityNodeInfo cachedInfo = nodes.get(sourceId); // If the source is not in the cache - nothing to do. if (cachedInfo == null) { - return; - } - // The node changed so we will just refresh it right now. - if (mAccessibilityNodeRefresher.refreshNode(cachedInfo, true)) { - return; - } - // Weird, we could not refresh. Just evict the entire sub-tree. - clearSubTreeLocked(windowId, sourceId); - } - - private void refreshCachedWindowLocked(int windowId) { - if (DEBUG) { - Log.i(LOG_TAG, "Refreshing cached window."); - } - - if (windowId == AccessibilityWindowInfo.UNDEFINED_WINDOW_ID) { - return; - } - - final int displayCounts = mWindowCacheByDisplay.size(); - for (int i = 0; i < displayCounts; i++) { - final SparseArray<AccessibilityWindowInfo> windowsOfDisplay = - mWindowCacheByDisplay.valueAt(i); - if (windowsOfDisplay == null) { - continue; - } - final AccessibilityWindowInfo window = windowsOfDisplay.get(windowId); - if (window == null) { - continue; - } - if (!mAccessibilityNodeRefresher.refreshWindow(window)) { - // If we fail to refresh the window, clear all windows. - clearWindowCacheLocked(); - } - return; + return null; } + nodes.remove(sourceId); + return cachedInfo; } /** @@ -450,7 +429,7 @@ public class AccessibilityCache { if (clone.isAccessibilityFocused()) { if (mAccessibilityFocus != AccessibilityNodeInfo.UNDEFINED_ITEM_ID && mAccessibilityFocus != sourceId) { - refreshCachedNodeLocked(windowId, mAccessibilityFocus); + removeCachedNodeLocked(windowId, mAccessibilityFocus); } mAccessibilityFocus = sourceId; mAccessibilityFocusedWindow = windowId; diff --git a/core/tests/coretests/src/android/view/accessibility/AccessibilityCacheTest.java b/core/tests/coretests/src/android/view/accessibility/AccessibilityCacheTest.java index 0d5db6d791f1..d2b52ba35073 100644 --- a/core/tests/coretests/src/android/view/accessibility/AccessibilityCacheTest.java +++ b/core/tests/coretests/src/android/view/accessibility/AccessibilityCacheTest.java @@ -563,7 +563,7 @@ public class AccessibilityCacheTest { } @Test - public void nodeWithA11yFocusWhenAnotherNodeGetsFocus_getsRefreshed() { + public void nodeWithA11yFocusWhenAnotherNodeGetsFocus_getsRemoved() { AccessibilityNodeInfo nodeInfo = getNodeWithA11yAndWindowId(SINGLE_VIEW_ID, WINDOW_ID_1); nodeInfo.setAccessibilityFocused(true); mAccessibilityCache.add(nodeInfo); @@ -573,7 +573,7 @@ public class AccessibilityCacheTest { mAccessibilityCache.onAccessibilityEvent(event); event.recycle(); try { - verify(mAccessibilityNodeRefresher).refreshNode(nodeInfo, true); + assertNull(mAccessibilityCache.getNode(WINDOW_ID_1, SINGLE_VIEW_ID)); } finally { nodeInfo.recycle(); } @@ -614,7 +614,7 @@ public class AccessibilityCacheTest { } @Test - public void nodeWithInputFocusWhenAnotherNodeGetsFocus_getsRefreshed() { + public void nodeWithInputFocusWhenAnotherNodeGetsFocus_getsRemoved() { AccessibilityNodeInfo nodeInfo = getNodeWithA11yAndWindowId(SINGLE_VIEW_ID, WINDOW_ID_1); nodeInfo.setFocused(true); mAccessibilityCache.add(nodeInfo); @@ -624,7 +624,7 @@ public class AccessibilityCacheTest { mAccessibilityCache.onAccessibilityEvent(event); event.recycle(); try { - verify(mAccessibilityNodeRefresher).refreshNode(nodeInfo, true); + assertNull(mAccessibilityCache.getNode(WINDOW_ID_1, SINGLE_VIEW_ID)); } finally { nodeInfo.recycle(); } @@ -733,20 +733,15 @@ public class AccessibilityCacheTest { } @Test - public void addA11yFocusNodeBeforeFocusClearedEvent_previousA11yFocusNodeGetsRefreshed() { + public void addA11yFocusNodeBeforeFocusClearedEvent_previousA11yFocusNodeGetsRemoved() { AccessibilityNodeInfo nodeInfo1 = getNodeWithA11yAndWindowId(SINGLE_VIEW_ID, WINDOW_ID_1); nodeInfo1.setAccessibilityFocused(true); mAccessibilityCache.add(nodeInfo1); AccessibilityNodeInfo nodeInfo2 = getNodeWithA11yAndWindowId(OTHER_VIEW_ID, WINDOW_ID_1); nodeInfo2.setAccessibilityFocused(true); mAccessibilityCache.add(nodeInfo2); - AccessibilityEvent event = AccessibilityEvent.obtain( - AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED); - event.setSource(getMockViewWithA11yAndWindowIds(SINGLE_VIEW_ID, WINDOW_ID_1)); - mAccessibilityCache.onAccessibilityEvent(event); - event.recycle(); try { - verify(mAccessibilityNodeRefresher).refreshNode(nodeInfo1, true); + assertNull(mAccessibilityCache.getNode(WINDOW_ID_1, SINGLE_VIEW_ID)); } finally { nodeInfo1.recycle(); nodeInfo2.recycle(); |