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