Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 #!/usr/bin/python | 1 #!/usr/bin/python |
| 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
| 4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
| 5 | 5 |
| 6 # Virtual Me2Me implementation. This script runs and manages the processes | 6 # Virtual Me2Me implementation. This script runs and manages the processes |
| 7 # required for a Virtual Me2Me desktop, which are: X server, X desktop | 7 # required for a Virtual Me2Me desktop, which are: X server, X desktop |
| 8 # session, and Host process. | 8 # session, and Host process. |
| 9 # This script is intended to run continuously as a background daemon | 9 # This script is intended to run continuously as a background daemon |
| 10 # process, running under an ordinary (non-root) user account. | 10 # process, running under an ordinary (non-root) user account. |
| (...skipping 24 matching lines...) Expand all Loading... | |
| 35 import time | 35 import time |
| 36 import uuid | 36 import uuid |
| 37 | 37 |
| 38 LOG_FILE_ENV_VAR = "CHROME_REMOTE_DESKTOP_LOG_FILE" | 38 LOG_FILE_ENV_VAR = "CHROME_REMOTE_DESKTOP_LOG_FILE" |
| 39 | 39 |
| 40 # This script has a sensible default for the initial and maximum desktop size, | 40 # This script has a sensible default for the initial and maximum desktop size, |
| 41 # which can be overridden either on the command-line, or via a comma-separated | 41 # which can be overridden either on the command-line, or via a comma-separated |
| 42 # list of sizes in this environment variable. | 42 # list of sizes in this environment variable. |
| 43 DEFAULT_SIZES_ENV_VAR = "CHROME_REMOTE_DESKTOP_DEFAULT_DESKTOP_SIZES" | 43 DEFAULT_SIZES_ENV_VAR = "CHROME_REMOTE_DESKTOP_DEFAULT_DESKTOP_SIZES" |
| 44 | 44 |
| 45 # By default, this script launches Xvfb as the virtual X display. When this | |
| 46 # environment variable is set, the script will instead launch an instance of | |
| 47 # Xorg using the dummy display driver and void input device. In order for this | |
| 48 # to work, both the dummy display driver and void input device need to be | |
| 49 # installed: | |
| 50 # | |
| 51 # sudo apt-get install xserver-xorg-video-dummy | |
| 52 # sudo apt-get install xserver-xorg-input-void | |
|
Lambros
2016/05/10 21:06:57
This is OK for now, but when we make Xorg+dummy th
rkjnsn
2016/05/10 21:38:03
Certainly. Should I add a TODO?
| |
| 53 USE_XORG_ENV_VAR = "CHROME_REMOTE_DESKTOP_USE_XORG" | |
| 54 | |
| 55 # The amount of video RAM the dummy driver should claim to have, which limits | |
| 56 # the maximum possible resolution. | |
| 57 # 1048576 KiB = 1 GiB, which is the amount of video RAM needed to have a | |
| 58 # 16384x16384 pixel frame buffer (the maximum size supported by VP8) with 32 | |
| 59 # bits per pixel. | |
| 60 XORG_DUMMY_VIDEO_RAM = 1048576 # KiB | |
| 61 | |
| 45 # By default, provide a maximum size that is large enough to support clients | 62 # By default, provide a maximum size that is large enough to support clients |
| 46 # with large or multiple monitors. This is a comma-separated list of | 63 # with large or multiple monitors. This is a comma-separated list of |
| 47 # resolutions that will be made available if the X server supports RANDR. These | 64 # resolutions that will be made available if the X server supports RANDR. These |
| 48 # defaults can be overridden in ~/.profile. | 65 # defaults can be overridden in ~/.profile. |
| 49 DEFAULT_SIZES = "1600x1200,3840x2560" | 66 DEFAULT_SIZES = "1600x1200,3840x2560" |
| 50 | 67 |
| 51 # If RANDR is not available, use a smaller default size. Only a single | 68 # If RANDR is not available, use a smaller default size. Only a single |
| 52 # resolution is supported in this case. | 69 # resolution is supported in this case. |
| 53 DEFAULT_SIZE_NO_RANDR = "1600x1200" | 70 DEFAULT_SIZE_NO_RANDR = "1600x1200" |
| 54 | 71 |
| (...skipping 27 matching lines...) Expand all Loading... | |
| 82 | 99 |
| 83 # Thresholds for switching from fast- to slow-restart and for giving up | 100 # Thresholds for switching from fast- to slow-restart and for giving up |
| 84 # trying to restart entirely. | 101 # trying to restart entirely. |
| 85 SHORT_BACKOFF_THRESHOLD = 5 | 102 SHORT_BACKOFF_THRESHOLD = 5 |
| 86 MAX_LAUNCH_FAILURES = SHORT_BACKOFF_THRESHOLD + 10 | 103 MAX_LAUNCH_FAILURES = SHORT_BACKOFF_THRESHOLD + 10 |
| 87 | 104 |
| 88 # Globals needed by the atexit cleanup() handler. | 105 # Globals needed by the atexit cleanup() handler. |
| 89 g_desktops = [] | 106 g_desktops = [] |
| 90 g_host_hash = hashlib.md5(socket.gethostname()).hexdigest() | 107 g_host_hash = hashlib.md5(socket.gethostname()).hexdigest() |
| 91 | 108 |
| 109 def gen_xorg_config(sizes): | |
| 110 return ( | |
| 111 # This causes X to load the default GLX module, even if a proprietary one | |
| 112 # is installed in a different directory. | |
| 113 'Section "Files"\n' | |
| 114 ' ModulePath "/usr/lib/xorg/modules"\n' | |
| 115 'EndSection\n' | |
| 116 '\n' | |
| 117 # Suppress device probing, which happens by default. | |
| 118 'Section "ServerFlags"\n' | |
| 119 ' Option "AutoAddDevices" "false"\n' | |
| 120 ' Option "AutoEnableDevices" "false"\n' | |
| 121 ' Option "DontVTSwitch" "true"\n' | |
| 122 ' Option "PciForceNone" "true"\n' | |
| 123 'EndSection\n' | |
| 124 '\n' | |
| 125 'Section "InputDevice"\n' | |
| 126 # The host looks for this name to check whether it's running in a virtual | |
| 127 # session | |
| 128 ' Identifier "Chrome Remote Desktop Input"\n' | |
| 129 # While the xorg.conf man page specifies that both of these options are | |
| 130 # deprecated synonyms for `Option "Floating" "false"`, it turns out that | |
| 131 # if both aren't specified, the Xorg server will automatically attempt to | |
| 132 # add additional devices. | |
| 133 ' Option "CoreKeyboard" "true"\n' | |
| 134 ' Option "CorePointer" "true"\n' | |
| 135 ' Driver "void"\n' | |
| 136 'EndSection\n' | |
| 137 '\n' | |
| 138 'Section "Device"\n' | |
| 139 ' Identifier "Chrome Remote Desktop Videocard"\n' | |
| 140 ' Driver "dummy"\n' | |
| 141 ' VideoRam {video_ram}\n' | |
| 142 'EndSection\n' | |
| 143 '\n' | |
| 144 'Section "Monitor"\n' | |
| 145 ' Identifier "Chrome Remote Desktop Monitor"\n' | |
| 146 # The horizontal sync rate was calculated from the vertical refresh rate | |
| 147 # and the modline template: | |
| 148 # (33000 (vert total) * 0.1 Hz = 3.3 kHz) | |
| 149 ' HorizSync 3.3\n' # kHz | |
| 150 # The vertical refresh rate was chosen both to be low enough to have an | |
| 151 # acceptable dot clock at high resolutions, and then bumped down a little | |
| 152 # more so that in the unlikely event that a low refresh rate would break | |
| 153 # something, it would break obviously. | |
| 154 ' VertRefresh 0.1\n' # Hz | |
| 155 '{modelines}' | |
| 156 'EndSection\n' | |
| 157 '\n' | |
| 158 'Section "Screen"\n' | |
| 159 ' Identifier "Chrome Remote Desktop Screen"\n' | |
| 160 ' Device "Chrome Remote Desktop Videocard"\n' | |
| 161 ' Monitor "Chrome Remote Desktop Monitor"\n' | |
| 162 ' DefaultDepth 24\n' | |
| 163 ' SubSection "Display"\n' | |
| 164 ' Viewport 0 0\n' | |
| 165 ' Depth 24\n' | |
| 166 ' Modes {modes}\n' | |
| 167 ' EndSubSection\n' | |
| 168 'EndSection\n' | |
| 169 '\n' | |
| 170 'Section "ServerLayout"\n' | |
| 171 ' Identifier "Chrome Remote Desktop Layout"\n' | |
| 172 ' Screen "Chrome Remote Desktop Screen"\n' | |
| 173 ' InputDevice "Chrome Remote Desktop Input"\n' | |
| 174 'EndSection\n'.format( | |
| 175 # This Modeline template allows resolutions up to the dummy driver's | |
| 176 # max supported resolution of 32767x32767 without additional | |
| 177 # calculation while meeting the driver's dot clock requirements. Note | |
| 178 # that VP8 (and thus the amount of video RAM chosen) only support a | |
| 179 # maximum resolution of 16384x16384. | |
| 180 # 32767x32767 should be possible if we switch fully to VP9 and | |
| 181 # increase the video RAM to 4GiB. | |
| 182 # The dot clock was calculated to match the VirtRefresh chosen above. | |
| 183 # (33000 * 33000 * 0.1 Hz = 108.9 MHz) | |
| 184 # Changes this line require matching changes to HorizSync and | |
| 185 # VertRefresh. | |
| 186 modelines="".join( | |
| 187 ' Modeline "{0}x{1}" 108.9 {0} 32998 32999 33000 ' | |
| 188 '{1} 32998 32999 33000\n'.format(w, h) for w, h in sizes), | |
| 189 modes=" ".join('"{0}x{1}"'.format(w, h) for w, h in sizes), | |
| 190 video_ram=XORG_DUMMY_VIDEO_RAM)) | |
| 191 | |
| 92 | 192 |
| 93 def is_supported_platform(): | 193 def is_supported_platform(): |
| 94 # Always assume that the system is supported if the config directory or | 194 # Always assume that the system is supported if the config directory or |
| 95 # session file exist. | 195 # session file exist. |
| 96 if (os.path.isdir(CONFIG_DIR) or os.path.isfile(SESSION_FILE_PATH) or | 196 if (os.path.isdir(CONFIG_DIR) or os.path.isfile(SESSION_FILE_PATH) or |
| 97 os.path.isfile(SYSTEM_SESSION_FILE_PATH)): | 197 os.path.isfile(SYSTEM_SESSION_FILE_PATH)): |
| 98 return True | 198 return True |
| 99 | 199 |
| 100 # The host has been tested only on Ubuntu. | 200 # The host has been tested only on Ubuntu. |
| 101 distribution = platform.linux_distribution() | 201 distribution = platform.linux_distribution() |
| 102 return (distribution[0]).lower() == 'ubuntu' | 202 return (distribution[0]).lower() == 'ubuntu' |
| 103 | 203 |
| 104 | 204 |
| 105 def get_randr_supporting_x_server(): | 205 def locate_xvfb_randr(): |
| 106 """Returns a path to an X server that supports the RANDR extension, if this | 206 """Returns a path to our RANDR-supporting Xvfb server, if it is found on the |
| 107 is found on the system. Otherwise returns None.""" | 207 system. Otherwise returns None.""" |
| 108 | 208 |
| 109 xvfb = "/usr/bin/Xvfb-randr" | 209 xvfb = "/usr/bin/Xvfb-randr" |
| 110 if os.path.exists(xvfb): | 210 if os.path.exists(xvfb): |
| 111 return xvfb | 211 return xvfb |
| 112 | 212 |
| 113 xvfb = os.path.join(SCRIPT_DIR, "Xvfb-randr") | 213 xvfb = os.path.join(SCRIPT_DIR, "Xvfb-randr") |
| 114 if os.path.exists(xvfb): | 214 if os.path.exists(xvfb): |
| 115 return xvfb | 215 return xvfb |
| 116 | 216 |
| 117 return None | 217 return None |
| (...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 231 | 331 |
| 232 class Desktop: | 332 class Desktop: |
| 233 """Manage a single virtual desktop""" | 333 """Manage a single virtual desktop""" |
| 234 | 334 |
| 235 def __init__(self, sizes): | 335 def __init__(self, sizes): |
| 236 self.x_proc = None | 336 self.x_proc = None |
| 237 self.session_proc = None | 337 self.session_proc = None |
| 238 self.host_proc = None | 338 self.host_proc = None |
| 239 self.child_env = None | 339 self.child_env = None |
| 240 self.sizes = sizes | 340 self.sizes = sizes |
| 341 self.xorg_conf = None | |
| 241 self.pulseaudio_pipe = None | 342 self.pulseaudio_pipe = None |
| 242 self.server_supports_exact_resize = False | 343 self.server_supports_exact_resize = False |
| 243 self.host_ready = False | 344 self.host_ready = False |
| 244 self.ssh_auth_sockname = None | 345 self.ssh_auth_sockname = None |
| 245 g_desktops.append(self) | 346 g_desktops.append(self) |
| 246 | 347 |
| 247 @staticmethod | 348 @staticmethod |
| 248 def get_unused_display_number(): | 349 def get_unused_display_number(): |
| 249 """Return a candidate display number for which there is currently no | 350 """Return a candidate display number for which there is currently no |
| 250 X Server lock file""" | 351 X Server lock file""" |
| (...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 349 self.child_env["PULSE_STATE_PATH"] = pulse_path | 450 self.child_env["PULSE_STATE_PATH"] = pulse_path |
| 350 self.child_env["PULSE_SINK"] = sink_name | 451 self.child_env["PULSE_SINK"] = sink_name |
| 351 self.pulseaudio_pipe = pipe_name | 452 self.pulseaudio_pipe = pipe_name |
| 352 | 453 |
| 353 return True | 454 return True |
| 354 | 455 |
| 355 def _setup_gnubby(self): | 456 def _setup_gnubby(self): |
| 356 self.ssh_auth_sockname = ("/tmp/chromoting.%s.ssh_auth_sock" % | 457 self.ssh_auth_sockname = ("/tmp/chromoting.%s.ssh_auth_sock" % |
| 357 os.environ["USER"]) | 458 os.environ["USER"]) |
| 358 | 459 |
| 460 def _launch_xvfb(self, display, x_auth_file, extra_x_args): | |
| 461 max_width = max([width for width, height in self.sizes]) | |
| 462 max_height = max([height for width, height in self.sizes]) | |
| 463 | |
| 464 xvfb = locate_xvfb_randr() | |
| 465 if xvfb: | |
| 466 self.server_supports_exact_resize = True | |
| 467 else: | |
| 468 xvfb = "Xvfb" | |
| 469 self.server_supports_exact_resize = False | |
| 470 | |
| 471 logging.info("Starting %s on display :%d" % (xvfb, display)) | |
| 472 screen_option = "%dx%dx24" % (max_width, max_height) | |
| 473 self.x_proc = subprocess.Popen( | |
| 474 [xvfb, ":%d" % display, | |
| 475 "-auth", x_auth_file, | |
| 476 "-nolisten", "tcp", | |
| 477 "-noreset", | |
| 478 "-screen", "0", screen_option | |
| 479 ] + extra_x_args) | |
| 480 if not self.x_proc.pid: | |
| 481 raise Exception("Could not start Xvfb.") | |
| 482 | |
| 483 def _launch_xorg(self, display, x_auth_file, extra_x_args): | |
| 484 with tempfile.NamedTemporaryFile( | |
| 485 prefix="chrome_remote_desktop_", | |
| 486 suffix=".conf", delete=False) as config_file: | |
| 487 config_file.write(gen_xorg_config(self.sizes)) | |
| 488 | |
| 489 # For now, we don't support exact resize with Xorg+dummy | |
| 490 self.server_supports_exact_resize = False | |
| 491 self.xorg_conf = config_file.name | |
| 492 | |
| 493 logging.info("Starting Xorg on display :%d" % display) | |
| 494 # We use the child environment so the Xorg server picks up the Mesa libGL | |
| 495 # instead of any proprietary versions that may be installed, thanks to | |
| 496 # LD_LIBRARY_PATH. | |
| 497 # Note: This prevents any environment variable the user has set from | |
| 498 # affecting the Xorg server. | |
| 499 self.x_proc = subprocess.Popen( | |
| 500 ["Xorg", ":%d" % display, | |
| 501 "-auth", x_auth_file, | |
| 502 "-nolisten", "tcp", | |
| 503 "-noreset", | |
| 504 # Disable logging to a file and instead bump up the stderr verbosity | |
| 505 # so the equivalent information gets logged in our main log file. | |
| 506 "-logfile", "/dev/null", | |
| 507 "-verbose", "3", | |
| 508 "-config", config_file.name | |
| 509 ] + extra_x_args, env=self.child_env) | |
| 510 if not self.x_proc.pid: | |
| 511 raise Exception("Could not start Xorg.") | |
| 512 | |
| 359 def _launch_x_server(self, extra_x_args): | 513 def _launch_x_server(self, extra_x_args): |
| 360 x_auth_file = os.path.expanduser("~/.Xauthority") | 514 x_auth_file = os.path.expanduser("~/.Xauthority") |
| 361 self.child_env["XAUTHORITY"] = x_auth_file | 515 self.child_env["XAUTHORITY"] = x_auth_file |
| 362 devnull = open(os.devnull, "r+") | 516 devnull = open(os.devnull, "r+") |
| 363 display = self.get_unused_display_number() | 517 display = self.get_unused_display_number() |
| 364 | 518 |
| 365 # Run "xauth add" with |child_env| so that it modifies the same XAUTHORITY | 519 # Run "xauth add" with |child_env| so that it modifies the same XAUTHORITY |
| 366 # file which will be used for the X session. | 520 # file which will be used for the X session. |
| 367 ret_code = subprocess.call("xauth add :%d . `mcookie`" % display, | 521 ret_code = subprocess.call("xauth add :%d . `mcookie`" % display, |
| 368 env=self.child_env, shell=True) | 522 env=self.child_env, shell=True) |
| 369 if ret_code != 0: | 523 if ret_code != 0: |
| 370 raise Exception("xauth failed with code %d" % ret_code) | 524 raise Exception("xauth failed with code %d" % ret_code) |
| 371 | 525 |
| 372 max_width = max([width for width, height in self.sizes]) | |
| 373 max_height = max([height for width, height in self.sizes]) | |
| 374 | |
| 375 xvfb = get_randr_supporting_x_server() | |
| 376 if xvfb: | |
| 377 self.server_supports_exact_resize = True | |
| 378 else: | |
| 379 xvfb = "Xvfb" | |
| 380 self.server_supports_exact_resize = False | |
| 381 | |
| 382 # Disable the Composite extension iff the X session is the default | 526 # Disable the Composite extension iff the X session is the default |
| 383 # Unity-2D, since it uses Metacity which fails to generate DAMAGE | 527 # Unity-2D, since it uses Metacity which fails to generate DAMAGE |
| 384 # notifications correctly. See crbug.com/166468. | 528 # notifications correctly. See crbug.com/166468. |
| 385 x_session = choose_x_session() | 529 x_session = choose_x_session() |
| 386 if (len(x_session) == 2 and | 530 if (len(x_session) == 2 and |
| 387 x_session[1] == "/usr/bin/gnome-session --session=ubuntu-2d"): | 531 x_session[1] == "/usr/bin/gnome-session --session=ubuntu-2d"): |
| 388 extra_x_args.extend(["-extension", "Composite"]) | 532 extra_x_args.extend(["-extension", "Composite"]) |
| 389 | 533 |
| 390 logging.info("Starting %s on display :%d" % (xvfb, display)) | 534 if USE_XORG_ENV_VAR in os.environ: |
| 391 screen_option = "%dx%dx24" % (max_width, max_height) | 535 self._launch_xorg(display, x_auth_file, extra_x_args) |
| 392 self.x_proc = subprocess.Popen( | 536 else: |
| 393 [xvfb, ":%d" % display, | 537 self._launch_xvfb(display, x_auth_file, extra_x_args) |
| 394 "-auth", x_auth_file, | |
| 395 "-nolisten", "tcp", | |
| 396 "-noreset", | |
| 397 "-screen", "0", screen_option | |
| 398 ] + extra_x_args) | |
| 399 if not self.x_proc.pid: | |
| 400 raise Exception("Could not start Xvfb.") | |
| 401 | 538 |
| 402 self.child_env["DISPLAY"] = ":%d" % display | 539 self.child_env["DISPLAY"] = ":%d" % display |
| 403 self.child_env["CHROME_REMOTE_DESKTOP_SESSION"] = "1" | 540 self.child_env["CHROME_REMOTE_DESKTOP_SESSION"] = "1" |
| 404 | 541 |
| 405 # Use a separate profile for any instances of Chrome that are started in | 542 # Use a separate profile for any instances of Chrome that are started in |
| 406 # the virtual session. Chrome doesn't support sharing a profile between | 543 # the virtual session. Chrome doesn't support sharing a profile between |
| 407 # multiple DISPLAYs, but Chrome Sync allows for a reasonable compromise. | 544 # multiple DISPLAYs, but Chrome Sync allows for a reasonable compromise. |
| 408 chrome_profile = os.path.join(CONFIG_DIR, "chrome-profile") | 545 chrome_profile = os.path.join(CONFIG_DIR, "chrome-profile") |
| 409 self.child_env["CHROME_USER_DATA_DIR"] = chrome_profile | 546 self.child_env["CHROME_USER_DATA_DIR"] = chrome_profile |
| 410 | 547 |
| 411 # Set SSH_AUTH_SOCK to the file name to listen on. | 548 # Set SSH_AUTH_SOCK to the file name to listen on. |
| 412 if self.ssh_auth_sockname: | 549 if self.ssh_auth_sockname: |
| 413 self.child_env["SSH_AUTH_SOCK"] = self.ssh_auth_sockname | 550 self.child_env["SSH_AUTH_SOCK"] = self.ssh_auth_sockname |
| 414 | 551 |
| 415 # Wait for X to be active. | 552 # Wait for X to be active. |
| 416 for _test in range(20): | 553 for _test in range(20): |
| 417 retcode = subprocess.call("xdpyinfo", env=self.child_env, stdout=devnull) | 554 retcode = subprocess.call("xdpyinfo", env=self.child_env, stdout=devnull) |
| 418 if retcode == 0: | 555 if retcode == 0: |
| 419 break | 556 break |
| 420 time.sleep(0.5) | 557 time.sleep(0.5) |
| 421 if retcode != 0: | 558 if retcode != 0: |
| 422 raise Exception("Could not connect to Xvfb.") | 559 raise Exception("Could not connect to X server.") |
| 423 else: | 560 else: |
| 424 logging.info("Xvfb is active.") | 561 logging.info("X server is active.") |
| 425 | 562 |
| 426 # The remoting host expects the server to use "evdev" keycodes, but Xvfb | 563 # The remoting host expects the server to use "evdev" keycodes, but Xvfb |
| 427 # starts configured to use the "base" ruleset, resulting in XKB configuring | 564 # starts configured to use the "base" ruleset, resulting in XKB configuring |
| 428 # for "xfree86" keycodes, and screwing up some keys. See crbug.com/119013. | 565 # for "xfree86" keycodes, and screwing up some keys. See crbug.com/119013. |
| 429 # Reconfigure the X server to use "evdev" keymap rules. The X server must | 566 # Reconfigure the X server to use "evdev" keymap rules. The X server must |
| 430 # be started with -noreset otherwise it'll reset as soon as the command | 567 # be started with -noreset otherwise it'll reset as soon as the command |
| 431 # completes, since there are no other X clients running yet. | 568 # completes, since there are no other X clients running yet. |
| 432 retcode = subprocess.call("setxkbmap -rules evdev", env=self.child_env, | 569 retcode = subprocess.call("setxkbmap -rules evdev", env=self.child_env, |
| 433 shell=True) | 570 shell=True) |
| 434 if retcode != 0: | 571 if retcode != 0: |
| (...skipping 389 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 824 # Close the temporary file-descriptors. | 961 # Close the temporary file-descriptors. |
| 825 os.close(devnull_fd) | 962 os.close(devnull_fd) |
| 826 os.close(log_fd) | 963 os.close(log_fd) |
| 827 | 964 |
| 828 | 965 |
| 829 def cleanup(): | 966 def cleanup(): |
| 830 logging.info("Cleanup.") | 967 logging.info("Cleanup.") |
| 831 | 968 |
| 832 global g_desktops | 969 global g_desktops |
| 833 for desktop in g_desktops: | 970 for desktop in g_desktops: |
| 834 for proc, name in [(desktop.x_proc, "Xvfb"), | 971 for proc, name in [(desktop.x_proc, "X server"), |
| 835 (desktop.session_proc, "session"), | 972 (desktop.session_proc, "session"), |
| 836 (desktop.host_proc, "host")]: | 973 (desktop.host_proc, "host")]: |
| 837 if proc is not None: | 974 if proc is not None: |
| 838 logging.info("Terminating " + name) | 975 logging.info("Terminating " + name) |
| 839 try: | 976 try: |
| 840 psutil_proc = psutil.Process(proc.pid) | 977 psutil_proc = psutil.Process(proc.pid) |
| 841 psutil_proc.terminate() | 978 psutil_proc.terminate() |
| 842 | 979 |
| 843 # Use a short timeout, to avoid delaying service shutdown if the | 980 # Use a short timeout, to avoid delaying service shutdown if the |
| 844 # process refuses to die for some reason. | 981 # process refuses to die for some reason. |
| 845 psutil_proc.wait(timeout=10) | 982 psutil_proc.wait(timeout=10) |
| 846 except psutil.TimeoutExpired: | 983 except psutil.TimeoutExpired: |
| 847 logging.error("Timed out - sending SIGKILL") | 984 logging.error("Timed out - sending SIGKILL") |
| 848 psutil_proc.kill() | 985 psutil_proc.kill() |
| 849 except psutil.Error: | 986 except psutil.Error: |
| 850 logging.error("Error terminating process") | 987 logging.error("Error terminating process") |
| 988 if desktop.xorg_conf is not None: | |
| 989 os.remove(desktop.xorg_conf) | |
| 851 | 990 |
| 852 g_desktops = [] | 991 g_desktops = [] |
| 853 if ParentProcessLogger.instance(): | 992 if ParentProcessLogger.instance(): |
| 854 ParentProcessLogger.instance().release_parent(False) | 993 ParentProcessLogger.instance().release_parent(False) |
| 855 | 994 |
| 856 class SignalHandler: | 995 class SignalHandler: |
| 857 """Reload the config file on SIGHUP. Since we pass the configuration to the | 996 """Reload the config file on SIGHUP. Since we pass the configuration to the |
| 858 host processes via stdin, they can't reload it, so terminate them. They will | 997 host processes via stdin, they can't reload it, so terminate them. They will |
| 859 be relaunched automatically with the new config.""" | 998 be relaunched automatically with the new config.""" |
| 860 | 999 |
| (...skipping 180 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1041 def main(): | 1180 def main(): |
| 1042 EPILOG = """This script is not intended for use by end-users. To configure | 1181 EPILOG = """This script is not intended for use by end-users. To configure |
| 1043 Chrome Remote Desktop, please install the app from the Chrome | 1182 Chrome Remote Desktop, please install the app from the Chrome |
| 1044 Web Store: https://chrome.google.com/remotedesktop""" | 1183 Web Store: https://chrome.google.com/remotedesktop""" |
| 1045 parser = optparse.OptionParser( | 1184 parser = optparse.OptionParser( |
| 1046 usage="Usage: %prog [options] [ -- [ X server options ] ]", | 1185 usage="Usage: %prog [options] [ -- [ X server options ] ]", |
| 1047 epilog=EPILOG) | 1186 epilog=EPILOG) |
| 1048 parser.add_option("-s", "--size", dest="size", action="append", | 1187 parser.add_option("-s", "--size", dest="size", action="append", |
| 1049 help="Dimensions of virtual desktop. This can be specified " | 1188 help="Dimensions of virtual desktop. This can be specified " |
| 1050 "multiple times to make multiple screen resolutions " | 1189 "multiple times to make multiple screen resolutions " |
| 1051 "available (if the Xvfb server supports this).") | 1190 "available (if the X server supports this).") |
| 1052 parser.add_option("-f", "--foreground", dest="foreground", default=False, | 1191 parser.add_option("-f", "--foreground", dest="foreground", default=False, |
| 1053 action="store_true", | 1192 action="store_true", |
| 1054 help="Don't run as a background daemon.") | 1193 help="Don't run as a background daemon.") |
| 1055 parser.add_option("", "--start", dest="start", default=False, | 1194 parser.add_option("", "--start", dest="start", default=False, |
| 1056 action="store_true", | 1195 action="store_true", |
| 1057 help="Start the host.") | 1196 help="Start the host.") |
| 1058 parser.add_option("-k", "--stop", dest="stop", default=False, | 1197 parser.add_option("-k", "--stop", dest="stop", default=False, |
| 1059 action="store_true", | 1198 action="store_true", |
| 1060 help="Stop the daemon currently running.") | 1199 help="Stop the daemon currently running.") |
| 1061 parser.add_option("", "--get-status", dest="get_status", default=False, | 1200 parser.add_option("", "--get-status", dest="get_status", default=False, |
| (...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1175 watch_for_resolution_changes(options.watch_resolution) | 1314 watch_for_resolution_changes(options.watch_resolution) |
| 1176 return 0 | 1315 return 0 |
| 1177 | 1316 |
| 1178 if not options.start: | 1317 if not options.start: |
| 1179 # If no modal command-line options specified, print an error and exit. | 1318 # If no modal command-line options specified, print an error and exit. |
| 1180 print(EPILOG, file=sys.stderr) | 1319 print(EPILOG, file=sys.stderr) |
| 1181 return 1 | 1320 return 1 |
| 1182 | 1321 |
| 1183 # If a RANDR-supporting Xvfb is not available, limit the default size to | 1322 # If a RANDR-supporting Xvfb is not available, limit the default size to |
| 1184 # something more sensible. | 1323 # something more sensible. |
| 1185 if get_randr_supporting_x_server(): | 1324 if USE_XORG_ENV_VAR not in os.environ and locate_xvfb_randr(): |
| 1186 default_sizes = DEFAULT_SIZES | 1325 default_sizes = DEFAULT_SIZES |
| 1187 else: | 1326 else: |
| 1188 default_sizes = DEFAULT_SIZE_NO_RANDR | 1327 default_sizes = DEFAULT_SIZE_NO_RANDR |
| 1189 | 1328 |
| 1190 # Collate the list of sizes that XRANDR should support. | 1329 # Collate the list of sizes that XRANDR should support. |
| 1191 if not options.size: | 1330 if not options.size: |
| 1192 if DEFAULT_SIZES_ENV_VAR in os.environ: | 1331 if DEFAULT_SIZES_ENV_VAR in os.environ: |
| 1193 default_sizes = os.environ[DEFAULT_SIZES_ENV_VAR] | 1332 default_sizes = os.environ[DEFAULT_SIZES_ENV_VAR] |
| 1194 options.size = default_sizes.split(",") | 1333 options.size = default_sizes.split(",") |
| 1195 | 1334 |
| (...skipping 180 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1376 else: | 1515 else: |
| 1377 logging.info("Host exited with status %s." % os.WEXITSTATUS(status)) | 1516 logging.info("Host exited with status %s." % os.WEXITSTATUS(status)) |
| 1378 elif os.WIFSIGNALED(status): | 1517 elif os.WIFSIGNALED(status): |
| 1379 logging.info("Host terminated by signal %s." % os.WTERMSIG(status)) | 1518 logging.info("Host terminated by signal %s." % os.WTERMSIG(status)) |
| 1380 | 1519 |
| 1381 | 1520 |
| 1382 if __name__ == "__main__": | 1521 if __name__ == "__main__": |
| 1383 logging.basicConfig(level=logging.DEBUG, | 1522 logging.basicConfig(level=logging.DEBUG, |
| 1384 format="%(asctime)s:%(levelname)s:%(message)s") | 1523 format="%(asctime)s:%(levelname)s:%(message)s") |
| 1385 sys.exit(main()) | 1524 sys.exit(main()) |
| OLD | NEW |