Android_Input分析

本文详细剖析了Android 2.3.7版本的Input子系统架构,包括驱动、Native层和Java层的InputManager组件。介绍了Input事件的处理流程及自动化测试工具Monkey和Monkeyrunner的工作原理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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 日志的方法 在 Android 中,Input Manager Service (IMS) 是负责处理输入事件的核心组件之一。要解析和分析与 `Input` 相关的日志,可以通过以下方式实现: #### 1. 使用 Logcat 工具捕获日志 Logcat 是 Android 提供的一个强大的工具,用于捕获设备上的运行时日志信息。对于 `InputManagerService` 的调试,可以过滤特定标签或优先级来获取相关日志。 命令如下: ```bash adb logcat | grep "Input" ``` 此命令会筛选出所有包含关键字 `"Input"` 的日志条目[^1]。如果需要更精确的过滤,还可以指定日志级别(如 DEBUG 或 VERBOSE),例如: ```bash adb logcat -v threadtime Input:V *:S ``` 上述命令仅显示来自 `Input` 类别的详细日志,并屏蔽其他无关类别。 --- #### 2. 配置 Debug 参数以启用额外日志 某些情况下,默认日志可能不足以满足需求。可以在启动系统服务之前设置环境变量或者修改源码配置文件,强制开启更多详细的调试信息。 例如,在 AOSP 源码中找到 `InputManagerService.java` 文件并调整其内部的 LOG_TAG 定义为 true 来增加输出量: ```java private static final boolean DEBUG = true; ``` 重新编译项目后部署到目标设备上即可获得增强版日志记录功能。 --- #### 3. 利用 Memory Logs 进行深入剖析 除了常规的日志打印外,当遇到复杂场景比如卡顿现象或是异常崩溃时,则需借助内存快照技术进一步诊断原因所在。按照先前提到过的关于 **Android 内存日志** 实践指南[^2] ,能够有效定位潜在瓶颈位置以及评估整体表现状况。 具体操作步骤包括但不限于导出 HPROF 数据包、加载至 MAT(Heap Analyzer Tools)界面查看对象分配链路图谱等等手段相结合完成全面审查工作流。 --- #### 示例代码片段展示如何自定义拦截器抓取按键动作轨迹 下面给出一段简单的 Java 示例程序演示怎样创建广播接收者监听全局范围内的键盘敲击行为并向控制台发送通知消息: ```java public class KeyEventListener extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if ("android.intent.action.KEY_EVENT".equals(action)) { KeyEvent event = (KeyEvent)intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT); int keyCode = event.getKeyCode(); long timestamp = System.currentTimeMillis(); Log.d("KeyEventListener", "KeyCode:" + keyCode + ", Timestamp:" + timestamp); } } } ``` 注册该类实例以便实时响应各类物理按钮触发信号变化过程从而便于后续统计汇总用途。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值