android底层事件注入,Monkey源代码分析番外篇之Android注入事件的三种方法比較

原文:http://www.pocketmagic.net/2012/04/injecting-events-programatically-on-android/#.VEoIoIuUcaV

往下分析monkey事件注入源代码之前先了解下在android系统下事件注入的方式。翻译一篇国外文章例如以下。

Method 1: Using internal APIs

方法1:使用内部APIs

This approach has its risks, like it is always with internal, unpublished APIs.

该方法和其它全部内部没有向外正式发布的APIs一样存在它自己的风险。

The idea is to get an instance of WindowManager in order to access the injectKeyEvent / injectPointerEvent methods.

原理是通过获得WindowManager的一个实例来訪问injectKeyEvent/injectPointerEvent这两个事件注入方法。

IBinder wmbinder = ServiceManager.getService( "window" );

IWindowManager m_WndManager = IWindowManager.Stub.asInterface( wmbinder );The ServiceManager and WindowsManager are defined as Stubs. We can then bind to these services and call the methods we need.

ServiceManager和Windowsmanager被定义为存根Stubs类。我们依据我们的须要绑定上这些服务并訪问里面的方法。

To send a key do the following:

通过下面方式发送一个事件:

// key down

m_WndManager.injectKeyEvent( new KeyEvent( KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_A ),true );

// key up

m_WndManager.injectKeyEvent( new KeyEvent( KeyEvent.ACTION_UP, KeyEvent.KEYCODE_A ),true );To send touch/mouse events use:

发送touch/mouse事件:

//pozx goes from 0 to SCREEN WIDTH , pozy goes from 0 to SCREEN HEIGHT

m_WndManager.injectPointerEvent(MotionEvent.obtain(SystemClock.uptimeMillis(),

SystemClock.uptimeMillis(),MotionEvent.ACTION_DOWN,pozx, pozy, 0), true);

m_WndManager.injectPointerEvent(MotionEvent.obtain(SystemClock.uptimeMillis(),

SystemClock.uptimeMillis(),MotionEvent.ACTION_UP,pozx, pozy, 0), true);This works fine, but only inside your application

这样的方法能在你的应用中非常好的工作,但,也只只能在你的应用中而已

41569649d7912d4af7078094083de6ae.png

The moment you're trying to inject keys/touch events to any other window, you'll get a force close because of the following exception:

一旦你想要往其它窗体注入keys/touch事件,你将会得到一个强制关闭的消息:

ea72c5143a403d24402f2c33d625f991.png

E/AndroidRuntime(4908): java.lang.SecurityException: Injecting to another application requires INJECT_EVENTS permissionNot much joy, as INJECT_EVENTS is a system permission. A possible solution is discussed here and here.

苦逼了吧,毕竟INJECT_EVENTS是须要系统权限的,一些可能解决的方案在这里和这里有讨论到。

Method 2: Using an instrumentation object

方法2: 使用instrumentation对象

This is a clean solution based on public API, but unfortunately it still requires that INJECT_EVENTS permission.

相对以上的隐藏接口和方法,这个是比較干净(上面的是隐藏的。故须要用到android不干净不推荐的方法去获取)的方式,但不幸的事它依旧有上面的JINECT_EVENTS这个仅仅有系统应用(基本上就是android自己提供的,如monkey)才被同意的权限问题。

Instrumentation m_Instrumentation = new Instrumentation();

m_Instrumentation.sendKeyDownUpSync( KeyEvent.KEYCODE_B );For touch events you can use:

下面是触摸事件实例:

//pozx goes from 0 to SCREEN WIDTH , pozy goes from 0 to SCREEN HEIGHT

m_Instrumentation.sendPointerSync(MotionEvent.obtain(SystemClock.uptimeMillis(),

SystemClock.uptimeMillis(),MotionEvent.ACTION_DOWN,pozx, pozy, 0);

m_Instrumentation.sendPointerSync(MotionEvent.obtain(SystemClock.uptimeMillis(),

SystemClock.uptimeMillis(),MotionEvent.ACTION_UP,pozx, pozy, 0);SouthEast

All good inside the test application, and will crash instantly when trying to inject keys to outside apps, not because the approach doesn't work, but because Android Developers have chosen so. Thanks guys, you rock! Not.

在应用内操作的话全然没有问题,但一旦跳出这个应用去触发按键事件的话就会崩溃。不是由于这种方法不工作,而是由于android开发人员做了限制。谢谢你们,android的开发人员们,你牛逼!

个屁。

By looking at sendPointerSync's code, you will quickly see it uses the same approach as presented in method 1). So this is the same thing, but packed nicely in a easy to use API:

通过分析sendPointerSync的相应代码。能够看到事实上instrumentation使用到的注入事件方式事实上和方法一提到的通过WindowManager.injectPointerEvents是一样的。所以穿的都是同一条内裤,仅仅是Robotium出来走动的时候套上条时尚喇叭裤。而以上直接调用WindowManager的方式就宛如仅仅穿一条内裤出街的差别而已。

public void sendPointerSync(MotionEvent event) {

validateNotAppThread();

try {

(IWindowManager.Stub.asInterface(ServiceManager.getService("window")))

.injectPointerEvent(event, true);

} catch (RemoteException e) {

}

}

Method 3: Direct event injection to /dev/input/eventX

方法3:直接注入事件到设备/dev/input/eventX

Linux exposes a uniform input event interface for each device as /dev/input/eventX where X is an integer. We can use it directly and skip the above Android Platform permission issues.

linux以系统设备的方式向用户暴露了一套统一的事件注入接口/dev/input/eventX(当中X代表一个整数)。

我们能够直接跳用而跳过以上的平台(android这个机遇linux的平台)限制问题。

For this to work, we will need root access, so this approach only works on a rooted device.

可是这须要工作的话,你须要rooted过的设备。

By default the eventX files have the permission set for 660 (read and write for Owner and Group only). To inject keys from our application, we need to make it writable. So do this first:

设备文件eventX默认是被设置为660这个权限的(Owner和同组成员有读写,而owner是root)。为了向这个设备注入事件。你必须让它能可写。所以请先做下面动作:

bf794256ee043795dd18d822f95cef53.png

adb shell

su

chmod 666 /dev/input/event3You will need root to run the chmod command.

你将须要root权限来执行chmod命令。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值