Loading core/java/android/view/accessibility/AccessibilityManager.java +34 −122 Original line number Diff line number Diff line Loading @@ -92,9 +92,6 @@ public final class AccessibilityManager { /** @hide */ public static final int AUTOCLICK_DELAY_DEFAULT = 600; /** @hide */ public static final int MAX_A11Y_EVENTS_PER_SERVICE_CALL = 20; static final Object sInstanceSync = new Object(); private static AccessibilityManager sInstance; Loading @@ -103,8 +100,6 @@ public final class AccessibilityManager { private IAccessibilityManager mService; private EventDispatchThread mEventDispatchThread; final int mUserId; final Handler mHandler; Loading Loading @@ -303,7 +298,14 @@ public final class AccessibilityManager { * their descendants. */ public void sendAccessibilityEvent(AccessibilityEvent event) { if (!isEnabled()) { final IAccessibilityManager service; final int userId; synchronized (mLock) { service = getServiceLocked(); if (service == null) { return; } if (!mIsEnabled) { Looper myLooper = Looper.myLooper(); if (myLooper == Looper.getMainLooper()) { throw new IllegalStateException( Loading @@ -317,18 +319,23 @@ public final class AccessibilityManager { return; } } event.setEventTime(SystemClock.uptimeMillis()); getEventDispatchThread().scheduleEvent(event); userId = mUserId; } private EventDispatchThread getEventDispatchThread() { synchronized (mLock) { if (mEventDispatchThread == null) { mEventDispatchThread = new EventDispatchThread(mService, mUserId); mEventDispatchThread.start(); try { event.setEventTime(SystemClock.uptimeMillis()); // it is possible that this manager is in the same process as the service but // client using it is called through Binder from another process. Example: MMS // app adds a SMS notification and the NotificationManagerService calls this method long identityToken = Binder.clearCallingIdentity(); service.sendAccessibilityEvent(event, userId); Binder.restoreCallingIdentity(identityToken); if (DEBUG) { Log.i(LOG_TAG, event + " sent"); } return mEventDispatchThread; } catch (RemoteException re) { Log.e(LOG_TAG, "Error during sending " + event + " ", re); } finally { event.recycle(); } } Loading Loading @@ -713,99 +720,4 @@ public final class AccessibilityManager { } } } private static class EventDispatchThread extends Thread { // Second lock used to keep UI thread performant. Never try to grab mLock when holding // this one, or the UI thread will block in send AccessibilityEvent. private final Object mEventQueueLock = new Object(); // Two lists to hold events. The app thread fills one while we empty the other. private final ArrayList<AccessibilityEvent> mEventLists0 = new ArrayList<>(MAX_A11Y_EVENTS_PER_SERVICE_CALL); private final ArrayList<AccessibilityEvent> mEventLists1 = new ArrayList<>(MAX_A11Y_EVENTS_PER_SERVICE_CALL); private boolean mPingPongListToggle; private final IAccessibilityManager mService; private final int mUserId; EventDispatchThread(IAccessibilityManager service, int userId) { mService = service; mUserId = userId; } @Override public void run() { while (true) { ArrayList<AccessibilityEvent> listBeingDrained; synchronized (mEventQueueLock) { ArrayList<AccessibilityEvent> listBeingFilled = getListBeingFilledLocked(); if (listBeingFilled.isEmpty()) { try { mEventQueueLock.wait(); } catch (InterruptedException e) { // Treat as a notify } } // Swap buffers mPingPongListToggle = !mPingPongListToggle; listBeingDrained = listBeingFilled; } dispatchEvents(listBeingDrained); } } public void scheduleEvent(AccessibilityEvent event) { synchronized (mEventQueueLock) { getListBeingFilledLocked().add(event); mEventQueueLock.notifyAll(); } } private ArrayList<AccessibilityEvent> getListBeingFilledLocked() { return (mPingPongListToggle) ? mEventLists0 : mEventLists1; } private void dispatchEvents(ArrayList<AccessibilityEvent> events) { int eventListCapacityLowerBound = events.size(); while (events.size() > 0) { // We don't want to consume extra memory if an app sends a lot of events in a // one-off event. Cap the list length at double the max events per call. // We'll end up with extra GC for apps that send huge numbers of events, but // sending that many events will lead to bad performance in any case. if ((eventListCapacityLowerBound > 2 * MAX_A11Y_EVENTS_PER_SERVICE_CALL) && (events.size() <= 2 * MAX_A11Y_EVENTS_PER_SERVICE_CALL)) { events.trimToSize(); eventListCapacityLowerBound = events.size(); } // We only expect this loop to run once, as the app shouldn't be sending // huge numbers of events. // The clear in the called method will remove the sent events dispatchOneBatchOfEvents(events.subList(0, Math.min(events.size(), MAX_A11Y_EVENTS_PER_SERVICE_CALL))); } } private void dispatchOneBatchOfEvents(List<AccessibilityEvent> events) { if (events.isEmpty()) { return; } long identityToken = Binder.clearCallingIdentity(); try { mService.sendAccessibilityEvents(new ParceledListSlice<>(events), mUserId); } catch (RemoteException re) { Log.e(LOG_TAG, "Error sending multiple events"); } Binder.restoreCallingIdentity(identityToken); if (DEBUG) { Log.i(LOG_TAG, events.size() + " events sent"); } for (int i = events.size() - 1; i >= 0; i--) { events.remove(i).recycle(); } } } } core/java/android/view/accessibility/IAccessibilityManager.aidl +1 −4 Original line number Diff line number Diff line Loading @@ -21,7 +21,6 @@ import android.accessibilityservice.AccessibilityServiceInfo; import android.accessibilityservice.IAccessibilityServiceConnection; import android.accessibilityservice.IAccessibilityServiceClient; import android.content.ComponentName; import android.content.pm.ParceledListSlice; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityNodeInfo; import android.view.accessibility.IAccessibilityInteractionConnection; Loading @@ -30,7 +29,7 @@ import android.view.IWindow; /** * Interface implemented by the AccessibilityManagerService called by * the AccessibilityMasngers. * the AccessibilityManagers. * * @hide */ Loading @@ -40,8 +39,6 @@ interface IAccessibilityManager { void sendAccessibilityEvent(in AccessibilityEvent uiEvent, int userId); void sendAccessibilityEvents(in ParceledListSlice events, int userId); List<AccessibilityServiceInfo> getInstalledAccessibilityServiceList(int userId); List<AccessibilityServiceInfo> getEnabledAccessibilityServiceList(int feedbackType, int userId); Loading services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java +0 −14 Original line number Diff line number Diff line Loading @@ -497,20 +497,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { } } @Override public void sendAccessibilityEvents(ParceledListSlice events, int userId) { List<AccessibilityEvent> a11yEvents = events.getList(); // Grab the lock once for the entire batch synchronized (mLock) { int numEventsToProcess = Math.min(a11yEvents.size(), AccessibilityManager.MAX_A11Y_EVENTS_PER_SERVICE_CALL); for (int i = 0; i < numEventsToProcess; i++) { AccessibilityEvent event = a11yEvents.get(i); sendAccessibilityEvent(event, userId); } } } @Override public List<AccessibilityServiceInfo> getInstalledAccessibilityServiceList(int userId) { synchronized (mLock) { Loading Loading
core/java/android/view/accessibility/AccessibilityManager.java +34 −122 Original line number Diff line number Diff line Loading @@ -92,9 +92,6 @@ public final class AccessibilityManager { /** @hide */ public static final int AUTOCLICK_DELAY_DEFAULT = 600; /** @hide */ public static final int MAX_A11Y_EVENTS_PER_SERVICE_CALL = 20; static final Object sInstanceSync = new Object(); private static AccessibilityManager sInstance; Loading @@ -103,8 +100,6 @@ public final class AccessibilityManager { private IAccessibilityManager mService; private EventDispatchThread mEventDispatchThread; final int mUserId; final Handler mHandler; Loading Loading @@ -303,7 +298,14 @@ public final class AccessibilityManager { * their descendants. */ public void sendAccessibilityEvent(AccessibilityEvent event) { if (!isEnabled()) { final IAccessibilityManager service; final int userId; synchronized (mLock) { service = getServiceLocked(); if (service == null) { return; } if (!mIsEnabled) { Looper myLooper = Looper.myLooper(); if (myLooper == Looper.getMainLooper()) { throw new IllegalStateException( Loading @@ -317,18 +319,23 @@ public final class AccessibilityManager { return; } } event.setEventTime(SystemClock.uptimeMillis()); getEventDispatchThread().scheduleEvent(event); userId = mUserId; } private EventDispatchThread getEventDispatchThread() { synchronized (mLock) { if (mEventDispatchThread == null) { mEventDispatchThread = new EventDispatchThread(mService, mUserId); mEventDispatchThread.start(); try { event.setEventTime(SystemClock.uptimeMillis()); // it is possible that this manager is in the same process as the service but // client using it is called through Binder from another process. Example: MMS // app adds a SMS notification and the NotificationManagerService calls this method long identityToken = Binder.clearCallingIdentity(); service.sendAccessibilityEvent(event, userId); Binder.restoreCallingIdentity(identityToken); if (DEBUG) { Log.i(LOG_TAG, event + " sent"); } return mEventDispatchThread; } catch (RemoteException re) { Log.e(LOG_TAG, "Error during sending " + event + " ", re); } finally { event.recycle(); } } Loading Loading @@ -713,99 +720,4 @@ public final class AccessibilityManager { } } } private static class EventDispatchThread extends Thread { // Second lock used to keep UI thread performant. Never try to grab mLock when holding // this one, or the UI thread will block in send AccessibilityEvent. private final Object mEventQueueLock = new Object(); // Two lists to hold events. The app thread fills one while we empty the other. private final ArrayList<AccessibilityEvent> mEventLists0 = new ArrayList<>(MAX_A11Y_EVENTS_PER_SERVICE_CALL); private final ArrayList<AccessibilityEvent> mEventLists1 = new ArrayList<>(MAX_A11Y_EVENTS_PER_SERVICE_CALL); private boolean mPingPongListToggle; private final IAccessibilityManager mService; private final int mUserId; EventDispatchThread(IAccessibilityManager service, int userId) { mService = service; mUserId = userId; } @Override public void run() { while (true) { ArrayList<AccessibilityEvent> listBeingDrained; synchronized (mEventQueueLock) { ArrayList<AccessibilityEvent> listBeingFilled = getListBeingFilledLocked(); if (listBeingFilled.isEmpty()) { try { mEventQueueLock.wait(); } catch (InterruptedException e) { // Treat as a notify } } // Swap buffers mPingPongListToggle = !mPingPongListToggle; listBeingDrained = listBeingFilled; } dispatchEvents(listBeingDrained); } } public void scheduleEvent(AccessibilityEvent event) { synchronized (mEventQueueLock) { getListBeingFilledLocked().add(event); mEventQueueLock.notifyAll(); } } private ArrayList<AccessibilityEvent> getListBeingFilledLocked() { return (mPingPongListToggle) ? mEventLists0 : mEventLists1; } private void dispatchEvents(ArrayList<AccessibilityEvent> events) { int eventListCapacityLowerBound = events.size(); while (events.size() > 0) { // We don't want to consume extra memory if an app sends a lot of events in a // one-off event. Cap the list length at double the max events per call. // We'll end up with extra GC for apps that send huge numbers of events, but // sending that many events will lead to bad performance in any case. if ((eventListCapacityLowerBound > 2 * MAX_A11Y_EVENTS_PER_SERVICE_CALL) && (events.size() <= 2 * MAX_A11Y_EVENTS_PER_SERVICE_CALL)) { events.trimToSize(); eventListCapacityLowerBound = events.size(); } // We only expect this loop to run once, as the app shouldn't be sending // huge numbers of events. // The clear in the called method will remove the sent events dispatchOneBatchOfEvents(events.subList(0, Math.min(events.size(), MAX_A11Y_EVENTS_PER_SERVICE_CALL))); } } private void dispatchOneBatchOfEvents(List<AccessibilityEvent> events) { if (events.isEmpty()) { return; } long identityToken = Binder.clearCallingIdentity(); try { mService.sendAccessibilityEvents(new ParceledListSlice<>(events), mUserId); } catch (RemoteException re) { Log.e(LOG_TAG, "Error sending multiple events"); } Binder.restoreCallingIdentity(identityToken); if (DEBUG) { Log.i(LOG_TAG, events.size() + " events sent"); } for (int i = events.size() - 1; i >= 0; i--) { events.remove(i).recycle(); } } } }
core/java/android/view/accessibility/IAccessibilityManager.aidl +1 −4 Original line number Diff line number Diff line Loading @@ -21,7 +21,6 @@ import android.accessibilityservice.AccessibilityServiceInfo; import android.accessibilityservice.IAccessibilityServiceConnection; import android.accessibilityservice.IAccessibilityServiceClient; import android.content.ComponentName; import android.content.pm.ParceledListSlice; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityNodeInfo; import android.view.accessibility.IAccessibilityInteractionConnection; Loading @@ -30,7 +29,7 @@ import android.view.IWindow; /** * Interface implemented by the AccessibilityManagerService called by * the AccessibilityMasngers. * the AccessibilityManagers. * * @hide */ Loading @@ -40,8 +39,6 @@ interface IAccessibilityManager { void sendAccessibilityEvent(in AccessibilityEvent uiEvent, int userId); void sendAccessibilityEvents(in ParceledListSlice events, int userId); List<AccessibilityServiceInfo> getInstalledAccessibilityServiceList(int userId); List<AccessibilityServiceInfo> getEnabledAccessibilityServiceList(int feedbackType, int userId); Loading
services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java +0 −14 Original line number Diff line number Diff line Loading @@ -497,20 +497,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { } } @Override public void sendAccessibilityEvents(ParceledListSlice events, int userId) { List<AccessibilityEvent> a11yEvents = events.getList(); // Grab the lock once for the entire batch synchronized (mLock) { int numEventsToProcess = Math.min(a11yEvents.size(), AccessibilityManager.MAX_A11Y_EVENTS_PER_SERVICE_CALL); for (int i = 0; i < numEventsToProcess; i++) { AccessibilityEvent event = a11yEvents.get(i); sendAccessibilityEvent(event, userId); } } } @Override public List<AccessibilityServiceInfo> getInstalledAccessibilityServiceList(int userId) { synchronized (mLock) { Loading