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