5

I've ditched MonkeyRunner for AndroidViewClient to benefit from its added reliability and simplicity of implementation (thank God for pure Python).

I need to perform several device.touch() events as fast as possible, however AndroidViewClient seems to achieve those significantly slower than MonkeyRunner.

Here's the code I used to time them both:

for iteration in range(1,6):
    ts_start = datetime.datetime.now()
    device.touch(1,1,'DOWN_AND_UP')
    chrono = datetime.datetime.now() - ts_start
    print str(iteration)+': '+str(chrono)

Here's MonkeyRunner's output:

1: 0:00:00.003000
2: 0:00:00.002001
3: 0:00:00.002001
4: 0:00:00.002001
5: 0:00:00.002000

Here's AVC's output:

1: 0:00:00.460000
2: 0:00:00.515000
3: 0:00:00.499000
4: 0:00:00.508000
5: 0:00:00.456000

That's about 200 times slower on average.

It seems like it's possible to store events in a binary file, then pushing and running it directly on the phone. However, I'd like to stick with a pure AVC approach.

Is that possible?

Edit:

Since it's not possible for now to achieve better performance the way I'd like to, I had to implement the event-files way like I mentioned.

I used two resources in order to do so:

Here is how one of those files looks like (truncated):

#!/bin/sh
sendevent /dev/input/event1 3 57 0
sendevent /dev/input/event1 3 55 0
sendevent /dev/input/event1 3 53 640
sendevent /dev/input/event1 3 54 900
sendevent /dev/input/event1 3 58 1
sendevent /dev/input/event1 0 2 0
sendevent /dev/input/event1 0 0 0
sendevent /dev/input/event1 0 2 0
sendevent /dev/input/event1 0 0 0
sendevent /dev/input/event1 3 57 0
sendevent /dev/input/event1 3 55 0
sendevent /dev/input/event1 3 53 640
sendevent /dev/input/event1 3 54 730
sendevent /dev/input/event1 3 58 1
sendevent /dev/input/event1 0 2 0
sendevent /dev/input/event1 0 0 0
sendevent /dev/input/event1 0 2 0
sendevent /dev/input/event1 0 0 0
sendevent /dev/input/event1 3 57 0
sendevent /dev/input/event1 3 55 0
sendevent /dev/input/event1 3 53 500
sendevent /dev/input/event1 3 54 900
sendevent /dev/input/event1 3 58 1
sendevent /dev/input/event1 0 2 0
sendevent /dev/input/event1 0 0 0
sendevent /dev/input/event1 0 2 0
sendevent /dev/input/event1 0 0 0

Performance-wise, it's about twice as slow as a MonkeyRunner implementation.

dJe
  • 51
  • 5
  • Great workaround! I won't be that difficult to generate these from `culebra` reading `getevent`'s output. – Diego Torres Milano Jun 05 '15 at 18:47
  • no need to use either `sendevent` nor even `adb shell` - just fill a `bytearray` with all kernel input events you want to send and `adb push` it directly to the input device file. works much faster this way. `MonkeyRunner` still works faster (just slightly) - because it skips the kernel input event loop altogether and injects the events directly into the Android Framework – Alex P. Jun 05 '15 at 19:36
  • @AlexP. thank you for your suggestion. Would you have an example for that? – dJe Jun 08 '15 at 10:01
  • my previous comment was intended mostly for Diego. My code won't help you much since it is not using `AVC` and has many other dependencies. So you will have to wait for Diego to implement support for the `adb SYNC` protocol. – Alex P. Jun 08 '15 at 18:21

2 Answers2

1

You're absolutely correct, if you look at the codes of AVC and MonkeyRunner, I think the flow chart is like below, both are using sockets but the difference of speed is because Monkeyrunner uses direct client socket to connect to Monkey server on the device to send command like tap, press once the monkey server is started on the device. AVC socket communicates to adb server to send the input tap/press, I don't know which "sauce" is in adb input, I guess it is Java which produce this slow response time. I think the owner of AVC can implement the Monkey server in a blink of eyes, but there is a problem, Uiautomator and Monkey can not coexist together, so I guess he should make a tradeoff between speed and stability for the majority of users:

