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

Commit 224c55d4 authored by Ryan Lin's avatar Ryan Lin Committed by Android (Google) Code Review
Browse files

Merge "Fix the race condition that cause windows cache stale"

parents 5caf17ce e169358d
Loading
Loading
Loading
Loading
+16 −1
Original line number Original line Diff line number Diff line
@@ -20,6 +20,7 @@ package android.view.accessibility;
import static android.view.accessibility.AccessibilityNodeInfo.FOCUS_ACCESSIBILITY;
import static android.view.accessibility.AccessibilityNodeInfo.FOCUS_ACCESSIBILITY;


import android.os.Build;
import android.os.Build;
import android.os.SystemClock;
import android.util.ArraySet;
import android.util.ArraySet;
import android.util.Log;
import android.util.Log;
import android.util.LongArray;
import android.util.LongArray;
@@ -71,6 +72,11 @@ public class AccessibilityCache {


    private long mAccessibilityFocus = AccessibilityNodeInfo.UNDEFINED_ITEM_ID;
    private long mAccessibilityFocus = AccessibilityNodeInfo.UNDEFINED_ITEM_ID;
    private long mInputFocus = AccessibilityNodeInfo.UNDEFINED_ITEM_ID;
    private long mInputFocus = AccessibilityNodeInfo.UNDEFINED_ITEM_ID;
    /**
     * The event time of the {@link AccessibilityEvent} which presents the populated windows cache
     * before it is stale.
     */
    private long mValidWindowCacheTimeStamp = 0;


    private int mAccessibilityFocusedWindow = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID;
    private int mAccessibilityFocusedWindow = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID;
    private int mInputFocusWindow = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID;
    private int mInputFocusWindow = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID;
@@ -97,13 +103,20 @@ public class AccessibilityCache {
     * The key of SparseArray is display ID.
     * The key of SparseArray is display ID.
     *
     *
     * @param windowsOnAllDisplays The accessibility windows of all displays.
     * @param windowsOnAllDisplays The accessibility windows of all displays.
     * @param populationTimeStamp The timestamp from {@link SystemClock#uptimeMillis()} when the
     *                            client requests the data.
     */
     */
    public void setWindowsOnAllDisplays(
    public void setWindowsOnAllDisplays(
            SparseArray<List<AccessibilityWindowInfo>> windowsOnAllDisplays) {
            SparseArray<List<AccessibilityWindowInfo>> windowsOnAllDisplays,
            long populationTimeStamp) {
        synchronized (mLock) {
        synchronized (mLock) {
            if (DEBUG) {
            if (DEBUG) {
                Log.i(LOG_TAG, "Set windows");
                Log.i(LOG_TAG, "Set windows");
            }
            }
            if (mValidWindowCacheTimeStamp > populationTimeStamp) {
                // Discard the windows because it might be stale.
                return;
            }
            clearWindowCacheLocked();
            clearWindowCacheLocked();
            if (windowsOnAllDisplays == null) {
            if (windowsOnAllDisplays == null) {
                return;
                return;
@@ -224,6 +237,7 @@ public class AccessibilityCache {
                } break;
                } break;


                case AccessibilityEvent.TYPE_WINDOWS_CHANGED:
                case AccessibilityEvent.TYPE_WINDOWS_CHANGED:
                    mValidWindowCacheTimeStamp = event.getEventTime();
                    if (event.getWindowChanges()
                    if (event.getWindowChanges()
                            == AccessibilityEvent.WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED) {
                            == AccessibilityEvent.WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED) {
                        // Don't need to clear all cache. Unless the changes are related to
                        // Don't need to clear all cache. Unless the changes are related to
@@ -232,6 +246,7 @@ public class AccessibilityCache {
                        break;
                        break;
                    }
                    }
                case AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED: {
                case AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED: {
                    mValidWindowCacheTimeStamp = event.getEventTime();
                    clear();
                    clear();
                } break;
                } break;
            }
            }
+3 −1
Original line number Original line Diff line number Diff line
@@ -435,8 +435,10 @@ public final class AccessibilityInteractionClient
                    }
                    }
                }
                }


                long populationTimeStamp;
                final long identityToken = Binder.clearCallingIdentity();
                final long identityToken = Binder.clearCallingIdentity();
                try {
                try {
                    populationTimeStamp = SystemClock.uptimeMillis();
                    windows = connection.getWindows();
                    windows = connection.getWindows();
                } finally {
                } finally {
                    Binder.restoreCallingIdentity(identityToken);
                    Binder.restoreCallingIdentity(identityToken);
@@ -446,7 +448,7 @@ public final class AccessibilityInteractionClient
                }
                }
                if (windows != null) {
                if (windows != null) {
                    if (sAccessibilityCache != null) {
                    if (sAccessibilityCache != null) {
                        sAccessibilityCache.setWindowsOnAllDisplays(windows);
                        sAccessibilityCache.setWindowsOnAllDisplays(windows, populationTimeStamp);
                    }
                    }
                    return windows;
                    return windows;
                }
                }
+49 −2
Original line number Original line Diff line number Diff line
@@ -35,6 +35,7 @@ import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.mockito.Mockito.when;


import android.os.SystemClock;
import android.util.SparseArray;
import android.util.SparseArray;
import android.view.Display;
import android.view.Display;
import android.view.View;
import android.view.View;
@@ -299,7 +300,8 @@ public class AccessibilityCacheTest {
            SparseArray<List<AccessibilityWindowInfo>> allWindows = new SparseArray<>();
            SparseArray<List<AccessibilityWindowInfo>> allWindows = new SparseArray<>();
            allWindows.put(Display.DEFAULT_DISPLAY, windowsIn1);
            allWindows.put(Display.DEFAULT_DISPLAY, windowsIn1);
            allWindows.put(SECONDARY_DISPLAY_ID, windowsIn2);
            allWindows.put(SECONDARY_DISPLAY_ID, windowsIn2);
            mAccessibilityCache.setWindowsOnAllDisplays(allWindows);
            final long populationTimeStamp = SystemClock.uptimeMillis();
            mAccessibilityCache.setWindowsOnAllDisplays(allWindows, populationTimeStamp);
            // Gets windows at default display.
            // Gets windows at default display.
            windowsOut1 = getWindowsByDisplay(Display.DEFAULT_DISPLAY);
            windowsOut1 = getWindowsByDisplay(Display.DEFAULT_DISPLAY);
            window1Out = mAccessibilityCache.getWindow(WINDOW_ID_1);
            window1Out = mAccessibilityCache.getWindow(WINDOW_ID_1);
@@ -338,6 +340,46 @@ public class AccessibilityCacheTest {
        }
        }
    }
    }


    @Test
    public void setInvalidWindowsAfterWindowsChangedEvent_notInCache() {
        final AccessibilityEvent event = new AccessibilityEvent(
                AccessibilityEvent.TYPE_WINDOWS_CHANGED);
        final long eventTime = 1000L;
        event.setEventTime(eventTime);
        mAccessibilityCache.onAccessibilityEvent(event);

        final AccessibilityWindowInfo windowInfo1 = obtainAccessibilityWindowInfo(WINDOW_ID_1,
                SPECIFIC_WINDOW_LAYER);
        List<AccessibilityWindowInfo> windowsIn = Arrays.asList(windowInfo1);
        setWindowsByDisplay(Display.DEFAULT_DISPLAY, windowsIn, eventTime - 10);

        try {
            assertNull(getWindowsByDisplay(Display.DEFAULT_DISPLAY));
        } finally {
            windowInfo1.recycle();
        }
    }

    @Test
    public void setInvalidWindowsAfterStateChangedEvent_notInCache() {
        final AccessibilityEvent event = new AccessibilityEvent(
                AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
        final long eventTime = 1000L;
        event.setEventTime(eventTime);
        mAccessibilityCache.onAccessibilityEvent(event);

        final AccessibilityWindowInfo windowInfo1 = obtainAccessibilityWindowInfo(WINDOW_ID_1,
                SPECIFIC_WINDOW_LAYER);
        List<AccessibilityWindowInfo> windowsIn = Arrays.asList(windowInfo1);
        setWindowsByDisplay(Display.DEFAULT_DISPLAY, windowsIn, eventTime - 10);

        try {
            assertNull(getWindowsByDisplay(Display.DEFAULT_DISPLAY));
        } finally {
            windowInfo1.recycle();
        }
    }

    @Test
    @Test
    public void addWindowThenStateChangedEvent_noLongerInCache() {
    public void addWindowThenStateChangedEvent_noLongerInCache() {
        putWindowWithWindowIdAndDisplayIdInCache(WINDOW_ID_1, Display.DEFAULT_DISPLAY,
        putWindowWithWindowIdAndDisplayIdInCache(WINDOW_ID_1, Display.DEFAULT_DISPLAY,
@@ -1063,9 +1105,14 @@ public class AccessibilityCacheTest {
    }
    }


    private void setWindowsByDisplay(int displayId, List<AccessibilityWindowInfo> windows) {
    private void setWindowsByDisplay(int displayId, List<AccessibilityWindowInfo> windows) {
        setWindowsByDisplay(displayId, windows, SystemClock.uptimeMillis());
    }

    private void setWindowsByDisplay(int displayId, List<AccessibilityWindowInfo> windows,
            long populationTimeStamp) {
        SparseArray<List<AccessibilityWindowInfo>> allWindows = new SparseArray<>();
        SparseArray<List<AccessibilityWindowInfo>> allWindows = new SparseArray<>();
        allWindows.put(displayId, windows);
        allWindows.put(displayId, windows);
        mAccessibilityCache.setWindowsOnAllDisplays(allWindows);
        mAccessibilityCache.setWindowsOnAllDisplays(allWindows, populationTimeStamp);
    }
    }


    private List<AccessibilityWindowInfo> getWindowsByDisplay(int displayId) {
    private List<AccessibilityWindowInfo> getWindowsByDisplay(int displayId) {