dtmilano / AndroidViewClient

Android ViewServer and ADB client
Apache License 2.0
1.63k stars 347 forks source link

dump command hangs #26

Open androidjelly opened 11 years ago

androidjelly commented 11 years ago

I am using AndroidViewClient for these configurations: Intel PC , with Android jellybean desktop version Model number :Full android on PC Android version: 4.1.2 Kernel version : 3.4.5

I am doing this in my monkeyrunner script - vc = ViewClient(device) vc.dump()

But the vc.dump() function hangs sometimes

I get this in the adb logcat -

W/WindowManager(13245): Could not send command dump with parameters W/WindowManager(13245): java.net.SocketException: Socket is closed W/WindowManager(13245): at java.net.PlainSocketImpl.checkNotClosed(PlainSocketImpl.java:134) W/WindowManager(13245): at java.net.PlainSocketImpl.getOutputStream(PlainSocketImpl.java:249) W/WindowManager(13245): at java.net.Socket.getOutputStream(Socket.java:385) W/WindowManager(13245): at com.android.server.wm.WindowManagerService.viewServerWindowCommand(WindowManagerService.java:6156) W/WindowManager(13245): at com.android.server.wm.ViewServer$ViewServerWorker.run(ViewServer.java:249) W/WindowManager(13245): at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:442) W/WindowManager(13245): at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305) W/WindowManager(13245): at java.util.concurrent.FutureTask.run(FutureTask.java:137) W/WindowManager(13245): at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1076) W/WindowManager(13245): at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:569) W/WindowManager(13245): at java.lang.Thread.run(Thread.java:856) W/ViewServer(13245): An error occurred with the command: dump

dtmilano commented 11 years ago

Please add:

For API >= 16, UiAutomator backend should be automatically selected. Did you force the use of ViewServer?

androidjelly commented 11 years ago

Hi,

I don't know which version it is and what is the API level.This is the dump function in the version i am using-

def dump(self, windowId=-1, sleep=1): ''' Dumps the window content.

    Sleep is useful to wait some time before obtaining the new content

when something in the window has changed.

    @type windowId: int
    @param windowId: the window id of the window to dump or -1 to dump

all windows @type sleep: int @param sleep: sleep in seconds before proceeding to dump the content

    @return: the list of Views as C{str} received from the server after

being split into lines '''

    if sleep > 0:
        MonkeyRunner.sleep(sleep)
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.connect((VIEW_SERVER_HOST, VIEW_SERVER_PORT))
    s.send('dump %d\r\n' % windowId)
    received = ""
    doneRE = re.compile("DONE")
    i = 0
    # it is getting hanged here in this loop
    while True:
        received += s.recv(1024)
        if doneRE.search(received[-7:]):
            break
    s.close()
    if DEBUG_RECEIVED:
        print >>sys.stderr
        print >>sys.stderr, received
        print >>sys.stderr
    self.setViews(received)

    if DEBUG_TREE:
        self.traverse(self.root)

    return self.views

As i had mentioned earlier my android device is a PC with jellybean desktop version installed on it. I have written a monkeyrunner script and importing androidviewclent in it. Basically i am using androidviewclient for detecting UI text prompts of the awesomeplayer in android.What i do is connect to the device using monkeyrunner API,invoke the player through monkeyrunner API and then do vc = Viewclient(device) vc.dump() now this dump function is getting hanged sometimes.

Regards, Prachi

On Fri, May 10, 2013 at 2:22 AM, Diego Torres Milano < notifications@github.com> wrote:

Please add:

  • AndroidViewClientVersion version
  • API level (I guess it's API 16)
  • more details about how you run the script

For API >= 16, UiAutomator backend should be automatically selected. Did you force the use of ViewServer?

— Reply to this email directly or view it on GitHubhttps://github.com/dtmilano/AndroidViewClient/issues/26#issuecomment-17689026 .

Diob commented 11 years ago

try s.shutdown(1) before closing the socket.

dtmilano commented 11 years ago

You should upgrade to the latest version and also move from monkeyrunner to python.

Diob commented 10 years ago

This seems to work for me as a workaround for the dump hang when not using UIAutomator.

I have modified the while True loop in dump and list from:

            while True:
                if DEBUG_RECEIVED:
                    print >>sys.stderr, "    reading from socket..."
                received += s.recv(1024)
                if doneRE.search(received[-7:]):
                    break
s.close()

to:

            while True:
                try:
                    if DEBUG_RECEIVED:
                        print >>sys.stderr, "    reading from socket..."
                    received += s.recv(1024)
                except socket.timeout, e:
                    err = e.args[0]
                    if err == 'timed out':
                        time.sleep(1)
                        print 'recv timed out, retry later'
                        continue
                    else:
                        print e
                        sys.exit(1)
                except socket.error, e:
                    print e
                    sys.exit(1)
                else:
                    if len(received) == 0:
                        print 'shutdown on server end'
                        try:
                            s.shutdown(socket.SHUT_RDWR)
                            s.close()
                        except socket.error, exc:
                            if exc.errno != errno.ENOTCONN:
                                raise
                        try:
                            s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
                            s.connect((VIEW_SERVER_HOST, self.localPort))
                            s.send(cmd)
                        except socket.error, ex:
                            raise RuntimeError("ERROR: Connecting to %s:%d: %s" % (VIEW_SERVER_HOST, self.localPort, ex))
                    else:
                        # print 'got a message...'
                        if doneRE.search(received[-7:]):
                            s.shutdown(socket.SHUT_RDWR)
                            s.close()
                            break

From the python howto: When a recv returns 0 bytes, it means the other side has closed (or is in the process of closing) the connection. You will not receive any more data on this connection. Ever. But if you plan to reuse your socket for further transfers, you need to realize that there is no EOT on a socket. I repeat: if a socket send or recv returns after handling 0 bytes, the connection has been broken. If the connection has not been broken, you may wait on a recv forever, because the socket will not tell you that there’s nothing more to read (for now).

So what I did was add an extra check to detect if the server closes the connection (you will not receive messages. message length = 0). If it does, clear the descriptor by closing the socket and recreate it again, connect and resend the message. The above code needs some cleanup since you won't need all of it. I used it more for debugging purposes.

I also tried another approach by keeping the socket connection open forever, but that will never work, because the viewserver uses the accept method for the socket. The socket will block until a new client connects. Therefore only the first message will be sent.