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

Commit 7628589c authored by Riley Jones's avatar Riley Jones
Browse files

Fix for a11yManager package force stop

Change updates logic to only remove shortcut targets
corresponding to continuous pacakges that've been force stopped,
rather than all continuous packages

Bug: 350768888
Flag: EXEMPT small internal bugfix
Test: atest AccessibilityManagerServiceTest
Change-Id: I2995f5e8eb03925efc9f72b2f3de37e40cc10a82
parent ea96f6ba
Loading
Loading
Loading
Loading
+17 −14
Original line number Original line Diff line number Diff line
@@ -41,6 +41,7 @@ import static android.content.Context.DEVICE_ID_DEFAULT;
import static android.provider.Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED;
import static android.provider.Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED;
import static android.view.accessibility.AccessibilityManager.FlashNotificationReason;
import static android.view.accessibility.AccessibilityManager.FlashNotificationReason;


import static com.android.hardware.input.Flags.keyboardA11yMouseKeys;
import static com.android.internal.accessibility.AccessibilityShortcutController.ACCESSIBILITY_HEARING_AIDS_COMPONENT_NAME;
import static com.android.internal.accessibility.AccessibilityShortcutController.ACCESSIBILITY_HEARING_AIDS_COMPONENT_NAME;
import static com.android.internal.accessibility.AccessibilityShortcutController.MAGNIFICATION_COMPONENT_NAME;
import static com.android.internal.accessibility.AccessibilityShortcutController.MAGNIFICATION_COMPONENT_NAME;
import static com.android.internal.accessibility.AccessibilityShortcutController.MAGNIFICATION_CONTROLLER_NAME;
import static com.android.internal.accessibility.AccessibilityShortcutController.MAGNIFICATION_CONTROLLER_NAME;
@@ -57,7 +58,6 @@ import static com.android.internal.accessibility.util.AccessibilityStatsLogUtils
import static com.android.internal.util.FunctionalUtils.ignoreRemoteException;
import static com.android.internal.util.FunctionalUtils.ignoreRemoteException;
import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
import static com.android.server.accessibility.AccessibilityUserState.doesShortcutTargetsStringContain;
import static com.android.server.accessibility.AccessibilityUserState.doesShortcutTargetsStringContain;
import static com.android.hardware.input.Flags.keyboardA11yMouseKeys;
import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;


