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

Commit a4725efd authored by Svetoslav's avatar Svetoslav Committed by Svetoslav Ganov
Browse files

Improve the window query API performamce.

We are caching the window data in the accessibility service process.
When windows change we were sending the dalta of the windows the
service knows about. To make this work when the app asked for all
windows we had to call into the system as new windows may have
appeared. This was slow.

Now we are telling the service some windows change and if it gets
the windows we cache them. We call into the system only on a cache
miss and evict all windows from the cache on window change event.
We do not evict the nodes of the window as the former may have
just moved. If views in a window change they fire accessibility
events that trigger the correct eviction.

Change-Id: I586a72a2497b0d44a75288fa758e7e88817f3300
parent 0dcebb92
Loading
Loading
Loading
Loading
+0 −36
Original line number Diff line number Diff line
@@ -23,7 +23,6 @@ import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
import android.os.SystemClock;
import android.util.Log;
import android.view.KeyEvent;
import android.view.accessibility.AccessibilityEvent;
@@ -659,16 +658,12 @@ public abstract class AccessibilityService extends Service {
     */
    public static class IAccessibilityServiceClientWrapper extends IAccessibilityServiceClient.Stub
            implements HandlerCaller.Callback {

        static final int NO_ID = -1;

        private static final int DO_SET_SET_CONNECTION = 1;
        private static final int DO_ON_INTERRUPT = 2;
        private static final int DO_ON_ACCESSIBILITY_EVENT = 3;
        private static final int DO_ON_GESTURE = 4;
        private static final int DO_CLEAR_ACCESSIBILITY_CACHE = 5;
        private static final int DO_ON_KEY_EVENT = 6;
        private static final int DO_ON_WINDOWS_CHANGED = 7;

        private final HandlerCaller mCaller;

@@ -714,12 +709,6 @@ public abstract class AccessibilityService extends Service {
            mCaller.sendMessage(message);
        }

        @Override
        public void onWindowsChanged(int[] windowIds) {
            Message message = mCaller.obtainMessageO(DO_ON_WINDOWS_CHANGED, windowIds);
            mCaller.sendMessage(message);
        }

        @Override
        public void executeMessage(Message message) {
            switch (message.what) {
@@ -791,31 +780,6 @@ public abstract class AccessibilityService extends Service {
                    }
                } return;

                case DO_ON_WINDOWS_CHANGED: {
                    final int[] windowIds = (int[]) message.obj;

                    // Update the cached windows first.
                    // NOTE: The cache will hold on to the windows so do not recycle.
                    if (windowIds != null) {
                        AccessibilityInteractionClient.getInstance().removeWindows(windowIds);
                    }

                    // Let the client know the windows changed.
                    AccessibilityEvent event = AccessibilityEvent.obtain(
                            AccessibilityEvent.TYPE_WINDOWS_CHANGED);
                    event.setEventTime(SystemClock.uptimeMillis());
                    event.setSealed(true);

                    mCallback.onAccessibilityEvent(event);

                    // Make sure the event is recycled.
                    try {
                        event.recycle();
                    } catch (IllegalStateException ise) {
                        /* ignore - best effort */
                    }
                } break;

                default :
                    Log.w(LOG_TAG, "Unknown message type " + message.what);
            }
+0 −2
Original line number Diff line number Diff line
@@ -39,6 +39,4 @@ import android.view.KeyEvent;
    void clearAccessibilityCache();

    void onKeyEvent(in KeyEvent event, int sequence);

    void onWindowsChanged(in int[] changedWindowIds);
}
+10 −8
Original line number Diff line number Diff line
@@ -58,20 +58,18 @@ final class AccessibilityCache {
        }
    }

    public void removeWindows(int[] windowIds) {
    public void clearWindows() {
        synchronized (mLock) {
            final int windowCount = windowIds.length;
            for (int i = 0; i < windowCount; i++) {
                final int windowId = windowIds[i];
                AccessibilityWindowInfo window = mWindowCache.get(windowId);
            final int windowCount = mWindowCache.size();
            for (int i = windowCount - 1; i >= 0; i--) {
                AccessibilityWindowInfo window = mWindowCache.valueAt(i);
                if (window != null) {
                    if (DEBUG) {
                        Log.i(LOG_TAG, "Removing window: " + windowId);
                        Log.i(LOG_TAG, "Removing window: " + window.getId());
                    }
                    window.recycle();
                    mWindowCache.remove(windowId);
                    mWindowCache.removeAt(i);
                }
                clearNodesForWindowLocked(windowIds[i]);
            }
        }
    }
@@ -111,6 +109,10 @@ final class AccessibilityCache {
                case AccessibilityEvent.TYPE_VIEW_SCROLLED: {
                    clearSubTreeLocked(event.getWindowId(), event.getSourceNodeId());
                } break;

                case AccessibilityEvent.TYPE_WINDOWS_CHANGED: {
                    clearWindows();
                } break;
            }
        }

+16 −28
Original line number Diff line number Diff line
@@ -84,7 +84,7 @@ public final class AccessibilityInteractionClient
    private static final Object sStaticLock = new Object();

    private static final LongSparseArray<AccessibilityInteractionClient> sClients =
        new LongSparseArray<AccessibilityInteractionClient>();
        new LongSparseArray<>();

    private final AtomicInteger mInteractionIdCounter = new AtomicInteger();

@@ -101,7 +101,7 @@ public final class AccessibilityInteractionClient
    private Message mSameThreadMessage;

    private static final SparseArray<IAccessibilityServiceConnection> sConnectionCache =
        new SparseArray<IAccessibilityServiceConnection>();
        new SparseArray<>();

    private static final AccessibilityCache sAccessibilityCache =
        new AccessibilityCache();
@@ -162,19 +162,6 @@ public final class AccessibilityInteractionClient
                false, AccessibilityNodeInfo.FLAG_PREFETCH_DESCENDANTS);
    }

    /**
     * Gets the root {@link AccessibilityNodeInfo} in a given window.
     *
     * @param connectionId The id of a connection for interacting with the system.
     * @param windowId The window id.
     * @return The root {@link AccessibilityNodeInfo} if found, null otherwise.
     */
    public AccessibilityNodeInfo getRootInWindow(int connectionId, int windowId) {
        return findAccessibilityNodeInfoByAccessibilityId(connectionId, windowId,
                AccessibilityNodeInfo.ROOT_NODE_ID, false,
                AccessibilityNodeInfo.FLAG_PREFETCH_DESCENDANTS);
    }

    /**
     * Gets the info for a window.
     *
@@ -225,11 +212,17 @@ public final class AccessibilityInteractionClient
        try {
            IAccessibilityServiceConnection connection = getConnection(connectionId);
            if (connection != null) {
                // The system is just sending data for windows that we introspected
                // and changed but not ones that appeared, so we have to always call
                // into the system process. This is less expensice as opposed to
                // sending all windows on every window change.
                List<AccessibilityWindowInfo> windows = connection.getWindows();
                List<AccessibilityWindowInfo> windows = sAccessibilityCache.getWindows();
                if (windows != null) {
                    if (DEBUG) {
                        Log.i(LOG_TAG, "Windows cache hit");
                    }
                    return windows;
                }
                if (DEBUG) {
                    Log.i(LOG_TAG, "Windows cache miss");
                }
                windows = connection.getWindows();
                if (windows != null) {
                    final int windowCount = windows.size();
                    for (int i = 0; i < windowCount; i++) {
@@ -534,10 +527,6 @@ public final class AccessibilityInteractionClient
        sAccessibilityCache.onAccessibilityEvent(event);
    }

    public void removeWindows(int[] windowIds) {
        sAccessibilityCache.removeWindows(windowIds);
    }

    /**
     * Gets the the result of an async request that returns an {@link AccessibilityNodeInfo}.
     *
@@ -603,8 +592,7 @@ public final class AccessibilityInteractionClient
                    // instantiate new result list to avoid passing internal instances to clients.
                    final boolean isIpcCall = (Binder.getCallingPid() != Process.myPid());
                    if (!isIpcCall) {
                        mFindAccessibilityNodeInfosResult =
                            new ArrayList<AccessibilityNodeInfo>(infos);
                        mFindAccessibilityNodeInfosResult = new ArrayList<>(infos);
                    } else {
                        mFindAccessibilityNodeInfosResult = infos;
                    }
@@ -795,8 +783,8 @@ public final class AccessibilityInteractionClient
            Log.e(LOG_TAG, "No root.");
        }
        // Check for duplicates.
        HashSet<AccessibilityNodeInfo> seen = new HashSet<AccessibilityNodeInfo>();
        Queue<AccessibilityNodeInfo> fringe = new LinkedList<AccessibilityNodeInfo>();
        HashSet<AccessibilityNodeInfo> seen = new HashSet<>();
        Queue<AccessibilityNodeInfo> fringe = new LinkedList<>();
        fringe.add(root);
        while (!fringe.isEmpty()) {
            AccessibilityNodeInfo current = fringe.poll();
+45 −130
Original line number Diff line number Diff line
@@ -62,7 +62,6 @@ import android.os.UserManager;
import android.provider.Settings;
import android.text.TextUtils;
import android.text.TextUtils.SimpleStringSplitter;
import android.util.LongArray;
import android.util.Pools.Pool;
import android.util.Pools.SimplePool;
import android.util.Slog;
@@ -114,8 +113,6 @@ import java.util.concurrent.CopyOnWriteArrayList;
 * accessed only by the system. The task of this service is to be a centralized
 * event dispatch for {@link AccessibilityEvent}s generated across all processes
 * on the device. Events are dispatched to {@link AccessibilityService}s.
 *
 * @hide
 */
