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 android.accessibilityservice.AccessibilityServiceInfo;
     20 import android.accessibilityservice.IAccessibilityServiceClient;
     21 import android.annotation.Nullable;
     22 import android.app.UiAutomation;
     23 import android.content.ComponentName;
     24 import android.content.Context;
     25 import android.os.Handler;
     26 import android.os.IBinder;
     27 import android.os.IBinder.DeathRecipient;
     28 import android.os.RemoteException;
     29 import android.util.Slog;
     30 import android.view.accessibility.AccessibilityEvent;
     31 
     32 import com.android.internal.util.DumpUtils;
     33 import com.android.server.wm.WindowManagerInternal;
     34 
     35 import java.io.FileDescriptor;
     36 import java.io.PrintWriter;
     37 
     38 /**
     39  * Class to manage UiAutomation.
     40  */
     41 class UiAutomationManager {
     42     private static final ComponentName COMPONENT_NAME =
     43             new ComponentName("com.android.server.accessibility", "UiAutomation");
     44     private static final String LOG_TAG = "UiAutomationManager";
     45 
     46     private UiAutomationService mUiAutomationService;
     47 
     48     private AccessibilityServiceInfo mUiAutomationServiceInfo;
     49 
     50     private AbstractAccessibilityServiceConnection.SystemSupport mSystemSupport;
     51 
     52     private int mUiAutomationFlags;
     53 
     54     private IBinder mUiAutomationServiceOwner;
     55     private final DeathRecipient mUiAutomationServiceOwnerDeathRecipient =
     56             new DeathRecipient() {
     57                 @Override
     58                 public void binderDied() {
     59                     mUiAutomationServiceOwner.unlinkToDeath(this, 0);
     60                     mUiAutomationServiceOwner = null;
     61                     if (mUiAutomationService != null) {
     62                         destroyUiAutomationService();
     63                     }
     64                 }
     65             };
     66 
     67     /**
     68      * Register a UiAutomation. Only one may be registered at a time.
     69      *
     70      * @param owner A binder object owned by the process that owns the UiAutomation to be
     71      *              registered.
     72      * @param serviceClient The UiAutomation's service interface.
     73      * @param accessibilityServiceInfo The UiAutomation's service info
     74      * @param flags The UiAutomation's flags
     75      * @param id The id for the service connection
     76      */
     77     void registerUiTestAutomationServiceLocked(IBinder owner,
     78             IAccessibilityServiceClient serviceClient,
     79             Context context, AccessibilityServiceInfo accessibilityServiceInfo,
     80             int id, Handler mainHandler, Object lock,
     81             AccessibilityManagerService.SecurityPolicy securityPolicy,
     82             AbstractAccessibilityServiceConnection.SystemSupport systemSupport,
     83             WindowManagerInternal windowManagerInternal,
     84             GlobalActionPerformer globalActionPerfomer, int flags) {
     85         accessibilityServiceInfo.setComponentName(COMPONENT_NAME);
     86 
     87         if (mUiAutomationService != null) {
     88             throw new IllegalStateException("UiAutomationService " + serviceClient
     89                     + "already registered!");
     90         }
     91 
     92         try {
     93             owner.linkToDeath(mUiAutomationServiceOwnerDeathRecipient, 0);
     94         } catch (RemoteException re) {
     95             Slog.e(LOG_TAG, "Couldn't register for the death of a UiTestAutomationService!", re);
     96             return;
     97         }
     98 
     99         mSystemSupport = systemSupport;
    100         mUiAutomationService = new UiAutomationService(context, accessibilityServiceInfo, id,
    101                 mainHandler, lock, securityPolicy, systemSupport, windowManagerInternal,
    102                 globalActionPerfomer);
    103         mUiAutomationServiceOwner = owner;
    104         mUiAutomationFlags = flags;
    105         mUiAutomationServiceInfo = accessibilityServiceInfo;
    106         mUiAutomationService.mServiceInterface = serviceClient;
    107         mUiAutomationService.onAdded();
    108         try {
    109             mUiAutomationService.mServiceInterface.asBinder().linkToDeath(mUiAutomationService, 0);
    110         } catch (RemoteException re) {
    111             Slog.e(LOG_TAG, "Failed registering death link: " + re);
    112             destroyUiAutomationService();
    113             return;
    114         }
    115 
    116         mUiAutomationService.connectServiceUnknownThread();
    117     }
    118 
    119     void unregisterUiTestAutomationServiceLocked(IAccessibilityServiceClient serviceClient) {
    120         if ((mUiAutomationService == null)
    121                 || (serviceClient == null)
    122                 || (mUiAutomationService.mServiceInterface == null)
    123                 || (serviceClient.asBinder()
    124                         != mUiAutomationService.mServiceInterface.asBinder())) {
    125             throw new IllegalStateException("UiAutomationService " + serviceClient
    126                     + " not registered!");
    127         }
    128 
    129         destroyUiAutomationService();
    130     }
    131 
    132     void sendAccessibilityEventLocked(AccessibilityEvent event) {
    133         if (mUiAutomationService != null) {
    134             mUiAutomationService.notifyAccessibilityEvent(event);
    135         }
    136     }
    137 
    138     boolean isUiAutomationRunningLocked() {
    139         return (mUiAutomationService != null);
    140     }
    141 
    142     boolean suppressingAccessibilityServicesLocked() {
    143         return (mUiAutomationService != null) && ((mUiAutomationFlags
    144                 & UiAutomation.FLAG_DONT_SUPPRESS_ACCESSIBILITY_SERVICES) == 0);
    145     }
    146 
    147     boolean isTouchExplorationEnabledLocked() {
    148         return (mUiAutomationService != null)
    149                 && mUiAutomationService.mRequestTouchExplorationMode;
    150     }
    151 
    152     boolean canRetrieveInteractiveWindowsLocked() {
    153         return (mUiAutomationService != null) && mUiAutomationService.mRetrieveInteractiveWindows;
    154     }
    155 
    156     int getRequestedEventMaskLocked() {
    157         if (mUiAutomationService == null) return 0;
    158         return mUiAutomationService.mEventTypes;
    159     }
    160 
    161     int getRelevantEventTypes() {
    162         if (mUiAutomationService == null) return 0;
    163         return mUiAutomationService.getRelevantEventTypes();
    164     }
    165 
    166     @Nullable
    167     AccessibilityServiceInfo getServiceInfo() {
    168         if (mUiAutomationService == null) return null;
    169         return mUiAutomationService.getServiceInfo();
    170     }
    171 
    172     void dumpUiAutomationService(FileDescriptor fd, final PrintWriter pw, String[] args) {
    173         if (mUiAutomationService != null) {
    174             mUiAutomationService.dump(fd, pw, args);
    175         }
    176     }
    177 
    178     private void destroyUiAutomationService() {
    179         mUiAutomationService.mServiceInterface.asBinder().unlinkToDeath(mUiAutomationService, 0);
    180         mUiAutomationService.onRemoved();
    181         mUiAutomationService.resetLocked();
    182         mUiAutomationService = null;
    183         mUiAutomationFlags = 0;
    184         if (mUiAutomationServiceOwner != null) {
    185             mUiAutomationServiceOwner.unlinkToDeath(mUiAutomationServiceOwnerDeathRecipient, 0);
    186             mUiAutomationServiceOwner = null;
    187         }
    188         mSystemSupport.onClientChange(false);
    189     }
    190 
    191     private class UiAutomationService extends AbstractAccessibilityServiceConnection {
    192         private final Handler mMainHandler;
    193 
    194         UiAutomationService(Context context, AccessibilityServiceInfo accessibilityServiceInfo,
    195                 int id, Handler mainHandler, Object lock,
    196                 AccessibilityManagerService.SecurityPolicy securityPolicy,
    197                 SystemSupport systemSupport, WindowManagerInternal windowManagerInternal,
    198                 GlobalActionPerformer globalActionPerfomer) {
    199             super(context, COMPONENT_NAME, accessibilityServiceInfo, id, mainHandler, lock,
    200                     securityPolicy, systemSupport, windowManagerInternal, globalActionPerfomer);
    201             mMainHandler = mainHandler;
    202         }
    203 
    204         void connectServiceUnknownThread() {
    205             // This needs to be done on the main thread
    206             mMainHandler.post(() -> {
    207                 try {
    208                     final IAccessibilityServiceClient serviceInterface;
    209                     final IBinder service;
    210                     synchronized (mLock) {
    211                         serviceInterface = mServiceInterface;
    212                         mService = (serviceInterface == null) ? null : mServiceInterface.asBinder();
    213                         service = mService;
    214                     }
    215                     // If the serviceInterface is null, the UiAutomation has been shut down on
    216                     // another thread.
    217                     if (serviceInterface != null) {
    218                         service.linkToDeath(this, 0);
    219                         serviceInterface.init(this, mId, mOverlayWindowToken);
    220                     }
    221                 } catch (RemoteException re) {
    222                     Slog.w(LOG_TAG, "Error initialized connection", re);
    223                     destroyUiAutomationService();
    224                 }
    225             });
    226         }
    227 
    228         @Override
    229         public void binderDied() {
    230             destroyUiAutomationService();
    231         }
    232 
    233         @Override
    234         protected boolean isCalledForCurrentUserLocked() {
    235             // Allow UiAutomation to work for any user
    236             return true;
    237         }
    238 
    239         @Override
    240         protected boolean supportsFlagForNotImportantViews(AccessibilityServiceInfo info) {
    241             return true;
    242         }
    243 
    244         @Override
    245         public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) {
    246             if (!DumpUtils.checkDumpPermission(mContext, LOG_TAG, pw)) return;
    247             synchronized (mLock) {
    248                 pw.append("Ui Automation[eventTypes="
    249                         + AccessibilityEvent.eventTypeToString(mEventTypes));
    250                 pw.append(", notificationTimeout=" + mNotificationTimeout);
    251                 pw.append("]");
    252             }
    253         }
    254 
    255         // Since this isn't really an accessibility service, several methods are just stubbed here.
    256         @Override
    257         public boolean setSoftKeyboardShowMode(int mode) {
    258             return false;
    259         }
    260 
    261         @Override
    262         public boolean isAccessibilityButtonAvailable() {
    263             return false;
    264         }
    265 
    266         @Override
    267         public void disableSelf() {}
    268 
    269         @Override
    270         public void onServiceConnected(ComponentName componentName, IBinder service) {}
    271 
    272         @Override
    273         public void onServiceDisconnected(ComponentName componentName) {}
    274 
    275         @Override
    276         public boolean isCapturingFingerprintGestures() {
    277             return false;
    278         }
    279 
    280         @Override
    281         public void onFingerprintGestureDetectionActiveChanged(boolean active) {}
    282 
    283         @Override
    284         public void onFingerprintGesture(int gesture) {}
    285     }
    286 }
    287