1 /* 2 * Copyright (C) 2019 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.accessibility; 18 19 import static android.accessibilityservice.AccessibilityService.SoftKeyboardController.ENABLE_IME_FAIL_BY_ADMIN; 20 import static android.accessibilityservice.AccessibilityService.SoftKeyboardController.ENABLE_IME_SUCCESS; 21 import static android.companion.AssociationRequest.DEVICE_PROFILE_APP_STREAMING; 22 23 import android.Manifest; 24 import android.accessibilityservice.AccessibilityService; 25 import android.accessibilityservice.AccessibilityServiceInfo; 26 import android.annotation.NonNull; 27 import android.annotation.Nullable; 28 import android.app.AppOpsManager; 29 import android.app.role.RoleManager; 30 import android.appwidget.AppWidgetManagerInternal; 31 import android.content.ComponentName; 32 import android.content.Context; 33 import android.content.pm.PackageManager; 34 import android.content.pm.PackageManagerInternal; 35 import android.content.pm.ResolveInfo; 36 import android.content.pm.ServiceInfo; 37 import android.content.pm.UserInfo; 38 import android.os.Binder; 39 import android.os.IBinder; 40 import android.os.Process; 41 import android.os.UserHandle; 42 import android.os.UserManager; 43 import android.util.ArraySet; 44 import android.util.Slog; 45 import android.util.SparseBooleanArray; 46 import android.view.accessibility.AccessibilityEvent; 47 import android.view.inputmethod.InputMethodInfo; 48 49 import com.android.internal.util.ArrayUtils; 50 import com.android.server.inputmethod.InputMethodManagerInternal; 51 52 import libcore.util.EmptyArray; 53 54 import java.util.ArrayList; 55 import java.util.List; 56 import java.util.Set; 57 58 /** 59 * This class provides APIs of accessibility security policies for accessibility manager 60 * to grant accessibility capabilities or events access right to accessibility services. And also 61 * monitors the current bound accessibility services to prompt permission warnings for 62 * not accessibility-categorized ones. 63 */ 64 public class AccessibilitySecurityPolicy { 65 private static final int OWN_PROCESS_ID = android.os.Process.myPid(); 66 private static final String LOG_TAG = "AccessibilitySecurityPolicy"; 67 68 private static final int KEEP_SOURCE_EVENT_TYPES = AccessibilityEvent.TYPE_VIEW_CLICKED 69 | AccessibilityEvent.TYPE_VIEW_FOCUSED 70 | AccessibilityEvent.TYPE_VIEW_HOVER_ENTER 71 | AccessibilityEvent.TYPE_VIEW_HOVER_EXIT 72 | AccessibilityEvent.TYPE_VIEW_LONG_CLICKED 73 | AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED 74 | AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED 75 | AccessibilityEvent.TYPE_WINDOWS_CHANGED 76 | AccessibilityEvent.TYPE_VIEW_SELECTED 77 | AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED 78 | AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED 79 | AccessibilityEvent.TYPE_VIEW_SCROLLED 80 | AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED 81 | AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED 82 | AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY 83 | AccessibilityEvent.TYPE_VIEW_TARGETED_BY_SCROLL; 84 85 /** 86 * Methods that should find their way into separate modules, but are still in AMS 87 * TODO (b/111889696): Refactoring UserState to AccessibilityUserManager. 88 */ 89 public interface AccessibilityUserManager { 90 /** 91 * Returns current userId maintained in accessibility manager service 92 */ getCurrentUserIdLocked()93 int getCurrentUserIdLocked(); 94 // TODO: Should include resolveProfileParentLocked, but that was already in SecurityPolicy 95 96 // TODO(b/255426725): temporary hack; see comment on A11YMS.mVisibleBgUserIds 97 /** 98 * Returns the {@link android.os.UserManager#getVisibleUsers() visible users}. 99 */ getVisibleUserIdsLocked()100 @Nullable SparseBooleanArray getVisibleUserIdsLocked(); 101 } 102 103 private final Context mContext; 104 private final PackageManager mPackageManager; 105 private final PackageManagerInternal mPackageManagerInternal; 106 private final UserManager mUserManager; 107 private final AppOpsManager mAppOpsManager; 108 private final AccessibilityUserManager mAccessibilityUserManager; 109 private final PolicyWarningUIController mPolicyWarningUIController; 110 /** All bound accessibility services which don't belong to accessibility category. */ 111 private final ArraySet<ComponentName> mNonA11yCategoryServices = new ArraySet<>(); 112 113 private AppWidgetManagerInternal mAppWidgetService; 114 private AccessibilityWindowManager mAccessibilityWindowManager; 115 private int mCurrentUserId = UserHandle.USER_NULL; 116 private boolean mSendNonA11yToolNotificationEnabled = false; 117 118 /** 119 * Constructor for AccessibilityManagerService. 120 */ AccessibilitySecurityPolicy(PolicyWarningUIController policyWarningUIController, @NonNull Context context, @NonNull AccessibilityUserManager a11yUserManager, @NonNull PackageManagerInternal packageManagerInternal)121 public AccessibilitySecurityPolicy(PolicyWarningUIController policyWarningUIController, 122 @NonNull Context context, 123 @NonNull AccessibilityUserManager a11yUserManager, 124 @NonNull PackageManagerInternal packageManagerInternal) { 125 mContext = context; 126 mAccessibilityUserManager = a11yUserManager; 127 mPackageManager = mContext.getPackageManager(); 128 mPackageManagerInternal = packageManagerInternal; 129 mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE); 130 mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE); 131 mPolicyWarningUIController = policyWarningUIController; 132 } 133 134 /** 135 * Enables sending the notification for non-AccessibilityTool services with the given state. 136 * 137 */ setSendingNonA11yToolNotificationLocked(boolean enable)138 public void setSendingNonA11yToolNotificationLocked(boolean enable) { 139 if (enable == mSendNonA11yToolNotificationEnabled) { 140 return; 141 } 142 143 mSendNonA11yToolNotificationEnabled = enable; 144 mPolicyWarningUIController.enableSendingNonA11yToolNotification(enable); 145 if (enable) { 146 for (int i = 0; i < mNonA11yCategoryServices.size(); i++) { 147 final ComponentName service = mNonA11yCategoryServices.valueAt(i); 148 mPolicyWarningUIController.onNonA11yCategoryServiceBound(mCurrentUserId, service); 149 } 150 } 151 } 152 153 /** 154 * Setup AccessibilityWindowManager. This isn't part of the constructor because the 155 * window manager and security policy both call each other. 156 */ setAccessibilityWindowManager(@onNull AccessibilityWindowManager awm)157 public void setAccessibilityWindowManager(@NonNull AccessibilityWindowManager awm) { 158 mAccessibilityWindowManager = awm; 159 } 160 161 /** 162 * Setup AppWidgetManger during boot phase. 163 */ setAppWidgetManager(@onNull AppWidgetManagerInternal appWidgetManager)164 public void setAppWidgetManager(@NonNull AppWidgetManagerInternal appWidgetManager) { 165 mAppWidgetService = appWidgetManager; 166 } 167 168 /** 169 * Check if an accessibility event can be dispatched. Events should be dispatched only if they 170 * are dispatched from items that services can see. 171 * 172 * @param userId The userId to check 173 * @param event The event to check 174 * @return {@code true} if the event can be dispatched 175 */ canDispatchAccessibilityEventLocked(int userId, @NonNull AccessibilityEvent event)176 public boolean canDispatchAccessibilityEventLocked(int userId, 177 @NonNull AccessibilityEvent event) { 178 final int eventType = event.getEventType(); 179 switch (eventType) { 180 // All events that are for changes in a global window 181 // state should *always* be dispatched. 182 case AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED: 183 case AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED: 184 case AccessibilityEvent.TYPE_ANNOUNCEMENT: 185 // All events generated by the user touching the 186 // screen should *always* be dispatched. 187 case AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_START: 188 case AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_END: 189 case AccessibilityEvent.TYPE_GESTURE_DETECTION_START: 190 case AccessibilityEvent.TYPE_GESTURE_DETECTION_END: 191 case AccessibilityEvent.TYPE_TOUCH_INTERACTION_START: 192 case AccessibilityEvent.TYPE_TOUCH_INTERACTION_END: 193 case AccessibilityEvent.TYPE_VIEW_HOVER_ENTER: 194 case AccessibilityEvent.TYPE_VIEW_HOVER_EXIT: 195 // Also always dispatch the event that assist is reading context. 196 case AccessibilityEvent.TYPE_ASSIST_READING_CONTEXT: 197 // Also windows changing should always be dispatched. 198 case AccessibilityEvent.TYPE_WINDOWS_CHANGED: { 199 return true; 200 } 201 // All events for changes in window content should be 202 // dispatched *only* if this window is one of the windows 203 // the accessibility layer reports which are windows 204 // that a sighted user can touch. 205 default: { 206 return isRetrievalAllowingWindowLocked(userId, event.getWindowId()); 207 } 208 } 209 } 210 211 /** 212 * Find a valid package name for an app to expose to accessibility 213 * 214 * @param packageName The package name the app wants to expose 215 * @param appId The app's id 216 * @param userId The app's user id 217 * @param pid The app's process pid that requested this 218 * @return A package name that is valid to report 219 */ 220 @Nullable resolveValidReportedPackageLocked( @ullable CharSequence packageName, int appId, int userId, int pid)221 public String resolveValidReportedPackageLocked( 222 @Nullable CharSequence packageName, int appId, int userId, int pid) { 223 // Okay to pass no package 224 if (packageName == null) { 225 return null; 226 } 227 // The system gets to pass any package 228 if (appId == Process.SYSTEM_UID) { 229 return packageName.toString(); 230 } 231 // Passing a package in your UID is fine 232 final String packageNameStr = packageName.toString(); 233 final int resolvedUid = UserHandle.getUid(userId, appId); 234 if (isValidPackageForUid(packageNameStr, resolvedUid)) { 235 return packageName.toString(); 236 } 237 // Appwidget hosts get to pass packages for widgets they host 238 if (mAppWidgetService != null && ArrayUtils.contains(mAppWidgetService 239 .getHostedWidgetPackages(resolvedUid), packageNameStr)) { 240 return packageName.toString(); 241 } 242 // If app has the targeted permission to act as another package 243 if (mContext.checkPermission(Manifest.permission.ACT_AS_PACKAGE_FOR_ACCESSIBILITY, 244 pid, resolvedUid) == PackageManager.PERMISSION_GRANTED) { 245 return packageName.toString(); 246 } 247 // Otherwise, set the package to the first one in the UID 248 final String[] packageNames = mPackageManager.getPackagesForUid(resolvedUid); 249 if (ArrayUtils.isEmpty(packageNames)) { 250 return null; 251 } 252 // Okay, the caller reported a package it does not have access to. 253 // Instead of crashing the caller for better backwards compatibility 254 // we report the first package in the UID. Since most of the time apps 255 // don't use shared user id, this will yield correct results and for 256 // the edge case of using a shared user id we may report the wrong 257 // package but this is fine since first, this is a cheating app and 258 // second there is no way to get the correct package anyway. 259 return packageNames[0]; 260 } 261 262 /** 263 * Get the packages that are valid for a uid. In some situations, like app widgets, there 264 * could be several valid packages 265 * 266 * @param targetPackage A package that is known to be valid for this id 267 * @param targetUid The whose packages should be checked 268 * @return An array of all valid package names. An empty array means any package is OK 269 */ 270 @NonNull computeValidReportedPackages( @onNull String targetPackage, int targetUid)271 public String[] computeValidReportedPackages( 272 @NonNull String targetPackage, int targetUid) { 273 if (UserHandle.getAppId(targetUid) == Process.SYSTEM_UID) { 274 // Empty array means any package is Okay 275 return EmptyArray.STRING; 276 } 277 // IMPORTANT: The target package is already vetted to be in the target UID 278 String[] uidPackages = new String[]{targetPackage}; 279 // Appwidget hosts get to pass packages for widgets they host 280 if (mAppWidgetService != null) { 281 final ArraySet<String> widgetPackages = mAppWidgetService 282 .getHostedWidgetPackages(targetUid); 283 if (widgetPackages != null && !widgetPackages.isEmpty()) { 284 final String[] validPackages = new String[uidPackages.length 285 + widgetPackages.size()]; 286 System.arraycopy(uidPackages, 0, validPackages, 0, uidPackages.length); 287 final int widgetPackageCount = widgetPackages.size(); 288 for (int i = 0; i < widgetPackageCount; i++) { 289 validPackages[uidPackages.length + i] = widgetPackages.valueAt(i); 290 } 291 return validPackages; 292 } 293 } 294 return uidPackages; 295 } 296 297 /** 298 * Reset the event source for events that should not carry one 299 * 300 * @param event The event potentially to modify 301 */ updateEventSourceLocked(@onNull AccessibilityEvent event)302 public void updateEventSourceLocked(@NonNull AccessibilityEvent event) { 303 if ((event.getEventType() & KEEP_SOURCE_EVENT_TYPES) == 0) { 304 event.setSource(null); 305 } 306 } 307 308 /** 309 * Check if a service can have access to a window 310 * 311 * @param userId The id of the user running the service 312 * @param service The service requesting access 313 * @param windowId The window it wants access to 314 * 315 * @return Whether ot not the service may retrieve info from the window 316 */ canGetAccessibilityNodeInfoLocked(int userId, @NonNull AbstractAccessibilityServiceConnection service, int windowId)317 public boolean canGetAccessibilityNodeInfoLocked(int userId, 318 @NonNull AbstractAccessibilityServiceConnection service, int windowId) { 319 return canRetrieveWindowContentLocked(service) 320 && isRetrievalAllowingWindowLocked(userId, windowId); 321 } 322 323 /** 324 * Check if a service can have access the list of windows 325 * 326 * @param service The service requesting access 327 * 328 * @return Whether ot not the service may retrieve the window list 329 */ canRetrieveWindowsLocked( @onNull AbstractAccessibilityServiceConnection service)330 public boolean canRetrieveWindowsLocked( 331 @NonNull AbstractAccessibilityServiceConnection service) { 332 return canRetrieveWindowContentLocked(service) && service.mRetrieveInteractiveWindows; 333 } 334 335 /** 336 * Check if a service can have access the content of windows on the screen 337 * 338 * @param service The service requesting access 339 * 340 * @return Whether ot not the service may retrieve the content 341 */ canRetrieveWindowContentLocked( @onNull AbstractAccessibilityServiceConnection service)342 public boolean canRetrieveWindowContentLocked( 343 @NonNull AbstractAccessibilityServiceConnection service) { 344 return (service.getCapabilities() 345 & AccessibilityServiceInfo.CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT) != 0; 346 } 347 348 /** 349 * Check if a service can control magnification 350 * 351 * @param service The service requesting access 352 * 353 * @return Whether ot not the service may control magnification 354 */ canControlMagnification( @onNull AbstractAccessibilityServiceConnection service)355 public boolean canControlMagnification( 356 @NonNull AbstractAccessibilityServiceConnection service) { 357 return (service.getCapabilities() 358 & AccessibilityServiceInfo.CAPABILITY_CAN_CONTROL_MAGNIFICATION) != 0; 359 } 360 361 /** 362 * Check if a service can perform gestures 363 * 364 * @param service The service requesting access 365 * 366 * @return Whether ot not the service may perform gestures 367 */ canPerformGestures(@onNull AccessibilityServiceConnection service)368 public boolean canPerformGestures(@NonNull AccessibilityServiceConnection service) { 369 return (service.getCapabilities() 370 & AccessibilityServiceInfo.CAPABILITY_CAN_PERFORM_GESTURES) != 0; 371 } 372 373 /** 374 * Check if a service can capture gestures from the fingerprint sensor 375 * 376 * @param service The service requesting access 377 * 378 * @return Whether ot not the service may capture gestures from the fingerprint sensor 379 */ canCaptureFingerprintGestures(@onNull AccessibilityServiceConnection service)380 public boolean canCaptureFingerprintGestures(@NonNull AccessibilityServiceConnection service) { 381 return (service.getCapabilities() 382 & AccessibilityServiceInfo.CAPABILITY_CAN_REQUEST_FINGERPRINT_GESTURES) != 0; 383 } 384 385 /** 386 * Checks if a service can take screenshot. 387 * 388 * @param service The service requesting access 389 * 390 * @return Whether ot not the service may take screenshot 391 */ canTakeScreenshotLocked( @onNull AbstractAccessibilityServiceConnection service)392 public boolean canTakeScreenshotLocked( 393 @NonNull AbstractAccessibilityServiceConnection service) { 394 return (service.getCapabilities() 395 & AccessibilityServiceInfo.CAPABILITY_CAN_TAKE_SCREENSHOT) != 0; 396 } 397 398 /** 399 * Check whether the input method can be enabled or disabled by the accessibility service. 400 * 401 * @param imeId The id of the input method. 402 * @param service The accessibility service connection. 403 * @return Whether the input method can be enabled/disabled or the reason why it can't be 404 * enabled/disabled. 405 * @throws SecurityException if the input method is not in the same package as the service. 406 */ 407 @AccessibilityService.SoftKeyboardController.EnableImeResult canEnableDisableInputMethod(String imeId, AbstractAccessibilityServiceConnection service)408 int canEnableDisableInputMethod(String imeId, AbstractAccessibilityServiceConnection service) 409 throws SecurityException { 410 final String servicePackageName = service.getComponentName().getPackageName(); 411 final int callingUserId = UserHandle.getCallingUserId(); 412 413 InputMethodInfo inputMethodInfo = null; 414 List<InputMethodInfo> inputMethodInfoList = 415 InputMethodManagerInternal.get().getInputMethodListAsUser(callingUserId); 416 if (inputMethodInfoList != null) { 417 for (InputMethodInfo info : inputMethodInfoList) { 418 if (info.getId().equals(imeId)) { 419 inputMethodInfo = info; 420 break; 421 } 422 } 423 } 424 425 if (inputMethodInfo == null 426 || !inputMethodInfo.getPackageName().equals(servicePackageName)) { 427 throw new SecurityException("The input method is in a different package with the " 428 + "accessibility service"); 429 } 430 431 // TODO(b/207697949, b/208872785): Add cts test for managed device. 432 // Use RestrictedLockUtilsInternal in AccessibilitySecurityPolicy 433 if (RestrictedLockUtilsInternal.checkIfInputMethodDisallowed( 434 mContext, inputMethodInfo.getPackageName(), callingUserId) != null) { 435 return ENABLE_IME_FAIL_BY_ADMIN; 436 } 437 438 return ENABLE_IME_SUCCESS; 439 } 440 441 /** 442 * Returns the parent userId of the profile according to the specified userId. 443 * 444 * @param userId The userId to check 445 * @return the parent userId of the profile, or self if no parent exist 446 */ resolveProfileParentLocked(int userId)447 public int resolveProfileParentLocked(int userId) { 448 if (userId != mAccessibilityUserManager.getCurrentUserIdLocked()) { 449 final long identity = Binder.clearCallingIdentity(); 450 try { 451 UserInfo parent = mUserManager.getProfileParent(userId); 452 if (parent != null) { 453 return parent.getUserHandle().getIdentifier(); 454 } 455 } finally { 456 Binder.restoreCallingIdentity(identity); 457 } 458 } 459 return userId; 460 } 461 462 /** 463 * Returns the parent userId of the profile according to the specified userId. Enforcing 464 * permissions check if specified userId is not caller's userId. 465 * 466 * @param userId The userId to check 467 * @return the parent userId of the profile, or self if no parent exist 468 * @throws SecurityException if caller cannot interact across users 469 * @throws IllegalArgumentException if specified invalid userId 470 */ resolveCallingUserIdEnforcingPermissionsLocked(int userId)471 public int resolveCallingUserIdEnforcingPermissionsLocked(int userId) { 472 final int callingUid = Binder.getCallingUid(); 473 final int currentUserId = mAccessibilityUserManager.getCurrentUserIdLocked(); 474 if (callingUid == 0 475 || callingUid == Process.SYSTEM_UID 476 || callingUid == Process.SHELL_UID) { 477 if (userId == UserHandle.USER_CURRENT 478 || userId == UserHandle.USER_CURRENT_OR_SELF) { 479 return currentUserId; 480 } 481 return resolveProfileParentLocked(userId); 482 } 483 final int callingUserId = UserHandle.getUserId(callingUid); 484 if (callingUserId == userId) { 485 return resolveProfileParentLocked(userId); 486 } 487 final int callingUserParentId = resolveProfileParentLocked(callingUserId); 488 if (callingUserParentId == currentUserId && (userId == UserHandle.USER_CURRENT 489 || userId == UserHandle.USER_CURRENT_OR_SELF)) { 490 return currentUserId; 491 } 492 if (!hasPermission(Manifest.permission.INTERACT_ACROSS_USERS) 493 && !hasPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL)) { 494 throw new SecurityException("Call from user " + callingUserId + " as user " 495 + userId + " without permission INTERACT_ACROSS_USERS or " 496 + "INTERACT_ACROSS_USERS_FULL not allowed."); 497 } 498 if (userId == UserHandle.USER_CURRENT 499 || userId == UserHandle.USER_CURRENT_OR_SELF) { 500 return currentUserId; 501 } 502 return resolveProfileParentLocked(userId); 503 } 504 505 /** 506 * Returns false if caller is not SYSTEM and SHELL, and tried to interact across users. 507 * 508 * @param userId The userId to interact. 509 * @return false if caller cannot interact across users. 510 */ isCallerInteractingAcrossUsers(int userId)511 public boolean isCallerInteractingAcrossUsers(int userId) { 512 final int callingUid = Binder.getCallingUid(); 513 return (Binder.getCallingPid() == android.os.Process.myPid() 514 || callingUid == Process.SHELL_UID 515 || userId == UserHandle.USER_CURRENT 516 || userId == UserHandle.USER_CURRENT_OR_SELF); 517 } 518 isValidPackageForUid(String packageName, int uid)519 private boolean isValidPackageForUid(String packageName, int uid) { 520 final long token = Binder.clearCallingIdentity(); 521 try { 522 // Since we treat calls from a profile as if made by its parent, using 523 // MATCH_ANY_USER to query the uid of the given package name. 524 return mPackageManagerInternal.isSameApp(packageName, PackageManager.MATCH_ANY_USER, 525 uid, UserHandle.getUserId(uid)); 526 } finally { 527 Binder.restoreCallingIdentity(token); 528 } 529 } 530 isRetrievalAllowingWindowLocked(int userId, int windowId)531 private boolean isRetrievalAllowingWindowLocked(int userId, int windowId) { 532 // The system gets to interact with any window it wants. 533 if (Binder.getCallingUid() == Process.SYSTEM_UID) { 534 return true; 535 } 536 if (Binder.getCallingUid() == Process.SHELL_UID) { 537 if (!isShellAllowedToRetrieveWindowLocked(userId, windowId)) { 538 return false; 539 } 540 } 541 if (mAccessibilityWindowManager.resolveParentWindowIdLocked(windowId) 542 == mAccessibilityWindowManager.getActiveWindowId(userId)) { 543 return true; 544 } 545 return mAccessibilityWindowManager.findA11yWindowInfoByIdLocked(windowId) != null; 546 } 547 isShellAllowedToRetrieveWindowLocked(int userId, int windowId)548 private boolean isShellAllowedToRetrieveWindowLocked(int userId, int windowId) { 549 final long token = Binder.clearCallingIdentity(); 550 try { 551 IBinder windowToken = mAccessibilityWindowManager 552 .getWindowTokenForUserAndWindowIdLocked(userId, windowId); 553 if (windowToken == null) { 554 return false; 555 } 556 int windowOwnerUserId = mAccessibilityWindowManager.getWindowOwnerUserId(windowToken); 557 if (windowOwnerUserId == UserHandle.USER_NULL) { 558 return false; 559 } 560 return !mUserManager.hasUserRestriction( 561 UserManager.DISALLOW_DEBUGGING_FEATURES, UserHandle.of(windowOwnerUserId)); 562 } finally { 563 Binder.restoreCallingIdentity(token); 564 } 565 } 566 567 /** 568 * Enforcing permission check to caller. 569 * 570 * @param permission The permission to check 571 * @param function The function name to check 572 */ enforceCallingPermission(@onNull String permission, @Nullable String function)573 public void enforceCallingPermission(@NonNull String permission, @Nullable String function) { 574 if (OWN_PROCESS_ID == Binder.getCallingPid()) { 575 return; 576 } 577 if (!hasPermission(permission)) { 578 throw new SecurityException("You do not have " + permission 579 + " required to call " + function + " from pid=" 580 + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()); 581 } 582 } 583 584 /** 585 * Permission check to caller. 586 * 587 * @param permission The permission to check 588 * @return true if caller has permission 589 */ hasPermission(@onNull String permission)590 public boolean hasPermission(@NonNull String permission) { 591 return mContext.checkCallingPermission(permission) == PackageManager.PERMISSION_GRANTED; 592 } 593 594 /** 595 * Checks if accessibility service could register into the system. 596 * 597 * @param serviceInfo The ServiceInfo 598 * @return True if it could register into the system 599 */ canRegisterService(@onNull ServiceInfo serviceInfo)600 public boolean canRegisterService(@NonNull ServiceInfo serviceInfo) { 601 if (!android.Manifest.permission.BIND_ACCESSIBILITY_SERVICE.equals( 602 serviceInfo.permission)) { 603 Slog.w(LOG_TAG, "Skipping accessibility service " + new ComponentName( 604 serviceInfo.packageName, serviceInfo.name).flattenToShortString() 605 + ": it does not require the permission " 606 + android.Manifest.permission.BIND_ACCESSIBILITY_SERVICE); 607 return false; 608 } 609 610 if ((serviceInfo.flags & ServiceInfo.FLAG_EXTERNAL_SERVICE) != 0) { 611 Slog.w(LOG_TAG, "Skipping accessibility service " + new ComponentName( 612 serviceInfo.packageName, serviceInfo.name).flattenToShortString() 613 + ": the service is the external one and doesn't allow to register as " 614 + "an accessibility service "); 615 return false; 616 } 617 618 int servicePackageUid = serviceInfo.applicationInfo.uid; 619 if (mAppOpsManager.noteOpNoThrow(AppOpsManager.OPSTR_BIND_ACCESSIBILITY_SERVICE, 620 servicePackageUid, serviceInfo.packageName, null, null) 621 != AppOpsManager.MODE_ALLOWED) { 622 Slog.w(LOG_TAG, "Skipping accessibility service " + new ComponentName( 623 serviceInfo.packageName, serviceInfo.name).flattenToShortString() 624 + ": disallowed by AppOps"); 625 return false; 626 } 627 628 return true; 629 } 630 631 /** 632 * Checks if accessibility service could execute accessibility operations. 633 * 634 * @param service The accessibility service connection 635 * @return True if it could execute accessibility operations 636 */ checkAccessibilityAccess(AbstractAccessibilityServiceConnection service)637 public boolean checkAccessibilityAccess(AbstractAccessibilityServiceConnection service) { 638 final String packageName = service.getComponentName().getPackageName(); 639 final ResolveInfo resolveInfo = service.getServiceInfo().getResolveInfo(); 640 641 if (resolveInfo == null) { 642 // For InteractionBridge, UiAutomation, and Proxy. 643 return true; 644 } 645 646 final int servicePackageUid = resolveInfo.serviceInfo.applicationInfo.uid; 647 final int callingPid = Binder.getCallingPid(); 648 final long identityToken = Binder.clearCallingIdentity(); 649 final String attributionTag = service.getAttributionTag(); 650 try { 651 // For the caller is system, just block the data to a11y services. 652 if (OWN_PROCESS_ID == callingPid) { 653 return mAppOpsManager.noteOpNoThrow(AppOpsManager.OPSTR_ACCESS_ACCESSIBILITY, 654 servicePackageUid, packageName, attributionTag, null) 655 == AppOpsManager.MODE_ALLOWED; 656 } 657 658 return mAppOpsManager.noteOp(AppOpsManager.OPSTR_ACCESS_ACCESSIBILITY, 659 servicePackageUid, packageName, attributionTag, null) 660 == AppOpsManager.MODE_ALLOWED; 661 } finally { 662 Binder.restoreCallingIdentity(identityToken); 663 } 664 } 665 666 /** 667 * Enforcing permission check to IPC caller or grant it if it's not through IPC. 668 * 669 * @param permission The permission to check 670 */ enforceCallingOrSelfPermission(@onNull String permission)671 public void enforceCallingOrSelfPermission(@NonNull String permission) { 672 if (mContext.checkCallingOrSelfPermission(permission) 673 != PackageManager.PERMISSION_GRANTED) { 674 throw new SecurityException("Caller does not hold permission " 675 + permission); 676 } 677 } 678 679 /** 680 * Throws a SecurityException if the caller has neither the MANAGE_ACCESSIBILITY permission nor 681 * the COMPANION_DEVICE_APP_STREAMING role. 682 */ checkForAccessibilityPermissionOrRole()683 public void checkForAccessibilityPermissionOrRole() { 684 final boolean canManageAccessibility = 685 mContext.checkCallingOrSelfPermission(Manifest.permission.MANAGE_ACCESSIBILITY) 686 == PackageManager.PERMISSION_GRANTED; 687 if (canManageAccessibility) { 688 return; 689 } 690 final int callingUid = Binder.getCallingUid(); 691 final long identity = Binder.clearCallingIdentity(); 692 try { 693 final RoleManager roleManager = mContext.getSystemService(RoleManager.class); 694 if (roleManager != null) { 695 final List<String> holders = roleManager.getRoleHoldersAsUser( 696 DEVICE_PROFILE_APP_STREAMING, UserHandle.getUserHandleForUid(callingUid)); 697 final String[] packageNames = mPackageManager.getPackagesForUid(callingUid); 698 if (packageNames != null) { 699 for (String packageName : packageNames) { 700 if (holders.contains(packageName)) { 701 return; 702 } 703 } 704 } 705 } 706 throw new SecurityException( 707 "Cannot register a proxy for a device without the " 708 + "android.app.role.COMPANION_DEVICE_APP_STREAMING role or the" 709 + " MANAGE_ACCESSIBILITY permission."); 710 } finally { 711 Binder.restoreCallingIdentity(identity); 712 } 713 } 714 715 /** 716 * Called after a service was bound or unbound. Checks the current bound accessibility 717 * services and updates alarms. 718 * 719 * @param userId The user id 720 * @param boundServices The bound services 721 */ onBoundServicesChangedLocked(int userId, ArrayList<AccessibilityServiceConnection> boundServices)722 public void onBoundServicesChangedLocked(int userId, 723 ArrayList<AccessibilityServiceConnection> boundServices) { 724 if (mAccessibilityUserManager.getCurrentUserIdLocked() != userId) { 725 return; 726 } 727 728 ArraySet<ComponentName> tempNonA11yCategoryServices = new ArraySet<>(); 729 for (int i = 0; i < boundServices.size(); i++) { 730 final AccessibilityServiceInfo a11yServiceInfo = boundServices.get( 731 i).getServiceInfo(); 732 final ComponentName service = a11yServiceInfo.getComponentName().clone(); 733 if (!a11yServiceInfo.isAccessibilityTool()) { 734 tempNonA11yCategoryServices.add(service); 735 if (mNonA11yCategoryServices.contains(service)) { 736 mNonA11yCategoryServices.remove(service); 737 } else { 738 if (mSendNonA11yToolNotificationEnabled) { 739 mPolicyWarningUIController.onNonA11yCategoryServiceBound(userId, service); 740 } 741 } 742 } 743 } 744 745 for (int i = 0; i < mNonA11yCategoryServices.size(); i++) { 746 final ComponentName service = mNonA11yCategoryServices.valueAt(i); 747 mPolicyWarningUIController.onNonA11yCategoryServiceUnbound(userId, service); 748 } 749 mNonA11yCategoryServices.clear(); 750 mNonA11yCategoryServices.addAll(tempNonA11yCategoryServices); 751 } 752 753 /** 754 * Called after switching to another user. Resets data and cancels old alarms after 755 * switching to another user. 756 * 757 * @param userId The user id 758 * @param enabledServices The enabled services 759 */ onSwitchUserLocked(int userId, Set<ComponentName> enabledServices)760 public void onSwitchUserLocked(int userId, Set<ComponentName> enabledServices) { 761 if (mCurrentUserId == userId) { 762 return; 763 } 764 mPolicyWarningUIController.onSwitchUser(userId, 765 new ArraySet<>(enabledServices)); 766 767 for (int i = 0; i < mNonA11yCategoryServices.size(); i++) { 768 mPolicyWarningUIController.onNonA11yCategoryServiceUnbound(mCurrentUserId, 769 mNonA11yCategoryServices.valueAt(i)); 770 } 771 mNonA11yCategoryServices.clear(); 772 mCurrentUserId = userId; 773 } 774 775 /** 776 * Called after the enabled accessibility services changed. 777 * 778 * @param userId The user id 779 * @param enabledServices The enabled services 780 */ onEnabledServicesChangedLocked(int userId, Set<ComponentName> enabledServices)781 public void onEnabledServicesChangedLocked(int userId, Set<ComponentName> enabledServices) { 782 if (mAccessibilityUserManager.getCurrentUserIdLocked() != userId) { 783 return; 784 } 785 mPolicyWarningUIController.onEnabledServicesChanged(userId, 786 new ArraySet<>(enabledServices)); 787 } 788 } 789