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