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 static android.accessibilityservice.AccessibilityService.SoftKeyboardController.ENABLE_IME_FAIL_UNKNOWN;
20 import static android.accessibilityservice.AccessibilityService.SoftKeyboardController.ENABLE_IME_SUCCESS;
21 
22 import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
23 
24 import android.Manifest;
25 import android.accessibilityservice.AccessibilityService;
26 import android.accessibilityservice.AccessibilityServiceInfo;
27 import android.accessibilityservice.AccessibilityTrace;
28 import android.accessibilityservice.IAccessibilityServiceClient;
29 import android.accessibilityservice.TouchInteractionController;
30 import android.app.PendingIntent;
31 import android.content.ComponentName;
32 import android.content.Context;
33 import android.content.Intent;
34 import android.content.pm.ParceledListSlice;
35 import android.os.Binder;
36 import android.os.Handler;
37 import android.os.IBinder;
38 import android.os.Message;
39 import android.os.Process;
40 import android.os.RemoteException;
41 import android.os.UserHandle;
42 import android.provider.Settings;
43 import android.util.Slog;
44 import android.view.Display;
45 import android.view.MotionEvent;
46 
47 
48 import com.android.server.inputmethod.InputMethodManagerInternal;
49 import com.android.server.wm.ActivityTaskManagerInternal;
50 import com.android.server.wm.WindowManagerInternal;
51 
52 import java.lang.ref.WeakReference;
53 import java.util.Set;
54 
55 /**
56  * This class represents an accessibility service. It stores all per service
57  * data required for the service management, provides API for starting/stopping the
58  * service and is responsible for adding/removing the service in the data structures
59  * for service management. The class also exposes configuration interface that is
60  * passed to the service it represents as soon it is bound. It also serves as the
61  * connection for the service.
62  */
63 class AccessibilityServiceConnection extends AbstractAccessibilityServiceConnection {
64     private static final String LOG_TAG = "AccessibilityServiceConnection";
65 
66     /*
67      Holding a weak reference so there isn't a loop of references. AccessibilityUserState keeps
68      lists of bound and binding services. These are freed on user changes, but just in case it
69      somehow gets lost the weak reference will let the memory get GCed.
70 
71      Having the reference be null when being called is a very bad sign, but we check the condition.
72     */
73     final WeakReference<AccessibilityUserState> mUserStateWeakReference;
74     final Intent mIntent;
75     final ActivityTaskManagerInternal mActivityTaskManagerService;
76 
77     private final Handler mMainHandler;
78 
AccessibilityServiceConnection(AccessibilityUserState userState, Context context, ComponentName componentName, AccessibilityServiceInfo accessibilityServiceInfo, int id, Handler mainHandler, Object lock, AccessibilitySecurityPolicy securityPolicy, SystemSupport systemSupport, AccessibilityTrace trace, WindowManagerInternal windowManagerInternal, SystemActionPerformer systemActionPerfomer, AccessibilityWindowManager awm, ActivityTaskManagerInternal activityTaskManagerService)79     AccessibilityServiceConnection(AccessibilityUserState userState, Context context,
80             ComponentName componentName,
81             AccessibilityServiceInfo accessibilityServiceInfo, int id, Handler mainHandler,
82             Object lock, AccessibilitySecurityPolicy securityPolicy, SystemSupport systemSupport,
83             AccessibilityTrace trace, WindowManagerInternal windowManagerInternal,
84             SystemActionPerformer systemActionPerfomer, AccessibilityWindowManager awm,
85             ActivityTaskManagerInternal activityTaskManagerService) {
86         super(context, componentName, accessibilityServiceInfo, id, mainHandler, lock,
87                 securityPolicy, systemSupport, trace, windowManagerInternal, systemActionPerfomer,
88                 awm);
89         mUserStateWeakReference = new WeakReference<AccessibilityUserState>(userState);
90         mIntent = new Intent().setComponent(mComponentName);
91         mMainHandler = mainHandler;
92         mIntent.putExtra(Intent.EXTRA_CLIENT_LABEL,
93                 com.android.internal.R.string.accessibility_binding_label);
94         mActivityTaskManagerService = activityTaskManagerService;
95         final long identity = Binder.clearCallingIdentity();
96         try {
97             mIntent.putExtra(Intent.EXTRA_CLIENT_INTENT, mSystemSupport.getPendingIntentActivity(
98                     mContext, 0, new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS),
99                     PendingIntent.FLAG_IMMUTABLE));
100         } finally {
101             Binder.restoreCallingIdentity(identity);
102         }
103     }
104 
bindLocked()105     public void bindLocked() {
106         AccessibilityUserState userState = mUserStateWeakReference.get();
107         if (userState == null) return;
108         final long identity = Binder.clearCallingIdentity();
109         try {
110             int flags = Context.BIND_AUTO_CREATE
111                     | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE
112                     | Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS
113                     | Context.BIND_INCLUDE_CAPABILITIES;
114             if (userState.getBindInstantServiceAllowedLocked()) {
115                 flags |= Context.BIND_ALLOW_INSTANT;
116             }
117             if (mService == null && mContext.bindServiceAsUser(
118                     mIntent, this, flags, new UserHandle(userState.mUserId))) {
119                 userState.getBindingServicesLocked().add(mComponentName);
120             }
121         } finally {
122             Binder.restoreCallingIdentity(identity);
123         }
124         mActivityTaskManagerService.setAllowAppSwitches(mComponentName.flattenToString(),
125                 mAccessibilityServiceInfo.getResolveInfo().serviceInfo.applicationInfo.uid,
126                 userState.mUserId);
127     }
128 
unbindLocked()129     public void unbindLocked() {
130         if (requestImeApis()) {
131             mSystemSupport.unbindImeLocked(this);
132         }
133         mContext.unbindService(this);
134         AccessibilityUserState userState = mUserStateWeakReference.get();
135         if (userState == null) return;
136         userState.removeServiceLocked(this);
137         mSystemSupport.getMagnificationProcessor().resetAllIfNeeded(mId);
138         mActivityTaskManagerService.setAllowAppSwitches(mComponentName.flattenToString(), -1,
139                 userState.mUserId);
140         resetLocked();
141     }
142 
canRetrieveInteractiveWindowsLocked()143     public boolean canRetrieveInteractiveWindowsLocked() {
144         return mSecurityPolicy.canRetrieveWindowContentLocked(this) && mRetrieveInteractiveWindows;
145     }
146 
147     @Override
disableSelf()148     public void disableSelf() {
149         if (svcConnTracingEnabled()) {
150             logTraceSvcConn("disableSelf", "");
151         }
152         synchronized (mLock) {
153             AccessibilityUserState userState = mUserStateWeakReference.get();
154             if (userState == null) return;
155             if (userState.getEnabledServicesLocked().remove(mComponentName)) {
156                 final long identity = Binder.clearCallingIdentity();
157                 try {
158                     mSystemSupport.persistComponentNamesToSettingLocked(
159                             Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
160                             userState.getEnabledServicesLocked(), userState.mUserId);
161                 } finally {
162                     Binder.restoreCallingIdentity(identity);
163                 }
164                 mSystemSupport.onClientChangeLocked(false);
165             }
166         }
167     }
168 
169     @Override
onServiceConnected(ComponentName componentName, IBinder service)170     public void onServiceConnected(ComponentName componentName, IBinder service) {
171         synchronized (mLock) {
172             if (mService != service) {
173                 if (mService != null) {
174                     mService.unlinkToDeath(this, 0);
175                 }
176                 mService = service;
177                 try {
178                     mService.linkToDeath(this, 0);
179                 } catch (RemoteException re) {
180                     Slog.e(LOG_TAG, "Failed registering death link");
181                     binderDied();
182                     return;
183                 }
184             }
185             mServiceInterface = IAccessibilityServiceClient.Stub.asInterface(service);
186             AccessibilityUserState userState = mUserStateWeakReference.get();
187             if (userState == null) return;
188             userState.addServiceLocked(this);
189             mSystemSupport.onClientChangeLocked(false);
190             // Initialize the service on the main handler after we're done setting up for
191             // the new configuration (for example, initializing the input filter).
192             mMainHandler.sendMessage(obtainMessage(
193                     AccessibilityServiceConnection::initializeService, this));
194             if (requestImeApis()) {
195                 mSystemSupport.requestImeLocked(this);
196             }
197         }
198     }
199 
200     @Override
getServiceInfo()201     public AccessibilityServiceInfo getServiceInfo() {
202         return mAccessibilityServiceInfo;
203     }
204 
initializeService()205     private void initializeService() {
206         IAccessibilityServiceClient serviceInterface = null;
207         synchronized (mLock) {
208             AccessibilityUserState userState = mUserStateWeakReference.get();
209             if (userState == null) return;
210             final Set<ComponentName> bindingServices = userState.getBindingServicesLocked();
211             final Set<ComponentName> crashedServices = userState.getCrashedServicesLocked();
212             if (bindingServices.contains(mComponentName)
213                     || crashedServices.contains(mComponentName)) {
214                 bindingServices.remove(mComponentName);
215                 crashedServices.remove(mComponentName);
216                 mAccessibilityServiceInfo.crashed = false;
217                 serviceInterface = mServiceInterface;
218             }
219             // There's a chance that service is removed from enabled_accessibility_services setting
220             // key, but skip unbinding because of it's in binding state. Unbinds it if it's
221             // not in enabled service list.
222             if (serviceInterface != null
223                     && !userState.getEnabledServicesLocked().contains(mComponentName)) {
224                 mSystemSupport.onClientChangeLocked(false);
225                 return;
226             }
227         }
228         if (serviceInterface == null) {
229             binderDied();
230             return;
231         }
232         try {
233             if (svcClientTracingEnabled()) {
234                 logTraceSvcClient("init",
235                         this + "," + mId + "," + mOverlayWindowTokens.get(Display.DEFAULT_DISPLAY));
236             }
237             serviceInterface.init(this, mId, mOverlayWindowTokens.get(Display.DEFAULT_DISPLAY));
238         } catch (RemoteException re) {
239             Slog.w(LOG_TAG, "Error while setting connection for service: "
240                     + serviceInterface, re);
241             binderDied();
242         }
243     }
244 
245     @Override
onServiceDisconnected(ComponentName componentName)246     public void onServiceDisconnected(ComponentName componentName) {
247         binderDied();
248         AccessibilityUserState userState = mUserStateWeakReference.get();
249         if (userState != null) {
250             mActivityTaskManagerService.setAllowAppSwitches(mComponentName.flattenToString(), -1,
251                     userState.mUserId);
252         }
253     }
254 
255     @Override
hasRightsToCurrentUserLocked()256     protected boolean hasRightsToCurrentUserLocked() {
257         // We treat calls from a profile as if made by its parent as profiles
258         // share the accessibility state of the parent. The call below
259         // performs the current profile parent resolution.
260         final int callingUid = Binder.getCallingUid();
261         if (callingUid == Process.ROOT_UID
262                 || callingUid == Process.SYSTEM_UID
263                 || callingUid == Process.SHELL_UID) {
264             return true;
265         }
266         if (mSecurityPolicy.resolveProfileParentLocked(UserHandle.getUserId(callingUid))
267                 == mSystemSupport.getCurrentUserIdLocked()) {
268             return true;
269         }
270         if (mSecurityPolicy.hasPermission(Manifest.permission.INTERACT_ACROSS_USERS)
271                 || mSecurityPolicy.hasPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL)) {
272             return true;
273         }
274         return false;
275     }
276 
277     @Override
setSoftKeyboardShowMode(int showMode)278     public boolean setSoftKeyboardShowMode(int showMode) {
279         if (svcConnTracingEnabled()) {
280             logTraceSvcConn("setSoftKeyboardShowMode", "showMode=" + showMode);
281         }
282         synchronized (mLock) {
283             if (!hasRightsToCurrentUserLocked()) {
284                 return false;
285             }
286             final AccessibilityUserState userState = mUserStateWeakReference.get();
287             if (userState == null) return false;
288             return userState.setSoftKeyboardModeLocked(showMode, mComponentName);
289         }
290     }
291 
292     @Override
getSoftKeyboardShowMode()293     public int getSoftKeyboardShowMode() {
294         if (svcConnTracingEnabled()) {
295             logTraceSvcConn("getSoftKeyboardShowMode", "");
296         }
297         final AccessibilityUserState userState = mUserStateWeakReference.get();
298         return (userState != null) ? userState.getSoftKeyboardShowModeLocked() : 0;
299     }
300 
301     @Override
switchToInputMethod(String imeId)302     public boolean switchToInputMethod(String imeId) {
303         if (svcConnTracingEnabled()) {
304             logTraceSvcConn("switchToInputMethod", "imeId=" + imeId);
305         }
306         synchronized (mLock) {
307             if (!hasRightsToCurrentUserLocked()) {
308                 return false;
309             }
310         }
311         final boolean result;
312         final int callingUserId = UserHandle.getCallingUserId();
313         final long identity = Binder.clearCallingIdentity();
314         try {
315             result = InputMethodManagerInternal.get().switchToInputMethod(imeId, callingUserId);
316         } finally {
317             Binder.restoreCallingIdentity(identity);
318         }
319         return result;
320     }
321 
322     @Override
323     @AccessibilityService.SoftKeyboardController.EnableImeResult
setInputMethodEnabled(String imeId, boolean enabled)324     public int setInputMethodEnabled(String imeId, boolean enabled) throws SecurityException {
325         if (svcConnTracingEnabled()) {
326             logTraceSvcConn("switchToInputMethod", "imeId=" + imeId);
327         }
328         synchronized (mLock) {
329             if (!hasRightsToCurrentUserLocked()) {
330                 return ENABLE_IME_FAIL_UNKNOWN;
331             }
332         }
333 
334         final int callingUserId = UserHandle.getCallingUserId();
335         final InputMethodManagerInternal inputMethodManagerInternal =
336                 InputMethodManagerInternal.get();
337 
338         final @AccessibilityService.SoftKeyboardController.EnableImeResult int checkResult;
339         final long identity = Binder.clearCallingIdentity();
340         try {
341             synchronized (mLock) {
342                 checkResult = mSecurityPolicy.canEnableDisableInputMethod(imeId, this);
343             }
344             if (checkResult != ENABLE_IME_SUCCESS) {
345                 return checkResult;
346             }
347             if (inputMethodManagerInternal.setInputMethodEnabled(imeId,
348                         enabled, callingUserId)) {
349                 return ENABLE_IME_SUCCESS;
350             }
351         } finally {
352             Binder.restoreCallingIdentity(identity);
353         }
354         return ENABLE_IME_FAIL_UNKNOWN;
355     }
356 
357     @Override
isAccessibilityButtonAvailable()358     public boolean isAccessibilityButtonAvailable() {
359         if (svcConnTracingEnabled()) {
360             logTraceSvcConn("isAccessibilityButtonAvailable", "");
361         }
362         synchronized (mLock) {
363             if (!hasRightsToCurrentUserLocked()) {
364                 return false;
365             }
366             AccessibilityUserState userState = mUserStateWeakReference.get();
367             return (userState != null) && isAccessibilityButtonAvailableLocked(userState);
368         }
369     }
370 
371     @Override
binderDied()372     public void binderDied() {
373         synchronized (mLock) {
374             // It is possible that this service's package was force stopped during
375             // whose handling the death recipient is unlinked and still get a call
376             // on binderDied since the call was made before we unlink but was
377             // waiting on the lock we held during the force stop handling.
378             if (!isConnectedLocked()) {
379                 return;
380             }
381             if (requestImeApis()) {
382                 mSystemSupport.unbindImeLocked(this);
383             }
384             mAccessibilityServiceInfo.crashed = true;
385             AccessibilityUserState userState = mUserStateWeakReference.get();
386             if (userState != null) {
387                 userState.serviceDisconnectedLocked(this);
388             }
389             resetLocked();
390             mSystemSupport.getMagnificationProcessor().resetAllIfNeeded(mId);
391             mSystemSupport.onClientChangeLocked(false);
392         }
393     }
394 
isAccessibilityButtonAvailableLocked(AccessibilityUserState userState)395     public boolean isAccessibilityButtonAvailableLocked(AccessibilityUserState userState) {
396         // If the service does not request the accessibility button, it isn't available
397         if (!mRequestAccessibilityButton) {
398             return false;
399         }
400         // If the accessibility button isn't currently shown, it cannot be available to services
401         if (!mSystemSupport.isAccessibilityButtonShown()) {
402             return false;
403         }
404         return true;
405     }
406 
407     @Override
isCapturingFingerprintGestures()408     public boolean isCapturingFingerprintGestures() {
409         return (mServiceInterface != null)
410                 && mSecurityPolicy.canCaptureFingerprintGestures(this)
411                 && mCaptureFingerprintGestures;
412     }
413 
414     @Override
onFingerprintGestureDetectionActiveChanged(boolean active)415     public void onFingerprintGestureDetectionActiveChanged(boolean active) {
416         if (!isCapturingFingerprintGestures()) {
417             return;
418         }
419         IAccessibilityServiceClient serviceInterface;
420         synchronized (mLock) {
421             serviceInterface = mServiceInterface;
422         }
423         if (serviceInterface != null) {
424             try {
425                 if (svcClientTracingEnabled()) {
426                     logTraceSvcClient(
427                             "onFingerprintCapturingGesturesChanged", String.valueOf(active));
428                 }
429                 mServiceInterface.onFingerprintCapturingGesturesChanged(active);
430             } catch (RemoteException e) {
431             }
432         }
433     }
434 
435     @Override
onFingerprintGesture(int gesture)436     public void onFingerprintGesture(int gesture) {
437         if (!isCapturingFingerprintGestures()) {
438             return;
439         }
440         IAccessibilityServiceClient serviceInterface;
441         synchronized (mLock) {
442             serviceInterface = mServiceInterface;
443         }
444         if (serviceInterface != null) {
445             try {
446                 if (svcClientTracingEnabled()) {
447                     logTraceSvcClient("onFingerprintGesture", String.valueOf(gesture));
448                 }
449                 mServiceInterface.onFingerprintGesture(gesture);
450             } catch (RemoteException e) {
451             }
452         }
453     }
454 
455     @Override
dispatchGesture(int sequence, ParceledListSlice gestureSteps, int displayId)456     public void dispatchGesture(int sequence, ParceledListSlice gestureSteps, int displayId) {
457         synchronized (mLock) {
458             if (mServiceInterface != null && mSecurityPolicy.canPerformGestures(this)) {
459                 MotionEventInjector motionEventInjector =
460                         mSystemSupport.getMotionEventInjectorForDisplayLocked(displayId);
461                 if (wmTracingEnabled()) {
462                     logTraceWM("isTouchOrFaketouchDevice", "");
463                 }
464                 if (motionEventInjector != null
465                         && mWindowManagerService.isTouchOrFaketouchDevice()) {
466                     motionEventInjector.injectEvents(
467                             gestureSteps.getList(), mServiceInterface, sequence, displayId);
468                 } else {
469                     try {
470                         if (svcClientTracingEnabled()) {
471                             logTraceSvcClient("onPerformGestureResult", sequence + ", false");
472                         }
473                         mServiceInterface.onPerformGestureResult(sequence, false);
474                     } catch (RemoteException re) {
475                         Slog.e(LOG_TAG, "Error sending motion event injection failure to "
476                                 + mServiceInterface, re);
477                     }
478                 }
479             }
480         }
481     }
482 
483     @Override
setFocusAppearance(int strokeWidth, int color)484     public void setFocusAppearance(int strokeWidth, int color) {
485         AccessibilityUserState userState = mUserStateWeakReference.get();
486         if (userState == null) {
487             return;
488         }
489 
490         synchronized (mLock) {
491             if (!hasRightsToCurrentUserLocked()) {
492                 return;
493             }
494 
495             if (!mSecurityPolicy.checkAccessibilityAccess(this)) {
496                 return;
497             }
498 
499             if (userState.getFocusStrokeWidthLocked() == strokeWidth
500                     && userState.getFocusColorLocked() == color) {
501                 return;
502             }
503 
504             // Sets the appearance data in the A11yUserState.
505             userState.setFocusAppearanceLocked(strokeWidth, color);
506             // Updates the appearance data in the A11yManager.
507             mSystemSupport.onClientChangeLocked(false);
508         }
509     }
510 
notifyMotionEvent(MotionEvent event)511     public void notifyMotionEvent(MotionEvent event) {
512         final Message msg = obtainMessage(
513                 AccessibilityServiceConnection::notifyMotionEventInternal,
514                 AccessibilityServiceConnection.this, event);
515         mMainHandler.sendMessage(msg);
516     }
517 
notifyTouchState(int displayId, int state)518     public void notifyTouchState(int displayId, int state) {
519         final Message msg = obtainMessage(
520                 AccessibilityServiceConnection::notifyTouchStateInternal,
521                 AccessibilityServiceConnection.this, displayId, state);
522         mMainHandler.sendMessage(msg);
523     }
524 
requestImeApis()525     public boolean requestImeApis() {
526         return mRequestImeApis;
527     }
528 
notifyMotionEventInternal(MotionEvent event)529     private void notifyMotionEventInternal(MotionEvent event) {
530         final IAccessibilityServiceClient listener = getServiceInterfaceSafely();
531         if (listener != null) {
532             try {
533                 if (mTrace.isA11yTracingEnabled()) {
534                     logTraceSvcClient(".onMotionEvent ",
535                             event.toString());
536                 }
537                 listener.onMotionEvent(event);
538             } catch (RemoteException re) {
539                 Slog.e(LOG_TAG, "Error sending motion event to" + mService, re);
540             }
541         }
542     }
543 
notifyTouchStateInternal(int displayId, int state)544     private void notifyTouchStateInternal(int displayId, int state) {
545         final IAccessibilityServiceClient listener = getServiceInterfaceSafely();
546         if (listener != null) {
547             try {
548                 if (mTrace.isA11yTracingEnabled()) {
549                     logTraceSvcClient(".onTouchStateChanged ",
550                             TouchInteractionController.stateToString(state));
551                 }
552                 listener.onTouchStateChanged(displayId, state);
553             } catch (RemoteException re) {
554                 Slog.e(LOG_TAG, "Error sending motion event to" + mService, re);
555             }
556         }
557     }
558 }
559