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

Commit fbac8382 authored by Jackal Guo's avatar Jackal Guo
Browse files

Allow restarting of crashed a11y services

After an accessibility service crashes a few times in a short period
of time, framework would add it into a “blacklist”. User wouldn’t be
able to use (re-enable) it. If users express an intent in them working
again, we remove the crashed accessibility service from the blacklist.

Bug: 129689483
Test: a11y CTS & unit tests
Test: manual
      1. Install and enable an intentional crashed a11y service.
      2. After it's crashed and malfunctioning, re-enable it.
      3. Check if it's bound again.

Change-Id: Ia89121f11bc5e05fc829e0e3ecb266150409678b
parent 198f9bdb
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -428,7 +428,7 @@ public class AccessibilityServiceInfo implements Parcelable {

    /**
     * Whether or not the service has crashed and is awaiting restart. Only valid from {@link
     * android.view.accessibility.AccessibilityManager#getEnabledAccessibilityServiceList(int)},
     * android.view.accessibility.AccessibilityManager#getInstalledAccessibilityServiceList()},
     * because that is populated from the internal list of running services.
     *
     * @hide
+2 −2
Original line number Diff line number Diff line
@@ -707,10 +707,10 @@ public final class AccessibilityManager {
        try {
            services = service.getEnabledAccessibilityServiceList(feedbackTypeFlags, userId);
            if (DEBUG) {
                Log.i(LOG_TAG, "Installed AccessibilityServices " + services);
                Log.i(LOG_TAG, "Enabled AccessibilityServices " + services);
            }
        } catch (RemoteException re) {
            Log.e(LOG_TAG, "Error while obtaining the installed AccessibilityServices. ", re);
            Log.e(LOG_TAG, "Error while obtaining the enabled AccessibilityServices. ", re);
        }
        if (mAccessibilityPolicy != null) {
            services = mAccessibilityPolicy.getEnabledAccessibilityServiceList(
+14 −4
Original line number Diff line number Diff line
@@ -48,11 +48,21 @@ public class AccessibilityUtils {
        return getEnabledServicesFromSettings(context, UserHandle.myUserId());
    }

    /**
     * Check if the accessibility service is crashed
     *
     * @param packageName The package name to check
     * @param serviceName The service name to check
     * @param installedServiceInfos The list of installed accessibility service
     * @return {@code true} if the accessibility service is crashed for the user.
     * {@code false} otherwise.
     */
    public static boolean hasServiceCrashed(String packageName, String serviceName,
            List<AccessibilityServiceInfo> enabledServiceInfos) {
        for (int i = 0; i < enabledServiceInfos.size(); i++) {
            AccessibilityServiceInfo accessibilityServiceInfo = enabledServiceInfos.get(i);
            final ServiceInfo serviceInfo = enabledServiceInfos.get(i).getResolveInfo().serviceInfo;
            List<AccessibilityServiceInfo> installedServiceInfos) {
        for (int i = 0; i < installedServiceInfos.size(); i++) {
            final AccessibilityServiceInfo accessibilityServiceInfo = installedServiceInfos.get(i);
            final ServiceInfo serviceInfo =
                    installedServiceInfos.get(i).getResolveInfo().serviceInfo;
            if (TextUtils.equals(serviceInfo.packageName, packageName)
                    && TextUtils.equals(serviceInfo.name, serviceName)) {
                return accessibilityServiceInfo.crashed;
+14 −4
Original line number Diff line number Diff line
@@ -366,9 +366,11 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
                    if (userId != mCurrentUserId) {
                        return;
                    }
                    AccessibilityUserState userState = getUserStateLocked(userId);
                    boolean reboundAService = userState.getBindingServicesLocked().removeIf(
                    final AccessibilityUserState userState = getUserStateLocked(userId);
                    final boolean reboundAService = userState.getBindingServicesLocked().removeIf(
                            component -> component != null
                                    && component.getPackageName().equals(packageName))
                            || userState.mCrashedServices.removeIf(component -> component != null
                                    && component.getPackageName().equals(packageName));
                    if (reboundAService) {
                        onUserStateChangedLocked(userState);
@@ -393,6 +395,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
                        if (compPkg.equals(packageName)) {
                            it.remove();
                            userState.getBindingServicesLocked().remove(comp);
                            userState.getCrashedServicesLocked().remove(comp);
                            // Update the enabled services setting.
                            persistComponentNamesToSettingLocked(
                                    Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
@@ -753,6 +756,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
            userState.mEnabledServices.clear();
            userState.mEnabledServices.add(service);
            userState.getBindingServicesLocked().clear();
            userState.getCrashedServicesLocked().clear();
            userState.mTouchExplorationGrantedServices.clear();
            userState.mTouchExplorationGrantedServices.add(service);

@@ -1178,6 +1182,10 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
            AccessibilityServiceInfo accessibilityServiceInfo;
            try {
                accessibilityServiceInfo = new AccessibilityServiceInfo(resolveInfo, mContext);
                if (userState.mCrashedServices.contains(serviceInfo.getComponentName())) {
                    // Restore the crashed attribute.
                    accessibilityServiceInfo.crashed = true;
                }
                mTempAccessibilityServiceInfoList.add(accessibilityServiceInfo);
            } catch (XmlPullParserException | IOException xppe) {
                Slog.e(LOG_TAG, "Error while initializing AccessibilityServiceInfo", xppe);
@@ -1418,8 +1426,9 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
                continue;
            }

            // Wait for the binding if it is in process.
            if (userState.getBindingServicesLocked().contains(componentName)) {
            // Skip the component since it may be in process or crashed.
            if (userState.getBindingServicesLocked().contains(componentName)
                    || userState.getCrashedServicesLocked().contains(componentName)) {
                continue;
            }
            if (userState.mEnabledServices.contains(componentName)
@@ -2687,6 +2696,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
                    }
                } else if (mEnabledAccessibilityServicesUri.equals(uri)) {
                    if (readEnabledAccessibilityServicesLocked(userState)) {
                        userState.updateCrashedServicesIfNeededLocked();
                        onUserStateChangedLocked(userState);
                    }
                } else if (mTouchExplorationGrantedAccessibilityServicesUri.equals(uri)) {
+7 −9
Original line number Diff line number Diff line
@@ -62,9 +62,6 @@ class AccessibilityServiceConnection extends AbstractAccessibilityServiceConnect

    private final Handler mMainHandler;

    private boolean mWasConnectedAndDied;


    AccessibilityServiceConnection(AccessibilityUserState userState, Context context,
            ComponentName componentName,
            AccessibilityServiceInfo accessibilityServiceInfo, int id, Handler mainHandler,
@@ -168,8 +165,6 @@ class AccessibilityServiceConnection extends AbstractAccessibilityServiceConnect

    @Override
    public AccessibilityServiceInfo getServiceInfo() {
        // Update crashed data
        mAccessibilityServiceInfo.crashed = mWasConnectedAndDied;
        return mAccessibilityServiceInfo;
    }

@@ -178,10 +173,13 @@ class AccessibilityServiceConnection extends AbstractAccessibilityServiceConnect
        synchronized (mLock) {
            AccessibilityUserState userState = mUserStateWeakReference.get();
            if (userState == null) return;
            Set<ComponentName> bindingServices = userState.getBindingServicesLocked();
            if (bindingServices.contains(mComponentName) || mWasConnectedAndDied) {
            final Set<ComponentName> bindingServices = userState.getBindingServicesLocked();
            final Set<ComponentName> crashedServices = userState.getCrashedServicesLocked();
            if (bindingServices.contains(mComponentName)
                    || crashedServices.contains(mComponentName)) {
                bindingServices.remove(mComponentName);
                mWasConnectedAndDied = false;
                crashedServices.remove(mComponentName);
                mAccessibilityServiceInfo.crashed = false;
                serviceInterface = mServiceInterface;
            }
            // There's a chance that service is removed from enabled_accessibility_services setting
@@ -271,7 +269,7 @@ class AccessibilityServiceConnection extends AbstractAccessibilityServiceConnect
            if (!isConnectedLocked()) {
                return;
            }
            mWasConnectedAndDied = true;
            mAccessibilityServiceInfo.crashed = true;
            AccessibilityUserState userState = mUserStateWeakReference.get();
            if (userState != null) {
                userState.serviceDisconnectedLocked(this);
Loading