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