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