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