Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
454 views
in Technique[技术] by (71.8m points)

python - Android Monkey Runner Device Calls Hang but Work when Process Is Killed

So for starters, I have a rather complex system that connects to a python web socket to fire off some various Android events. I was more or less given this system in working form on a Mac Mini. I have since ported it to Ubuntu 13.04 with some success. The problem I'm running into is with two python scripts I'm using to actually trigger these Android events.

What I have are two .py files, run_wsh and performAction. Essentially run_wsh is connected to via a socket and told what events to fire. run_wsh starts a subprocess for performAction and pipes input to performAction and performAction's output back to run_wsh.

The first major call is "Install" in run_wsh. run_wsh sends this down to performAction which has been running in a while True: loop, waiting for input. This may be where the problem lies, but I'm not sure. performAction reads in by setting the following (using python 2 something so raw_input is standard):

input = raw_input()

performAction then checks that by the following:

if input is None:
    continue
if input == "Install":
    device.installPackage('pathToMyApk.apk')
    runComponent = 'blah/.activityBlah'
    device.startActivity(component=runComponent)
    time.sleep(1)
    subprocess.call(['blah/adb', 'pull', '/pathToTextFileInAndroid.txt', '/pathToTextFileInUbuntu.txt']
    print "Install Successful"

This is after the initial waitForConnection call to the emulator which does succeed. Now whenever "Install" is sent down, it just hangs without anything happening. I know this, because no output can ever be read from the run_wsh script. For reference, below is the relevant bits from run_wsh.

args = ['pathToMonkeyRunner', 'pathToPerformAction.py']
prog = subprocess.Popen(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
prog.stdout.readline()
#This is to spit out a printed connection statement for when waitForConnection finishes
...
#Inside install call
inputToWrite = "Install"
prog.stdin.write(inputToWrite)
s = prog.stdout.readline()
f = open('/pathToTextFileInUbuntu.txt', 'r')
t = f.read()
#Read from the file and send information back out through the socket

I've inserted print statements before to verify that the line, s = prog.stdout.readline(), is never hit. There are other elif cases for different inputs in performAction, which also fail, but I'm just looking at this case for now. The real bugger here though is that when this hangs, I eventually just kill off the python process from the terminal. When I've done this with the install part commented out (and my apk already installed by hand via adb), once the process has been killed, the emulator finally pulls up the activity page like it is supposed to (I'm running with the window open for debugging purposes, but normally would have -no-window on). Strangest thing in the world. I've tried inserting various time.sleep calls into the code thinking perhaps if I have a data race, I can steer it one way or another, but alas, this also seems to have failed.

Please, I know this is a huge question in a large system, but any help would be magnificent. I have scoured the web looking for more in depth help with python, monkey runner, and Android with nothing particularly addressing this problem.

Also please ignore any silly typos in the code or my writing. The code I hand copied over from staring at a terminal in a vm rather than actual copy paste. I've changed the various paths to garbage, but they should be sufficient for understanding. Thanks!

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

I had this same stdin problem with monkeyrunner too. (I first thought it was a problem with my C# host app, but if I instead spawned a local python 3 program it would read input without problems.)

A different answer says there's a bug with Jython 2.5.3 and you can replace that with the Jython 2.5.4rc1 jar, but that didn't fix it for me on Windows.


What I needed was only the ability to send messages to the jython process, so instead of stdin I ultimately ended up running an HTTP server:

import time
from com.android.monkeyrunner import MonkeyRunner, MonkeyDevice
from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer

class PostHandler(BaseHTTPRequestHandler):
  def do_POST(self):
    content_len = int(self.headers.getheader('content-length', 0))
    post_body = self.rfile.read(content_len)
    for pair in post_body.split(';'):
      x, y = map(int, pair.split(','))
      device.touch(x, y, MonkeyDevice.DOWN_AND_UP)
      time.sleep(0.08)
    
    self.send_response(200)

if __name__ == '__main__':
  print 'Waiting for device connection...'
  device = MonkeyRunner.waitForConnection()

  server = HTTPServer(('localhost', 8080), PostHandler)
  print 'Got device, starting server, use <Ctrl-C> to stop'
  server.serve_forever()

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...