diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java index 364d3c9c8e5de..d2630d531436f 100644 --- a/core/java/android/app/AppOpsManager.java +++ b/core/java/android/app/AppOpsManager.java @@ -555,9 +555,11 @@ public class AppOpsManager { public static final int OP_WRITE_MEDIA_IMAGES = 86; /** @hide Has a legacy (non-isolated) view of storage. */ public static final int OP_LEGACY_STORAGE = 87; + /** @hide Accessing accessibility features */ + public static final int OP_ACCESS_ACCESSIBILITY = 88; /** @hide */ @UnsupportedAppUsage - public static final int _NUM_OP = 88; + public static final int _NUM_OP = 89; /** Access to coarse location information. */ public static final String OPSTR_COARSE_LOCATION = "android:coarse_location"; @@ -826,6 +828,8 @@ public class AppOpsManager { public static final String OPSTR_WRITE_MEDIA_IMAGES = "android:write_media_images"; /** @hide Has a legacy (non-isolated) view of storage. */ public static final String OPSTR_LEGACY_STORAGE = "android:legacy_storage"; + /** @hide Interact with accessibility. */ + public static final String OPSTR_ACCESS_ACCESSIBILITY = "android:access_accessibility"; // Warning: If an permission is added here it also has to be added to // com.android.packageinstaller.permission.utils.EventLogger @@ -985,6 +989,7 @@ public class AppOpsManager { OP_READ_MEDIA_IMAGES, // READ_MEDIA_IMAGES OP_WRITE_MEDIA_IMAGES, // WRITE_MEDIA_IMAGES OP_LEGACY_STORAGE, // LEGACY_STORAGE + OP_ACCESS_ACCESSIBILITY, // ACCESS_ACCESSIBILITY }; /** @@ -1079,6 +1084,7 @@ public class AppOpsManager { OPSTR_READ_MEDIA_IMAGES, OPSTR_WRITE_MEDIA_IMAGES, OPSTR_LEGACY_STORAGE, + OPSTR_ACCESS_ACCESSIBILITY, }; /** @@ -1174,6 +1180,7 @@ public class AppOpsManager { "READ_MEDIA_IMAGES", "WRITE_MEDIA_IMAGES", "LEGACY_STORAGE", + "ACCESS_ACCESSIBILITY", }; /** @@ -1270,6 +1277,7 @@ public class AppOpsManager { Manifest.permission.READ_MEDIA_IMAGES, null, // no permission for OP_WRITE_MEDIA_IMAGES null, // no permission for OP_LEGACY_STORAGE + null, // no permission for OP_ACCESS_ACCESSIBILITY }; /** @@ -1366,6 +1374,7 @@ public class AppOpsManager { null, // READ_MEDIA_IMAGES null, // WRITE_MEDIA_IMAGES null, // LEGACY_STORAGE + null, // ACCESS_ACCESSIBILITY }; /** @@ -1461,6 +1470,7 @@ public class AppOpsManager { false, // READ_MEDIA_IMAGES false, // WRITE_MEDIA_IMAGES false, // LEGACY_STORAGE + false, // ACCESS_ACCESSIBILITY }; /** @@ -1555,6 +1565,7 @@ public class AppOpsManager { AppOpsManager.MODE_ALLOWED, // READ_MEDIA_IMAGES AppOpsManager.MODE_ERRORED, // WRITE_MEDIA_IMAGES AppOpsManager.MODE_DEFAULT, // LEGACY_STORAGE + AppOpsManager.MODE_ALLOWED, // ACCESS_ACCESSIBILITY }; /** @@ -1653,6 +1664,7 @@ public class AppOpsManager { false, // READ_MEDIA_IMAGES false, // WRITE_MEDIA_IMAGES false, // LEGACY_STORAGE + false, // ACCESS_ACCESSIBILITY }; /** diff --git a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java index 2c075dc809d03..f4ac130749038 100644 --- a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java +++ b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java @@ -275,6 +275,9 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ & AccessibilityServiceInfo.CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS) == 0) { return false; } + if (!mSecurityPolicy.checkAccessibilityAccess(this)) { + return false; + } try { mServiceInterface.onKeyEvent(keyEvent, sequenceNumber); } catch (RemoteException e) { @@ -388,6 +391,9 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ if (mSecurityPolicy.mWindows == null) { return null; } + if (!mSecurityPolicy.checkAccessibilityAccess(this)) { + return null; + } List windows = new ArrayList<>(); final int windowCount = mSecurityPolicy.mWindows.size(); for (int i = 0; i < windowCount; i++) { @@ -413,6 +419,9 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ if (!permissionGranted) { return null; } + if (!mSecurityPolicy.checkAccessibilityAccess(this)) { + return null; + } AccessibilityWindowInfo window = mSecurityPolicy.findA11yWindowInfoById(windowId); if (window != null) { AccessibilityWindowInfo windowClone = AccessibilityWindowInfo.obtain(window); @@ -455,6 +464,9 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ } spec = mSystemSupport.getCompatibleMagnificationSpecLocked(resolvedWindowId); } + if (!mSecurityPolicy.checkAccessibilityAccess(this)) { + return null; + } final int interrogatingPid = Binder.getCallingPid(); callback = mSystemSupport.replaceCallbackIfNeeded(callback, resolvedWindowId, interactionId, interrogatingPid, interrogatingTid); @@ -511,6 +523,9 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ } spec = mSystemSupport.getCompatibleMagnificationSpecLocked(resolvedWindowId); } + if (!mSecurityPolicy.checkAccessibilityAccess(this)) { + return null; + } final int interrogatingPid = Binder.getCallingPid(); callback = mSystemSupport.replaceCallbackIfNeeded(callback, resolvedWindowId, interactionId, interrogatingPid, interrogatingTid); @@ -567,6 +582,9 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ } spec = mSystemSupport.getCompatibleMagnificationSpecLocked(resolvedWindowId); } + if (!mSecurityPolicy.checkAccessibilityAccess(this)) { + return null; + } final int interrogatingPid = Binder.getCallingPid(); callback = mSystemSupport.replaceCallbackIfNeeded(callback, resolvedWindowId, interactionId, interrogatingPid, interrogatingTid); @@ -623,6 +641,9 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ } spec = mSystemSupport.getCompatibleMagnificationSpecLocked(resolvedWindowId); } + if (!mSecurityPolicy.checkAccessibilityAccess(this)) { + return null; + } final int interrogatingPid = Binder.getCallingPid(); callback = mSystemSupport.replaceCallbackIfNeeded(callback, resolvedWindowId, interactionId, interrogatingPid, interrogatingTid); @@ -678,6 +699,9 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ } spec = mSystemSupport.getCompatibleMagnificationSpecLocked(resolvedWindowId); } + if (!mSecurityPolicy.checkAccessibilityAccess(this)) { + return null; + } final int interrogatingPid = Binder.getCallingPid(); callback = mSystemSupport.replaceCallbackIfNeeded(callback, resolvedWindowId, interactionId, interrogatingPid, interrogatingTid); @@ -722,6 +746,9 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ return false; } } + if (!mSecurityPolicy.checkAccessibilityAccess(this)) { + return false; + } boolean returnValue = mSystemSupport.performAccessibilityAction(resolvedWindowId, accessibilityNodeId, action, arguments, interactionId, callback, mFetchFlags, interrogatingTid); @@ -974,6 +1001,9 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ return; } + if (!mSecurityPolicy.checkAccessibilityAccess(this)) { + return; + } // 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. diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java index 305c53e1e26a3..f88d5217ab2f6 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java @@ -3787,6 +3787,31 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub return findWindowIdLocked(token); } } + + public boolean checkAccessibilityAccess(AbstractAccessibilityServiceConnection service) { + final String packageName = service.getComponentName().getPackageName(); + final ResolveInfo resolveInfo = service.getServiceInfo().getResolveInfo(); + + if (resolveInfo == null) { + // For InteractionBridge and UiAutomation + return true; + } + + final int uid = resolveInfo.serviceInfo.applicationInfo.uid; + final long identityToken = Binder.clearCallingIdentity(); + try { + // For the caller is system, just block the data to a11y services. + if (OWN_PROCESS_ID == Binder.getCallingPid()) { + return mAppOpsManager.noteOpNoThrow(AppOpsManager.OPSTR_ACCESS_ACCESSIBILITY, + uid, packageName) == AppOpsManager.MODE_ALLOWED; + } + + return mAppOpsManager.noteOp(AppOpsManager.OPSTR_ACCESS_ACCESSIBILITY, + uid, packageName) == AppOpsManager.MODE_ALLOWED; + } finally { + Binder.restoreCallingIdentity(identityToken); + } + } } /**