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.AccessibilityServiceInfo; 20 import android.accessibilityservice.AccessibilityTrace; 21 import android.accessibilityservice.IAccessibilityServiceClient; 22 import android.annotation.Nullable; 23 import android.app.UiAutomation; 24 import android.content.ComponentName; 25 import android.content.Context; 26 import android.os.Handler; 27 import android.os.IBinder; 28 import android.os.IBinder.DeathRecipient; 29 import android.os.RemoteCallback; 30 import android.os.RemoteException; 31 import android.util.Slog; 32 import android.view.Display; 33 import android.view.accessibility.AccessibilityEvent; 34 35 import com.android.internal.util.DumpUtils; 36 import com.android.server.wm.WindowManagerInternal; 37 38 import java.io.FileDescriptor; 39 import java.io.PrintWriter; 40 41 /** 42 * Class to manage UiAutomation. 43 */ 44 class UiAutomationManager { 45 private static final ComponentName COMPONENT_NAME = 46 new ComponentName("com.android.server.accessibility", "UiAutomation"); 47 private static final String LOG_TAG = "UiAutomationManager"; 48 49 private final Object mLock; 50 51 private UiAutomationService mUiAutomationService; 52 53 private AccessibilityServiceInfo mUiAutomationServiceInfo; 54 55 private AbstractAccessibilityServiceConnection.SystemSupport mSystemSupport; 56 57 private AccessibilityTrace mTrace; 58 59 private int mUiAutomationFlags; 60 UiAutomationManager(Object lock)61 UiAutomationManager(Object lock) { 62 mLock = lock; 63 } 64 65 private IBinder mUiAutomationServiceOwner; 66 private final DeathRecipient mUiAutomationServiceOwnerDeathRecipient = 67 new DeathRecipient() { 68 @Override 69 public void binderDied() { 70 mUiAutomationServiceOwner.unlinkToDeath(this, 0); 71 mUiAutomationServiceOwner = null; 72 destroyUiAutomationService(); 73 Slog.v(LOG_TAG, "UiAutomation service owner died"); 74 } 75 }; 76 77 /** 78 * Register a UiAutomation if it uses the accessibility subsystem. Only one may be registered 79 * at a time. 80 * 81 * @param owner A binder object owned by the process that owns the UiAutomation to be 82 * registered. 83 * @param serviceClient The UiAutomation's service interface. 84 * @param accessibilityServiceInfo The UiAutomation's service info 85 * @param flags The UiAutomation's flags 86 * @param id The id for the service connection 87 * @see UiAutomation#FLAG_DONT_USE_ACCESSIBILITY 88 */ 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)89 void registerUiTestAutomationServiceLocked(IBinder owner, 90 IAccessibilityServiceClient serviceClient, 91 Context context, AccessibilityServiceInfo accessibilityServiceInfo, 92 int id, Handler mainHandler, 93 AccessibilitySecurityPolicy securityPolicy, 94 AbstractAccessibilityServiceConnection.SystemSupport systemSupport, 95 AccessibilityTrace trace, 96 WindowManagerInternal windowManagerInternal, 97 SystemActionPerformer systemActionPerformer, 98 AccessibilityWindowManager awm, int flags) { 99 synchronized (mLock) { 100 accessibilityServiceInfo.setComponentName(COMPONENT_NAME); 101 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 mTrace = trace; 119 // Ignore registering UiAutomation if it is not allowed to use the accessibility 120 // subsystem. 121 if (!useAccessibility()) { 122 return; 123 } 124 mUiAutomationService = new UiAutomationService(context, accessibilityServiceInfo, id, 125 mainHandler, mLock, securityPolicy, systemSupport, trace, windowManagerInternal, 126 systemActionPerformer, awm); 127 mUiAutomationServiceOwner = owner; 128 mUiAutomationServiceInfo = accessibilityServiceInfo; 129 mUiAutomationService.mServiceInterface = serviceClient; 130 mUiAutomationService.onAdded(); 131 try { 132 mUiAutomationService.mServiceInterface.asBinder().linkToDeath(mUiAutomationService, 133 0); 134 } catch (RemoteException re) { 135 Slog.e(LOG_TAG, "Failed registering death link: " + re); 136 destroyUiAutomationService(); 137 return; 138 } 139 140 mUiAutomationService.connectServiceUnknownThread(); 141 } 142 } 143 unregisterUiTestAutomationServiceLocked(IAccessibilityServiceClient serviceClient)144 void unregisterUiTestAutomationServiceLocked(IAccessibilityServiceClient serviceClient) { 145 synchronized (mLock) { 146 if (useAccessibility() 147 && ((mUiAutomationService == null) 148 || (serviceClient == null) 149 || (mUiAutomationService.mServiceInterface == null) 150 || (serviceClient.asBinder() 151 != mUiAutomationService.mServiceInterface.asBinder()))) { 152 throw new IllegalStateException("UiAutomationService " + serviceClient 153 + " not registered!"); 154 } 155 destroyUiAutomationService(); 156 } 157 } 158 sendAccessibilityEventLocked(AccessibilityEvent event)159 void sendAccessibilityEventLocked(AccessibilityEvent event) { 160 if (mUiAutomationService != null) { 161 mUiAutomationService.notifyAccessibilityEvent(event); 162 } 163 } 164 isUiAutomationRunningLocked()165 boolean isUiAutomationRunningLocked() { 166 return (mUiAutomationService != null || !useAccessibility()); 167 } 168 suppressingAccessibilityServicesLocked()169 boolean suppressingAccessibilityServicesLocked() { 170 return (mUiAutomationService != null || !useAccessibility()) 171 && ((mUiAutomationFlags 172 & UiAutomation.FLAG_DONT_SUPPRESS_ACCESSIBILITY_SERVICES) == 0); 173 } 174 useAccessibility()175 boolean useAccessibility() { 176 return ((mUiAutomationFlags & UiAutomation.FLAG_DONT_USE_ACCESSIBILITY) == 0); 177 } 178 isTouchExplorationEnabledLocked()179 boolean isTouchExplorationEnabledLocked() { 180 return (mUiAutomationService != null) 181 && mUiAutomationService.mRequestTouchExplorationMode; 182 } 183 canRetrieveInteractiveWindowsLocked()184 boolean canRetrieveInteractiveWindowsLocked() { 185 return (mUiAutomationService != null) && mUiAutomationService.mRetrieveInteractiveWindows; 186 } 187 getRequestedEventMaskLocked()188 int getRequestedEventMaskLocked() { 189 if (mUiAutomationService == null) return 0; 190 return mUiAutomationService.mEventTypes; 191 } 192 getRelevantEventTypes()193 int getRelevantEventTypes() { 194 UiAutomationService uiAutomationService; 195 synchronized (mLock) { 196 uiAutomationService = mUiAutomationService; 197 } 198 if (uiAutomationService == null) return 0; 199 return uiAutomationService.getRelevantEventTypes(); 200 } 201 202 @Nullable getServiceInfo()203 AccessibilityServiceInfo getServiceInfo() { 204 UiAutomationService uiAutomationService; 205 synchronized (mLock) { 206 uiAutomationService = mUiAutomationService; 207 } 208 if (uiAutomationService == null) return null; 209 return uiAutomationService.getServiceInfo(); 210 } 211 dumpUiAutomationService(FileDescriptor fd, final PrintWriter pw, String[] args)212 void dumpUiAutomationService(FileDescriptor fd, final PrintWriter pw, String[] args) { 213 UiAutomationService uiAutomationService; 214 synchronized (mLock) { 215 uiAutomationService = mUiAutomationService; 216 } 217 if (uiAutomationService != null) { 218 uiAutomationService.dump(fd, pw, args); 219 } 220 } 221 destroyUiAutomationService()222 private void destroyUiAutomationService() { 223 synchronized (mLock) { 224 if (mUiAutomationService != null) { 225 mUiAutomationService.mServiceInterface.asBinder().unlinkToDeath( 226 mUiAutomationService, 0); 227 mUiAutomationService.onRemoved(); 228 mUiAutomationService.resetLocked(); 229 mUiAutomationService = null; 230 if (mUiAutomationServiceOwner != null) { 231 mUiAutomationServiceOwner.unlinkToDeath( 232 mUiAutomationServiceOwnerDeathRecipient, 0); 233 mUiAutomationServiceOwner = null; 234 } 235 } 236 mUiAutomationFlags = 0; 237 mSystemSupport.onClientChangeLocked(false); 238 } 239 } 240 241 private class UiAutomationService extends AbstractAccessibilityServiceConnection { 242 private final Handler mMainHandler; 243 UiAutomationService(Context context, AccessibilityServiceInfo accessibilityServiceInfo, int id, Handler mainHandler, Object lock, AccessibilitySecurityPolicy securityPolicy, SystemSupport systemSupport, AccessibilityTrace trace, WindowManagerInternal windowManagerInternal, SystemActionPerformer systemActionPerformer, AccessibilityWindowManager awm)244 UiAutomationService(Context context, AccessibilityServiceInfo accessibilityServiceInfo, 245 int id, Handler mainHandler, Object lock, 246 AccessibilitySecurityPolicy securityPolicy, 247 SystemSupport systemSupport, AccessibilityTrace trace, 248 WindowManagerInternal windowManagerInternal, 249 SystemActionPerformer systemActionPerformer, AccessibilityWindowManager awm) { 250 super(context, COMPONENT_NAME, accessibilityServiceInfo, id, mainHandler, lock, 251 securityPolicy, systemSupport, trace, windowManagerInternal, 252 systemActionPerformer, awm); 253 mMainHandler = mainHandler; 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 isAccessibilityButtonAvailable()335 public boolean isAccessibilityButtonAvailable() { 336 return false; 337 } 338 339 @Override disableSelf()340 public void disableSelf() {} 341 342 @Override onServiceConnected(ComponentName componentName, IBinder service)343 public void onServiceConnected(ComponentName componentName, IBinder service) {} 344 345 @Override onServiceDisconnected(ComponentName componentName)346 public void onServiceDisconnected(ComponentName componentName) {} 347 348 @Override isCapturingFingerprintGestures()349 public boolean isCapturingFingerprintGestures() { 350 return false; 351 } 352 353 @Override onFingerprintGestureDetectionActiveChanged(boolean active)354 public void onFingerprintGestureDetectionActiveChanged(boolean active) {} 355 356 @Override onFingerprintGesture(int gesture)357 public void onFingerprintGesture(int gesture) {} 358 359 @Override takeScreenshot(int displayId, RemoteCallback callback)360 public void takeScreenshot(int displayId, RemoteCallback callback) {} 361 } 362 } 363