Avoid A11y features blocked by IT admin can be allowed to bind at the system level

Root cause: Address A11y features blocked by IT admin by adjusting the UI, which seems like a good idea but might not cover all cases
Solution: Avoid A11y features blocked by IT admin can be allowed to bind at the system level

Bug: 254223085
Test: atest CtsAccessibilityServiceTestCases
Test: `adb shell settings put secure enabled_accessibility_service` disallowed service & verify the service would not be bound by `adb shell dumpsys accessibility`
Change-Id: I6ce326c82d063923d8737d637aa5f7f570cfc950
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index d422f9a..0edb8f2 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -2263,6 +2263,15 @@
             }
             if (userState.mEnabledServices.contains(componentName)
                     && !mUiAutomationManager.suppressingAccessibilityServicesLocked()) {
+                // Skip the enabling service disallowed by device admin policy.
+                if (!isAccessibilityTargetAllowed(componentName.getPackageName(),
+                        installedService.getResolveInfo().serviceInfo.applicationInfo.uid,
+                        userState.mUserId)) {
+                    Slog.d(LOG_TAG, "Skipping enabling service disallowed by device admin policy: "
+                            + componentName);
+                    disableAccessibilityServiceLocked(componentName, userState.mUserId);
+                    continue;
+                }
                 if (service == null) {
                     service = new AccessibilityServiceConnection(userState, mContext, componentName,
                             installedService, sIdCounter++, mMainHandler, mLock, mSecurityPolicy,
@@ -3875,32 +3884,29 @@
         }
     }
 
-    @Override
-    @RequiresPermission(anyOf = {
-            android.Manifest.permission.MANAGE_USERS,
-            android.Manifest.permission.QUERY_ADMIN_POLICY})
     public boolean isAccessibilityTargetAllowed(String packageName, int uid, int userId) {
-        final DevicePolicyManager dpm = mContext.getSystemService(DevicePolicyManager.class);
-        final List<String> permittedServices = dpm.getPermittedAccessibilityServices(userId);
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            final DevicePolicyManager dpm = mContext.getSystemService(DevicePolicyManager.class);
+            final List<String> permittedServices = dpm.getPermittedAccessibilityServices(userId);
 
-        // permittedServices null means all accessibility services are allowed.
-        boolean allowed = permittedServices == null || permittedServices.contains(packageName);
-        if (allowed) {
-            final AppOpsManager appOps = mContext.getSystemService(AppOpsManager.class);
-            final int mode = appOps.noteOpNoThrow(
-                    AppOpsManager.OP_ACCESS_RESTRICTED_SETTINGS,
-                    uid, packageName, /* attributionTag= */ null, /* message= */ null);
-            final boolean ecmEnabled = mContext.getResources().getBoolean(
-                    R.bool.config_enhancedConfirmationModeEnabled);
-            return !ecmEnabled || mode == AppOpsManager.MODE_ALLOWED;
+            // permittedServices null means all accessibility services are allowed.
+            boolean allowed = permittedServices == null || permittedServices.contains(packageName);
+            if (allowed) {
+                final AppOpsManager appOps = mContext.getSystemService(AppOpsManager.class);
+                final int mode = appOps.noteOpNoThrow(
+                        AppOpsManager.OP_ACCESS_RESTRICTED_SETTINGS,
+                        uid, packageName, /* attributionTag= */ null, /* message= */ null);
+                final boolean ecmEnabled = mContext.getResources().getBoolean(
+                        R.bool.config_enhancedConfirmationModeEnabled);
+                return !ecmEnabled || mode == AppOpsManager.MODE_ALLOWED;
+            }
+            return false;
+        } finally {
+            Binder.restoreCallingIdentity(identity);
         }
-        return false;
     }
 
-    @Override
-    @RequiresPermission(anyOf = {
-            android.Manifest.permission.MANAGE_USERS,
-            android.Manifest.permission.QUERY_ADMIN_POLICY})
     public boolean sendRestrictedDialogIntent(String packageName, int uid, int userId) {
         // The accessibility service is allowed. Don't show the restricted dialog.
         if (isAccessibilityTargetAllowed(packageName, uid, userId)) {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 6cd9f1c..664e6b6 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -11776,6 +11776,20 @@
         final CallerIdentity caller = getCallerIdentity();
         Preconditions.checkCallAuthorization(canManageUsers(caller) || canQueryAdminPolicy(caller));
 
+        // Move AccessibilityManager out of lock to prevent potential deadlock
+        final List<AccessibilityServiceInfo> installedServices;
+        long id = mInjector.binderClearCallingIdentity();
+        try {
+            UserInfo user = getUserInfo(userId);
+            if (user.isManagedProfile()) {
+                userId = user.profileGroupId;
+            }
+            installedServices = withAccessibilityManager(userId,
+                    AccessibilityManager::getInstalledAccessibilityServiceList);
+        } finally {
+            mInjector.binderRestoreCallingIdentity(id);
+        }
+
         synchronized (getLockObject()) {
             List<String> result = null;
             // If we have multiple profiles we return the intersection of the
@@ -11802,27 +11816,14 @@
 
             // If we have a permitted list add all system accessibility services.
             if (result != null) {
-                long id = mInjector.binderClearCallingIdentity();
-                try {
-                    UserInfo user = getUserInfo(userId);
-                    if (user.isManagedProfile()) {
-                        userId = user.profileGroupId;
-                    }
-                    final List<AccessibilityServiceInfo> installedServices =
-                            withAccessibilityManager(userId,
-                                    AccessibilityManager::getInstalledAccessibilityServiceList);
-
-                    if (installedServices != null) {
-                        for (AccessibilityServiceInfo service : installedServices) {
-                            ServiceInfo serviceInfo = service.getResolveInfo().serviceInfo;
-                            ApplicationInfo applicationInfo = serviceInfo.applicationInfo;
-                            if ((applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
-                                result.add(serviceInfo.packageName);
-                            }
+                if (installedServices != null) {
+                    for (AccessibilityServiceInfo service : installedServices) {
+                        ServiceInfo serviceInfo = service.getResolveInfo().serviceInfo;
+                        ApplicationInfo applicationInfo = serviceInfo.applicationInfo;
+                        if ((applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
+                            result.add(serviceInfo.packageName);
                         }
                     }
-                } finally {
-                    mInjector.binderRestoreCallingIdentity(id);
                 }
             }