AVC: client socket ---> ADB server ---> ADB daemon on device
MonkeyRunner: client socket ---> Monkey server on device
AbrtFus
  • 29
  • 7
  • If I'm not mistaken, dtmilano made a point getting rid of jython and Monkey so it's unlikely it'll be back. I guess that this tradeoff you mention is right here in my hands : we usually don't really need the inputs to be processed that fast (which I think is why dtmilano asks about my use case ;) ). – dJe May 29 '15 at 12:21
  • You are right, monkey and uiautomator cannot coexist. AVC even detect if monkey is running to prevent wrong behavior. – Diego Torres Milano May 29 '15 at 14:54
  • There was a similar problem with keyevents, perhaps a more common case, and IIRC I made a patch to let `input` accept more than one `keyevent` in the same command line, but I forgot to do the same for `tap`. I could make a new patch, but would take month to get to android. – Diego Torres Milano May 29 '15 at 14:56
  • The other alternative, and is one I'm experimenting now to solve a different problem (i.e. allow you to enter foreign language characters), is to have a `uitest` (uiautomator) that does this kind of things (perhaps listening to a socket). Comments are welcome. – Diego Torres Milano May 29 '15 at 14:58
  • there is no need of jython, it's still pure python 100%, just initiate the monkey server on the device via adb, create a new socket to communicate with monkey server and override the current methods touch, press to send command touch, press etc, all can be done in AVC adbclient.py, it works really well at the speed like MonkeyRunner. The only issue is that you can't use Uiautomator to dump, you must use ViewServer. – AbrtFus May 29 '15 at 16:45
  • @dtmilano, if I remember well, keyevent code sequences depends on the version of android and even the type of device at least from my tests, it would be a nightmare to support and maintenance, even for you :) – AbrtFus May 29 '15 at 16:54
  • wow, supporting unicode would be really a nice feature, I guess you need to create your own virtual keyboard which can accept unicodes, just on the road, you can make your own tap, press so it can override the current adb input :) by using port forwarding and get a regular client/server socket connection with your own application on the device.. – AbrtFus May 29 '15 at 18:00
0

One quick workaround you can try is

cmd = ''
for _ in range(6):
    cmd += 'input tap 1 1;'
ts_start = datetime.datetime.now()
device.shell(cmd)
chrono = datetime.datetime.now() - ts_start
print str(chrono)

it may help you but may not be suitable for all the cases.

Diego Torres Milano
  • 65,697
  • 9
  • 111
  • 134
  • It didn't make any difference, so I checked how those two really behaved by making them type digits in the phone app. They both get the correct number of presses registered by the phone. Would MonkeyRunner be careless about waiting for the end of the event? (meaning the end of the 'UP' part?) – dJe May 28 '15 at 21:21
  • What's the use case? Why are you so concerned about the speed? – Diego Torres Milano May 29 '15 at 00:16
  • I need to automate an app with a 3D engine that has sequences that can be sped through with taps. Unfortunately, the frequency at which the taps are handled and processed through adb do not allow me to speed through it as much as I'd need: much of the sequences still play at normal speed. The efficiency is crucialy linked to the number of iterations I can go through in a given time. As of now my iterations have gone from less than a minute (MR) up to more than 2 minutes (AVC/adb). I realize that it's an unusual use case, though. – dJe May 29 '15 at 12:23
  • @Diego, we discussed this before. Most of the delay comes not from starting an `adb shell` itself but from starting separate java apps (i.e. separate `input` commands). So this "workaround" does not provide any measurable performance benefit. – Alex P. Jun 02 '15 at 21:47
  • I'm experimenting a new service running on android (`uiautonatorhelper`) which would work as a `monkey` replacement, compatible with `uiautomator`. It will also provide the ability to type UTF-8 text (now `input` does not allow it). Coming soon... – Diego Torres Milano Jun 02 '15 at 23:20
  • Would be great. In the mean time, I'm using 'sendevent' files filled with the coordinates I need to speed up the process while using AVC. It's fast enough, but I'd love falling back to the natural implementation. – dJe Jun 05 '15 at 09:02