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