• 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 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