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 android.accessibilityservice.AccessibilityService; 20 import android.accessibilityservice.AccessibilityServiceInfo; 21 import android.accessibilityservice.AccessibilityTrace; 22 import android.accessibilityservice.IAccessibilityServiceClient; 23 import android.annotation.Nullable; 24 import android.app.UiAutomation; 25 import android.content.ComponentName; 26 import android.content.Context; 27 import android.os.Binder; 28 import android.os.Handler; 29 import android.os.IBinder; 30 import android.os.IBinder.DeathRecipient; 31 import android.os.RemoteCallback; 32 import android.os.RemoteException; 33 import android.util.Slog; 34 import android.view.Display; 35 import android.view.accessibility.AccessibilityEvent; 36 37 import com.android.internal.util.DumpUtils; 38 import com.android.server.utils.Slogf; 39 import com.android.server.wm.WindowManagerInternal; 40 41 import java.io.FileDescriptor; 42 import java.io.PrintWriter; 43 44 /** 45 * Class to manage UiAutomation. 46 */ 47 class UiAutomationManager { 48 private static final ComponentName COMPONENT_NAME = 49 new ComponentName("com.android.server.accessibility", "UiAutomation"); 50 private static final String LOG_TAG = "UiAutomationManager"; 51 52 private final Object mLock; 53 54 private UiAutomationService mUiAutomationService; 55 56 private AbstractAccessibilityServiceConnection.SystemSupport mSystemSupport; 57 58 private int mUiAutomationFlags; 59 UiAutomationManager(Object lock)60 UiAutomationManager(Object lock) { 61 mLock = lock; 62 } 63 64 private IBinder mUiAutomationServiceOwner; 65 private final DeathRecipient mUiAutomationServiceOwnerDeathRecipient = 66 new DeathRecipient() { 67 @Override 68 public void binderDied() { 69 mUiAutomationServiceOwner.unlinkToDeath(this, 0); 70 mUiAutomationServiceOwner = null; 71 destroyUiAutomationService(); 72 Slog.v(LOG_TAG, "UiAutomation service owner died"); 73 } 74 }; 75 76 /** 77 * Register a UiAutomation if it uses the accessibility subsystem. Only one may be registered 78 * at a time. 79 * 80 * @param owner A binder object owned by the process that owns the UiAutomation to be 81 * registered. 82 * @param serviceClient The UiAutomation's service interface. 83 * @param accessibilityServiceInfo The UiAutomation's service info 84 * @param flags The UiAutomation's flags 85 * @param id The id for the service connection 86 * @see UiAutomation#FLAG_DONT_USE_ACCESSIBILITY 87 */ registerUiTestAutomationServiceLocked(IBinder owner, IAccessibilityServiceClient serviceClient, Context context, AccessibilityServiceInfo accessibilityServiceInfo, int id, Handler mainHandler, AccessibilitySecurityPolicy securityPolicy, AbstractAccessibilityServiceConnection.SystemSupport systemSupport, AccessibilityTrace trace, WindowManagerInternal windowManagerInternal, SystemActionPerformer systemActionPerformer, AccessibilityWindowManager awm, int flags)88 void registerUiTestAutomationServiceLocked(IBinder owner, 89 IAccessibilityServiceClient serviceClient, 90 Context context, AccessibilityServiceInfo accessibilityServiceInfo, 91 int id, Handler mainHandler, 92 AccessibilitySecurityPolicy securityPolicy, 93 AbstractAccessibilityServiceConnection.SystemSupport systemSupport, 94 AccessibilityTrace trace, 95 WindowManagerInternal windowManagerInternal, 96 SystemActionPerformer systemActionPerformer, 97 AccessibilityWindowManager awm, int flags) { 98 accessibilityServiceInfo.setComponentName(COMPONENT_NAME); 99 Slogf.i(LOG_TAG, "Registering UiTestAutomationService (id=%s) when called by user %d", 100 accessibilityServiceInfo.getId(), Binder.getCallingUserHandle().getIdentifier()); 101 synchronized (mLock) { 102 if (mUiAutomationService != null) { 103 throw new IllegalStateException( 104 "UiAutomationService " + mUiAutomationService.mServiceInterface 105 + "already registered!"); 106 } 107 108 try { 109 owner.linkToDeath(mUiAutomationServiceOwnerDeathRecipient, 0); 110 } catch (RemoteException re) { 111 Slog.e(LOG_TAG, "Couldn't register for the death of a UiTestAutomationService!", 112 re); 113 return; 114 } 115 116 mUiAutomationFlags = flags; 117 mSystemSupport = systemSupport; 118 // Ignore registering UiAutomation if it is not allowed to use the accessibility 119 // subsystem. 120 if (!useAccessibility()) { 121 return; 122 } 123 mUiAutomationService = new UiAutomationService(context, accessibilityServiceInfo, id, 124 mainHandler, mLock, securityPolicy, systemSupport, trace, windowManagerInternal, 125 systemActionPerformer, awm); 126 mUiAutomationServiceOwner = owner; 127 mUiAutomationService.mServiceInterface = serviceClient; 128 try { 129 mUiAutomationService.mServiceInterface.asBinder().linkToDeath(mUiAutomationService, 130 0); 131 } catch (RemoteException re) { 132 Slog.e(LOG_TAG, "Failed registering death link: " + re); 133 destroyUiAutomationService(); 134 return; 135 } 136 137 mUiAutomationService.onAdded(); 138 139 mUiAutomationService.connectServiceUnknownThread(); 140 } 141 } 142 unregisterUiTestAutomationServiceLocked(IAccessibilityServiceClient serviceClient)143 void unregisterUiTestAutomationServiceLocked(IAccessibilityServiceClient serviceClient) { 144 synchronized (mLock) { 145 if (useAccessibility() 146 && ((mUiAutomationService == null) 147 || (serviceClient == null) 148 || (mUiAutomationService.mServiceInterface == null) 149 || (serviceClient.asBinder() 150 != mUiAutomationService.mServiceInterface.asBinder()))) { 151 throw new IllegalStateException("UiAutomationService " + serviceClient 152 + " not registered!"); 153 } 154 destroyUiAutomationService(); 155 } 156 } 157 sendAccessibilityEventLocked(AccessibilityEvent event)158 void sendAccessibilityEventLocked(AccessibilityEvent event) { 159 if (mUiAutomationService != null) { 160 mUiAutomationService.notifyAccessibilityEvent(event); 161 } 162 } 163 isUiAutomationRunningLocked()164 boolean isUiAutomationRunningLocked() { 165 return (mUiAutomationService != null || !useAccessibility()); 166 } 167 suppressingAccessibilityServicesLocked()168 boolean suppressingAccessibilityServicesLocked() { 169 return (mUiAutomationService != null || !useAccessibility()) 170 && ((mUiAutomationFlags 171 & UiAutomation.FLAG_DONT_SUPPRESS_ACCESSIBILITY_SERVICES) == 0); 172 } 173 useAccessibility()174 boolean useAccessibility() { 175 return ((mUiAutomationFlags & UiAutomation.FLAG_DONT_USE_ACCESSIBILITY) == 0); 176 } 177 isTouchExplorationEnabledLocked()178 boolean isTouchExplorationEnabledLocked() { 179 return (mUiAutomationService != null) 180 && mUiAutomationService.mRequestTouchExplorationMode; 181 } 182 canRetrieveInteractiveWindowsLocked()183 boolean canRetrieveInteractiveWindowsLocked() { 184 return (mUiAutomationService != null) && mUiAutomationService.mRetrieveInteractiveWindows; 185 } 186 getRequestedEventMaskLocked()187 int getRequestedEventMaskLocked() { 188 if (mUiAutomationService == null) return 0; 189 return mUiAutomationService.mEventTypes; 190 } 191 getRelevantEventTypes()192 int getRelevantEventTypes() { 193 UiAutomationService uiAutomationService; 194 synchronized (mLock) { 195 uiAutomationService = mUiAutomationService; 196 } 197 if (uiAutomationService == null) return 0; 198 return uiAutomationService.getRelevantEventTypes(); 199 } 200 201 @Nullable getServiceInfo()202 AccessibilityServiceInfo getServiceInfo() { 203 UiAutomationService uiAutomationService; 204 synchronized (mLock) { 205 uiAutomationService = mUiAutomationService; 206 } 207 if (uiAutomationService == null) return null; 208 return uiAutomationService.getServiceInfo(); 209 } 210 dumpUiAutomationService(FileDescriptor fd, final PrintWriter pw, String[] args)211 void dumpUiAutomationService(FileDescriptor fd, final PrintWriter pw, String[] args) { 212 UiAutomationService uiAutomationService; 213 synchronized (mLock) { 214 uiAutomationService = mUiAutomationService; 215 } 216 if (uiAutomationService != null) { 217 uiAutomationService.dump(fd, pw, args); 218 } 219 } 220 destroyUiAutomationService()221 private void destroyUiAutomationService() { 222 synchronized (mLock) { 223 if (mUiAutomationService != null) { 224 mUiAutomationService.mServiceInterface.asBinder().unlinkToDeath( 225 mUiAutomationService, 0); 226 mUiAutomationService.onRemoved(); 227 mUiAutomationService.resetLocked(); 228 mUiAutomationService = null; 229 if (mUiAutomationServiceOwner != null) { 230 mUiAutomationServiceOwner.unlinkToDeath( 231 mUiAutomationServiceOwnerDeathRecipient, 0); 232 mUiAutomationServiceOwner = null; 233 } 234 } 235 mUiAutomationFlags = 0; 236 mSystemSupport.onClientChangeLocked(false); 237 } 238 } 239 240 private class UiAutomationService extends AbstractAccessibilityServiceConnection { 241 private final Handler mMainHandler; 242 UiAutomationService(Context context, AccessibilityServiceInfo accessibilityServiceInfo, int id, Handler mainHandler, Object lock, AccessibilitySecurityPolicy securityPolicy, SystemSupport systemSupport, AccessibilityTrace trace, WindowManagerInternal windowManagerInternal, SystemActionPerformer systemActionPerformer, AccessibilityWindowManager awm)243 UiAutomationService(Context context, AccessibilityServiceInfo accessibilityServiceInfo, 244 int id, Handler mainHandler, Object lock, 245 AccessibilitySecurityPolicy securityPolicy, 246 SystemSupport systemSupport, AccessibilityTrace trace, 247 WindowManagerInternal windowManagerInternal, 248 SystemActionPerformer systemActionPerformer, AccessibilityWindowManager awm) { 249 super(context, COMPONENT_NAME, accessibilityServiceInfo, id, mainHandler, lock, 250 securityPolicy, systemSupport, trace, windowManagerInternal, 251 systemActionPerformer, awm); 252 mMainHandler = mainHandler; 253 setDisplayTypes(DISPLAY_TYPE_DEFAULT | DISPLAY_TYPE_PROXY); 254 } 255 connectServiceUnknownThread()256 void connectServiceUnknownThread() { 257 // This needs to be done on the main thread 258 mMainHandler.post(() -> { 259 try { 260 final IAccessibilityServiceClient serviceInterface; 261 synchronized (mLock) { 262 serviceInterface = mServiceInterface; 263 if (serviceInterface == null) { 264 mService = null; 265 } else { 266 mService = mServiceInterface.asBinder(); 267 mService.linkToDeath(this, 0); 268 } 269 } 270 // If the serviceInterface is null, the UiAutomation has been shut down on 271 // another thread. 272 if (serviceInterface != null) { 273 if (mTrace.isA11yTracingEnabledForTypes( 274 AccessibilityTrace.FLAGS_ACCESSIBILITY_SERVICE_CLIENT)) { 275 mTrace.logTrace("UiAutomationService.connectServiceUnknownThread", 276 AccessibilityTrace.FLAGS_ACCESSIBILITY_SERVICE_CLIENT, 277 "serviceConnection=" + this + ";connectionId=" + mId 278 + "windowToken=" 279 + mOverlayWindowTokens.get(Display.DEFAULT_DISPLAY)); 280 } 281 serviceInterface.init(this, mId, 282 mOverlayWindowTokens.get(Display.DEFAULT_DISPLAY)); 283 } 284 } catch (RemoteException re) { 285 Slog.w(LOG_TAG, "Error initialized connection", re); 286 destroyUiAutomationService(); 287 } 288 }); 289 } 290 291 @Override binderDied()292 public void binderDied() { 293 destroyUiAutomationService(); 294 } 295 296 @Override hasRightsToCurrentUserLocked()297 protected boolean hasRightsToCurrentUserLocked() { 298 // Allow UiAutomation to work for any user 299 return true; 300 } 301 302 @Override supportsFlagForNotImportantViews(AccessibilityServiceInfo info)303 protected boolean supportsFlagForNotImportantViews(AccessibilityServiceInfo info) { 304 return true; 305 } 306 307 @Override dump(FileDescriptor fd, final PrintWriter pw, String[] args)308 public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) { 309 if (!DumpUtils.checkDumpPermission(mContext, LOG_TAG, pw)) return; 310 synchronized (mLock) { 311 pw.append("Ui Automation[eventTypes=" 312 + AccessibilityEvent.eventTypeToString(mEventTypes)); 313 pw.append(", notificationTimeout=" + mNotificationTimeout); 314 pw.append("]"); 315 } 316 } 317 318 // Since this isn't really an accessibility service, several methods are just stubbed here. 319 @Override setSoftKeyboardShowMode(int mode)320 public boolean setSoftKeyboardShowMode(int mode) { 321 return false; 322 } 323 324 @Override getSoftKeyboardShowMode()325 public int getSoftKeyboardShowMode() { 326 return 0; 327 } 328 329 @Override switchToInputMethod(String imeId)330 public boolean switchToInputMethod(String imeId) { 331 return false; 332 } 333 334 @Override setInputMethodEnabled(String imeId, boolean enabled)335 public int setInputMethodEnabled(String imeId, boolean enabled) { 336 return AccessibilityService.SoftKeyboardController.ENABLE_IME_FAIL_UNKNOWN; 337 } 338 339 @Override isAccessibilityButtonAvailable()340 public boolean isAccessibilityButtonAvailable() { 341 return false; 342 } 343 344 @Override disableSelf()345 public void disableSelf() {} 346 347 @Override onServiceConnected(ComponentName componentName, IBinder service)348 public void onServiceConnected(ComponentName componentName, IBinder service) {} 349 350 @Override onServiceDisconnected(ComponentName componentName)351 public void onServiceDisconnected(ComponentName componentName) {} 352 353 @Override isCapturingFingerprintGestures()354 public boolean isCapturingFingerprintGestures() { 355 return false; 356 } 357 358 @Override onFingerprintGestureDetectionActiveChanged(boolean active)359 public void onFingerprintGestureDetectionActiveChanged(boolean active) {} 360 361 @Override onFingerprintGesture(int gesture)362 public void onFingerprintGesture(int gesture) {} 363 364 @Override takeScreenshot(int displayId, RemoteCallback callback)365 public void takeScreenshot(int displayId, RemoteCallback callback) {} 366 } 367 } 368