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