public class AccessibilityManagerService extends IAccessibilityManager.Stub {

@@ -155,13 +152,13 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
    private final Object mLock = new Object();

    private final Pool<PendingEvent> mPendingEventPool =
            new SimplePool<PendingEvent>(MAX_POOL_SIZE);
            new SimplePool<>(MAX_POOL_SIZE);

    private final SimpleStringSplitter mStringColonSplitter =
            new SimpleStringSplitter(COMPONENT_NAME_SEPARATOR);

    private final List<AccessibilityServiceInfo> mEnabledServicesForFeedbackTempList =
            new ArrayList<AccessibilityServiceInfo>();
            new ArrayList<>();

    private final Rect mTempRect = new Rect();

@@ -183,27 +180,25 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {

    private boolean mHasInputFilter;

    private final Set<ComponentName> mTempComponentNameSet = new HashSet<ComponentName>();
    private final Set<ComponentName> mTempComponentNameSet = new HashSet<>();

    private final List<AccessibilityServiceInfo> mTempAccessibilityServiceInfoList =
            new ArrayList<AccessibilityServiceInfo>();
            new ArrayList<>();

    private final RemoteCallbackList<IAccessibilityManagerClient> mGlobalClients =
            new RemoteCallbackList<IAccessibilityManagerClient>();
            new RemoteCallbackList<>();

    private final SparseArray<AccessibilityConnectionWrapper> mGlobalInteractionConnections =
            new SparseArray<AccessibilityConnectionWrapper>();
            new SparseArray<>();

    private final SparseArray<IBinder> mGlobalWindowTokens = new SparseArray<IBinder>();
    private final SparseArray<IBinder> mGlobalWindowTokens = new SparseArray<>();

    private final SparseArray<UserState> mUserStates = new SparseArray<UserState>();
    private final SparseArray<UserState> mUserStates = new SparseArray<>();

    private final UserManager mUserManager;

    private int mCurrentUserId = UserHandle.USER_OWNER;

    private final LongArray mTempLongArray = new LongArray();

    //TODO: Remove this hack
    private boolean mInitialized;

@@ -439,10 +434,9 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
            // to clients as being installed - it really is not.
            UserState userState = getUserStateLocked(resolvedUserId);
            if (userState.mUiAutomationService != null) {
                List<AccessibilityServiceInfo> installedServices =
                        new ArrayList<AccessibilityServiceInfo>();
                List<AccessibilityServiceInfo> installedServices = new ArrayList<>();
                installedServices.addAll(userState.mInstalledServices);
                installedServices.remove(userState.mUiAutomationService);
                installedServices.remove(userState.mUiAutomationService.mAccessibilityServiceInfo);
                return installedServices;
            }
            return userState.mInstalledServices;
@@ -655,7 +649,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
            // Automation service is not bound, so pretend it died to perform clean up.
            if (userState.mUiAutomationService != null
                    && serviceClient != null
                    && userState.mUiAutomationService != null
                    && userState.mUiAutomationService.mServiceInterface != null
                    && userState.mUiAutomationService.mServiceInterface.asBinder()
                    == serviceClient.asBinder()) {
@@ -907,16 +900,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
        }
    }

