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