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

Commit 2756ddb8 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Communicate relevantEvents=0 for packages excluded from whitelist"

parents aa91b0d1 4b7c919e
Loading
Loading
Loading
Loading
+17 −0
Original line number Diff line number Diff line
@@ -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
+2 −2
Original line number Diff line number Diff line
@@ -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) {
+53 −5
Original line number Diff line number Diff line
@@ -16,6 +16,9 @@

package com.android.internal.util;

import android.os.RemoteException;

import java.util.function.Consumer;
import java.util.function.Supplier;

/**
@@ -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
     *
@@ -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
            }
        }
    }
}
+16 −5
Original line number Diff line number Diff line
@@ -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;
@@ -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,
@@ -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();
@@ -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.
@@ -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;
+94 −65
Original line number Diff line number Diff line
@@ -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;
@@ -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;
@@ -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;
@@ -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;

@@ -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
@@ -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.
@@ -485,7 +489,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
                }
                return IntPair.of(
                        (resolvedUserId == mCurrentUserId) ? userState.getClientState() : 0,
                        userState.mLastSentRelevantEventTypes);
                        client.mLastSentRelevantEventTypes);
            }
        }
    }
@@ -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.
     */
@@ -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) {
@@ -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)
@@ -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: {
@@ -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()));
        }
    }

@@ -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;
        }
@@ -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;

@@ -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