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