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