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