1 /* 2 ** Copyright 2017, 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_UNKNOWN; 20 import static android.accessibilityservice.AccessibilityService.SoftKeyboardController.ENABLE_IME_SUCCESS; 21 22 import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage; 23 24 import android.Manifest; 25 import android.accessibilityservice.AccessibilityService; 26 import android.accessibilityservice.AccessibilityServiceInfo; 27 import android.accessibilityservice.AccessibilityTrace; 28 import android.accessibilityservice.IAccessibilityServiceClient; 29 import android.accessibilityservice.TouchInteractionController; 30 import android.app.PendingIntent; 31 import android.content.ComponentName; 32 import android.content.Context; 33 import android.content.Intent; 34 import android.content.pm.ParceledListSlice; 35 import android.os.Binder; 36 import android.os.Handler; 37 import android.os.IBinder; 38 import android.os.Message; 39 import android.os.Process; 40 import android.os.RemoteException; 41 import android.os.UserHandle; 42 import android.provider.Settings; 43 import android.util.Slog; 44 import android.view.Display; 45 import android.view.MotionEvent; 46 47 48 import com.android.server.inputmethod.InputMethodManagerInternal; 49 import com.android.server.wm.ActivityTaskManagerInternal; 50 import com.android.server.wm.WindowManagerInternal; 51 52 import java.lang.ref.WeakReference; 53 import java.util.Set; 54 55 /** 56 * This class represents an accessibility service. It stores all per service 57 * data required for the service management, provides API for starting/stopping the 58 * service and is responsible for adding/removing the service in the data structures 59 * for service management. The class also exposes configuration interface that is 60 * passed to the service it represents as soon it is bound. It also serves as the 61 * connection for the service. 62 */ 63 class AccessibilityServiceConnection extends AbstractAccessibilityServiceConnection { 64 private static final String LOG_TAG = "AccessibilityServiceConnection"; 65 66 /* 67 Holding a weak reference so there isn't a loop of references. AccessibilityUserState keeps 68 lists of bound and binding services. These are freed on user changes, but just in case it 69 somehow gets lost the weak reference will let the memory get GCed. 70 71 Having the reference be null when being called is a very bad sign, but we check the condition. 72 */ 73 final WeakReference<AccessibilityUserState> mUserStateWeakReference; 74 final Intent mIntent; 75 final ActivityTaskManagerInternal mActivityTaskManagerService; 76 77 private final Handler mMainHandler; 78 AccessibilityServiceConnection(AccessibilityUserState userState, Context context, ComponentName componentName, AccessibilityServiceInfo accessibilityServiceInfo, int id, Handler mainHandler, Object lock, AccessibilitySecurityPolicy securityPolicy, SystemSupport systemSupport, AccessibilityTrace trace, WindowManagerInternal windowManagerInternal, SystemActionPerformer systemActionPerfomer, AccessibilityWindowManager awm, ActivityTaskManagerInternal activityTaskManagerService)79 AccessibilityServiceConnection(AccessibilityUserState userState, Context context, 80 ComponentName componentName, 81 AccessibilityServiceInfo accessibilityServiceInfo, int id, Handler mainHandler, 82 Object lock, AccessibilitySecurityPolicy securityPolicy, SystemSupport systemSupport, 83 AccessibilityTrace trace, WindowManagerInternal windowManagerInternal, 84 SystemActionPerformer systemActionPerfomer, AccessibilityWindowManager awm, 85 ActivityTaskManagerInternal activityTaskManagerService) { 86 super(context, componentName, accessibilityServiceInfo, id, mainHandler, lock, 87 securityPolicy, systemSupport, trace, windowManagerInternal, systemActionPerfomer, 88 awm); 89 mUserStateWeakReference = new WeakReference<AccessibilityUserState>(userState); 90 mIntent = new Intent().setComponent(mComponentName); 91 mMainHandler = mainHandler; 92 mIntent.putExtra(Intent.EXTRA_CLIENT_LABEL, 93 com.android.internal.R.string.accessibility_binding_label); 94 mActivityTaskManagerService = activityTaskManagerService; 95 final long identity = Binder.clearCallingIdentity(); 96 try { 97 mIntent.putExtra(Intent.EXTRA_CLIENT_INTENT, mSystemSupport.getPendingIntentActivity( 98 mContext, 0, new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS), 99 PendingIntent.FLAG_IMMUTABLE)); 100 } finally { 101 Binder.restoreCallingIdentity(identity); 102 } 103 } 104 bindLocked()105 public void bindLocked() { 106 AccessibilityUserState userState = mUserStateWeakReference.get(); 107 if (userState == null) return; 108 final long identity = Binder.clearCallingIdentity(); 109 try { 110 int flags = Context.BIND_AUTO_CREATE 111 | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE 112 | Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS 113 | Context.BIND_INCLUDE_CAPABILITIES; 114 if (userState.getBindInstantServiceAllowedLocked()) { 115 flags |= Context.BIND_ALLOW_INSTANT; 116 } 117 if (mService == null && mContext.bindServiceAsUser( 118 mIntent, this, flags, new UserHandle(userState.mUserId))) { 119 userState.getBindingServicesLocked().add(mComponentName); 120 } 121 } finally { 122 Binder.restoreCallingIdentity(identity); 123 } 124 mActivityTaskManagerService.setAllowAppSwitches(mComponentName.flattenToString(), 125 mAccessibilityServiceInfo.getResolveInfo().serviceInfo.applicationInfo.uid, 126 userState.mUserId); 127 } 128 unbindLocked()129 public void unbindLocked() { 130 if (requestImeApis()) { 131 mSystemSupport.unbindImeLocked(this); 132 } 133 mContext.unbindService(this); 134 AccessibilityUserState userState = mUserStateWeakReference.get(); 135 if (userState == null) return; 136 userState.removeServiceLocked(this); 137 mSystemSupport.getMagnificationProcessor().resetAllIfNeeded(mId); 138 mActivityTaskManagerService.setAllowAppSwitches(mComponentName.flattenToString(), -1, 139 userState.mUserId); 140 resetLocked(); 141 } 142 canRetrieveInteractiveWindowsLocked()143 public boolean canRetrieveInteractiveWindowsLocked() { 144 return mSecurityPolicy.canRetrieveWindowContentLocked(this) && mRetrieveInteractiveWindows; 145 } 146 147 @Override disableSelf()148 public void disableSelf() { 149 if (svcConnTracingEnabled()) { 150 logTraceSvcConn("disableSelf", ""); 151 } 152 synchronized (mLock) { 153 AccessibilityUserState userState = mUserStateWeakReference.get(); 154 if (userState == null) return; 155 if (userState.getEnabledServicesLocked().remove(mComponentName)) { 156 final long identity = Binder.clearCallingIdentity(); 157 try { 158 mSystemSupport.persistComponentNamesToSettingLocked( 159 Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, 160 userState.getEnabledServicesLocked(), userState.mUserId); 161 } finally { 162 Binder.restoreCallingIdentity(identity); 163 } 164 mSystemSupport.onClientChangeLocked(false); 165 } 166 } 167 } 168 169 @Override onServiceConnected(ComponentName componentName, IBinder service)170 public void onServiceConnected(ComponentName componentName, IBinder service) { 171 synchronized (mLock) { 172 if (mService != service) { 173 if (mService != null) { 174 mService.unlinkToDeath(this, 0); 175 } 176 mService = service; 177 try { 178 mService.linkToDeath(this, 0); 179 } catch (RemoteException re) { 180 Slog.e(LOG_TAG, "Failed registering death link"); 181 binderDied(); 182 return; 183 } 184 } 185 mServiceInterface = IAccessibilityServiceClient.Stub.asInterface(service); 186 AccessibilityUserState userState = mUserStateWeakReference.get(); 187 if (userState == null) return; 188 userState.addServiceLocked(this); 189 mSystemSupport.onClientChangeLocked(false); 190 // Initialize the service on the main handler after we're done setting up for 191 // the new configuration (for example, initializing the input filter). 192 mMainHandler.sendMessage(obtainMessage( 193 AccessibilityServiceConnection::initializeService, this)); 194 if (requestImeApis()) { 195 mSystemSupport.requestImeLocked(this); 196 } 197 } 198 } 199 200 @Override getServiceInfo()201 public AccessibilityServiceInfo getServiceInfo() { 202 return mAccessibilityServiceInfo; 203 } 204 initializeService()205 private void initializeService() { 206 IAccessibilityServiceClient serviceInterface = null; 207 synchronized (mLock) { 208 AccessibilityUserState userState = mUserStateWeakReference.get(); 209 if (userState == null) return; 210 final Set<ComponentName> bindingServices = userState.getBindingServicesLocked(); 211 final Set<ComponentName> crashedServices = userState.getCrashedServicesLocked(); 212 if (bindingServices.contains(mComponentName) 213 || crashedServices.contains(mComponentName)) { 214 bindingServices.remove(mComponentName); 215 crashedServices.remove(mComponentName); 216 mAccessibilityServiceInfo.crashed = false; 217 serviceInterface = mServiceInterface; 218 } 219 // There's a chance that service is removed from enabled_accessibility_services setting 220 // key, but skip unbinding because of it's in binding state. Unbinds it if it's 221 // not in enabled service list. 222 if (serviceInterface != null 223 && !userState.getEnabledServicesLocked().contains(mComponentName)) { 224 mSystemSupport.onClientChangeLocked(false); 225 return; 226 } 227 } 228 if (serviceInterface == null) { 229 binderDied(); 230 return; 231 } 232 try { 233 if (svcClientTracingEnabled()) { 234 logTraceSvcClient("init", 235 this + "," + mId + "," + mOverlayWindowTokens.get(Display.DEFAULT_DISPLAY)); 236 } 237 serviceInterface.init(this, mId, mOverlayWindowTokens.get(Display.DEFAULT_DISPLAY)); 238 } catch (RemoteException re) { 239 Slog.w(LOG_TAG, "Error while setting connection for service: " 240 + serviceInterface, re); 241 binderDied(); 242 } 243 } 244 245 @Override onServiceDisconnected(ComponentName componentName)246 public void onServiceDisconnected(ComponentName componentName) { 247 binderDied(); 248 AccessibilityUserState userState = mUserStateWeakReference.get(); 249 if (userState != null) { 250 mActivityTaskManagerService.setAllowAppSwitches(mComponentName.flattenToString(), -1, 251 userState.mUserId); 252 } 253 } 254 255 @Override hasRightsToCurrentUserLocked()256 protected boolean hasRightsToCurrentUserLocked() { 257 // We treat calls from a profile as if made by its parent as profiles 258 // share the accessibility state of the parent. The call below 259 // performs the current profile parent resolution. 260 final int callingUid = Binder.getCallingUid(); 261 if (callingUid == Process.ROOT_UID 262 || callingUid == Process.SYSTEM_UID 263 || callingUid == Process.SHELL_UID) { 264 return true; 265 } 266 if (mSecurityPolicy.resolveProfileParentLocked(UserHandle.getUserId(callingUid)) 267 == mSystemSupport.getCurrentUserIdLocked()) { 268 return true; 269 } 270 if (mSecurityPolicy.hasPermission(Manifest.permission.INTERACT_ACROSS_USERS) 271 || mSecurityPolicy.hasPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL)) { 272 return true; 273 } 274 return false; 275 } 276 277 @Override setSoftKeyboardShowMode(int showMode)278 public boolean setSoftKeyboardShowMode(int showMode) { 279 if (svcConnTracingEnabled()) { 280 logTraceSvcConn("setSoftKeyboardShowMode", "showMode=" + showMode); 281 } 282 synchronized (mLock) { 283 if (!hasRightsToCurrentUserLocked()) { 284 return false; 285 } 286 final AccessibilityUserState userState = mUserStateWeakReference.get(); 287 if (userState == null) return false; 288 return userState.setSoftKeyboardModeLocked(showMode, mComponentName); 289 } 290 } 291 292 @Override getSoftKeyboardShowMode()293 public int getSoftKeyboardShowMode() { 294 if (svcConnTracingEnabled()) { 295 logTraceSvcConn("getSoftKeyboardShowMode", ""); 296 } 297 final AccessibilityUserState userState = mUserStateWeakReference.get(); 298 return (userState != null) ? userState.getSoftKeyboardShowModeLocked() : 0; 299 } 300 301 @Override switchToInputMethod(String imeId)302 public boolean switchToInputMethod(String imeId) { 303 if (svcConnTracingEnabled()) { 304 logTraceSvcConn("switchToInputMethod", "imeId=" + imeId); 305 } 306 synchronized (mLock) { 307 if (!hasRightsToCurrentUserLocked()) { 308 return false; 309 } 310 } 311 final boolean result; 312 final int callingUserId = UserHandle.getCallingUserId(); 313 final long identity = Binder.clearCallingIdentity(); 314 try { 315 result = InputMethodManagerInternal.get().switchToInputMethod(imeId, callingUserId); 316 } finally { 317 Binder.restoreCallingIdentity(identity); 318 } 319 return result; 320 } 321 322 @Override 323 @AccessibilityService.SoftKeyboardController.EnableImeResult setInputMethodEnabled(String imeId, boolean enabled)324 public int setInputMethodEnabled(String imeId, boolean enabled) throws SecurityException { 325 if (svcConnTracingEnabled()) { 326 logTraceSvcConn("switchToInputMethod", "imeId=" + imeId); 327 } 328 synchronized (mLock) { 329 if (!hasRightsToCurrentUserLocked()) { 330 return ENABLE_IME_FAIL_UNKNOWN; 331 } 332 } 333 334 final int callingUserId = UserHandle.getCallingUserId(); 335 final InputMethodManagerInternal inputMethodManagerInternal = 336 InputMethodManagerInternal.get(); 337 338 final @AccessibilityService.SoftKeyboardController.EnableImeResult int checkResult; 339 final long identity = Binder.clearCallingIdentity(); 340 try { 341 synchronized (mLock) { 342 checkResult = mSecurityPolicy.canEnableDisableInputMethod(imeId, this); 343 } 344 if (checkResult != ENABLE_IME_SUCCESS) { 345 return checkResult; 346 } 347 if (inputMethodManagerInternal.setInputMethodEnabled(imeId, 348 enabled, callingUserId)) { 349 return ENABLE_IME_SUCCESS; 350 } 351 } finally { 352 Binder.restoreCallingIdentity(identity); 353 } 354 return ENABLE_IME_FAIL_UNKNOWN; 355 } 356 357 @Override isAccessibilityButtonAvailable()358 public boolean isAccessibilityButtonAvailable() { 359 if (svcConnTracingEnabled()) { 360 logTraceSvcConn("isAccessibilityButtonAvailable", ""); 361 } 362 synchronized (mLock) { 363 if (!hasRightsToCurrentUserLocked()) { 364 return false; 365 } 366 AccessibilityUserState userState = mUserStateWeakReference.get(); 367 return (userState != null) && isAccessibilityButtonAvailableLocked(userState); 368 } 369 } 370 371 @Override binderDied()372 public void binderDied() { 373 synchronized (mLock) { 374 // It is possible that this service's package was force stopped during 375 // whose handling the death recipient is unlinked and still get a call 376 // on binderDied since the call was made before we unlink but was 377 // waiting on the lock we held during the force stop handling. 378 if (!isConnectedLocked()) { 379 return; 380 } 381 if (requestImeApis()) { 382 mSystemSupport.unbindImeLocked(this); 383 } 384 mAccessibilityServiceInfo.crashed = true; 385 AccessibilityUserState userState = mUserStateWeakReference.get(); 386 if (userState != null) { 387 userState.serviceDisconnectedLocked(this); 388 } 389 resetLocked(); 390 mSystemSupport.getMagnificationProcessor().resetAllIfNeeded(mId); 391 mSystemSupport.onClientChangeLocked(false); 392 } 393 } 394 isAccessibilityButtonAvailableLocked(AccessibilityUserState userState)395 public boolean isAccessibilityButtonAvailableLocked(AccessibilityUserState userState) { 396 // If the service does not request the accessibility button, it isn't available 397 if (!mRequestAccessibilityButton) { 398 return false; 399 } 400 // If the accessibility button isn't currently shown, it cannot be available to services 401 if (!mSystemSupport.isAccessibilityButtonShown()) { 402 return false; 403 } 404 return true; 405 } 406 407 @Override isCapturingFingerprintGestures()408 public boolean isCapturingFingerprintGestures() { 409 return (mServiceInterface != null) 410 && mSecurityPolicy.canCaptureFingerprintGestures(this) 411 && mCaptureFingerprintGestures; 412 } 413 414 @Override onFingerprintGestureDetectionActiveChanged(boolean active)415 public void onFingerprintGestureDetectionActiveChanged(boolean active) { 416 if (!isCapturingFingerprintGestures()) { 417 return; 418 } 419 IAccessibilityServiceClient serviceInterface; 420 synchronized (mLock) { 421 serviceInterface = mServiceInterface; 422 } 423 if (serviceInterface != null) { 424 try { 425 if (svcClientTracingEnabled()) { 426 logTraceSvcClient( 427 "onFingerprintCapturingGesturesChanged", String.valueOf(active)); 428 } 429 mServiceInterface.onFingerprintCapturingGesturesChanged(active); 430 } catch (RemoteException e) { 431 } 432 } 433 } 434 435 @Override onFingerprintGesture(int gesture)436 public void onFingerprintGesture(int gesture) { 437 if (!isCapturingFingerprintGestures()) { 438 return; 439 } 440 IAccessibilityServiceClient serviceInterface; 441 synchronized (mLock) { 442 serviceInterface = mServiceInterface; 443 } 444 if (serviceInterface != null) { 445 try { 446 if (svcClientTracingEnabled()) { 447 logTraceSvcClient("onFingerprintGesture", String.valueOf(gesture)); 448 } 449 mServiceInterface.onFingerprintGesture(gesture); 450 } catch (RemoteException e) { 451 } 452 } 453 } 454 455 @Override dispatchGesture(int sequence, ParceledListSlice gestureSteps, int displayId)456 public void dispatchGesture(int sequence, ParceledListSlice gestureSteps, int displayId) { 457 synchronized (mLock) { 458 if (mServiceInterface != null && mSecurityPolicy.canPerformGestures(this)) { 459 MotionEventInjector motionEventInjector = 460 mSystemSupport.getMotionEventInjectorForDisplayLocked(displayId); 461 if (wmTracingEnabled()) { 462 logTraceWM("isTouchOrFaketouchDevice", ""); 463 } 464 if (motionEventInjector != null 465 && mWindowManagerService.isTouchOrFaketouchDevice()) { 466 motionEventInjector.injectEvents( 467 gestureSteps.getList(), mServiceInterface, sequence, displayId); 468 } else { 469 try { 470 if (svcClientTracingEnabled()) { 471 logTraceSvcClient("onPerformGestureResult", sequence + ", false"); 472 } 473 mServiceInterface.onPerformGestureResult(sequence, false); 474 } catch (RemoteException re) { 475 Slog.e(LOG_TAG, "Error sending motion event injection failure to " 476 + mServiceInterface, re); 477 } 478 } 479 } 480 } 481 } 482 483 @Override setFocusAppearance(int strokeWidth, int color)484 public void setFocusAppearance(int strokeWidth, int color) { 485 AccessibilityUserState userState = mUserStateWeakReference.get(); 486 if (userState == null) { 487 return; 488 } 489 490 synchronized (mLock) { 491 if (!hasRightsToCurrentUserLocked()) { 492 return; 493 } 494 495 if (!mSecurityPolicy.checkAccessibilityAccess(this)) { 496 return; 497 } 498 499 if (userState.getFocusStrokeWidthLocked() == strokeWidth 500 && userState.getFocusColorLocked() == color) { 501 return; 502 } 503 504 // Sets the appearance data in the A11yUserState. 505 userState.setFocusAppearanceLocked(strokeWidth, color); 506 // Updates the appearance data in the A11yManager. 507 mSystemSupport.onClientChangeLocked(false); 508 } 509 } 510 notifyMotionEvent(MotionEvent event)511 public void notifyMotionEvent(MotionEvent event) { 512 final Message msg = obtainMessage( 513 AccessibilityServiceConnection::notifyMotionEventInternal, 514 AccessibilityServiceConnection.this, event); 515 mMainHandler.sendMessage(msg); 516 } 517 notifyTouchState(int displayId, int state)518 public void notifyTouchState(int displayId, int state) { 519 final Message msg = obtainMessage( 520 AccessibilityServiceConnection::notifyTouchStateInternal, 521 AccessibilityServiceConnection.this, displayId, state); 522 mMainHandler.sendMessage(msg); 523 } 524 requestImeApis()525 public boolean requestImeApis() { 526 return mRequestImeApis; 527 } 528 notifyMotionEventInternal(MotionEvent event)529 private void notifyMotionEventInternal(MotionEvent event) { 530 final IAccessibilityServiceClient listener = getServiceInterfaceSafely(); 531 if (listener != null) { 532 try { 533 if (mTrace.isA11yTracingEnabled()) { 534 logTraceSvcClient(".onMotionEvent ", 535 event.toString()); 536 } 537 listener.onMotionEvent(event); 538 } catch (RemoteException re) { 539 Slog.e(LOG_TAG, "Error sending motion event to" + mService, re); 540 } 541 } 542 } 543 notifyTouchStateInternal(int displayId, int state)544 private void notifyTouchStateInternal(int displayId, int state) { 545 final IAccessibilityServiceClient listener = getServiceInterfaceSafely(); 546 if (listener != null) { 547 try { 548 if (mTrace.isA11yTracingEnabled()) { 549 logTraceSvcClient(".onTouchStateChanged ", 550 TouchInteractionController.stateToString(state)); 551 } 552 listener.onTouchStateChanged(displayId, state); 553 } catch (RemoteException re) { 554 Slog.e(LOG_TAG, "Error sending motion event to" + mService, re); 555 } 556 } 557 } 558 } 559