android跨进程事件注入(程序模拟用户输入)
轉(zhuǎn)載請注明出處
早想寫這篇,一直沒空,現(xiàn)在總結(jié)下。
需求:
需要在程序內(nèi)模擬用戶輸入,比如點(diǎn)擊屏幕,或者輸入鍵盤。模擬用戶的滑動等。具體的需求,比如測試的時(shí)候,測試打開瀏覽器1000次。或者通過網(wǎng)絡(luò)發(fā)送命令給手機(jī),在手機(jī)上執(zhí)行點(diǎn)擊或者輸入。再或者,平板和藍(lán)牙鼠標(biāo)通過藍(lán)牙通信,通過鼠標(biāo)讓平板上的鼠標(biāo)能移動和點(diǎn)擊。這些都需要用到事件注入。
分析:
模擬用戶輸入的方式有幾種,一是monkeyrunner,這個的原理是在PC上,通過python調(diào)用android的一些包,然后通過機(jī)器的調(diào)試端口和機(jī)器通信,機(jī)器接收到相應(yīng)的命令后再往硬件寫入相應(yīng)的事件。這個常用語測試。并且,不是所有的機(jī)器都開了調(diào)試端口,并且需要連接PC。二是IwindowManager的injectInputEventNoWait,這個調(diào)用方便,也很簡單,但是從1.5(1.6?)后android系統(tǒng)做了限制,不允許跨進(jìn)程注入,這個方法只能在自己這個程序內(nèi)用,home出去就不行了。三是直接往linux底層/dev/input/event*寫事件,這個實(shí)現(xiàn)起來復(fù)雜,需要root權(quán)限,但是卻能實(shí)現(xiàn)跨進(jìn)程,比如藍(lán)牙鼠標(biāo)的需求,也只能用這種方法實(shí)現(xiàn)。講這個具體實(shí)現(xiàn)的不多,本文詳細(xì)介紹下。對linux了解些的人應(yīng)該一看就懂知道怎么回事。android上實(shí)現(xiàn)只不過有些地方比較繞而已。
1.android界面點(diǎn)擊事件流程。
有必要先說下android界面捕獲事件的流程。用戶在屏幕上點(diǎn)擊一下后,程序里面的OnClickListener是怎樣收到這個事件的。大致流程如下
用戶點(diǎn)擊-(硬件驅(qū)動部分)硬件產(chǎn)生一個中斷,往/dev/input/event*寫入一個相應(yīng)的信號->jni部分,android循環(huán)讀取/dev/input/event*的事件,再分發(fā)給WindowManagerServer,最后再發(fā)到相應(yīng)的ViewGroup和View。這里可以通過往/dev/input/event*寫信號的方式,來達(dá)到模擬事件的目的,接下來關(guān)心的就是信號的協(xié)議了。
2.按鍵協(xié)議分析
連接手機(jī),adb shell,輸入getevent,關(guān)掉手機(jī)的自動旋轉(zhuǎn)屏幕,按一下手機(jī)的menu鍵,會看到類似如下輸出。
linux上的硬件會分別對應(yīng)/dev/input/event*,這里的*一般是0-9的數(shù)字,getevent開頭那部分已經(jīng)顯示,event2是keypad,event1是touchscreen等。
最下面的0001 008b 00000001分別叫做type,code,value。
參考linux input,type 對應(yīng) 【#define EV_KEY 0x01】,code 對應(yīng)【#define KEY_MENU 139】(8b == 139),value 1表示按下,0表示松開。那么按鍵的協(xié)議就很清楚了,試著在adb shell里面輸入“sendevent /dev/input/event2 0 139 1”和”sendevent /dev/input/event2 0 139 2“后發(fā)現(xiàn)menu彈出來了,和按鍵的效果一樣。
3.觸摸協(xié)議分析
ok,來點(diǎn)復(fù)雜的。觸摸協(xié)議稍微麻煩點(diǎn),分單點(diǎn)觸摸和多點(diǎn)觸摸。
先說單點(diǎn)觸摸,打開模擬器。同樣關(guān)閉自動旋屏,進(jìn)入adb shell。鼠標(biāo)點(diǎn)擊一下屏幕,要足夠快,不然數(shù)據(jù)太多。得到輸出和下面類似。
?
可以看到模擬器上的設(shè)備數(shù)少了很多,單點(diǎn)觸摸的協(xié)議每次點(diǎn)擊會寫6條信號。參考linux_input對應(yīng)的值以及分析分別如下?
/dev/input/event0: 0003 0000 00000117???EV_ABS??ABS_X? 0x117
觸摸點(diǎn)的x坐標(biāo)
/dev/input/event0: 0003 0001 0000020f????EV_ABS??ABS_Y? 0x20f
觸摸點(diǎn)的y坐標(biāo)
/dev/input/event0: 0001 014a 00000001?? EV_KEY??BTN_TOUCH?1
touch down
/dev/input/event0: 0000 0000 00000000???EV_SYN 0 0?
同步信號量
/dev/input/event0: 0001 014a 00000000?? EV_KEY??BTN_TOUCH?0
touch up
/dev/input/event0: 0000 0000 00000000?? EV_SYN 0 0
同步信號量
使用4.0的模擬器,settings-developer options-show touches 和pointer locations勾上后,可以看到點(diǎn)擊的軌跡,adb shell后分別用sendevent輸入以上消息,可以看到屏幕上出現(xiàn)點(diǎn)擊效果。
再看多點(diǎn)觸摸協(xié)議,使用adb shell 進(jìn)入手機(jī),關(guān)掉旋屏,getevent后快速點(diǎn)一下屏幕,可以看到類似如下輸出。(每個廠商的協(xié)議可能不同,以下數(shù)據(jù)為小米1的)
第一個坐標(biāo)
/dev/input/event1: 0003 0039 00000000 EV_ABS ABS_MT_TRACKING_ID 0
/dev/input/event1: 0003 0035 000001b0 EV_ABS ABS_MT_POSITION_X 0x1b0
/dev/input/event1: 0003 0036 000000d7 EV_ABS ABS_MT_POSITION_Y 0xd7
/dev/input/event1: 0003 003a 00000001 EV_ABS? ABS_MT_PRESSURE 0x1
/dev/input/event1: 0003 0032 00000001 EV_ABS ABS_MT_WIDTH_MAJOR 0x1
/dev/input/event1: 0000 0002 00000000 EV_SYN SYN_MT_REPORT 0
/dev/input/event1: 0000 0000 00000000 EV_SYN SYN_REPORT 0
第二個坐標(biāo)
/dev/input/event1: 0003 0039 00000000 EV_ABS ABS_MT_TRACKING_ID 0
/dev/input/event1: 0003 0035 000001b0 EV_ABS ABS_MT_POSITION_X 0x1b0
/dev/input/event1: 0003 0036 000000d7 EV_ABS ABS_MT_POSITION_Y 0xd7
/dev/input/event1: 0003 003a 00000001 EV_ABS? ABS_MT_PRESSURE 0x1
/dev/input/event1: 0003 0032 00000001 EV_ABS ABS_MT_WIDTH_MAJOR 0x1
/dev/input/event1: 0000 0002 00000000 EV_SYN SYN_MT_REPORT 0
/dev/input/event1: 0000 0000 00000000 EV_SYN SYN_REPORT 0
第三個坐標(biāo)
/dev/input/event1: 0003 0039 00000000 EV_ABS ABS_MT_TRACKING_ID 0
/dev/input/event1: 0003 0035 00000191 EV_ABS ABS_MT_POSITION_X 0x191
/dev/input/event1: 0003 0036 00000098 EV_ABS ABS_MT_POSITION_Y 0x98
/dev/input/event1: 0003 003a 00000001 EV_ABS? ABS_MT_PRESSURE 0x1
/dev/input/event1: 0003 0032 00000001 EV_ABS ABS_MT_WIDTH_MAJOR 0x1
/dev/input/event1: 0000 0002 00000000 EV_SYN SYN_MT_REPORT 0
/dev/input/event1: 0000 0000 00000000 EV_SYN SYN_REPORT 0
松開
/dev/input/event1: 0000 0002 00000000 EV_SYN SYN_MT_REPORT 0
/dev/input/event1: 0000 0000 00000000 EV_SYN SYN_REPORT 0
這里是一次點(diǎn)擊,注意到ABS_MT_TRACKING_ID都是一樣的。系統(tǒng)檢測到三個點(diǎn),每次會發(fā)送點(diǎn)的x,y,以及收到的壓力,觸摸的范圍。最后兩條表示松開這個點(diǎn)。如果兩個手指同時(shí)點(diǎn)擊,可以發(fā)現(xiàn)ABS_MT_TRACKING_ID會有兩個不同的值,分別是兩個點(diǎn)。據(jù)說最多支持5點(diǎn)。
每個廠商實(shí)現(xiàn)協(xié)議不一樣。htc g3如下
/dev/input/event1: 0003 003a 002a0002
/dev/input/event1: 0003 0039 8b8c0ddc
/dev/input/event1: 0003 003a 00000002
/dev/input/event1: 0003 0039 8bac0dde
/dev/input/event1: 0003 003a 00000000
/dev/input/event1: 0003 0039 802814b1
4.可能遇到的問題
實(shí)際實(shí)現(xiàn)的時(shí)候,還可能遇到問題
一是root,getevent和sendevent需要/dev/input/event*的權(quán)限。一般應(yīng)用是沒有這個權(quán)限的,需要在程序里面獲取su后,執(zhí)行chmod 666 /dev/input/event*。
二是設(shè)備名稱。因?yàn)槟悴恢烙|摸屏或者按鍵到底對應(yīng)的event*是多少。需要有一個初始化的過程,大致思路是往event0-event9分別寫入按鍵和觸摸信號,同時(shí)監(jiān)聽activity里的onkeydown和view的onclick,這樣來偵測設(shè)備。
三是廠商的實(shí)現(xiàn)不一樣,這個沒辦法,只能一個一個適配了,一般來說都還是標(biāo)準(zhǔn)的,有些廠商會有單獨(dú)的實(shí)現(xiàn)。
參考
http://lxr.free-electrons.com/source/include/uapi/linux/input.h#L803
http://source.android.com/tech/input/touch-devices.html
http://cjix.info/blog/misc/internal-input-event-handling-in-the-linux-kernel-and-the-android-userspace/
總結(jié)
以上是生活随笔為你收集整理的android跨进程事件注入(程序模拟用户输入)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 2019首套房贷款利率是多少?现在买房合
- 下一篇: qt for v210