12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)# Copyright (c) 2013 The Chromium Authors. All rights reserved.
22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)# Use of this source code is governed by a BSD-style license that can be
32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)# found in the LICENSE file.
42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)# pylint: disable=W0702
6a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import os
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import signal
92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import subprocess
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import sys
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import time
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)def _IsLinux():
152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  """Return True if on Linux; else False."""
162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return sys.platform.startswith('linux')
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class Xvfb(object):
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  """Class to start and stop Xvfb if relevant.  Nop if not Linux."""
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  def __init__(self):
232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    self._pid = 0
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  def Start(self):
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    """Start Xvfb and set an appropriate DISPLAY environment.  Linux only.
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Copied from tools/code_coverage/coverage_posix.py
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    """
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if not _IsLinux():
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    proc = subprocess.Popen(['Xvfb', ':9', '-screen', '0', '1024x768x24',
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                             '-ac'],
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                            stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    self._pid = proc.pid
362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if not self._pid:
372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      raise Exception('Could not start Xvfb')
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    os.environ['DISPLAY'] = ':9'
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    # Now confirm, giving a chance for it to start if needed.
412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for _ in range(10):
422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      proc = subprocess.Popen('xdpyinfo >/dev/null', shell=True)
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      _, retcode = os.waitpid(proc.pid, 0)
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if retcode == 0:
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        break
462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      time.sleep(0.25)
472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if retcode != 0:
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      raise Exception('Could not confirm Xvfb happiness')
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  def Stop(self):
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    """Stop Xvfb if needed.  Linux only."""
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if self._pid:
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      try:
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        os.kill(self._pid, signal.SIGKILL)
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      except:
562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        pass
572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      del os.environ['DISPLAY']
582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      self._pid = 0
59