Bug 972518 - Log qemu output to prevent stdout pipe from filling up, r=jgriffin
authorAndrew Halberstadt <ahalberstadt@mozilla.com>
Thu, 20 Feb 2014 09:28:22 -0500
changeset 170047 957e1906ee1ad92b35d99088f342093dc155d16c
parent 170046 7eba59bbc076c5d3ac1c61ebee5ba4cb5df2619b
child 170048 bb62f23c7c558732c6f794f34d7db16247844834
push id270
push userpvanderbeken@mozilla.com
push dateThu, 06 Mar 2014 09:24:21 +0000
reviewersjgriffin
bugs972518
milestone30.0a1
Bug 972518 - Log qemu output to prevent stdout pipe from filling up, r=jgriffin
testing/marionette/client/marionette/emulator.py
--- a/testing/marionette/client/marionette/emulator.py
+++ b/testing/marionette/client/marionette/emulator.py
@@ -18,26 +18,32 @@ import tempfile
 import time
 import traceback
 
 from emulator_battery import EmulatorBattery
 from emulator_geo import EmulatorGeo
 from emulator_screen import EmulatorScreen
 
 
-class LogcatProc(ProcessHandlerMixin):
-    """Process handler for logcat which saves all output to a logfile.
+class LogOutputProc(ProcessHandlerMixin):
+    """
+    Process handler for processes which save all output to a logfile.
+    If no logfile is specified, output will still be consumed to prevent
+    the output pipe's from overflowing.
     """
 
-    def __init__(self, logfile, cmd, **kwargs):
+    def __init__(self, cmd, logfile=None,  **kwargs):
         self.logfile = logfile
         kwargs.setdefault('processOutputLine', []).append(self.log_output)
         ProcessHandlerMixin.__init__(self, cmd, **kwargs)
 
     def log_output(self, line):
+        if not self.logfile:
+            return
+
         f = open(self.logfile, 'a')
         f.write(line + "\n")
         f.flush()
 
 
 class Emulator(object):
 
     deviceRe = re.compile(r"^emulator-(\d+)(\s*)(.*)$")
@@ -205,18 +211,17 @@ class Emulator(object):
     def _run_telnet(self, command):
         if not self.telnet:
             self.telnet = Telnet('localhost', self.port)
             self._get_telnet_response()
         return self._get_telnet_response(command)
 
     def close(self):
         if self.is_running and self._emulator_launched:
-            self.proc.terminate()
-            self.proc.wait()
+            self.proc.kill()
         if self._adb_started:
             self._run_adb(['kill-server'])
             self._adb_started = False
         if self.proc:
             retcode = self.proc.poll()
             self.proc = None
             if self._tmp_userdata:
                 os.remove(self._tmp_userdata)
@@ -312,19 +317,24 @@ waitFor(
         if self.copy_userdata:
             # Make a copy of the userdata.img for this instance of the emulator to use.
             self._tmp_userdata = tempfile.mktemp(prefix='marionette')
             shutil.copyfile(self.dataImg, self._tmp_userdata)
             qemu_args[qemu_args.index('-data') + 1] = self._tmp_userdata
 
         original_online, original_offline = self._get_adb_devices()
 
-        self.proc = subprocess.Popen(qemu_args,
-                                     stdout=subprocess.PIPE,
-                                     stderr=subprocess.PIPE)
+        filename = None
+        if self.logcat_dir:
+            filename = os.path.join(self.logcat_dir, 'qemu.log')
+            if os.path.isfile(filename):
+                self.rotate_log(filename)
+
+        self.proc = LogOutputProc(qemu_args, filename)
+        self.proc.run()
 
         online, offline = self._get_adb_devices()
         now = datetime.datetime.now()
         while online - original_online == set([]):
             time.sleep(1)
             if datetime.datetime.now() - now > datetime.timedelta(seconds=60):
                 raise Exception('timed out waiting for emulator to start')
             online, offline = self._get_adb_devices()
@@ -458,33 +468,39 @@ window.addEventListener('mozbrowserloade
         self.dm.pushFile(busybox, remote_file, retryLimit=10)
         self._run_adb(['shell', 'cd /system/bin; chmod 555 busybox; for x in `./busybox --list`; do ln -s ./busybox $x; done'])
         self.dm._verifyZip()
 
     def rotate_log(self, srclog, index=1):
         """ Rotate a logfile, by recursively rotating logs further in the sequence,
             deleting the last file if necessary.
         """
-        destlog = os.path.join(self.logcat_dir, 'emulator-%d.%d.log' % (self.port, index))
-        if os.access(destlog, os.F_OK):
+        basename = os.path.basename(srclog)
+        basename = basename[:-len('.log')]
+        if index > 1:
+            basename = basename[:-len('.1')]
+        basename = '%s.%d.log' % (basename, index)
+
+        destlog = os.path.join(self.logcat_dir, basename)
+        if os.path.isfile(destlog):
             if index == 3:
                 os.remove(destlog)
             else:
                 self.rotate_log(destlog, index+1)
         shutil.move(srclog, destlog)
 
     def save_logcat(self):
         """ Save the output of logcat to a file.
         """
         filename = os.path.join(self.logcat_dir, "emulator-%d.log" % self.port)
-        if os.access(filename, os.F_OK):
+        if os.path.isfile(filename):
             self.rotate_log(filename)
         cmd = [self.adb, '-s', 'emulator-%d' % self.port, 'logcat', '-v', 'threadtime']
 
-        self.logcat_proc = LogcatProc(filename, cmd)
+        self.logcat_proc = LogOutputProc(cmd, filename)
         self.logcat_proc.run()
 
     def setup_port_forwarding(self, remote_port):
         """ Set up TCP port forwarding to the specified port on the device,
             using any availble local port, and return the local port.
         """
         s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
         s.bind(("",0))