Loading core/java/android/os/RemoteCallbackList.java +17 −0 Original line number Diff line number Diff line Loading @@ -333,6 +333,23 @@ public class RemoteCallbackList<E extends IInterface> { } } /** * Performs {@code action} for each cookie associated with a callback, calling * {@link #beginBroadcast()}/{@link #finishBroadcast()} before/after looping * * @hide */ public <C> void broadcastForEachCookie(Consumer<C> action) { int itemCount = beginBroadcast(); try { for (int i = 0; i < itemCount; i++) { action.accept((C) getBroadcastCookie(i)); } } finally { finishBroadcast(); } } /** * Returns the number of registered callbacks. Note that the number of registered * callbacks may differ from the value returned by {@link #beginBroadcast()} since Loading core/java/com/android/internal/util/CollectionUtils.java +2 −2 Original line number Diff line number Diff line Loading @@ -290,11 +290,11 @@ public class CollectionUtils { if (cur instanceof ArraySet) { ArraySet<T> arraySet = (ArraySet<T>) cur; for (int i = 0; i < size; i++) { action.accept(arraySet.valueAt(i)); action.acceptOrThrow(arraySet.valueAt(i)); } } else { for (T t : cur) { action.accept(t); action.acceptOrThrow(t); } } } catch (Exception e) { Loading core/java/com/android/internal/util/FunctionalUtils.java +53 −5 Original line number Diff line number Diff line Loading @@ -16,6 +16,9 @@ package com.android.internal.util; import android.os.RemoteException; import java.util.function.Consumer; import java.util.function.Supplier; /** Loading @@ -24,6 +27,21 @@ import java.util.function.Supplier; public class FunctionalUtils { private FunctionalUtils() {} /** * Converts a lambda expression that throws a checked exception(s) into a regular * {@link Consumer} by propagating any checked exceptions as {@link RuntimeException} */ public static <T> Consumer<T> uncheckExceptions(ThrowingConsumer<T> action) { return action; } /** * */ public static <T> Consumer<T> ignoreRemoteException(RemoteExceptionIgnoringConsumer<T> action) { return action; } /** * An equivalent of {@link Runnable} that allows throwing checked exceptions * Loading @@ -47,13 +65,43 @@ public class FunctionalUtils { } /** * An equivalent of {@link java.util.function.Consumer} that allows throwing checked exceptions * A {@link Consumer} that allows throwing checked exceptions from its single abstract method. * * This can be used to specify a lambda argument without forcing all the checked exceptions * to be handled within it * Can be used together with {@link #uncheckExceptions} to effectively turn a lambda expression * that throws a checked exception into a regular {@link Consumer} */ @FunctionalInterface public interface ThrowingConsumer<T> { void accept(T t) throws Exception; @SuppressWarnings("FunctionalInterfaceMethodChanged") public interface ThrowingConsumer<T> extends Consumer<T> { void acceptOrThrow(T t) throws Exception; @Override default void accept(T t) { try { acceptOrThrow(t); } catch (Exception ex) { throw new RuntimeException(ex); } } } /** * A {@link Consumer} that automatically ignores any {@link RemoteException}s. * * Used by {@link #ignoreRemoteException} */ @FunctionalInterface @SuppressWarnings("FunctionalInterfaceMethodChanged") public interface RemoteExceptionIgnoringConsumer<T> extends Consumer<T> { void acceptOrThrow(T t) throws RemoteException; @Override default void accept(T t) { try { acceptOrThrow(t); } catch (RemoteException ex) { // ignore } } } } services/accessibility/java/com/android/server/accessibility/AccessibilityClientConnection.java→services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java +16 −5 Original line number Diff line number Diff line Loading @@ -71,7 +71,7 @@ import java.util.Set; * This class represents an accessibility client - either an AccessibilityService or a UiAutomation. * It is responsible for behavior common to both types of clients. */ abstract class AccessibilityClientConnection extends IAccessibilityServiceConnection.Stub abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServiceConnection.Stub implements ServiceConnection, IBinder.DeathRecipient, KeyEventDispatcher.KeyEventFilter, FingerprintGestureDispatcher.FingerprintGestureClient { private static final boolean DEBUG = false; Loading Loading @@ -238,7 +238,7 @@ abstract class AccessibilityClientConnection extends IAccessibilityServiceConnec int flags); } public AccessibilityClientConnection(Context context, ComponentName componentName, public AbstractAccessibilityServiceConnection(Context context, ComponentName componentName, AccessibilityServiceInfo accessibilityServiceInfo, int id, Handler mainHandler, Object lock, SecurityPolicy securityPolicy, SystemSupport systemSupport, WindowManagerInternal windowManagerInternal, Loading Loading @@ -339,6 +339,11 @@ abstract class AccessibilityClientConnection extends IAccessibilityServiceConnec } } int getRelevantEventTypes() { return (mUsesAccessibilityCache ? AccessibilityCache.CACHE_CRITICAL_EVENTS_MASK : 0) | mEventTypes; } @Override public void setServiceInfo(AccessibilityServiceInfo info) { final long identity = Binder.clearCallingIdentity(); Loading Loading @@ -954,13 +959,15 @@ abstract class AccessibilityClientConnection extends IAccessibilityServiceConnec public void notifyAccessibilityEvent(AccessibilityEvent event) { synchronized (mLock) { final int eventType = event.getEventType(); final boolean serviceWantsEvent = wantsEventLocked(event); if (!serviceWantsEvent && !mUsesAccessibilityCache && ((AccessibilityCache.CACHE_CRITICAL_EVENTS_MASK & event.getEventType()) == 0)) { final boolean requiredForCacheConsistency = mUsesAccessibilityCache && ((AccessibilityCache.CACHE_CRITICAL_EVENTS_MASK & eventType) != 0); if (!serviceWantsEvent && !requiredForCacheConsistency) { return; } final int eventType = event.getEventType(); // Make a copy since during dispatch it is possible the event to // be modified to remove its source if the receiving service does // not have permission to access the window content. Loading Loading @@ -1226,6 +1233,10 @@ abstract class AccessibilityClientConnection extends IAccessibilityServiceConnec return windowId; } public ComponentName getComponentName() { return mComponentName; } private final class InvocationHandler extends Handler { public static final int MSG_ON_GESTURE = 1; public static final int MSG_CLEAR_ACCESSIBILITY_CACHE = 2; Loading services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java +94 −65 Original line number Diff line number Diff line Loading @@ -20,6 +20,8 @@ import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY import static android.view.accessibility.AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS; import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS; import static com.android.internal.util.FunctionalUtils.ignoreRemoteException; import android.Manifest; import android.accessibilityservice.AccessibilityService; import android.accessibilityservice.AccessibilityServiceInfo; Loading Loading @@ -84,7 +86,6 @@ import android.view.MagnificationSpec; import android.view.View; import android.view.WindowInfo; import android.view.WindowManager; import android.view.accessibility.AccessibilityCache; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityInteractionClient; import android.view.accessibility.AccessibilityManager; Loading Loading @@ -114,6 +115,7 @@ import java.io.FileDescriptor; import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; Loading @@ -131,7 +133,7 @@ import java.util.function.Consumer; * on the device. Events are dispatched to {@link AccessibilityService}s. */ public class AccessibilityManagerService extends IAccessibilityManager.Stub implements AccessibilityClientConnection.SystemSupport { implements AbstractAccessibilityServiceConnection.SystemSupport { private static final boolean DEBUG = false; Loading Loading @@ -455,7 +457,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub } @Override public long addClient(IAccessibilityManagerClient client, int userId) { public long addClient(IAccessibilityManagerClient callback, int userId) { synchronized (mLock) { // We treat calls from a profile as if made by its parent as profiles // share the accessibility state of the parent. The call below Loading @@ -467,15 +469,17 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub // the system UI or the system we add it to the global state that // is shared across users. UserState userState = getUserStateLocked(resolvedUserId); Client client = new Client(callback, Binder.getCallingUid(), userState); if (mSecurityPolicy.isCallerInteractingAcrossUsers(userId)) { mGlobalClients.register(client); mGlobalClients.register(callback, client); if (DEBUG) { Slog.i(LOG_TAG, "Added global client for pid:" + Binder.getCallingPid()); } return IntPair.of( userState.getClientState(), userState.mLastSentRelevantEventTypes); userState.getClientState(), client.mLastSentRelevantEventTypes); } else { userState.mUserClients.register(client); userState.mUserClients.register(callback, client); // If this client is not for the current user we do not // return a state since it is not for the foreground user. // We will send the state to the client on a user switch. Loading @@ -485,7 +489,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub } return IntPair.of( (resolvedUserId == mCurrentUserId) ? userState.getClientState() : 0, userState.mLastSentRelevantEventTypes); client.mLastSentRelevantEventTypes); } } } Loading Loading @@ -951,7 +955,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub * Has no effect if no item has accessibility focus, if the item with accessibility * focus does not expose the specified action, or if the action fails. * * @param actionId The id of the action to perform. * @param action The action to perform. * * @return {@code true} if the action was performed. {@code false} if it was not. */ Loading Loading @@ -1329,33 +1333,67 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub } private void updateRelevantEventsLocked(UserState userState) { int relevantEventTypes = AccessibilityCache.CACHE_CRITICAL_EVENTS_MASK; for (AccessibilityServiceConnection service : userState.mBoundServices) { relevantEventTypes |= service.mEventTypes; } relevantEventTypes |= mUiAutomationManager.getRequestedEventMaskLocked(); int finalRelevantEventTypes = relevantEventTypes; if (userState.mLastSentRelevantEventTypes != finalRelevantEventTypes) { userState.mLastSentRelevantEventTypes = finalRelevantEventTypes; mMainHandler.obtainMessage(MainHandler.MSG_SEND_RELEVANT_EVENTS_CHANGED_TO_CLIENTS, userState.mUserId, finalRelevantEventTypes); mMainHandler.post(() -> { broadcastToClients(userState, (client) -> { try { client.setRelevantEventTypes(finalRelevantEventTypes); } catch (RemoteException re) { /* ignore */ broadcastToClients(userState, ignoreRemoteException(client -> { int relevantEventTypes = computeRelevantEventTypes(userState, client); if (client.mLastSentRelevantEventTypes != relevantEventTypes) { client.mLastSentRelevantEventTypes = relevantEventTypes; client.mCallback.setRelevantEventTypes(relevantEventTypes); } }); })); }); } private int computeRelevantEventTypes(UserState userState, Client client) { int relevantEventTypes = 0; int numBoundServices = userState.mBoundServices.size(); for (int i = 0; i < numBoundServices; i++) { AccessibilityServiceConnection service = userState.mBoundServices.get(i); relevantEventTypes |= isClientInPackageWhitelist(service.getServiceInfo(), client) ? service.getRelevantEventTypes() : 0; } relevantEventTypes |= isClientInPackageWhitelist( mUiAutomationManager.getServiceInfo(), client) ? mUiAutomationManager.getRelevantEventTypes() : 0; return relevantEventTypes; } private static boolean isClientInPackageWhitelist( @Nullable AccessibilityServiceInfo serviceInfo, Client client) { if (serviceInfo == null) return false; String[] clientPackages = client.mPackageNames; boolean result = ArrayUtils.isEmpty(serviceInfo.packageNames); if (!result && clientPackages != null) { for (String packageName : clientPackages) { if (ArrayUtils.contains(serviceInfo.packageNames, packageName)) { result = true; break; } } } if (!result) { if (DEBUG) { Slog.d(LOG_TAG, "Dropping events: " + Arrays.toString(clientPackages) + " -> " + serviceInfo.getComponentName().flattenToShortString() + " due to not being in package whitelist " + Arrays.toString(serviceInfo.packageNames)); } } return result; } private void broadcastToClients( UserState userState, Consumer<IAccessibilityManagerClient> clientAction) { mGlobalClients.broadcast(clientAction); userState.mUserClients.broadcast(clientAction); UserState userState, Consumer<Client> clientAction) { mGlobalClients.broadcastForEachCookie(clientAction); userState.mUserClients.broadcastForEachCookie(clientAction); } private void unbindAllServicesLocked(UserState userState) { Loading Loading @@ -2156,6 +2194,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub * permission to write secure settings, since someone with that permission can enable * accessibility services themselves. */ @Override public void performAccessibilityShortcut() { if ((UserHandle.getAppId(Binder.getCallingUid()) != Process.SYSTEM_UID) && (mContext.checkCallingPermission(Manifest.permission.WRITE_SECURE_SETTINGS) Loading Loading @@ -2445,13 +2484,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub synchronized (mLock) { userState = getUserStateLocked(userId); } broadcastToClients(userState, (client) -> { try { client.setRelevantEventTypes(relevantEventTypes); } catch (RemoteException re) { /* ignore */ } }); broadcastToClients(userState, ignoreRemoteException( client -> client.mCallback.setRelevantEventTypes(relevantEventTypes))); } break; case MSG_SEND_ACCESSIBILITY_BUTTON_TO_INPUT_FILTER: { Loading Loading @@ -2500,30 +2534,14 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub private void sendStateToClients(int clientState, RemoteCallbackList<IAccessibilityManagerClient> clients) { clients.broadcast((client) -> { try { client.setState(clientState); } catch (RemoteException re) { /* ignore */ } }); clients.broadcast(ignoreRemoteException( client -> client.setState(clientState))); } private void notifyClientsOfServicesStateChange( RemoteCallbackList<IAccessibilityManagerClient> clients) { try { final int userClientCount = clients.beginBroadcast(); for (int i = 0; i < userClientCount; i++) { IAccessibilityManagerClient client = clients.getBroadcastItem(i); try { client.notifyServicesStateChanged(); } catch (RemoteException re) { /* ignore */ } } } finally { clients.finishBroadcast(); } clients.broadcast(ignoreRemoteException( client -> client.notifyServicesStateChanged())); } } Loading Loading @@ -3335,20 +3353,20 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub } public boolean canGetAccessibilityNodeInfoLocked( AccessibilityClientConnection service, int windowId) { AbstractAccessibilityServiceConnection service, int windowId) { return canRetrieveWindowContentLocked(service) && isRetrievalAllowingWindow(windowId); } public boolean canRetrieveWindowsLocked(AccessibilityClientConnection service) { public boolean canRetrieveWindowsLocked(AbstractAccessibilityServiceConnection service) { return canRetrieveWindowContentLocked(service) && service.mRetrieveInteractiveWindows; } public boolean canRetrieveWindowContentLocked(AccessibilityClientConnection service) { public boolean canRetrieveWindowContentLocked(AbstractAccessibilityServiceConnection service) { return (service.mAccessibilityServiceInfo.getCapabilities() & AccessibilityServiceInfo.CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT) != 0; } public boolean canControlMagnification(AccessibilityClientConnection service) { public boolean canControlMagnification(AbstractAccessibilityServiceConnection service) { return (service.mAccessibilityServiceInfo.getCapabilities() & AccessibilityServiceInfo.CAPABILITY_CAN_CONTROL_MAGNIFICATION) != 0; } Loading Loading @@ -3476,6 +3494,19 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub } } /** Represents an {@link AccessibilityManager} */ class Client { final IAccessibilityManagerClient mCallback; final String[] mPackageNames; int mLastSentRelevantEventTypes; private Client(IAccessibilityManagerClient callback, int clientUid, UserState userState) { mCallback = callback; mPackageNames = mPackageManager.getPackagesForUid(clientUid); mLastSentRelevantEventTypes = computeRelevantEventTypes(userState, this); } } public class UserState { public final int mUserId; Loading @@ -3494,8 +3525,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub public final CopyOnWriteArrayList<AccessibilityServiceConnection> mBoundServices = new CopyOnWriteArrayList<>(); public int mLastSentRelevantEventTypes = AccessibilityEvent.TYPES_ALL_MASK; public final Map<ComponentName, AccessibilityServiceConnection> mComponentNameToServiceMap = new HashMap<>(); Loading Loading
core/java/android/os/RemoteCallbackList.java +17 −0 Original line number Diff line number Diff line Loading @@ -333,6 +333,23 @@ public class RemoteCallbackList<E extends IInterface> { } } /** * Performs {@code action} for each cookie associated with a callback, calling * {@link #beginBroadcast()}/{@link #finishBroadcast()} before/after looping * * @hide */ public <C> void broadcastForEachCookie(Consumer<C> action) { int itemCount = beginBroadcast(); try { for (int i = 0; i < itemCount; i++) { action.accept((C) getBroadcastCookie(i)); } } finally { finishBroadcast(); } } /** * Returns the number of registered callbacks. Note that the number of registered * callbacks may differ from the value returned by {@link #beginBroadcast()} since Loading
core/java/com/android/internal/util/CollectionUtils.java +2 −2 Original line number Diff line number Diff line Loading @@ -290,11 +290,11 @@ public class CollectionUtils { if (cur instanceof ArraySet) { ArraySet<T> arraySet = (ArraySet<T>) cur; for (int i = 0; i < size; i++) { action.accept(arraySet.valueAt(i)); action.acceptOrThrow(arraySet.valueAt(i)); } } else { for (T t : cur) { action.accept(t); action.acceptOrThrow(t); } } } catch (Exception e) { Loading
core/java/com/android/internal/util/FunctionalUtils.java +53 −5 Original line number Diff line number Diff line Loading @@ -16,6 +16,9 @@ package com.android.internal.util; import android.os.RemoteException; import java.util.function.Consumer; import java.util.function.Supplier; /** Loading @@ -24,6 +27,21 @@ import java.util.function.Supplier; public class FunctionalUtils { private FunctionalUtils() {} /** * Converts a lambda expression that throws a checked exception(s) into a regular * {@link Consumer} by propagating any checked exceptions as {@link RuntimeException} */ public static <T> Consumer<T> uncheckExceptions(ThrowingConsumer<T> action) { return action; } /** * */ public static <T> Consumer<T> ignoreRemoteException(RemoteExceptionIgnoringConsumer<T> action) { return action; } /** * An equivalent of {@link Runnable} that allows throwing checked exceptions * Loading @@ -47,13 +65,43 @@ public class FunctionalUtils { } /** * An equivalent of {@link java.util.function.Consumer} that allows throwing checked exceptions * A {@link Consumer} that allows throwing checked exceptions from its single abstract method. * * This can be used to specify a lambda argument without forcing all the checked exceptions * to be handled within it * Can be used together with {@link #uncheckExceptions} to effectively turn a lambda expression * that throws a checked exception into a regular {@link Consumer} */ @FunctionalInterface public interface ThrowingConsumer<T> { void accept(T t) throws Exception; @SuppressWarnings("FunctionalInterfaceMethodChanged") public interface ThrowingConsumer<T> extends Consumer<T> { void acceptOrThrow(T t) throws Exception; @Override default void accept(T t) { try { acceptOrThrow(t); } catch (Exception ex) { throw new RuntimeException(ex); } } } /** * A {@link Consumer} that automatically ignores any {@link RemoteException}s. * * Used by {@link #ignoreRemoteException} */ @FunctionalInterface @SuppressWarnings("FunctionalInterfaceMethodChanged") public interface RemoteExceptionIgnoringConsumer<T> extends Consumer<T> { void acceptOrThrow(T t) throws RemoteException; @Override default void accept(T t) { try { acceptOrThrow(t); } catch (RemoteException ex) { // ignore } } } }
services/accessibility/java/com/android/server/accessibility/AccessibilityClientConnection.java→services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java +16 −5 Original line number Diff line number Diff line Loading @@ -71,7 +71,7 @@ import java.util.Set; * This class represents an accessibility client - either an AccessibilityService or a UiAutomation. * It is responsible for behavior common to both types of clients. */ abstract class AccessibilityClientConnection extends IAccessibilityServiceConnection.Stub abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServiceConnection.Stub implements ServiceConnection, IBinder.DeathRecipient, KeyEventDispatcher.KeyEventFilter, FingerprintGestureDispatcher.FingerprintGestureClient { private static final boolean DEBUG = false; Loading Loading @@ -238,7 +238,7 @@ abstract class AccessibilityClientConnection extends IAccessibilityServiceConnec int flags); } public AccessibilityClientConnection(Context context, ComponentName componentName, public AbstractAccessibilityServiceConnection(Context context, ComponentName componentName, AccessibilityServiceInfo accessibilityServiceInfo, int id, Handler mainHandler, Object lock, SecurityPolicy securityPolicy, SystemSupport systemSupport, WindowManagerInternal windowManagerInternal, Loading Loading @@ -339,6 +339,11 @@ abstract class AccessibilityClientConnection extends IAccessibilityServiceConnec } } int getRelevantEventTypes() { return (mUsesAccessibilityCache ? AccessibilityCache.CACHE_CRITICAL_EVENTS_MASK : 0) | mEventTypes; } @Override public void setServiceInfo(AccessibilityServiceInfo info) { final long identity = Binder.clearCallingIdentity(); Loading Loading @@ -954,13 +959,15 @@ abstract class AccessibilityClientConnection extends IAccessibilityServiceConnec public void notifyAccessibilityEvent(AccessibilityEvent event) { synchronized (mLock) { final int eventType = event.getEventType(); final boolean serviceWantsEvent = wantsEventLocked(event); if (!serviceWantsEvent && !mUsesAccessibilityCache && ((AccessibilityCache.CACHE_CRITICAL_EVENTS_MASK & event.getEventType()) == 0)) { final boolean requiredForCacheConsistency = mUsesAccessibilityCache && ((AccessibilityCache.CACHE_CRITICAL_EVENTS_MASK & eventType) != 0); if (!serviceWantsEvent && !requiredForCacheConsistency) { return; } final int eventType = event.getEventType(); // Make a copy since during dispatch it is possible the event to // be modified to remove its source if the receiving service does // not have permission to access the window content. Loading Loading @@ -1226,6 +1233,10 @@ abstract class AccessibilityClientConnection extends IAccessibilityServiceConnec return windowId; } public ComponentName getComponentName() { return mComponentName; } private final class InvocationHandler extends Handler { public static final int MSG_ON_GESTURE = 1; public static final int MSG_CLEAR_ACCESSIBILITY_CACHE = 2; Loading
services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java +94 −65 Original line number Diff line number Diff line Loading @@ -20,6 +20,8 @@ import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY import static android.view.accessibility.AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS; import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS; import static com.android.internal.util.FunctionalUtils.ignoreRemoteException; import android.Manifest; import android.accessibilityservice.AccessibilityService; import android.accessibilityservice.AccessibilityServiceInfo; Loading Loading @@ -84,7 +86,6 @@ import android.view.MagnificationSpec; import android.view.View; import android.view.WindowInfo; import android.view.WindowManager; import android.view.accessibility.AccessibilityCache; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityInteractionClient; import android.view.accessibility.AccessibilityManager; Loading Loading @@ -114,6 +115,7 @@ import java.io.FileDescriptor; import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; Loading @@ -131,7 +133,7 @@ import java.util.function.Consumer; * on the device. Events are dispatched to {@link AccessibilityService}s. */ public class AccessibilityManagerService extends IAccessibilityManager.Stub implements AccessibilityClientConnection.SystemSupport { implements AbstractAccessibilityServiceConnection.SystemSupport { private static final boolean DEBUG = false; Loading Loading @@ -455,7 +457,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub } @Override public long addClient(IAccessibilityManagerClient client, int userId) { public long addClient(IAccessibilityManagerClient callback, int userId) { synchronized (mLock) { // We treat calls from a profile as if made by its parent as profiles // share the accessibility state of the parent. The call below Loading @@ -467,15 +469,17 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub // the system UI or the system we add it to the global state that // is shared across users. UserState userState = getUserStateLocked(resolvedUserId); Client client = new Client(callback, Binder.getCallingUid(), userState); if (mSecurityPolicy.isCallerInteractingAcrossUsers(userId)) { mGlobalClients.register(client); mGlobalClients.register(callback, client); if (DEBUG) { Slog.i(LOG_TAG, "Added global client for pid:" + Binder.getCallingPid()); } return IntPair.of( userState.getClientState(), userState.mLastSentRelevantEventTypes); userState.getClientState(), client.mLastSentRelevantEventTypes); } else { userState.mUserClients.register(client); userState.mUserClients.register(callback, client); // If this client is not for the current user we do not // return a state since it is not for the foreground user. // We will send the state to the client on a user switch. Loading @@ -485,7 +489,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub } return IntPair.of( (resolvedUserId == mCurrentUserId) ? userState.getClientState() : 0, userState.mLastSentRelevantEventTypes); client.mLastSentRelevantEventTypes); } } } Loading Loading @@ -951,7 +955,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub * Has no effect if no item has accessibility focus, if the item with accessibility * focus does not expose the specified action, or if the action fails. * * @param actionId The id of the action to perform. * @param action The action to perform. * * @return {@code true} if the action was performed. {@code false} if it was not. */ Loading Loading @@ -1329,33 +1333,67 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub } private void updateRelevantEventsLocked(UserState userState) { int relevantEventTypes = AccessibilityCache.CACHE_CRITICAL_EVENTS_MASK; for (AccessibilityServiceConnection service : userState.mBoundServices) { relevantEventTypes |= service.mEventTypes; } relevantEventTypes |= mUiAutomationManager.getRequestedEventMaskLocked(); int finalRelevantEventTypes = relevantEventTypes; if (userState.mLastSentRelevantEventTypes != finalRelevantEventTypes) { userState.mLastSentRelevantEventTypes = finalRelevantEventTypes; mMainHandler.obtainMessage(MainHandler.MSG_SEND_RELEVANT_EVENTS_CHANGED_TO_CLIENTS, userState.mUserId, finalRelevantEventTypes); mMainHandler.post(() -> { broadcastToClients(userState, (client) -> { try { client.setRelevantEventTypes(finalRelevantEventTypes); } catch (RemoteException re) { /* ignore */ broadcastToClients(userState, ignoreRemoteException(client -> { int relevantEventTypes = computeRelevantEventTypes(userState, client); if (client.mLastSentRelevantEventTypes != relevantEventTypes) { client.mLastSentRelevantEventTypes = relevantEventTypes; client.mCallback.setRelevantEventTypes(relevantEventTypes); } }); })); }); } private int computeRelevantEventTypes(UserState userState, Client client) { int relevantEventTypes = 0; int numBoundServices = userState.mBoundServices.size(); for (int i = 0; i < numBoundServices; i++) { AccessibilityServiceConnection service = userState.mBoundServices.get(i); relevantEventTypes |= isClientInPackageWhitelist(service.getServiceInfo(), client) ? service.getRelevantEventTypes() : 0; } relevantEventTypes |= isClientInPackageWhitelist( mUiAutomationManager.getServiceInfo(), client) ? mUiAutomationManager.getRelevantEventTypes() : 0; return relevantEventTypes; } private static boolean isClientInPackageWhitelist( @Nullable AccessibilityServiceInfo serviceInfo, Client client) { if (serviceInfo == null) return false; String[] clientPackages = client.mPackageNames; boolean result = ArrayUtils.isEmpty(serviceInfo.packageNames); if (!result && clientPackages != null) { for (String packageName : clientPackages) { if (ArrayUtils.contains(serviceInfo.packageNames, packageName)) { result = true; break; } } } if (!result) { if (DEBUG) { Slog.d(LOG_TAG, "Dropping events: " + Arrays.toString(clientPackages) + " -> " + serviceInfo.getComponentName().flattenToShortString() + " due to not being in package whitelist " + Arrays.toString(serviceInfo.packageNames)); } } return result; } private void broadcastToClients( UserState userState, Consumer<IAccessibilityManagerClient> clientAction) { mGlobalClients.broadcast(clientAction); userState.mUserClients.broadcast(clientAction); UserState userState, Consumer<Client> clientAction) { mGlobalClients.broadcastForEachCookie(clientAction); userState.mUserClients.broadcastForEachCookie(clientAction); } private void unbindAllServicesLocked(UserState userState) { Loading Loading @@ -2156,6 +2194,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub * permission to write secure settings, since someone with that permission can enable * accessibility services themselves. */ @Override public void performAccessibilityShortcut() { if ((UserHandle.getAppId(Binder.getCallingUid()) != Process.SYSTEM_UID) && (mContext.checkCallingPermission(Manifest.permission.WRITE_SECURE_SETTINGS) Loading Loading @@ -2445,13 +2484,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub synchronized (mLock) { userState = getUserStateLocked(userId); } broadcastToClients(userState, (client) -> { try { client.setRelevantEventTypes(relevantEventTypes); } catch (RemoteException re) { /* ignore */ } }); broadcastToClients(userState, ignoreRemoteException( client -> client.mCallback.setRelevantEventTypes(relevantEventTypes))); } break; case MSG_SEND_ACCESSIBILITY_BUTTON_TO_INPUT_FILTER: { Loading Loading @@ -2500,30 +2534,14 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub private void sendStateToClients(int clientState, RemoteCallbackList<IAccessibilityManagerClient> clients) { clients.broadcast((client) -> { try { client.setState(clientState); } catch (RemoteException re) { /* ignore */ } }); clients.broadcast(ignoreRemoteException( client -> client.setState(clientState))); } private void notifyClientsOfServicesStateChange( RemoteCallbackList<IAccessibilityManagerClient> clients) { try { final int userClientCount = clients.beginBroadcast(); for (int i = 0; i < userClientCount; i++) { IAccessibilityManagerClient client = clients.getBroadcastItem(i); try { client.notifyServicesStateChanged(); } catch (RemoteException re) { /* ignore */ } } } finally { clients.finishBroadcast(); } clients.broadcast(ignoreRemoteException( client -> client.notifyServicesStateChanged())); } } Loading Loading @@ -3335,20 +3353,20 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub } public boolean canGetAccessibilityNodeInfoLocked( AccessibilityClientConnection service, int windowId) { AbstractAccessibilityServiceConnection service, int windowId) { return canRetrieveWindowContentLocked(service) && isRetrievalAllowingWindow(windowId); } public boolean canRetrieveWindowsLocked(AccessibilityClientConnection service) { public boolean canRetrieveWindowsLocked(AbstractAccessibilityServiceConnection service) { return canRetrieveWindowContentLocked(service) && service.mRetrieveInteractiveWindows; } public boolean canRetrieveWindowContentLocked(AccessibilityClientConnection service) { public boolean canRetrieveWindowContentLocked(AbstractAccessibilityServiceConnection service) { return (service.mAccessibilityServiceInfo.getCapabilities() & AccessibilityServiceInfo.CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT) != 0; } public boolean canControlMagnification(AccessibilityClientConnection service) { public boolean canControlMagnification(AbstractAccessibilityServiceConnection service) { return (service.mAccessibilityServiceInfo.getCapabilities() & AccessibilityServiceInfo.CAPABILITY_CAN_CONTROL_MAGNIFICATION) != 0; } Loading Loading @@ -3476,6 +3494,19 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub } } /** Represents an {@link AccessibilityManager} */ class Client { final IAccessibilityManagerClient mCallback; final String[] mPackageNames; int mLastSentRelevantEventTypes; private Client(IAccessibilityManagerClient callback, int clientUid, UserState userState) { mCallback = callback; mPackageNames = mPackageManager.getPackagesForUid(clientUid); mLastSentRelevantEventTypes = computeRelevantEventTypes(userState, this); } } public class UserState { public final int mUserId; Loading @@ -3494,8 +3525,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub public final CopyOnWriteArrayList<AccessibilityServiceConnection> mBoundServices = new CopyOnWriteArrayList<>(); public int mLastSentRelevantEventTypes = AccessibilityEvent.TYPES_ALL_MASK; public final Map<ComponentName, AccessibilityServiceConnection> mComponentNameToServiceMap = new HashMap<>(); Loading