    private void notifyWindowsChangedLocked(List<AccessibilityWindowInfo> windows) {
        UserState state = getCurrentUserStateLocked();
        for (int i = state.mBoundServices.size() - 1; i >= 0; i--) {
            Service service = state.mBoundServices.get(i);
            if (mSecurityPolicy.canRetrieveWindowsLocked(service)) {
                service.notifyWindowsChangedLocked(windows);
            }
        }
    }

    /**
     * Removes an AccessibilityInteractionConnection.
     *
@@ -961,10 +944,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
            try {
                accessibilityServiceInfo = new AccessibilityServiceInfo(resolveInfo, mContext);
                mTempAccessibilityServiceInfoList.add(accessibilityServiceInfo);
            } catch (XmlPullParserException xppe) {
            } catch (XmlPullParserException | IOException xppe) {
                Slog.e(LOG_TAG, "Error while initializing AccessibilityServiceInfo", xppe);
            } catch (IOException ioe) {
                Slog.e(LOG_TAG, "Error while initializing AccessibilityServiceInfo", ioe);
            }
        }

@@ -1035,7 +1016,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
            // An out of bounds exception can happen if services are going away
            // as the for loop is running. If that happens, just bail because
            // there are no more services to notify.
            return;
        }
    }

@@ -1053,7 +1033,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
     * Removes a service.
     *
     * @param service The service.
     * @return True if the service was removed, false otherwise.
     */
    private void removeServiceLocked(Service service, UserState userState) {
        userState.mBoundServices.remove(service);
@@ -1093,7 +1072,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
        }

