Android_Input分析

http://wenku.baidu.com/view/1f6650906bec0975f465e22f.html

Input Subsystem分析

 

Android2.3.7Input子系统由驱动、NativeInputManagerInputManager JNIJavaInputManager组成。

 

Input子系统的驱动被封装为字符设备,目录位于/dev/input,上层架构通过扫描该目录,得到输入设备,open()设备,read()来自底层驱动的输入事件,再由上层处理转发。

 

NativeInputManager有:

EventHub.cpp 使用poll机制,从字符设备获取事件。

 

InputReader.cpp 负责从EventHub获取事件并交给InputDispatcher进行分发。它有三个附属类协助其实现该层的功能,InputDeviceInputMapper(其子类有:SwitchInputMapperKeyboardInputMapperTouchInputMapperMouseInputMapperSingleTouchInputMapperMultiTouchInputMapper等各种输入类型的映射)将事件分类交给InputDispatcher。还有个InputReaderThread负责创建InputReader线程,由InputManager类管理,该线程会受到Poll机制的阻塞。

 

InputDispatcher.cpp负责将事件分发给Connection(即 foreground target,猜测是当前活动UI的代理)。他内部采用queue存储事件,并使用Looper类(使用epoll实现)实现对事件接收者的管理,一旦有事件来到,首先检查queue是否为空并插入事件,不空时立即唤醒Looper,进入事件处理循环。这里同样采用线程循环,名字是InputDispatcherThread,也是由InputManager类初始化,该线程同样会受到Poll机制的阻塞。InputDispatcher类比较复杂,其内部流程还不是很清楚,还有一些附属类尚未研究。

 

InputManager.cpp负责管理InputReaderThreadInputDispatcherThread线程,如它们的初始化、startstop

 

以上几个类都是从其相应的Interface抽象类继承下来的,表明它们是被作为独立的组件设计的,我们可以替换它们。但是JNI层依赖具体的InputManager2.3.7版本的InputManager实现比较简单,依附于WindowManager服务,4.0代码将InputManager也提升为一个service,可能输入响应要提高一个级别。

 

JNIInputManager有:

       com_android_server_InputManager.cpp负责初始化InputManager,向上面Java层提供Native调用。它继承自InputReaderPolicyInterfaceInputDispatcherPolicyInterface,并将自己作为参数传递给InputReaderInputDispatcher,大概是用来实现一些策略。

       它提供的功能很多,如registerInputChannel()函数提供给应用程序注册Input系统以实现事件输入,该机制被包装为InputChannel类,在Native层又被封装进Connection类,被Looper添加为事件接受者。

 

JavaInputManager有:

    InputManager.java几乎是对JNI层的封装,并为JNI提供了回调。它的初始化是在WindowManagerService的构造函数中,并在这里做一些Input子系统的初始化的工作,如设置display的大小。它是作为WindowManagerService的一个功能类来使用,基本上是又将InputManager.java封装了一次。其他附属类没有分析。

 

问题:InputManagerNativeC++代码没有入口函数,都是以线程的方式被上层Java框架经由JNI启动。问题是该线程所属的进程是谁?

 

 

自动化测试工具Monkey向系统插入Input事件的方法

 

Android2.3.7中的Monkey实现了三种途径向系统插入Input事件:

1.       随机生成Input事件,对应类为MonkeySourceRandom

2.       从脚本读取Input事件,对应类为MonkeySourceScript

3.       socket读取Input事件,对应类为MonkeySourceNetwork

 

这三个类均继承自MonkeyEventSource类,它们将从不同源获取到的event放进内部queue,在MonkeyrunMonkeyCycles()循环中取出这些event插入系统。

 

       代码:

       MonkeyEvent ev = mEventSource.getNextEvent();

            if (ev != null) {

                int injectCode = ev.injectEvent(mWm, mAm, mVerbose);

 

       这里还是实现了几种 MonkeyEvent模拟系统里面的Input Event,如MonkeyKeyEventMonkeyMotionEventMonkeyPowerEventMonkeyNoopEventMonkeyFlipEventMonkeyCommandEventMonkeyActivityEvent等。它们各自实现了 injectEvent()函数,因为是模拟事件,所以不是所有子类的都会向系统底层插入event

 

例如 MonkeyCommandEvent是执行一个命令,代码如下:

    public int injectEvent(IWindowManager iwm, IActivityManager iam, int verbose) {

        if (mCmd != null) {

            //Execute the shell command

            try {

                java.lang.Process p = Runtime.getRuntime().exec(mCmd);

                int status = p.waitFor();

                System.err.println("// Shell command " + mCmd + " status was " + status);

            } catch (Exception e) {

                System.err.println("// Exception from " + mCmd + ":");

                System.err.println(e.toString());

            }

        }

        return MonkeyEvent.INJECT_SUCCESS;

    }

 

向系统底层插入event的代码会这样写:iwm.injectKeyEvent(getEvent(), false) 插入的是Key事件。

androidJava层、JNI层、Native C++层都实现了类似的函数,它们是层层向下调用的关系,最终Input event会被插入到InputDispatcher的内部queue里面,进入事件分发循环。

 

从上至下依次实现:

1.       WindowManagerService.java中,injectKeyEvent()等;

2.       InputManager.java中,injectInputEvent()

3.       com_android_server_InputManager.cpp中,android_server_InputManager_nativeInjectInputEvent();

4.       InputDispatcher.cpp中,injectInputEvent()

 

 

自动化测试工具Monkeyrunner的工作方式

 

Monkeyrunner是基于ddmsMonkey开发的自动化测试工具,它使用Python作为脚本对自动化测试过程进行控制。有三个类实现其功能:

1.       MonkeyRunner PC端调用ddms库的功能,完成设备socket连接、adb初始化、向Monkey发送eventcommand、截屏等。在手机端由Monkey完成event的插入并执行一些command

2.       MonkeyRecorder XML格式记录执行过的commandevent,还提供了对记录脚本的打包功能,该脚本不是Python脚本,可用于Monkey的回放。

3.       ScriptRunner 负责加载Python脚本并执行它。

 

 

你可能感兴趣的:(Android_Input分析)