Merge "Report all content changes to a11y services." into nyc-dev
This commit is contained in:
@@ -2228,7 +2228,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
|
|||||||
@Override
|
@Override
|
||||||
public void handleMessage(Message message) {
|
public void handleMessage(Message message) {
|
||||||
final int eventType = message.what;
|
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
|
// be modified to remove its source if the receiving service does
|
||||||
// not have permission to access the window content.
|
// not have permission to access the window content.
|
||||||
AccessibilityEvent newEvent = AccessibilityEvent.obtain(event);
|
AccessibilityEvent newEvent = AccessibilityEvent.obtain(event);
|
||||||
AccessibilityEvent oldEvent = mPendingEvents.get(eventType);
|
Message message;
|
||||||
mPendingEvents.put(eventType, newEvent);
|
if ((mNotificationTimeout > 0)
|
||||||
|
&& (eventType != AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED)) {
|
||||||
final int what = eventType;
|
// Allow at most one pending event
|
||||||
if (oldEvent != null) {
|
final AccessibilityEvent oldEvent = mPendingEvents.get(eventType);
|
||||||
mEventDispatchHandler.removeMessages(what);
|
mPendingEvents.put(eventType, newEvent);
|
||||||
oldEvent.recycle();
|
if (oldEvent != null) {
|
||||||
|
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);
|
mEventDispatchHandler.sendMessageDelayed(message, mNotificationTimeout);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3149,9 +3156,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
|
|||||||
*
|
*
|
||||||
* @param eventType The type of the event to dispatch.
|
* @param eventType The type of the event to dispatch.
|
||||||
*/
|
*/
|
||||||
private void notifyAccessibilityEventInternal(int eventType) {
|
private void notifyAccessibilityEventInternal(int eventType, AccessibilityEvent event) {
|
||||||
IAccessibilityServiceClient listener;
|
IAccessibilityServiceClient listener;
|
||||||
AccessibilityEvent event;
|
|
||||||
|
|
||||||
synchronized (mLock) {
|
synchronized (mLock) {
|
||||||
listener = mServiceInterface;
|
listener = mServiceInterface;
|
||||||
@@ -3162,28 +3168,32 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
event = mPendingEvents.get(eventType);
|
// 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
|
||||||
// Check for null here because there is a concurrent scenario in which this
|
// minimal fuss.
|
||||||
// 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) {
|
if (event == null) {
|
||||||
return;
|
// 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);
|
||||||
|
if (event == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mPendingEvents.remove(eventType);
|
||||||
}
|
}
|
||||||
|
|
||||||
mPendingEvents.remove(eventType);
|
|
||||||
if (mSecurityPolicy.canRetrieveWindowContentLocked(this)) {
|
if (mSecurityPolicy.canRetrieveWindowContentLocked(this)) {
|
||||||
event.setConnectionId(mId);
|
event.setConnectionId(mId);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
Reference in New Issue
Block a user