import android.accessibilityservice.AccessibilityGestureEvent;
import android.accessibilityservice.AccessibilityGestureEvent;
@@ -825,25 +825,27 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
    @VisibleForTesting
    @VisibleForTesting
    boolean onPackagesForceStoppedLocked(
    boolean onPackagesForceStoppedLocked(
            String[] packages, AccessibilityUserState userState) {
            String[] packages, AccessibilityUserState userState) {
        final List<String> continuousServicePackages =
        final Set<String> packageSet = new HashSet<>(List.of(packages));
        final ArrayList<ComponentName> continuousServices = new ArrayList<>(
                userState.mInstalledServices.stream().filter(service ->
                userState.mInstalledServices.stream().filter(service ->
                        (service.flags & FLAG_REQUEST_ACCESSIBILITY_BUTTON)
                        (service.flags & FLAG_REQUEST_ACCESSIBILITY_BUTTON)
                                == FLAG_REQUEST_ACCESSIBILITY_BUTTON
                                == FLAG_REQUEST_ACCESSIBILITY_BUTTON
                ).map(service -> service.getComponentName().flattenToString()).toList();
                ).map(AccessibilityServiceInfo::getComponentName).toList());

        // Filter out continuous packages that are not from the array of stopped packages.
        continuousServices.removeIf(
                continuousName -> !packageSet.contains(continuousName.getPackageName()));


        boolean enabledServicesChanged = false;
        boolean enabledServicesChanged = false;
        final Iterator<ComponentName> it = userState.mEnabledServices.iterator();
        final Iterator<ComponentName> it = userState.mEnabledServices.iterator();
        while (it.hasNext()) {
        while (it.hasNext()) {
            final ComponentName comp = it.next();
            final ComponentName comp = it.next();
            final String compPkg = comp.getPackageName();
            final String compPkg = comp.getPackageName();
            for (String pkg : packages) {
            if (packageSet.contains(compPkg)) {
                if (compPkg.equals(pkg)) {
                it.remove();
                it.remove();
                userState.getBindingServicesLocked().remove(comp);
                userState.getBindingServicesLocked().remove(comp);
                userState.getCrashedServicesLocked().remove(comp);
                userState.getCrashedServicesLocked().remove(comp);
                enabledServicesChanged = true;
                enabledServicesChanged = true;
                    break;
                }
            }
            }
        }
        }
        if (enabledServicesChanged) {
        if (enabledServicesChanged) {
@@ -855,8 +857,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
        // Remove any button targets that match any stopped continuous services
        // Remove any button targets that match any stopped continuous services
        Set<String> buttonTargets = userState.getShortcutTargetsLocked(SOFTWARE);
        Set<String> buttonTargets = userState.getShortcutTargetsLocked(SOFTWARE);
        boolean buttonTargetsChanged = buttonTargets.removeIf(
        boolean buttonTargetsChanged = buttonTargets.removeIf(
                target -> continuousServicePackages.stream().anyMatch(
                target -> continuousServices.stream().anyMatch(
                        pkg -> Objects.equals(target, pkg)));
                        continuousName -> continuousName.flattenToString().equals(target)));
        if (buttonTargetsChanged) {
        if (buttonTargetsChanged) {
            userState.updateShortcutTargetsLocked(buttonTargets, SOFTWARE);
            userState.updateShortcutTargetsLocked(buttonTargets, SOFTWARE);
            persistColonDelimitedSetToSettingLocked(
            persistColonDelimitedSetToSettingLocked(
@@ -2641,7 +2643,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
        }
        }
    }
    }


    private <T> void persistColonDelimitedSetToSettingLocked(String settingName, int userId,
    @VisibleForTesting
    <T> void persistColonDelimitedSetToSettingLocked(String settingName, int userId,
            Set<T> set, Function<T, String> toString) {
            Set<T> set, Function<T, String> toString) {
        persistColonDelimitedSetToSettingLocked(settingName, userId, set,
        persistColonDelimitedSetToSettingLocked(settingName, userId, set,
                toString, /* defaultEmptyString= */ null);
                toString, /* defaultEmptyString= */ null);
+59 −7
Original line number Original line Diff line number Diff line
@@ -840,6 +840,10 @@ public class AccessibilityManagerServiceTest {
        info_a.setComponentName(COMPONENT_NAME);
        info_a.setComponentName(COMPONENT_NAME);
        final AccessibilityServiceInfo info_b = new AccessibilityServiceInfo();
        final AccessibilityServiceInfo info_b = new AccessibilityServiceInfo();
        info_b.setComponentName(new ComponentName("package", "class"));
        info_b.setComponentName(new ComponentName("package", "class"));
        writeStringsToSetting(Set.of(
                info_a.getComponentName().flattenToString(),
                info_b.getComponentName().flattenToString()),
                Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);


        AccessibilityUserState userState = mA11yms.getCurrentUserState();
        AccessibilityUserState userState = mA11yms.getCurrentUserState();
        userState.mInstalledServices.clear();
        userState.mInstalledServices.clear();
@@ -858,10 +862,9 @@ public class AccessibilityManagerServiceTest {
        userState = mA11yms.getCurrentUserState();
        userState = mA11yms.getCurrentUserState();
        assertThat(userState.mEnabledServices).containsExactly(info_b.getComponentName());
        assertThat(userState.mEnabledServices).containsExactly(info_b.getComponentName());
        //Assert setting change
        //Assert setting change
        final Set<ComponentName> componentsFromSetting = new ArraySet<>();
        final Set<String> enabledServices =
        mA11yms.readComponentNamesFromSettingLocked(Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
                readStringsFromSetting(Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);
                userState.mUserId, componentsFromSetting);
        assertThat(enabledServices).containsExactly(info_b.getComponentName().flattenToString());
        assertThat(componentsFromSetting).containsExactly(info_b.getComponentName());
    }
    }


    @Test
    @Test
@@ -880,6 +883,10 @@ public class AccessibilityManagerServiceTest {
                        info_a.getComponentName().flattenToString(),
                        info_a.getComponentName().flattenToString(),
                        info_b.getComponentName().flattenToString()),
                        info_b.getComponentName().flattenToString()),
                SOFTWARE);
                SOFTWARE);
        writeStringsToSetting(Set.of(
                        info_a.getComponentName().flattenToString(),
                        info_b.getComponentName().flattenToString()),
                ShortcutUtils.convertToKey(SOFTWARE));


        // despite force stopping both packages, only the first service has the relevant flag,
        // despite force stopping both packages, only the first service has the relevant flag,
        // so only the first should be removed.
        // so only the first should be removed.
@@ -896,12 +903,52 @@ public class AccessibilityManagerServiceTest {
        assertThat(userState.getShortcutTargetsLocked(SOFTWARE)).containsExactly(
        assertThat(userState.getShortcutTargetsLocked(SOFTWARE)).containsExactly(
                info_b.getComponentName().flattenToString());
                info_b.getComponentName().flattenToString());
        //Assert setting change
        //Assert setting change
        final Set<String> targetsFromSetting = new ArraySet<>();
        final Set<String> targetsFromSetting = readStringsFromSetting(
        mA11yms.readColonDelimitedSettingToSet(ShortcutUtils.convertToKey(SOFTWARE),
                ShortcutUtils.convertToKey(SOFTWARE));
                userState.mUserId, str -> str, targetsFromSetting);
        assertThat(targetsFromSetting).containsExactly(info_b.getComponentName().flattenToString());
        assertThat(targetsFromSetting).containsExactly(info_b.getComponentName().flattenToString());
    }
    }


    @Test
    public void testPackagesForceStopped_otherServiceStopped_doesNotRemoveContinuousTarget() {
        final AccessibilityServiceInfo info_a = new AccessibilityServiceInfo();
        info_a.setComponentName(COMPONENT_NAME);
        info_a.flags = FLAG_REQUEST_ACCESSIBILITY_BUTTON;
        final AccessibilityServiceInfo info_b = new AccessibilityServiceInfo();
        info_b.setComponentName(new ComponentName("package", "class"));
        writeStringsToSetting(Set.of(
                        info_a.getComponentName().flattenToString(),
                        info_b.getComponentName().flattenToString()),
                ShortcutUtils.convertToKey(SOFTWARE));

        AccessibilityUserState userState = mA11yms.getCurrentUserState();
        userState.mInstalledServices.clear();
        userState.mInstalledServices.add(info_a);
        userState.mInstalledServices.add(info_b);
        userState.updateShortcutTargetsLocked(Set.of(
                        info_a.getComponentName().flattenToString(),
                        info_b.getComponentName().flattenToString()),
                SOFTWARE);

        // Force stopping a service should not disable unrelated continuous services.
        synchronized (mA11yms.getLock()) {
            mA11yms.onPackagesForceStoppedLocked(
                    new String[]{info_b.getComponentName().getPackageName()},
                    userState);
        }

        //Assert user state change
        userState = mA11yms.getCurrentUserState();
        assertThat(userState.getShortcutTargetsLocked(SOFTWARE)).containsExactly(
                info_a.getComponentName().flattenToString(),
                info_b.getComponentName().flattenToString());
        //Assert setting unchanged
        final Set<String> targetsFromSetting = readStringsFromSetting(
                ShortcutUtils.convertToKey(SOFTWARE));
        assertThat(targetsFromSetting).containsExactly(
                info_a.getComponentName().flattenToString(),
                info_b.getComponentName().flattenToString());
    }

    @Test
    @Test
    public void testPackageMonitorScanPackages_scansWithoutHoldingLock() {
    public void testPackageMonitorScanPackages_scansWithoutHoldingLock() {
        setupAccessibilityServiceConnection(0);
        setupAccessibilityServiceConnection(0);
@@ -1844,6 +1891,11 @@ public class AccessibilityManagerServiceTest {
        return result;
        return result;
    }
    }


    private void writeStringsToSetting(Set<String> strings, String setting) {
        mA11yms.persistColonDelimitedSetToSettingLocked(
                setting, UserHandle.USER_SYSTEM, strings, str -> str);
    }

    private void broadcastSettingRestored(String setting, String newValue) {
    private void broadcastSettingRestored(String setting, String newValue) {
        Intent intent = new Intent(Intent.ACTION_SETTING_RESTORED)
        Intent intent = new Intent(Intent.ACTION_SETTING_RESTORED)
                .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY)
                .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY)