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.IAccessibilityServiceClient; 21 import android.annotation.Nullable; 22 import android.app.UiAutomation; 23 import android.content.ComponentName; 24 import android.content.Context; 25 import android.os.Handler; 26 import android.os.IBinder; 27 import android.os.IBinder.DeathRecipient; 28 import android.os.RemoteCallback; 29 import android.os.RemoteException; 30 import android.util.Slog; 31 import android.view.Display; 32 import android.view.accessibility.AccessibilityEvent; 33 34 import com.android.internal.util.DumpUtils; 35 import com.android.server.wm.WindowManagerInternal; 36 37 import java.io.FileDescriptor; 38 import java.io.PrintWriter; 39 40 /** 41 * Class to manage UiAutomation. 42 */ 43 class UiAutomationManager { 44 private static final ComponentName COMPONENT_NAME = 45 new ComponentName("com.android.server.accessibility", "UiAutomation"); 46 private static final String LOG_TAG = "UiAutomationManager"; 47 48 private final Object mLock; 49 50 private UiAutomationService mUiAutomationService; 51 52 private AccessibilityServiceInfo mUiAutomationServiceInfo; 53 54 private AbstractAccessibilityServiceConnection.SystemSupport mSystemSupport; 55 56 private AccessibilityTrace mTrace; 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 synchronized (mLock) { 99 accessibilityServiceInfo.setComponentName(COMPONENT_NAME); 100 101 if (mUiAutomationService != null) { 102 throw new IllegalStateException( 103 "UiAutomationService " + mUiAutomationService.mServiceInterface 104 + "already registered!"); 105 } 106 107 try { 108 owner.linkToDeath(mUiAutomationServiceOwnerDeathRecipient, 0); 109 } catch (RemoteException re) { 110 Slog.e(LOG_TAG, "Couldn't register for the death of a UiTestAutomationService!", 111 re); 112 return; 113 } 114 115 mUiAutomationFlags = flags; 116 mSystemSupport = systemSupport; 117 mTrace = trace; 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 mUiAutomationServiceInfo = accessibilityServiceInfo; 128 mUiAutomationService.mServiceInterface = serviceClient; 129 mUiAutomationService.onAdded(); 130 try { 131 mUiAutomationService.mServiceInterface.asBinder().linkToDeath(mUiAutomationService, 132 0); 133 } catch (RemoteException re) { 134 Slog.e(LOG_TAG, "Failed registering death link: " + re); 135 destroyUiAutomationService(); 136 return; 137 } 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 } 254 connectServiceUnknownThread()255 void connectServiceUnknownThread() { 256 // This needs to be done on the main thread 257 mMainHandler.post(() -> { 258 try { 259 final IAccessibilityServiceClient serviceInterface; 260 synchronized (mLock) { 261 serviceInterface = mServiceInterface; 262 if (serviceInterface == null) { 263 mService = null; 264 } else { 265 mService = mServiceInterface.asBinder(); 266 mService.linkToDeath(this, 0); 267 } 268 } 269 // If the serviceInterface is null, the UiAutomation has been shut down on 270 // another thread. 271 if (serviceInterface != null) { 272 serviceInterface.init(this, mId, 273 mOverlayWindowTokens.get(Display.DEFAULT_DISPLAY)); 274 } 275 } catch (RemoteException re) { 276 Slog.w(LOG_TAG, "Error initialized connection", re); 277 destroyUiAutomationService(); 278 } 279 }); 280 } 281 282 @Override binderDied()283 public void binderDied() { 284 destroyUiAutomationService(); 285 } 286 287 @Override hasRightsToCurrentUserLocked()288 protected boolean hasRightsToCurrentUserLocked() { 289 // Allow UiAutomation to work for any user 290 return true; 291 } 292 293 @Override supportsFlagForNotImportantViews(AccessibilityServiceInfo info)294 protected boolean supportsFlagForNotImportantViews(AccessibilityServiceInfo info) { 295 return true; 296 } 297 298 @Override dump(FileDescriptor fd, final PrintWriter pw, String[] args)299 public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) { 300 if (!DumpUtils.checkDumpPermission(mContext, LOG_TAG, pw)) return; 301 synchronized (mLock) { 302 pw.append("Ui Automation[eventTypes=" 303 + AccessibilityEvent.eventTypeToString(mEventTypes)); 304 pw.append(", notificationTimeout=" + mNotificationTimeout); 305 pw.append("]"); 306 } 307 } 308 309 // Since this isn't really an accessibility service, several methods are just stubbed here. 310 @Override setSoftKeyboardShowMode(int mode)311 public boolean setSoftKeyboardShowMode(int mode) { 312 return false; 313 } 314 315 @Override getSoftKeyboardShowMode()316 public int getSoftKeyboardShowMode() { 317 return 0; 318 } 319 320 @Override switchToInputMethod(String imeId)321 public boolean switchToInputMethod(String imeId) { 322 return false; 323 } 324 325 @Override isAccessibilityButtonAvailable()326 public boolean isAccessibilityButtonAvailable() { 327 return false; 328 } 329 330 @Override disableSelf()331 public void disableSelf() {} 332 333 @Override onServiceConnected(ComponentName componentName, IBinder service)334 public void onServiceConnected(ComponentName componentName, IBinder service) {} 335 336 @Override onServiceDisconnected(ComponentName componentName)337 public void onServiceDisconnected(ComponentName componentName) {} 338 339 @Override isCapturingFingerprintGestures()340 public boolean isCapturingFingerprintGestures() { 341 return false; 342 } 343 344 @Override onFingerprintGestureDetectionActiveChanged(boolean active)345 public void onFingerprintGestureDetectionActiveChanged(boolean active) {} 346 347 @Override onFingerprintGesture(int gesture)348 public void onFingerprintGesture(int gesture) {} 349 350 @Override takeScreenshot(int displayId, RemoteCallback callback)351 public void takeScreenshot(int displayId, RemoteCallback callback) {} 352 } 353 } 354