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