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