Android AccessibilityService源码分析

AccessibilityService首先你要继承AccessibilityService,你会被要求复写 onKeyEvent、onIntercept、onAccessibilityEvent等方法。我们看这些方法在AccessibilityService中是如何实现的。

public class AccessBackKeyService extends AccessibilityService {
        private static final String TAG = "jason";

        @Override
        protected boolean onKeyEvent(KeyEvent event) {
            Log.i(TAG, "onKeyEvent");

            if(event.getAction() == KeyEvent.ACTION_DOWN){
                return super.onKeyEvent(event);
            }
            Log.i(TAG, "onKeyEvent ACTION_DOWN");

            int key = event.getKeyCode();
            switch(key){
                case KeyEvent.KEYCODE_VOLUME_DOWN:
                    Log.i(TAG, "KEYCODE_VOLUME_DOWN");
                    break;
                case KeyEvent.KEYCODE_VOLUME_UP:
                    Log.i(TAG, "KEYCODE_VOLUME_UP");
                    Toast.makeText(this, "KEYCODE_VOLUME_UP", Toast.LENGTH_SHORT).show();
                    break;
                case KeyEvent.KEYCODE_BACK:

                    Log.i(TAG, "KEYCODE_BACK");
                    Toast.makeText(this, "KEYCODE_BACK, source:"+event.getSource(), Toast.LENGTH_SHORT).show();
                    break;
                case KeyEvent.KEYCODE_ESCAPE:
                    Log.i(TAG, "KEYCODE_ESCAPE");
                    Toast.makeText(this, "KEYCODE_ESCAPE", Toast.LENGTH_SHORT).show();
                    break;
            }
            return super.onKeyEvent(event);
        }



        @Override
        public void onInterrupt() {

        }

        @Override
        public void onCreate() {
            super.onCreate();
        }

        @Override
        public void onAccessibilityEvent(AccessibilityEvent event) {
            // TODO Auto-generated method stub

        }

    @Override
    protected boolean onGesture(int gestureId) {
        Log.i("jason", "onGesture:"+gestureId);
        return super.onGesture(gestureId);
    }
}



我们看到AccessibilityService中有一个接口


/**
 * @hide
 */
public interface Callbacks {
    public void onAccessibilityEvent(AccessibilityEvent event);
    public void onInterrupt();
    public void onServiceConnected();
    public void init(int connectionId, IBinder windowToken);
    public boolean onGesture(int gestureId);
    public boolean onKeyEvent(KeyEvent event);
    public void onMagnificationChanged(@NonNull Region region,
            float scale, float centerX, float centerY);
    public void onSoftKeyboardShowModeChanged(int showMode);
    public void onPerformGestureResult(int sequence, boolean completedSuccessfully);
}



AccessibilityService利用观察者模式的形式将自己封装进一个IAccessibilityServiceClientWrapper内部类中,在onBind方法中实现,猜测在辅助功能打开开关的时候,onBind这个方法将被调用,一会我们从源码分析,先分析一下
IAccessibilityServiceClientWrapper



@Override
public final IBinder onBind(Intent intent) {
    return new IAccessibilityServiceClientWrapper(this, getMainLooper(), new Callbacks() {
        @Override
        public void onServiceConnected() {
            AccessibilityService.this.dispatchServiceConnected();
        }

        @Override
        public void onInterrupt() {
            AccessibilityService.this.onInterrupt();
        }

        @Override
        public void onAccessibilityEvent(AccessibilityEvent event) {
            AccessibilityService.this.onAccessibilityEvent(event);
        }

        @Override
        public void init(int connectionId, IBinder windowToken) {
            mConnectionId = connectionId;
            mWindowToken = windowToken;

            // The client may have already obtained the window manager, so
            // update the default token on whatever manager we gave them.
            final WindowManagerImpl wm = (WindowManagerImpl) getSystemService(WINDOW_SERVICE);
            wm.setDefaultToken(windowToken);
        }

        @Override
        public boolean onGesture(int gestureId) {
            return AccessibilityService.this.onGesture(gestureId);
        }

        @Override
        public boolean onKeyEvent(KeyEvent event) {
            return AccessibilityService.this.onKeyEvent(event);
        }

        @Override
        public void onMagnificationChanged(@NonNull Region region,
                float scale, float centerX, float centerY) {
            AccessibilityService.this.onMagnificationChanged(region, scale, centerX, centerY);
        }

        @Override
        public void onSoftKeyboardShowModeChanged(int showMode) {
            AccessibilityService.this.onSoftKeyboardShowModeChanged(showMode);
        }

        @Override
        public void onPerformGestureResult(int sequence, boolean completedSuccessfully) {
            AccessibilityService.this.onPerformGestureResult(sequence, completedSuccessfully);
        }
    });
}