        Set<String> packageNames = service.mPackageNames;
        CharSequence packageName = event.getPackageName();
        String packageName = (event.getPackageName() != null)
                ? event.getPackageName().toString() : null;

        if (packageNames.isEmpty() || packageNames.contains(packageName)) {
            int feedbackType = service.mFeedbackType;
@@ -1386,8 +1366,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {

        if (mWindowsForAccessibilityCallback != null) {
            mWindowsForAccessibilityCallback = null;
            mWindowManagerService.setWindowsForAccessibilityCallback(
                    mWindowsForAccessibilityCallback);
            mWindowManagerService.setWindowsForAccessibilityCallback(null);
        }
    }

@@ -1437,8 +1416,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
    }

    private boolean readConfigurationForUserStateLocked(UserState userState) {
        boolean somthingChanged = false;
        somthingChanged |= readAccessibilityEnabledSettingLocked(userState);
        boolean somthingChanged = readAccessibilityEnabledSettingLocked(userState);
        somthingChanged |= readInstalledAccessibilityServiceLocked(userState);
        somthingChanged |= readEnabledAccessibilityServicesLocked(userState);
        somthingChanged |= readTouchExplorationGrantedAccessibilityServicesLocked(userState);
@@ -1868,7 +1846,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {

        int mFeedbackType;

        Set<String> mPackageNames = new HashSet<String>();
        Set<String> mPackageNames = new HashSet<>();

        boolean mIsDefault;

@@ -1890,20 +1868,16 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {

        boolean mIsAutomation;

        final Rect mTempBounds1 = new Rect();

        final Rect mTempBounds2 = new Rect();

        final ResolveInfo mResolveInfo;

        // the events pending events to be dispatched to this service
        final SparseArray<AccessibilityEvent> mPendingEvents =
            new SparseArray<AccessibilityEvent>();
            new SparseArray<>();

        final KeyEventDispatcher mKeyEventDispatcher = new KeyEventDispatcher();

        final SparseArray<AccessibilityWindowInfo> mIntrospectedWindows =
                new SparseArray<AccessibilityWindowInfo>();
                new SparseArray<>();

        boolean mWasConnectedAndDied;

@@ -2106,7 +2080,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
                if (!permissionGranted) {
                    return null;
                }
                List<AccessibilityWindowInfo> windows = new ArrayList<AccessibilityWindowInfo>();
                List<AccessibilityWindowInfo> windows = new ArrayList<>();
                final int windowCount = mSecurityPolicy.mWindows.size();
                for (int i = 0; i < windowCount; i++) {
                    AccessibilityWindowInfo window = mSecurityPolicy.mWindows.get(i);
@@ -2646,51 +2620,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
            }
        }

        public void notifyWindowsChangedLocked(List<AccessibilityWindowInfo> windows) {
            LongArray changedWindows = mTempLongArray;
            changedWindows.clear();

            // Figure out which windows the service cares about changed.
            final int windowCount = windows.size();
            for (int i = 0; i < windowCount; i++) {
                AccessibilityWindowInfo newState = windows.get(i);
                final int windowId = newState.getId();
                AccessibilityWindowInfo oldState = mIntrospectedWindows.get(windowId);
                if (oldState != null && oldState.changed(newState)) {
                    oldState.recycle();
                    mIntrospectedWindows.put(newState.getId(),
                            AccessibilityWindowInfo.obtain(newState));
                    changedWindows.add(windowId);
                }
            }

            // Figure out which windows the service cares about went away.
            final int introspectedWindowCount = mIntrospectedWindows.size();
            for (int i = introspectedWindowCount - 1; i >= 0; i--) {
                AccessibilityWindowInfo window = mIntrospectedWindows.valueAt(i);
                if (changedWindows.indexOf(window.getId()) < 0 && !windows.contains(window)) {
                    changedWindows.add(window.getId());
                    mIntrospectedWindows.removeAt(i);
                    window.recycle();
                }
            }

            int[] windowIds = null;

            final int changedWindowCount = changedWindows.size();
            if (changedWindowCount > 0) {
                windowIds = new int[changedWindowCount];
                for (int i = 0; i < changedWindowCount; i++) {
                    // Cast is fine as we use long array to cache ints.
                    windowIds[i] = (int) changedWindows.get(i);
                }
                changedWindows.clear();
            }

            mInvocationHandler.obtainMessage(InvocationHandler.MSG_ON_WINDOWS_CHANGED,
                    windowIds).sendToTarget();
        }

        private void notifyGestureInternal(int gestureId) {
            final IAccessibilityServiceClient listener;
            synchronized (mLock) {
@@ -2725,20 +2654,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
            }
        }

        private void notifyWindowsChangedInternal(int[] windowIds) {
            final IAccessibilityServiceClient listener;
            synchronized (mLock) {
                listener = mServiceInterface;
            }
            if (listener != null) {
                try {
                    listener.onWindowsChanged(windowIds);
                } catch (RemoteException re) {
                    Slog.e(LOG_TAG, "Error during sending windows to: " + mService, re);
                }
            }
        }

        private void sendDownAndUpKeyEvents(int keyCode) {
            final long token = Binder.clearCallingIdentity();

@@ -2844,7 +2759,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
            public static final int MSG_ON_KEY_EVENT = 2;
            public static final int MSG_CLEAR_ACCESSIBILITY_CACHE = 3;
            public static final int MSG_ON_KEY_EVENT_TIMEOUT = 4;
            public static final int MSG_ON_WINDOWS_CHANGED = 5;

            public InvocationHandler(Looper looper) {
                super(looper, null, true);
@@ -2874,11 +2788,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
                        setOnKeyEventResult(false, eventState.sequence);
                    } break;

                    case MSG_ON_WINDOWS_CHANGED: {
                        final int[] windowIds = (int[]) message.obj;
                        notifyWindowsChangedInternal(windowIds);
                    } break;

                    default: {
                        throw new IllegalArgumentException("Unknown message: " + type);
                    }
@@ -3028,14 +2937,11 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
        @Override
        public void onWindowsForAccessibilityChanged(List<WindowInfo> windows) {
            synchronized (mLock) {
                List<WindowInfo> receivedWindows = (List<WindowInfo>) windows;

                // Populate the windows to report.
                List<AccessibilityWindowInfo> reportedWindows =
                        new ArrayList<AccessibilityWindowInfo>();
                final int receivedWindowCount = receivedWindows.size();
                List<AccessibilityWindowInfo> reportedWindows = new ArrayList<>();
                final int receivedWindowCount = windows.size();
                for (int i = 0; i < receivedWindowCount; i++) {
                    WindowInfo receivedWindow = receivedWindows.get(i);
                    WindowInfo receivedWindow = windows.get(i);
                    AccessibilityWindowInfo reportedWindow = populateReportedWindow(
                            receivedWindow);
                    if (reportedWindow != null) {
@@ -3224,8 +3130,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
            | AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED
            | AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY;

        public final List<AccessibilityWindowInfo> mWindows =
                new ArrayList<AccessibilityWindowInfo>();
        public final List<AccessibilityWindowInfo> mWindows = new ArrayList<>();

        public int mActiveWindowId = INVALID_WINDOW_ID;
        public int mFocusedWindowId = INVALID_WINDOW_ID;
@@ -3265,7 +3170,9 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
                case AccessibilityEvent.TYPE_TOUCH_INTERACTION_START:
                case AccessibilityEvent.TYPE_TOUCH_INTERACTION_END:
                case AccessibilityEvent.TYPE_VIEW_HOVER_ENTER:
                case AccessibilityEvent.TYPE_VIEW_HOVER_EXIT: {
                case AccessibilityEvent.TYPE_VIEW_HOVER_EXIT:
                // Also windows changing should always be anounced.
                case AccessibilityEvent.TYPE_WINDOWS_CHANGED: {
                    return true;
                }
                // All events for changes in window content should be
@@ -3327,7 +3234,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
                }
            }

            notifyWindowsChangedLocked(mWindows);
            notifyWindowsChanged();

            // If we are delaying a window state change event as the window
            // source was showing when it was fired, now is the time to send.
@@ -3452,8 +3359,16 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
                    AccessibilityWindowInfo window = mWindows.get(i);
                    window.setActive(window.getId() == windowId);
                }
                notifyWindowsChangedLocked(mWindows);
                notifyWindowsChanged();
            }
        }

        private void notifyWindowsChanged() {
            // Let the client know the windows changed.
            AccessibilityEvent event = AccessibilityEvent.obtain(
                    AccessibilityEvent.TYPE_WINDOWS_CHANGED);
            event.setEventTime(SystemClock.uptimeMillis());
            sendAccessibilityEvent(event, mCurrentUserId);
        }

        public boolean canGetAccessibilityNodeInfoLocked(Service service, int windowId) {
@@ -3568,30 +3483,30 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
        // Non-transient state.

        public final RemoteCallbackList<IAccessibilityManagerClient> mClients =
            new RemoteCallbackList<IAccessibilityManagerClient>();
            new RemoteCallbackList<>();

        public final SparseArray<AccessibilityConnectionWrapper> mInteractionConnections =
                new SparseArray<AccessibilityConnectionWrapper>();
                new SparseArray<>();

        public final SparseArray<IBinder> mWindowTokens = new SparseArray<IBinder>();
        public final SparseArray<IBinder> mWindowTokens = new SparseArray<>();

        // Transient state.

        public final CopyOnWriteArrayList<Service> mBoundServices =
                new CopyOnWriteArrayList<Service>();
                new CopyOnWriteArrayList<>();

        public final Map<ComponentName, Service> mComponentNameToServiceMap =
                new HashMap<ComponentName, Service>();
                new HashMap<>();

        public final List<AccessibilityServiceInfo> mInstalledServices =
                new ArrayList<AccessibilityServiceInfo>();
                new ArrayList<>();

        public final Set<ComponentName> mBindingServices = new HashSet<ComponentName>();
        public final Set<ComponentName> mBindingServices = new HashSet<>();

        public final Set<ComponentName> mEnabledServices = new HashSet<ComponentName>();
        public final Set<ComponentName> mEnabledServices = new HashSet<>();

        public final Set<ComponentName> mTouchExplorationGrantedServices =
                new HashSet<ComponentName>();
                new HashSet<>();

        public int mHandledFeedbackTypes = 0;