Android 7.0以上Accessibility Service DispatchGesture调用流程

5,640 阅读2分钟

概述

Accessibility Service被广泛用于各类自动点击的app,但早期,它并没有提供丰富的API,受到控件的高度约束,能达成的效果与Instrumentation相去甚远。 Android 7.0中,AccessibilityService新加入了dispatchGesture API,开发者可以使用它在屏幕上进行高度定制化的操作,例如点击屏幕上的任意坐标。

网络上已经有大量对performAccessibilityAction相关API的源码分析,但很多人对dispatchGesture知之甚少。因此我对它的调用路径稍作分析,以便于开发和对抗。

对每个部分的源代码,我会附上AOSP的源码链接和关键代码的截图。

源码分析

入口函数:AccessibilityService::dispatchGesture (AccessibilityService.java)

调用逻辑:

connection在此处初始化:

dispatchGesture方法通过Binder调用sendGesture方法。 该connection对象定义在IAccessibilityServiceConnection.aidl(IAccessibilityServiceConnection.aidl)当中。

实现了该stub的类是AbstractAccessibilityServiceConnection(AbstractAccessibilityServiceConnection)

不了解Stub与aidl的朋友,可以先去找一些Binder与Android IPC的文章补习一下相关知识。

AbstractAccessibilityServiceConnection是一个抽象类,它的实现在AccessibilityServiceConnection(AccessibilityServiceConnection)当中。 其中sendGesture方法的实现调用了motionEventInject对象的InjectEvents方法

此对象是通过mSystemSupport获得的

mSystemSupport的初始化在AbstractAccessibilityServiceConnection类的构造函数当中:通过一个传入的对象初始化。

AccessibilityManagerService中可以看到,

传入的SystemSupport对象实际上就是this,也就是AccessibilityManagerService本身。

回过头去查看它的getMotionEventInjectorLocked方法: 它返回了一个成员。按照setMotionEventInjector的注释,这个成员在AccessibilityInputFilter当中初始化。

查看AccessibilityInputFilter(AccessibilityInputFilter.java),它的初始化确实就是那么简单,没有什么额外的花样。

再回到MotionEventInjector::injectEvents,其实现如下: MotionEventInjector.java

它调用了一个handler,这个handler的在构造函数中被初始化,Handler.callback就是这个类本身。

handleMessage函数就在这个类里:

sendMotionEventToNext会将事件传递给下一个handler,不过我们可以先关注injectEventsMainThread

它拆分了event,最终还是通过mHandler处理单个的事件。于是又回到了handleMessage函数,这次需要着重分析的就是sendMotionEventToNext了。

super.onMotionEvent应当是核心。 此方法的实现在EventStreamTransformation(EventStreamTransformation.java)当中。

后续会触发一个链式调用。调用的并非MotionEventInjector,而是AccessibilityInputFilter初始化时设置的handler。

查看AccessibilityInputFilteronMotionEvent方法,可以看到:

此处调用的是父类InputFilterInputFilter中的sendInputEvent方法。

最终会通过IInputFilterHost发起一个Binder调用。 实现了这个IInputFilterHost.stub的是InputManagerService(InputManagerService.java)。

从这里往后,注入事件的流程就跟Instrumentation相同了。感兴趣的朋友可以去阅读分析Instrumentation事件注入源码的文章。