IAccessibilityServiceClientWrapper采用了AIDL的方式,通过继承
IAccessibilityServiceClient.Stub方式,将自己设为进程间通信的服务端,那么代理Proxy在哪里?


public static class IAccessibilityServiceClientWrapper extends IAccessibilityServiceClient.Stub
        implements HandlerCaller.Callback {
...

    private final HandlerCaller mCaller;

    private final Callbacks mCallback;

    private int mConnectionId;

    public IAccessibilityServiceClientWrapper(Context context, Looper looper,
            Callbacks callback) {
        mCallback = callback;
        mCaller = new HandlerCaller(context, looper, this, true /*asyncHandler*/);
    }

    public void init(IAccessibilityServiceConnection connection, int connectionId,
            IBinder windowToken) {
        Message message = mCaller.obtainMessageIOO(DO_INIT, connectionId,
                connection, windowToken);
        mCaller.sendMessage(message);
    }

    public void onInterrupt() {
        Message message = mCaller.obtainMessage(DO_ON_INTERRUPT);
        mCaller.sendMessage(message);
    }

    public void onAccessibilityEvent(AccessibilityEvent event) {
        Message message = mCaller.obtainMessageO(DO_ON_ACCESSIBILITY_EVENT, event);
        mCaller.sendMessage(message);
    }

...

    @Override
    public void onKeyEvent(KeyEvent event, int sequence) {
        Message message = mCaller.obtainMessageIO(DO_ON_KEY_EVENT, sequence, event);
        mCaller.sendMessage(message);
    }



搜索源码我们在AccessibilityManagerService中找到了实现,在init中connectId返回给AccessibilityService,AccessibilityManagerService是在SystemService中启动的系统服务,和ActivityManagerService是一个等级的系统服务。


  @Override
        public void onServiceConnected(ComponentName componentName, IBinder service) {
            synchronized (mLock) {
                if (mService != service) {
                    if (mService != null) {
                        mService.unlinkToDeath(this, 0);
                    }
                    mService = service;
                    try {
                        mService.linkToDeath(this, 0);
                    } catch (RemoteException re) {
                        Slog.e(LOG_TAG, "Failed registering death link");
                        binderDied();
                        return;
                    }
                }
                mServiceInterface = IAccessibilityServiceClient.Stub.asInterface(service);
                UserState userState = getUserStateLocked(mUserId);
                addServiceLocked(this, userState);
                if (userState.mBindingServices.contains(mComponentName) || mWasConnectedAndDied) {
                    userState.mBindingServices.remove(mComponentName);
                    mWasConnectedAndDied = false;
                    try {
                       mServiceInterface.init(this, mId, mOverlayWindowToken);
                       onUserStateChangedLocked(userState);
                    } catch (RemoteException re) {
                        Slog.w(LOG_TAG, "Error while setting connection for service: "
                                + service, re);
                        binderDied();
                    }
                } else {
                    binderDied();
                }
            }
        }



它是
IAccessibilityManager进程间通信
的服务端,那么Proxy端一定就是我们要找的产生AccessibilityService事件的地方。
 

public class AccessibilityManagerService extends IAccessibilityManager.Stub

  private void tryConnectToServiceLocked(IAccessibilityManager service) {
        if (service == null) {
            IBinder iBinder = ServiceManager.getService(Context.ACCESSIBILITY_SERVICE);
            if (iBinder == null) {
                return;
            }
            service = IAccessibilityManager.Stub.asInterface(iBinder);
        }

        try {
            final int stateFlags = service.addClient(mClient, mUserId);
            setStateLocked(stateFlags);
            mService = service;
        } catch (RemoteException re) {
            Log.e(LOG_TAG, "AccessibilityManagerService is dead", re);
        }
    }

我们找到了AccessibilityManager, 
AccessibilityManager这个类在所有的View属性的类中都能找到它的影子,View的变化都会通过这个类来通知AccessibilityManagerService这里,再通过内部对象mServiceInterface回调给我们的AccessibilityService,过程分析完毕。


下面我们再验证一下前面留下的一个坑,AccessibilityService的onBind方法是在哪里调用的。
每当我们在辅助功能里打开或者关闭时,我们是怎么通知AccessibilityManagerService呢,AccessibilityManagerService肯定不可能轮询,而应该是采用观察者的模式,我们找到注册广播的地方。

private void registerBroadcastReceivers() {
        PackageMonitor monitor = new PackageMonitor() {
            @Override
            public void onSomePackagesChanged() {
                synchronized (mLock) {
                    // Only the profile parent can install accessibility services.
                    // Therefore we ignore packages from linked profiles.
                    if (getChangingUserId() != mCurrentUserId) {
                        return;
                    }
                    // We will update when the automation service dies.
                    UserState userState = getCurrentUserStateLocked();
                    // We have to reload the installed services since some services may
                    // have different attributes, resolve info (does not support equals),
                    // etc. Remove them then to force reload.
                    userState.mInstalledServices.clear();
                    if (!userState.isUiAutomationSuppressingOtherServices()) {
                        if (readConfigurationForUserStateLocked(userState)) {
                            onUserStateChangedLocked(userState);
                        }
                    }
                }
            }

发现有一个PackageMonitor的类,每当发生了变化,都会调用onUserStateChangedLocked这个方法

   /**
     * Called when any property of the user state has changed.
     *
     * @param userState the new user state
     */
    private void onUserStateChangedLocked(UserState userState) {
        // TODO: Remove this hack
        mInitialized = true;
        updateLegacyCapabilitiesLocked(userState);
        updateServicesLocked(userState);
        updateWindowsForAccessibilityCallbackLocked(userState);
        updateAccessibilityFocusBehaviorLocked(userState);
        updateFilterKeyEventsLocked(userState);
        updateTouchExplorationLocked(userState);
        updatePerformGesturesLocked(userState);
        updateEnhancedWebAccessibilityLocked(userState);
        updateDisplayDaltonizerLocked(userState);
        updateDisplayInversionLocked(userState);
        updateMagnificationLocked(userState);
        updateSoftKeyboardShowModeLocked(userState);
        scheduleUpdateInputFilter(userState);
        scheduleUpdateClientsIfNeededLocked(userState);
    }

之后updateServicesLocked直到调用了mContext.bindServiceAsUser,之后我们定义的AccessibilityService的onBind就被调用,之后就建立了通信,填坑完毕。

 private void updateServicesLocked(UserState userState) {
        Map<ComponentName, Service> componentNameToServiceMap =
                userState.mComponentNameToServiceMap;
        boolean isUnlockingOrUnlocked = mContext.getSystemService(UserManager.class)
                .isUserUnlockingOrUnlocked(userState.mUserId);

        for (int i = 0, count = userState.mInstalledServices.size(); i < count; i++) {
            AccessibilityServiceInfo installedService = userState.mInstalledServices.get(i);
            ComponentName componentName = ComponentName.unflattenFromString(
                    installedService.getId());

            Service service = componentNameToServiceMap.get(componentName);

            // Ignore non-encryption-aware services until user is unlocked
            if (!isUnlockingOrUnlocked && !installedService.isDirectBootAware()) {
                Slog.d(LOG_TAG, "Ignoring non-encryption-aware service " + componentName);
                continue;
            }

            // Wait for the binding if it is in process.
            if (userState.mBindingServices.contains(componentName)) {
                continue;
            }
            if (userState.mEnabledServices.contains(componentName)) {
                if (service == null) {
                    service = new Service(userState.mUserId, componentName, installedService);
                } else if (userState.mBoundServices.contains(service)) {
                    continue;
                }
                service.bindLocked();
            } else {
                if (service != null) {
                    service.unbindLocked();
                }
            }
        }

        updateAccessibilityEnabledSetting(userState);
    }
  public boolean bindLocked() {
            UserState userState = getUserStateLocked(mUserId);
            if (!mIsAutomation) {
                final long identity = Binder.clearCallingIdentity();
                try {
                    if (mService == null && mContext.bindServiceAsUser(
                            mIntent, this,
                            Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE,
                            new UserHandle(mUserId))) {
                        userState.mBindingServices.add(mComponentName);
                    }
                } finally {
                    Binder.restoreCallingIdentity(identity);
                }
            } else {
                userState.mBindingServices.add(mComponentName);
                mMainHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        // Simulate asynchronous connection since in onServiceConnected
                        // we may modify the state data in case of an error but bind is
                        // called while iterating over the data and bad things can happen.
                        onServiceConnected(mComponentName,
                                userState.mUiAutomationServiceClient.asBinder());
                    }
                });
                userState.mUiAutomationService = this;
            }
            return false;
        }
    原文作者:Android源码分析
    原文地址: https://blog.csdn.net/jasonwang18/article/details/57113053
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