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

Commit 403ee9c3 authored by Phil Weaver's avatar Phil Weaver Committed by android-build-merger
Browse files

Merge \"Report all content changes to a11y services.\" into nyc-dev

am: 8ac5bcba

Change-Id: I9338fd3ef749f80c4b0252c7c749fe6e395b3c0a
parents 7bc1db96 8ac5bcba
Loading
Loading
Loading
Loading
+41 −31
Original line number Diff line number Diff line
@@ -2228,7 +2228,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
            @Override
            public void handleMessage(Message message) {
                final int eventType =  message.what;
                notifyAccessibilityEventInternal(eventType);
                AccessibilityEvent event = (AccessibilityEvent) message.obj;
                notifyAccessibilityEventInternal(eventType, event);
            }
        };

@@ -3130,16 +3131,22 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
                // be modified to remove its source if the receiving service does
                // not have permission to access the window content.
                AccessibilityEvent newEvent = AccessibilityEvent.obtain(event);
                AccessibilityEvent oldEvent = mPendingEvents.get(eventType);
                Message message;
                if ((mNotificationTimeout > 0)
                        && (eventType != AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED)) {
                    // Allow at most one pending event
                    final AccessibilityEvent oldEvent = mPendingEvents.get(eventType);
                    mPendingEvents.put(eventType, newEvent);

                final int what = eventType;
                    if (oldEvent != null) {
                    mEventDispatchHandler.removeMessages(what);
                        mEventDispatchHandler.removeMessages(eventType);
                        oldEvent.recycle();
                    }
                    message = mEventDispatchHandler.obtainMessage(eventType);
                } else {
                    // Send all messages, bypassing mPendingEvents
                    message = mEventDispatchHandler.obtainMessage(eventType, newEvent);
                }

                Message message = mEventDispatchHandler.obtainMessage(what);
                mEventDispatchHandler.sendMessageDelayed(message, mNotificationTimeout);
            }
        }
@@ -3149,9 +3156,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
         *
         * @param eventType The type of the event to dispatch.
         */
        private void notifyAccessibilityEventInternal(int eventType) {
        private void notifyAccessibilityEventInternal(int eventType, AccessibilityEvent event) {
            IAccessibilityServiceClient listener;
            AccessibilityEvent event;

            synchronized (mLock) {
                listener = mServiceInterface;
@@ -3162,28 +3168,32 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
                    return;
                }

                // There are two ways we notify for events, throttled and non-throttled. If we
                // are not throttling, then messages come with events, which we handle with
                // minimal fuss.
                if (event == null) {
                    // We are throttling events, so we'll send the event for this type in
                    // mPendingEvents as long as it it's null. It can only null due to a race
                    // condition:
                    //
                    //   1) A binder thread calls notifyAccessibilityServiceDelayedLocked
                    //      which posts a message for dispatching an event and stores the event
                    //      in mPendingEvents.
                    //   2) The message is pulled from the queue by the handler on the service
                    //      thread and this method is just about to acquire the lock.
                    //   3) Another binder thread acquires the lock in notifyAccessibilityEvent
                    //   4) notifyAccessibilityEvent recycles the event that this method was about
                    //      to process, replaces it with a new one, and posts a second message
                    //   5) This method grabs the new event, processes it, and removes it from
                    //      mPendingEvents
                    //   6) The second message dispatched in (4) arrives, but the event has been
                    //      remvoved in (5).
                    event = mPendingEvents.get(eventType);

                // Check for null here because there is a concurrent scenario in which this
                // happens: 1) A binder thread calls notifyAccessibilityServiceDelayedLocked
                // which posts a message for dispatching an event. 2) The message is pulled
                // from the queue by the handler on the service thread and the latter is
                // just about to acquire the lock and call this method. 3) Now another binder
                // thread acquires the lock calling notifyAccessibilityServiceDelayedLocked
                // so the service thread waits for the lock; 4) The binder thread replaces
                // the event with a more recent one (assume the same event type) and posts a
                // dispatch request releasing the lock. 5) Now the main thread is unblocked and
                // dispatches the event which is removed from the pending ones. 6) And ... now
                // the service thread handles the last message posted by the last binder call
                // but the event is already dispatched and hence looking it up in the pending
                // ones yields null. This check is much simpler that keeping count for each
                // event type of each service to catch such a scenario since only one message
                // is processed at a time.
                    if (event == null) {
                        return;
                    }

                    mPendingEvents.remove(eventType);
                }
                if (mSecurityPolicy.canRetrieveWindowContentLocked(this)) {
                    event.setConnectionId(mId);
                } else {