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