• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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