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