1*6777b538SAndroid Build Coastguard Worker#!/usr/bin/env vpython3 2*6777b538SAndroid Build Coastguard Worker# Copyright 2012 The Chromium Authors 3*6777b538SAndroid Build Coastguard Worker# Use of this source code is governed by a BSD-style license that can be 4*6777b538SAndroid Build Coastguard Worker# found in the LICENSE file. 5*6777b538SAndroid Build Coastguard Worker 6*6777b538SAndroid Build Coastguard Worker"""Runs tests with Xvfb or Xorg and Openbox or Weston on Linux and normally on 7*6777b538SAndroid Build Coastguard Workerother platforms.""" 8*6777b538SAndroid Build Coastguard Worker 9*6777b538SAndroid Build Coastguard Workerfrom __future__ import print_function 10*6777b538SAndroid Build Coastguard Worker 11*6777b538SAndroid Build Coastguard Workerimport copy 12*6777b538SAndroid Build Coastguard Workerimport os 13*6777b538SAndroid Build Coastguard Workerimport os.path 14*6777b538SAndroid Build Coastguard Workerimport random 15*6777b538SAndroid Build Coastguard Workerimport re 16*6777b538SAndroid Build Coastguard Workerimport signal 17*6777b538SAndroid Build Coastguard Workerimport socket 18*6777b538SAndroid Build Coastguard Workerimport subprocess 19*6777b538SAndroid Build Coastguard Workerimport sys 20*6777b538SAndroid Build Coastguard Workerimport tempfile 21*6777b538SAndroid Build Coastguard Workerimport threading 22*6777b538SAndroid Build Coastguard Workerimport time 23*6777b538SAndroid Build Coastguard Worker 24*6777b538SAndroid Build Coastguard Workerimport psutil 25*6777b538SAndroid Build Coastguard Worker 26*6777b538SAndroid Build Coastguard Workerimport test_env 27*6777b538SAndroid Build Coastguard Worker 28*6777b538SAndroid Build Coastguard WorkerDEFAULT_XVFB_WHD = '1280x800x24' 29*6777b538SAndroid Build Coastguard Worker 30*6777b538SAndroid Build Coastguard Worker# pylint: disable=useless-object-inheritance 31*6777b538SAndroid Build Coastguard Worker 32*6777b538SAndroid Build Coastguard Worker 33*6777b538SAndroid Build Coastguard Workerclass _X11ProcessError(Exception): 34*6777b538SAndroid Build Coastguard Worker """Exception raised when Xvfb or Xorg cannot start.""" 35*6777b538SAndroid Build Coastguard Worker 36*6777b538SAndroid Build Coastguard Workerclass _WestonProcessError(Exception): 37*6777b538SAndroid Build Coastguard Worker """Exception raised when Weston cannot start.""" 38*6777b538SAndroid Build Coastguard Worker 39*6777b538SAndroid Build Coastguard Worker 40*6777b538SAndroid Build Coastguard Workerdef kill(proc, name, timeout_in_seconds=10): 41*6777b538SAndroid Build Coastguard Worker """Tries to kill |proc| gracefully with a timeout for each signal.""" 42*6777b538SAndroid Build Coastguard Worker if not proc: 43*6777b538SAndroid Build Coastguard Worker return 44*6777b538SAndroid Build Coastguard Worker 45*6777b538SAndroid Build Coastguard Worker thread = threading.Thread(target=proc.wait) 46*6777b538SAndroid Build Coastguard Worker try: 47*6777b538SAndroid Build Coastguard Worker proc.terminate() 48*6777b538SAndroid Build Coastguard Worker thread.start() 49*6777b538SAndroid Build Coastguard Worker 50*6777b538SAndroid Build Coastguard Worker thread.join(timeout_in_seconds) 51*6777b538SAndroid Build Coastguard Worker if thread.is_alive(): 52*6777b538SAndroid Build Coastguard Worker print('%s running after SIGTERM, trying SIGKILL.\n' % name, 53*6777b538SAndroid Build Coastguard Worker file=sys.stderr) 54*6777b538SAndroid Build Coastguard Worker proc.kill() 55*6777b538SAndroid Build Coastguard Worker except OSError as e: 56*6777b538SAndroid Build Coastguard Worker # proc.terminate()/kill() can raise, not sure if only ProcessLookupError 57*6777b538SAndroid Build Coastguard Worker # which is explained in https://bugs.python.org/issue40550#msg382427 58*6777b538SAndroid Build Coastguard Worker print('Exception while killing process %s: %s' % (name, e), file=sys.stderr) 59*6777b538SAndroid Build Coastguard Worker 60*6777b538SAndroid Build Coastguard Worker thread.join(timeout_in_seconds) 61*6777b538SAndroid Build Coastguard Worker if thread.is_alive(): 62*6777b538SAndroid Build Coastguard Worker print('%s running after SIGTERM and SIGKILL; good luck!\n' % name, 63*6777b538SAndroid Build Coastguard Worker file=sys.stderr) 64*6777b538SAndroid Build Coastguard Worker 65*6777b538SAndroid Build Coastguard Worker 66*6777b538SAndroid Build Coastguard Workerdef launch_dbus(env): # pylint: disable=inconsistent-return-statements 67*6777b538SAndroid Build Coastguard Worker """Starts a DBus session. 68*6777b538SAndroid Build Coastguard Worker 69*6777b538SAndroid Build Coastguard Worker Works around a bug in GLib where it performs operations which aren't 70*6777b538SAndroid Build Coastguard Worker async-signal-safe (in particular, memory allocations) between fork and exec 71*6777b538SAndroid Build Coastguard Worker when it spawns subprocesses. This causes threads inside Chrome's browser and 72*6777b538SAndroid Build Coastguard Worker utility processes to get stuck, and this harness to hang waiting for those 73*6777b538SAndroid Build Coastguard Worker processes, which will never terminate. This doesn't happen on users' 74*6777b538SAndroid Build Coastguard Worker machines, because they have an active desktop session and the 75*6777b538SAndroid Build Coastguard Worker DBUS_SESSION_BUS_ADDRESS environment variable set, but it can happen on 76*6777b538SAndroid Build Coastguard Worker headless environments. This is fixed by glib commit [1], but this workaround 77*6777b538SAndroid Build Coastguard Worker will be necessary until the fix rolls into Chromium's CI. 78*6777b538SAndroid Build Coastguard Worker 79*6777b538SAndroid Build Coastguard Worker [1] f2917459f745bebf931bccd5cc2c33aa81ef4d12 80*6777b538SAndroid Build Coastguard Worker 81*6777b538SAndroid Build Coastguard Worker Modifies the passed in environment with at least DBUS_SESSION_BUS_ADDRESS and 82*6777b538SAndroid Build Coastguard Worker DBUS_SESSION_BUS_PID set. 83*6777b538SAndroid Build Coastguard Worker 84*6777b538SAndroid Build Coastguard Worker Returns the pid of the dbus-daemon if started, or None otherwise. 85*6777b538SAndroid Build Coastguard Worker """ 86*6777b538SAndroid Build Coastguard Worker if 'DBUS_SESSION_BUS_ADDRESS' in os.environ: 87*6777b538SAndroid Build Coastguard Worker return 88*6777b538SAndroid Build Coastguard Worker try: 89*6777b538SAndroid Build Coastguard Worker dbus_output = subprocess.check_output( 90*6777b538SAndroid Build Coastguard Worker ['dbus-launch'], env=env).decode('utf-8').split('\n') 91*6777b538SAndroid Build Coastguard Worker for line in dbus_output: 92*6777b538SAndroid Build Coastguard Worker m = re.match(r'([^=]+)\=(.+)', line) 93*6777b538SAndroid Build Coastguard Worker if m: 94*6777b538SAndroid Build Coastguard Worker env[m.group(1)] = m.group(2) 95*6777b538SAndroid Build Coastguard Worker return int(env['DBUS_SESSION_BUS_PID']) 96*6777b538SAndroid Build Coastguard Worker except (subprocess.CalledProcessError, OSError, KeyError, ValueError) as e: 97*6777b538SAndroid Build Coastguard Worker print('Exception while running dbus_launch: %s' % e) 98*6777b538SAndroid Build Coastguard Worker 99*6777b538SAndroid Build Coastguard Worker 100*6777b538SAndroid Build Coastguard Worker# TODO(crbug.com/949194): Encourage setting flags to False. 101*6777b538SAndroid Build Coastguard Workerdef run_executable( 102*6777b538SAndroid Build Coastguard Worker cmd, env, stdoutfile=None, use_openbox=True, use_xcompmgr=True, 103*6777b538SAndroid Build Coastguard Worker xvfb_whd=None, cwd=None): 104*6777b538SAndroid Build Coastguard Worker """Runs an executable within Weston, Xvfb or Xorg on Linux or normally on 105*6777b538SAndroid Build Coastguard Worker other platforms. 106*6777b538SAndroid Build Coastguard Worker 107*6777b538SAndroid Build Coastguard Worker The method sets SIGUSR1 handler for Xvfb to return SIGUSR1 108*6777b538SAndroid Build Coastguard Worker when it is ready for connections. 109*6777b538SAndroid Build Coastguard Worker https://www.x.org/archive/X11R7.5/doc/man/man1/Xserver.1.html under Signals. 110*6777b538SAndroid Build Coastguard Worker 111*6777b538SAndroid Build Coastguard Worker Args: 112*6777b538SAndroid Build Coastguard Worker cmd: Command to be executed. 113*6777b538SAndroid Build Coastguard Worker env: A copy of environment variables. "DISPLAY" and will be set if Xvfb is 114*6777b538SAndroid Build Coastguard Worker used. "WAYLAND_DISPLAY" will be set if Weston is used. 115*6777b538SAndroid Build Coastguard Worker stdoutfile: If provided, symbolization via script is disabled and stdout 116*6777b538SAndroid Build Coastguard Worker is written to this file as well as to stdout. 117*6777b538SAndroid Build Coastguard Worker use_openbox: A flag to use openbox process. 118*6777b538SAndroid Build Coastguard Worker Some ChromeOS tests need a window manager. 119*6777b538SAndroid Build Coastguard Worker use_xcompmgr: A flag to use xcompmgr process. 120*6777b538SAndroid Build Coastguard Worker Some tests need a compositing wm to make use of transparent visuals. 121*6777b538SAndroid Build Coastguard Worker xvfb_whd: WxHxD to pass to xvfb or DEFAULT_XVFB_WHD if None 122*6777b538SAndroid Build Coastguard Worker cwd: Current working directory. 123*6777b538SAndroid Build Coastguard Worker 124*6777b538SAndroid Build Coastguard Worker Returns: 125*6777b538SAndroid Build Coastguard Worker the exit code of the specified commandline, or 1 on failure. 126*6777b538SAndroid Build Coastguard Worker """ 127*6777b538SAndroid Build Coastguard Worker 128*6777b538SAndroid Build Coastguard Worker # It might seem counterintuitive to support a --no-xvfb flag in a script 129*6777b538SAndroid Build Coastguard Worker # whose only job is to start xvfb, but doing so allows us to consolidate 130*6777b538SAndroid Build Coastguard Worker # the logic in the layers of buildbot scripts so that we *always* use 131*6777b538SAndroid Build Coastguard Worker # xvfb by default and don't have to worry about the distinction, it 132*6777b538SAndroid Build Coastguard Worker # can remain solely under the control of the test invocation itself. 133*6777b538SAndroid Build Coastguard Worker use_xvfb = True 134*6777b538SAndroid Build Coastguard Worker if '--no-xvfb' in cmd: 135*6777b538SAndroid Build Coastguard Worker use_xvfb = False 136*6777b538SAndroid Build Coastguard Worker cmd.remove('--no-xvfb') 137*6777b538SAndroid Build Coastguard Worker 138*6777b538SAndroid Build Coastguard Worker # Xorg is mostly a drop in replacement to Xvfb but has better support for 139*6777b538SAndroid Build Coastguard Worker # dummy drivers and multi-screen testing (See: crbug.com/40257169 and 140*6777b538SAndroid Build Coastguard Worker # http://tinyurl.com/4phsuupf). Requires Xorg binaries 141*6777b538SAndroid Build Coastguard Worker # (package: xserver-xorg-core) 142*6777b538SAndroid Build Coastguard Worker use_xorg = False 143*6777b538SAndroid Build Coastguard Worker if '--use-xorg' in cmd: 144*6777b538SAndroid Build Coastguard Worker use_xvfb = False 145*6777b538SAndroid Build Coastguard Worker use_xorg = True 146*6777b538SAndroid Build Coastguard Worker cmd.remove('--use-xorg') 147*6777b538SAndroid Build Coastguard Worker 148*6777b538SAndroid Build Coastguard Worker # Tests that run on Linux platforms with Ozone/Wayland backend require 149*6777b538SAndroid Build Coastguard Worker # a Weston instance. However, it is also required to disable xvfb so 150*6777b538SAndroid Build Coastguard Worker # that Weston can run in a pure headless environment. 151*6777b538SAndroid Build Coastguard Worker use_weston = False 152*6777b538SAndroid Build Coastguard Worker if '--use-weston' in cmd: 153*6777b538SAndroid Build Coastguard Worker if use_xvfb or use_xorg: 154*6777b538SAndroid Build Coastguard Worker print('Unable to use Weston with xvfb or Xorg.\n', file=sys.stderr) 155*6777b538SAndroid Build Coastguard Worker return 1 156*6777b538SAndroid Build Coastguard Worker use_weston = True 157*6777b538SAndroid Build Coastguard Worker cmd.remove('--use-weston') 158*6777b538SAndroid Build Coastguard Worker 159*6777b538SAndroid Build Coastguard Worker if sys.platform.startswith('linux') and (use_xvfb or use_xorg): 160*6777b538SAndroid Build Coastguard Worker return _run_with_x11(cmd, env, stdoutfile, use_openbox, use_xcompmgr, 161*6777b538SAndroid Build Coastguard Worker use_xorg, xvfb_whd or DEFAULT_XVFB_WHD, cwd) 162*6777b538SAndroid Build Coastguard Worker if use_weston: 163*6777b538SAndroid Build Coastguard Worker return _run_with_weston(cmd, env, stdoutfile, cwd) 164*6777b538SAndroid Build Coastguard Worker return test_env.run_executable(cmd, env, stdoutfile, cwd) 165*6777b538SAndroid Build Coastguard Worker 166*6777b538SAndroid Build Coastguard Worker 167*6777b538SAndroid Build Coastguard Workerdef _make_xorg_config(whd): 168*6777b538SAndroid Build Coastguard Worker """Generates an Xorg config file based on the specified WxHxD string and 169*6777b538SAndroid Build Coastguard Worker returns the file path. See: 170*6777b538SAndroid Build Coastguard Worker https://www.x.org/releases/current/doc/man/man5/xorg.conf.5.xhtml""" 171*6777b538SAndroid Build Coastguard Worker (width, height, depth) = whd.split('x') 172*6777b538SAndroid Build Coastguard Worker modeline = subprocess.check_output( 173*6777b538SAndroid Build Coastguard Worker ['cvt', width, height, '60'], stderr=subprocess.STDOUT, text=True) 174*6777b538SAndroid Build Coastguard Worker modeline_label = re.search( 175*6777b538SAndroid Build Coastguard Worker 'Modeline "(.*)"', modeline, re.IGNORECASE).group(1) 176*6777b538SAndroid Build Coastguard Worker config = f""" 177*6777b538SAndroid Build Coastguard WorkerSection "Monitor" 178*6777b538SAndroid Build Coastguard Worker Identifier "Monitor0" 179*6777b538SAndroid Build Coastguard Worker {modeline} 180*6777b538SAndroid Build Coastguard WorkerEndSection 181*6777b538SAndroid Build Coastguard WorkerSection "Device" 182*6777b538SAndroid Build Coastguard Worker Identifier "Device0" 183*6777b538SAndroid Build Coastguard Worker # Dummy driver requires package `xserver-xorg-video-dummy`. 184*6777b538SAndroid Build Coastguard Worker Driver "dummy" 185*6777b538SAndroid Build Coastguard Worker VideoRam 256000 186*6777b538SAndroid Build Coastguard WorkerEndSection 187*6777b538SAndroid Build Coastguard WorkerSection "Screen" 188*6777b538SAndroid Build Coastguard Worker DefaultDepth {depth} 189*6777b538SAndroid Build Coastguard Worker Identifier "Screen0" 190*6777b538SAndroid Build Coastguard Worker Device "Device0" 191*6777b538SAndroid Build Coastguard Worker Monitor "Monitor0" 192*6777b538SAndroid Build Coastguard Worker SubSection "Display" 193*6777b538SAndroid Build Coastguard Worker Depth {depth} 194*6777b538SAndroid Build Coastguard Worker Modes "{modeline_label}" 195*6777b538SAndroid Build Coastguard Worker EndSubSection 196*6777b538SAndroid Build Coastguard WorkerEndSection 197*6777b538SAndroid Build Coastguard Worker """ 198*6777b538SAndroid Build Coastguard Worker config_file = os.path.join(tempfile.gettempdir(), 'xorg.config') 199*6777b538SAndroid Build Coastguard Worker with open(config_file, 'w') as f: 200*6777b538SAndroid Build Coastguard Worker f.write(config) 201*6777b538SAndroid Build Coastguard Worker return config_file 202*6777b538SAndroid Build Coastguard Worker 203*6777b538SAndroid Build Coastguard Workerdef _run_with_x11(cmd, env, stdoutfile, use_openbox, 204*6777b538SAndroid Build Coastguard Worker use_xcompmgr, use_xorg, xvfb_whd, cwd): 205*6777b538SAndroid Build Coastguard Worker """Runs with an X11 server. Uses Xvfb by default and Xorg when use_xorg is 206*6777b538SAndroid Build Coastguard Worker True.""" 207*6777b538SAndroid Build Coastguard Worker openbox_proc = None 208*6777b538SAndroid Build Coastguard Worker openbox_ready = MutableBoolean() 209*6777b538SAndroid Build Coastguard Worker def set_openbox_ready(*_): 210*6777b538SAndroid Build Coastguard Worker openbox_ready.setvalue(True) 211*6777b538SAndroid Build Coastguard Worker 212*6777b538SAndroid Build Coastguard Worker xcompmgr_proc = None 213*6777b538SAndroid Build Coastguard Worker x11_proc = None 214*6777b538SAndroid Build Coastguard Worker x11_ready = MutableBoolean() 215*6777b538SAndroid Build Coastguard Worker def set_x11_ready(*_): 216*6777b538SAndroid Build Coastguard Worker x11_ready.setvalue(True) 217*6777b538SAndroid Build Coastguard Worker 218*6777b538SAndroid Build Coastguard Worker dbus_pid = None 219*6777b538SAndroid Build Coastguard Worker x11_binary = 'Xorg' if use_xorg else 'Xvfb' 220*6777b538SAndroid Build Coastguard Worker xorg_config_file = _make_xorg_config(xvfb_whd) if use_xorg else None 221*6777b538SAndroid Build Coastguard Worker try: 222*6777b538SAndroid Build Coastguard Worker signal.signal(signal.SIGTERM, raise_x11_error) 223*6777b538SAndroid Build Coastguard Worker signal.signal(signal.SIGINT, raise_x11_error) 224*6777b538SAndroid Build Coastguard Worker 225*6777b538SAndroid Build Coastguard Worker xvfb_help = None 226*6777b538SAndroid Build Coastguard Worker if not use_xorg: 227*6777b538SAndroid Build Coastguard Worker # Before [1], the maximum number of X11 clients was 256. After, the 228*6777b538SAndroid Build Coastguard Worker # default limit is 256 with a configurable maximum of 512. On systems 229*6777b538SAndroid Build Coastguard Worker # with a large number of CPUs, the old limit of 256 may be hit for certain 230*6777b538SAndroid Build Coastguard Worker # test suites [2] [3], so we set the limit to 512 when possible. This 231*6777b538SAndroid Build Coastguard Worker # flag is not available on Ubuntu 16.04 or 18.04, so a feature check is 232*6777b538SAndroid Build Coastguard Worker # required. Xvfb does not have a '-version' option, so checking the 233*6777b538SAndroid Build Coastguard Worker # '-help' output is required. 234*6777b538SAndroid Build Coastguard Worker # 235*6777b538SAndroid Build Coastguard Worker # [1] d206c240c0b85c4da44f073d6e9a692afb6b96d2 236*6777b538SAndroid Build Coastguard Worker # [2] https://crbug.com/1187948 237*6777b538SAndroid Build Coastguard Worker # [3] https://crbug.com/1120107 238*6777b538SAndroid Build Coastguard Worker xvfb_help = subprocess.check_output( 239*6777b538SAndroid Build Coastguard Worker ['Xvfb', '-help'], stderr=subprocess.STDOUT).decode('utf8') 240*6777b538SAndroid Build Coastguard Worker 241*6777b538SAndroid Build Coastguard Worker # Due to race condition for display number, Xvfb/Xorg might fail to run. 242*6777b538SAndroid Build Coastguard Worker # If it does fail, try again up to 10 times, similarly to xvfb-run. 243*6777b538SAndroid Build Coastguard Worker for _ in range(10): 244*6777b538SAndroid Build Coastguard Worker x11_ready.setvalue(False) 245*6777b538SAndroid Build Coastguard Worker display = find_display() 246*6777b538SAndroid Build Coastguard Worker 247*6777b538SAndroid Build Coastguard Worker x11_cmd = None 248*6777b538SAndroid Build Coastguard Worker if use_xorg: 249*6777b538SAndroid Build Coastguard Worker x11_cmd = ['Xorg', display, '-config', xorg_config_file] 250*6777b538SAndroid Build Coastguard Worker else: 251*6777b538SAndroid Build Coastguard Worker x11_cmd = ['Xvfb', display, '-screen', '0', xvfb_whd, '-ac', 252*6777b538SAndroid Build Coastguard Worker '-nolisten', 'tcp', '-dpi', '96', '+extension', 'RANDR'] 253*6777b538SAndroid Build Coastguard Worker if '-maxclients' in xvfb_help: 254*6777b538SAndroid Build Coastguard Worker x11_cmd += ['-maxclients', '512'] 255*6777b538SAndroid Build Coastguard Worker 256*6777b538SAndroid Build Coastguard Worker # Sets SIGUSR1 to ignore for Xvfb/Xorg to signal current process 257*6777b538SAndroid Build Coastguard Worker # when it is ready. Due to race condition, USR1 signal could be sent 258*6777b538SAndroid Build Coastguard Worker # before the process resets the signal handler, we cannot rely on 259*6777b538SAndroid Build Coastguard Worker # signal handler to change on time. 260*6777b538SAndroid Build Coastguard Worker signal.signal(signal.SIGUSR1, signal.SIG_IGN) 261*6777b538SAndroid Build Coastguard Worker x11_proc = subprocess.Popen(x11_cmd, stderr=subprocess.STDOUT, env=env) 262*6777b538SAndroid Build Coastguard Worker signal.signal(signal.SIGUSR1, set_x11_ready) 263*6777b538SAndroid Build Coastguard Worker for _ in range(30): 264*6777b538SAndroid Build Coastguard Worker time.sleep(.1) # gives Xvfb/Xorg time to start or fail. 265*6777b538SAndroid Build Coastguard Worker if x11_ready.getvalue() or x11_proc.poll() is not None: 266*6777b538SAndroid Build Coastguard Worker break # xvfb/xorg sent ready signal, or already failed and stopped. 267*6777b538SAndroid Build Coastguard Worker 268*6777b538SAndroid Build Coastguard Worker if x11_proc.poll() is None: 269*6777b538SAndroid Build Coastguard Worker if x11_ready.getvalue(): 270*6777b538SAndroid Build Coastguard Worker break # xvfb/xorg is ready 271*6777b538SAndroid Build Coastguard Worker kill(x11_proc, x11_binary) # still not ready, give up and retry 272*6777b538SAndroid Build Coastguard Worker 273*6777b538SAndroid Build Coastguard Worker if x11_proc.poll() is not None: 274*6777b538SAndroid Build Coastguard Worker raise _X11ProcessError('Failed to start after 10 tries') 275*6777b538SAndroid Build Coastguard Worker 276*6777b538SAndroid Build Coastguard Worker env['DISPLAY'] = display 277*6777b538SAndroid Build Coastguard Worker # Set dummy variable for scripts. 278*6777b538SAndroid Build Coastguard Worker env['XVFB_DISPLAY'] = display 279*6777b538SAndroid Build Coastguard Worker 280*6777b538SAndroid Build Coastguard Worker dbus_pid = launch_dbus(env) 281*6777b538SAndroid Build Coastguard Worker 282*6777b538SAndroid Build Coastguard Worker if use_openbox: 283*6777b538SAndroid Build Coastguard Worker # Openbox will send a SIGUSR1 signal to the current process notifying the 284*6777b538SAndroid Build Coastguard Worker # script it has started up. 285*6777b538SAndroid Build Coastguard Worker current_proc_id = os.getpid() 286*6777b538SAndroid Build Coastguard Worker 287*6777b538SAndroid Build Coastguard Worker # The CMD that is passed via the --startup flag. 288*6777b538SAndroid Build Coastguard Worker openbox_startup_cmd = 'kill --signal SIGUSR1 %s' % str(current_proc_id) 289*6777b538SAndroid Build Coastguard Worker # Setup the signal handlers before starting the openbox instance. 290*6777b538SAndroid Build Coastguard Worker signal.signal(signal.SIGUSR1, signal.SIG_IGN) 291*6777b538SAndroid Build Coastguard Worker signal.signal(signal.SIGUSR1, set_openbox_ready) 292*6777b538SAndroid Build Coastguard Worker openbox_proc = subprocess.Popen( 293*6777b538SAndroid Build Coastguard Worker ['openbox', '--sm-disable', '--startup', 294*6777b538SAndroid Build Coastguard Worker openbox_startup_cmd], stderr=subprocess.STDOUT, env=env) 295*6777b538SAndroid Build Coastguard Worker 296*6777b538SAndroid Build Coastguard Worker for _ in range(30): 297*6777b538SAndroid Build Coastguard Worker time.sleep(.1) # gives Openbox time to start or fail. 298*6777b538SAndroid Build Coastguard Worker if openbox_ready.getvalue() or openbox_proc.poll() is not None: 299*6777b538SAndroid Build Coastguard Worker break # openbox sent ready signal, or failed and stopped. 300*6777b538SAndroid Build Coastguard Worker 301*6777b538SAndroid Build Coastguard Worker if openbox_proc.poll() is not None or not openbox_ready.getvalue(): 302*6777b538SAndroid Build Coastguard Worker raise _X11ProcessError('Failed to start OpenBox.') 303*6777b538SAndroid Build Coastguard Worker 304*6777b538SAndroid Build Coastguard Worker if use_xcompmgr: 305*6777b538SAndroid Build Coastguard Worker xcompmgr_proc = subprocess.Popen( 306*6777b538SAndroid Build Coastguard Worker 'xcompmgr', stderr=subprocess.STDOUT, env=env) 307*6777b538SAndroid Build Coastguard Worker 308*6777b538SAndroid Build Coastguard Worker return test_env.run_executable(cmd, env, stdoutfile, cwd) 309*6777b538SAndroid Build Coastguard Worker except OSError as e: 310*6777b538SAndroid Build Coastguard Worker print('Failed to start %s or Openbox: %s\n' % (x11_binary, str(e)), 311*6777b538SAndroid Build Coastguard Worker file=sys.stderr) 312*6777b538SAndroid Build Coastguard Worker return 1 313*6777b538SAndroid Build Coastguard Worker except _X11ProcessError as e: 314*6777b538SAndroid Build Coastguard Worker print('%s fail: %s\n' % (x11_binary, str(e)), file=sys.stderr) 315*6777b538SAndroid Build Coastguard Worker return 1 316*6777b538SAndroid Build Coastguard Worker finally: 317*6777b538SAndroid Build Coastguard Worker kill(openbox_proc, 'openbox') 318*6777b538SAndroid Build Coastguard Worker kill(xcompmgr_proc, 'xcompmgr') 319*6777b538SAndroid Build Coastguard Worker kill(x11_proc, x11_binary) 320*6777b538SAndroid Build Coastguard Worker if xorg_config_file != None: 321*6777b538SAndroid Build Coastguard Worker os.remove(xorg_config_file) 322*6777b538SAndroid Build Coastguard Worker 323*6777b538SAndroid Build Coastguard Worker # dbus-daemon is not a subprocess, so we can't SIGTERM+waitpid() on it. 324*6777b538SAndroid Build Coastguard Worker # To ensure it exits, use SIGKILL which should be safe since all other 325*6777b538SAndroid Build Coastguard Worker # processes that it would have been servicing have exited. 326*6777b538SAndroid Build Coastguard Worker if dbus_pid: 327*6777b538SAndroid Build Coastguard Worker os.kill(dbus_pid, signal.SIGKILL) 328*6777b538SAndroid Build Coastguard Worker 329*6777b538SAndroid Build Coastguard Worker 330*6777b538SAndroid Build Coastguard Worker# TODO(https://crbug.com/1060466): Write tests. 331*6777b538SAndroid Build Coastguard Workerdef _run_with_weston(cmd, env, stdoutfile, cwd): 332*6777b538SAndroid Build Coastguard Worker weston_proc = None 333*6777b538SAndroid Build Coastguard Worker 334*6777b538SAndroid Build Coastguard Worker try: 335*6777b538SAndroid Build Coastguard Worker signal.signal(signal.SIGTERM, raise_weston_error) 336*6777b538SAndroid Build Coastguard Worker signal.signal(signal.SIGINT, raise_weston_error) 337*6777b538SAndroid Build Coastguard Worker 338*6777b538SAndroid Build Coastguard Worker dbus_pid = launch_dbus(env) 339*6777b538SAndroid Build Coastguard Worker 340*6777b538SAndroid Build Coastguard Worker # The bundled weston (//third_party/weston) is used by Linux Ozone Wayland 341*6777b538SAndroid Build Coastguard Worker # CI and CQ testers and compiled by //ui/ozone/platform/wayland whenever 342*6777b538SAndroid Build Coastguard Worker # there is a dependency on the Ozone/Wayland and use_bundled_weston is set 343*6777b538SAndroid Build Coastguard Worker # in gn args. However, some tests do not require Wayland or do not use 344*6777b538SAndroid Build Coastguard Worker # //ui/ozone at all, but still have --use-weston flag set by the 345*6777b538SAndroid Build Coastguard Worker # OZONE_WAYLAND variant (see //testing/buildbot/variants.pyl). This results 346*6777b538SAndroid Build Coastguard Worker # in failures and those tests cannot be run because of the exception that 347*6777b538SAndroid Build Coastguard Worker # informs about missing weston binary. Thus, to overcome the issue before 348*6777b538SAndroid Build Coastguard Worker # a better solution is found, add a check for the "weston" binary here and 349*6777b538SAndroid Build Coastguard Worker # run tests without Wayland compositor if the weston binary is not found. 350*6777b538SAndroid Build Coastguard Worker # TODO(https://1178788): find a better solution. 351*6777b538SAndroid Build Coastguard Worker if not os.path.isfile("./weston"): 352*6777b538SAndroid Build Coastguard Worker print('Weston is not available. Starting without Wayland compositor') 353*6777b538SAndroid Build Coastguard Worker return test_env.run_executable(cmd, env, stdoutfile, cwd) 354*6777b538SAndroid Build Coastguard Worker 355*6777b538SAndroid Build Coastguard Worker # Set $XDG_RUNTIME_DIR if it is not set. 356*6777b538SAndroid Build Coastguard Worker _set_xdg_runtime_dir(env) 357*6777b538SAndroid Build Coastguard Worker 358*6777b538SAndroid Build Coastguard Worker # Write options that can't be passed via CLI flags to the config file. 359*6777b538SAndroid Build Coastguard Worker # 1) panel-position=none - disables the panel, which might interfere with 360*6777b538SAndroid Build Coastguard Worker # the tests by blocking mouse input. 361*6777b538SAndroid Build Coastguard Worker with open(_weston_config_file_path(), 'w') as weston_config_file: 362*6777b538SAndroid Build Coastguard Worker weston_config_file.write('[shell]\npanel-position=none') 363*6777b538SAndroid Build Coastguard Worker 364*6777b538SAndroid Build Coastguard Worker # Weston is compiled along with the Ozone/Wayland platform, and is 365*6777b538SAndroid Build Coastguard Worker # fetched as data deps. Thus, run it from the current directory. 366*6777b538SAndroid Build Coastguard Worker # 367*6777b538SAndroid Build Coastguard Worker # Weston is used with the following flags: 368*6777b538SAndroid Build Coastguard Worker # 1) --backend=headless-backend.so - runs Weston in a headless mode 369*6777b538SAndroid Build Coastguard Worker # that does not require a real GPU card. 370*6777b538SAndroid Build Coastguard Worker # 2) --idle-time=0 - disables idle timeout, which prevents Weston 371*6777b538SAndroid Build Coastguard Worker # to enter idle state. Otherwise, Weston stops to send frame callbacks, 372*6777b538SAndroid Build Coastguard Worker # and tests start to time out (this typically happens after 300 seconds - 373*6777b538SAndroid Build Coastguard Worker # the default time after which Weston enters the idle state). 374*6777b538SAndroid Build Coastguard Worker # 3) --modules=ui-controls.so,systemd-notify.so - enables support for the 375*6777b538SAndroid Build Coastguard Worker # ui-controls Wayland protocol extension and the systemd-notify protocol. 376*6777b538SAndroid Build Coastguard Worker # 4) --width && --height set size of a virtual display: we need to set 377*6777b538SAndroid Build Coastguard Worker # an adequate size so that tests can have more room for managing size 378*6777b538SAndroid Build Coastguard Worker # of windows. 379*6777b538SAndroid Build Coastguard Worker # 5) --config=... - tells Weston to use our custom config. 380*6777b538SAndroid Build Coastguard Worker weston_cmd = ['./weston', '--backend=headless-backend.so', '--idle-time=0', 381*6777b538SAndroid Build Coastguard Worker '--modules=ui-controls.so,systemd-notify.so', '--width=1280', 382*6777b538SAndroid Build Coastguard Worker '--height=800', '--config=' + _weston_config_file_path()] 383*6777b538SAndroid Build Coastguard Worker 384*6777b538SAndroid Build Coastguard Worker if '--weston-use-gl' in cmd: 385*6777b538SAndroid Build Coastguard Worker # Runs Weston using hardware acceleration instead of SwiftShader. 386*6777b538SAndroid Build Coastguard Worker weston_cmd.append('--use-gl') 387*6777b538SAndroid Build Coastguard Worker cmd.remove('--weston-use-gl') 388*6777b538SAndroid Build Coastguard Worker 389*6777b538SAndroid Build Coastguard Worker if '--weston-debug-logging' in cmd: 390*6777b538SAndroid Build Coastguard Worker cmd.remove('--weston-debug-logging') 391*6777b538SAndroid Build Coastguard Worker env = copy.deepcopy(env) 392*6777b538SAndroid Build Coastguard Worker env['WAYLAND_DEBUG'] = '1' 393*6777b538SAndroid Build Coastguard Worker 394*6777b538SAndroid Build Coastguard Worker # We use the systemd-notify protocol to detect whether weston has launched 395*6777b538SAndroid Build Coastguard Worker # successfully. We listen on a unix socket and set the NOTIFY_SOCKET 396*6777b538SAndroid Build Coastguard Worker # environment variable to the socket's path. If we tell it to load its 397*6777b538SAndroid Build Coastguard Worker # systemd-notify module, weston will send a 'READY=1' message to the socket 398*6777b538SAndroid Build Coastguard Worker # once it has loaded that module. 399*6777b538SAndroid Build Coastguard Worker # See the sd_notify(3) man page and weston's compositor/systemd-notify.c for 400*6777b538SAndroid Build Coastguard Worker # more details. 401*6777b538SAndroid Build Coastguard Worker with socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM 402*6777b538SAndroid Build Coastguard Worker | socket.SOCK_NONBLOCK) as notify_socket: 403*6777b538SAndroid Build Coastguard Worker notify_socket.bind(_weston_notify_socket_address()) 404*6777b538SAndroid Build Coastguard Worker env['NOTIFY_SOCKET'] = _weston_notify_socket_address() 405*6777b538SAndroid Build Coastguard Worker 406*6777b538SAndroid Build Coastguard Worker weston_proc_display = None 407*6777b538SAndroid Build Coastguard Worker for _ in range(10): 408*6777b538SAndroid Build Coastguard Worker weston_proc = subprocess.Popen( 409*6777b538SAndroid Build Coastguard Worker weston_cmd, 410*6777b538SAndroid Build Coastguard Worker stderr=subprocess.STDOUT, env=env) 411*6777b538SAndroid Build Coastguard Worker 412*6777b538SAndroid Build Coastguard Worker for _ in range(25): 413*6777b538SAndroid Build Coastguard Worker time.sleep(0.1) # Gives weston some time to start. 414*6777b538SAndroid Build Coastguard Worker try: 415*6777b538SAndroid Build Coastguard Worker if notify_socket.recv(512) == b'READY=1': 416*6777b538SAndroid Build Coastguard Worker break 417*6777b538SAndroid Build Coastguard Worker except BlockingIOError: 418*6777b538SAndroid Build Coastguard Worker continue 419*6777b538SAndroid Build Coastguard Worker 420*6777b538SAndroid Build Coastguard Worker for _ in range(25): 421*6777b538SAndroid Build Coastguard Worker # The 'READY=1' message is sent as soon as weston loads the 422*6777b538SAndroid Build Coastguard Worker # systemd-notify module. This happens shortly before spawning its 423*6777b538SAndroid Build Coastguard Worker # subprocesses (e.g. desktop-shell). Wait some more to ensure they 424*6777b538SAndroid Build Coastguard Worker # have been spawned. 425*6777b538SAndroid Build Coastguard Worker time.sleep(0.1) 426*6777b538SAndroid Build Coastguard Worker 427*6777b538SAndroid Build Coastguard Worker # Get the $WAYLAND_DISPLAY set by Weston and pass it to the test 428*6777b538SAndroid Build Coastguard Worker # launcher. Please note that this env variable is local for the 429*6777b538SAndroid Build Coastguard Worker # process. That's the reason we have to read it from Weston 430*6777b538SAndroid Build Coastguard Worker # separately. 431*6777b538SAndroid Build Coastguard Worker weston_proc_display = _get_display_from_weston(weston_proc.pid) 432*6777b538SAndroid Build Coastguard Worker if weston_proc_display is not None: 433*6777b538SAndroid Build Coastguard Worker break # Weston could launch and we found the display. 434*6777b538SAndroid Build Coastguard Worker 435*6777b538SAndroid Build Coastguard Worker # Also break from the outer loop. 436*6777b538SAndroid Build Coastguard Worker if weston_proc_display is not None: 437*6777b538SAndroid Build Coastguard Worker break 438*6777b538SAndroid Build Coastguard Worker 439*6777b538SAndroid Build Coastguard Worker # If we couldn't find the display after 10 tries, raise an exception. 440*6777b538SAndroid Build Coastguard Worker if weston_proc_display is None: 441*6777b538SAndroid Build Coastguard Worker raise _WestonProcessError('Failed to start Weston.') 442*6777b538SAndroid Build Coastguard Worker 443*6777b538SAndroid Build Coastguard Worker env.pop('NOTIFY_SOCKET') 444*6777b538SAndroid Build Coastguard Worker 445*6777b538SAndroid Build Coastguard Worker env['WAYLAND_DISPLAY'] = weston_proc_display 446*6777b538SAndroid Build Coastguard Worker if '--chrome-wayland-debugging' in cmd: 447*6777b538SAndroid Build Coastguard Worker cmd.remove('--chrome-wayland-debugging') 448*6777b538SAndroid Build Coastguard Worker env['WAYLAND_DEBUG'] = '1' 449*6777b538SAndroid Build Coastguard Worker else: 450*6777b538SAndroid Build Coastguard Worker env['WAYLAND_DEBUG'] = '0' 451*6777b538SAndroid Build Coastguard Worker 452*6777b538SAndroid Build Coastguard Worker return test_env.run_executable(cmd, env, stdoutfile, cwd) 453*6777b538SAndroid Build Coastguard Worker except OSError as e: 454*6777b538SAndroid Build Coastguard Worker print('Failed to start Weston: %s\n' % str(e), file=sys.stderr) 455*6777b538SAndroid Build Coastguard Worker return 1 456*6777b538SAndroid Build Coastguard Worker except _WestonProcessError as e: 457*6777b538SAndroid Build Coastguard Worker print('Weston fail: %s\n' % str(e), file=sys.stderr) 458*6777b538SAndroid Build Coastguard Worker return 1 459*6777b538SAndroid Build Coastguard Worker finally: 460*6777b538SAndroid Build Coastguard Worker kill(weston_proc, 'weston') 461*6777b538SAndroid Build Coastguard Worker 462*6777b538SAndroid Build Coastguard Worker if os.path.exists(_weston_notify_socket_address()): 463*6777b538SAndroid Build Coastguard Worker os.remove(_weston_notify_socket_address()) 464*6777b538SAndroid Build Coastguard Worker 465*6777b538SAndroid Build Coastguard Worker if os.path.exists(_weston_config_file_path()): 466*6777b538SAndroid Build Coastguard Worker os.remove(_weston_config_file_path()) 467*6777b538SAndroid Build Coastguard Worker 468*6777b538SAndroid Build Coastguard Worker # dbus-daemon is not a subprocess, so we can't SIGTERM+waitpid() on it. 469*6777b538SAndroid Build Coastguard Worker # To ensure it exits, use SIGKILL which should be safe since all other 470*6777b538SAndroid Build Coastguard Worker # processes that it would have been servicing have exited. 471*6777b538SAndroid Build Coastguard Worker if dbus_pid: 472*6777b538SAndroid Build Coastguard Worker os.kill(dbus_pid, signal.SIGKILL) 473*6777b538SAndroid Build Coastguard Worker 474*6777b538SAndroid Build Coastguard Workerdef _weston_notify_socket_address(): 475*6777b538SAndroid Build Coastguard Worker return os.path.join(tempfile.gettempdir(), '.xvfb.py-weston-notify.sock') 476*6777b538SAndroid Build Coastguard Worker 477*6777b538SAndroid Build Coastguard Workerdef _weston_config_file_path(): 478*6777b538SAndroid Build Coastguard Worker return os.path.join(tempfile.gettempdir(), '.xvfb.py-weston.ini') 479*6777b538SAndroid Build Coastguard Worker 480*6777b538SAndroid Build Coastguard Workerdef _get_display_from_weston(weston_proc_pid): 481*6777b538SAndroid Build Coastguard Worker """Retrieves $WAYLAND_DISPLAY set by Weston. 482*6777b538SAndroid Build Coastguard Worker 483*6777b538SAndroid Build Coastguard Worker Returns the $WAYLAND_DISPLAY variable from one of weston's subprocesses. 484*6777b538SAndroid Build Coastguard Worker 485*6777b538SAndroid Build Coastguard Worker Weston updates this variable early in its startup in the main process, but we 486*6777b538SAndroid Build Coastguard Worker can only read the environment variables as they were when the process was 487*6777b538SAndroid Build Coastguard Worker created. Therefore we must use one of weston's subprocesses, which are all 488*6777b538SAndroid Build Coastguard Worker spawned with the new value for $WAYLAND_DISPLAY. Any of them will do, as they 489*6777b538SAndroid Build Coastguard Worker all have the same value set. 490*6777b538SAndroid Build Coastguard Worker 491*6777b538SAndroid Build Coastguard Worker Args: 492*6777b538SAndroid Build Coastguard Worker weston_proc_pid: The process of id of the main Weston process. 493*6777b538SAndroid Build Coastguard Worker 494*6777b538SAndroid Build Coastguard Worker Returns: 495*6777b538SAndroid Build Coastguard Worker the display set by Wayland, which clients can use to connect to. 496*6777b538SAndroid Build Coastguard Worker """ 497*6777b538SAndroid Build Coastguard Worker 498*6777b538SAndroid Build Coastguard Worker # Take the parent process. 499*6777b538SAndroid Build Coastguard Worker parent = psutil.Process(weston_proc_pid) 500*6777b538SAndroid Build Coastguard Worker if parent is None: 501*6777b538SAndroid Build Coastguard Worker return None # The process is not found. Give up. 502*6777b538SAndroid Build Coastguard Worker 503*6777b538SAndroid Build Coastguard Worker # Traverse through all the children processes and find one that has 504*6777b538SAndroid Build Coastguard Worker # $WAYLAND_DISPLAY set. 505*6777b538SAndroid Build Coastguard Worker children = parent.children(recursive=True) 506*6777b538SAndroid Build Coastguard Worker for process in children: 507*6777b538SAndroid Build Coastguard Worker weston_proc_display = process.environ().get('WAYLAND_DISPLAY') 508*6777b538SAndroid Build Coastguard Worker # If display is set, Weston could start successfully and we can use 509*6777b538SAndroid Build Coastguard Worker # that display for Wayland connection in Chromium. 510*6777b538SAndroid Build Coastguard Worker if weston_proc_display is not None: 511*6777b538SAndroid Build Coastguard Worker return weston_proc_display 512*6777b538SAndroid Build Coastguard Worker return None 513*6777b538SAndroid Build Coastguard Worker 514*6777b538SAndroid Build Coastguard Worker 515*6777b538SAndroid Build Coastguard Workerclass MutableBoolean(object): 516*6777b538SAndroid Build Coastguard Worker """Simple mutable boolean class. Used to be mutated inside an handler.""" 517*6777b538SAndroid Build Coastguard Worker 518*6777b538SAndroid Build Coastguard Worker def __init__(self): 519*6777b538SAndroid Build Coastguard Worker self._val = False 520*6777b538SAndroid Build Coastguard Worker 521*6777b538SAndroid Build Coastguard Worker def setvalue(self, val): 522*6777b538SAndroid Build Coastguard Worker assert isinstance(val, bool) 523*6777b538SAndroid Build Coastguard Worker self._val = val 524*6777b538SAndroid Build Coastguard Worker 525*6777b538SAndroid Build Coastguard Worker def getvalue(self): 526*6777b538SAndroid Build Coastguard Worker return self._val 527*6777b538SAndroid Build Coastguard Worker 528*6777b538SAndroid Build Coastguard Worker 529*6777b538SAndroid Build Coastguard Workerdef raise_x11_error(*_): 530*6777b538SAndroid Build Coastguard Worker raise _X11ProcessError('Terminated') 531*6777b538SAndroid Build Coastguard Worker 532*6777b538SAndroid Build Coastguard Worker 533*6777b538SAndroid Build Coastguard Workerdef raise_weston_error(*_): 534*6777b538SAndroid Build Coastguard Worker raise _WestonProcessError('Terminated') 535*6777b538SAndroid Build Coastguard Worker 536*6777b538SAndroid Build Coastguard Worker 537*6777b538SAndroid Build Coastguard Workerdef find_display(): 538*6777b538SAndroid Build Coastguard Worker """Iterates through X-lock files to find an available display number. 539*6777b538SAndroid Build Coastguard Worker 540*6777b538SAndroid Build Coastguard Worker The lower bound follows xvfb-run standard at 99, and the upper bound 541*6777b538SAndroid Build Coastguard Worker is set to 119. 542*6777b538SAndroid Build Coastguard Worker 543*6777b538SAndroid Build Coastguard Worker Returns: 544*6777b538SAndroid Build Coastguard Worker A string of a random available display number for Xvfb ':{99-119}'. 545*6777b538SAndroid Build Coastguard Worker 546*6777b538SAndroid Build Coastguard Worker Raises: 547*6777b538SAndroid Build Coastguard Worker _X11ProcessError: Raised when displays 99 through 119 are unavailable. 548*6777b538SAndroid Build Coastguard Worker """ 549*6777b538SAndroid Build Coastguard Worker 550*6777b538SAndroid Build Coastguard Worker available_displays = [ 551*6777b538SAndroid Build Coastguard Worker d for d in range(99, 120) 552*6777b538SAndroid Build Coastguard Worker if not os.path.isfile('/tmp/.X{}-lock'.format(d)) 553*6777b538SAndroid Build Coastguard Worker ] 554*6777b538SAndroid Build Coastguard Worker if available_displays: 555*6777b538SAndroid Build Coastguard Worker return ':{}'.format(random.choice(available_displays)) 556*6777b538SAndroid Build Coastguard Worker raise _X11ProcessError('Failed to find display number') 557*6777b538SAndroid Build Coastguard Worker 558*6777b538SAndroid Build Coastguard Worker 559*6777b538SAndroid Build Coastguard Workerdef _set_xdg_runtime_dir(env): 560*6777b538SAndroid Build Coastguard Worker """Sets the $XDG_RUNTIME_DIR variable if it hasn't been set before.""" 561*6777b538SAndroid Build Coastguard Worker runtime_dir = env.get('XDG_RUNTIME_DIR') 562*6777b538SAndroid Build Coastguard Worker if not runtime_dir: 563*6777b538SAndroid Build Coastguard Worker runtime_dir = '/tmp/xdg-tmp-dir/' 564*6777b538SAndroid Build Coastguard Worker if not os.path.exists(runtime_dir): 565*6777b538SAndroid Build Coastguard Worker os.makedirs(runtime_dir, 0o700) 566*6777b538SAndroid Build Coastguard Worker env['XDG_RUNTIME_DIR'] = runtime_dir 567*6777b538SAndroid Build Coastguard Worker 568*6777b538SAndroid Build Coastguard Worker 569*6777b538SAndroid Build Coastguard Workerdef main(): 570*6777b538SAndroid Build Coastguard Worker usage = ('Usage: xvfb.py ' 571*6777b538SAndroid Build Coastguard Worker '[command [--no-xvfb or --use_xorg or --use-weston] args...]') 572*6777b538SAndroid Build Coastguard Worker # TODO(crbug.com/326283384): Argparse-ify this. 573*6777b538SAndroid Build Coastguard Worker if len(sys.argv) < 2: 574*6777b538SAndroid Build Coastguard Worker print(usage + '\n', file=sys.stderr) 575*6777b538SAndroid Build Coastguard Worker return 2 576*6777b538SAndroid Build Coastguard Worker 577*6777b538SAndroid Build Coastguard Worker # If the user still thinks the first argument is the execution directory then 578*6777b538SAndroid Build Coastguard Worker # print a friendly error message and quit. 579*6777b538SAndroid Build Coastguard Worker if os.path.isdir(sys.argv[1]): 580*6777b538SAndroid Build Coastguard Worker print('Invalid command: \"%s\" is a directory\n' % sys.argv[1], 581*6777b538SAndroid Build Coastguard Worker file=sys.stderr) 582*6777b538SAndroid Build Coastguard Worker print(usage + '\n', file=sys.stderr) 583*6777b538SAndroid Build Coastguard Worker return 3 584*6777b538SAndroid Build Coastguard Worker 585*6777b538SAndroid Build Coastguard Worker return run_executable(sys.argv[1:], os.environ.copy()) 586*6777b538SAndroid Build Coastguard Worker 587*6777b538SAndroid Build Coastguard Worker 588*6777b538SAndroid Build Coastguard Workerif __name__ == '__main__': 589*6777b538SAndroid Build Coastguard Worker sys.exit(main()) 590