Commit e084e7b0 authored by Erik Jensen's avatar Erik Jensen Committed by Commit Bot

remoting: Implement session chooser for Linux.

Chrome Remote Desktop on Linux sets up a dedicated virtual X server
which runs its own desktop environment separate from any that the user
may be logged into locally. Previously, we would attempt to launch a
default session on boot. This had a few issues:

  1. A full desktop environment would be running at all times, taking up
     resources even if the user only used CRD occasionally.
  2. There was no guarantee that session we launched was the session the
     user wanted in CRD, especially when the system's default session
     might using a resource-hungry desktop environment.
  3. Some desktop environments have trouble running multiple instances
     at the same time under the same user. This could result in
     detrimental effects when logging in locally, in some cases
     including not being able to log in locally at all after installing
     Chrome Remote Desktop.

While all of these issues could be worked around by creating a custom
~/.chrome-remote-desktop-session file and customizing it appropriately,
this was not very discoverable or user friendly.

This patchset aims to address these issues by introducing a new session
chooser that allows the user to pick from among the various session
types installed on their machine. This chooser will appear by default
when no custom session has been configured, but can still be overridden
via /etc/chrome-remote-desktop-session or
~/.chrome-remote-desktop-session. By offering the user a choice of what
session to launch, this addresses (2). It also addresses (1) and (3)
because only the chooser dialog is launched at boot, and a desktop
environment is only started when the user connects and selects a session
type. Additionally, if the user logs out of their session, the CRD
environment will return to the chooser, rather than immediately
relaunching the full session.

Change-Id: Iead83fdad0691384fcde66192ecbba832d03e2d1
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1775932
Commit-Queue: Erik Jensen <rkjnsn@chromium.org>
Reviewed-by: default avatarLambros Lambrou <lambroslambrou@chromium.org>
Reviewed-by: default avatarJamie Walch <jamiewalch@chromium.org>
Cr-Commit-Position: refs/heads/master@{#692302}
parent fd9078ab
...@@ -292,6 +292,8 @@ static_library("common") { ...@@ -292,6 +292,8 @@ static_library("common") {
"username.h", "username.h",
"xmpp_register_support_host_request.cc", "xmpp_register_support_host_request.cc",
"xmpp_register_support_host_request.h", "xmpp_register_support_host_request.h",
"xsession_chooser_linux.cc",
"xsession_chooser_ui.inc",
] ]
libs = [] libs = []
...@@ -384,6 +386,7 @@ static_library("common") { ...@@ -384,6 +386,7 @@ static_library("common") {
"disconnect_window_linux.cc", "disconnect_window_linux.cc",
"me2me_desktop_environment.cc", "me2me_desktop_environment.cc",
"me2me_desktop_environment.h", "me2me_desktop_environment.h",
"xsession_chooser_linux.cc",
] ]
deps += [ deps += [
"//ash", "//ash",
......
...@@ -49,6 +49,9 @@ int DesktopProcessMain(); ...@@ -49,6 +49,9 @@ int DesktopProcessMain();
int FileChooserMain(); int FileChooserMain();
int RdpDesktopSessionMain(); int RdpDesktopSessionMain();
#endif // defined(OS_WIN) #endif // defined(OS_WIN)
#if defined(OS_LINUX)
int XSessionChooserMain();
#endif // defined(OS_LINUX)
namespace { namespace {
...@@ -143,6 +146,10 @@ MainRoutineFn SelectMainRoutine(const std::string& process_type) { ...@@ -143,6 +146,10 @@ MainRoutineFn SelectMainRoutine(const std::string& process_type) {
} else if (process_type == kProcessTypeRdpDesktopSession) { } else if (process_type == kProcessTypeRdpDesktopSession) {
main_routine = &RdpDesktopSessionMain; main_routine = &RdpDesktopSessionMain;
#endif // defined(OS_WIN) #endif // defined(OS_WIN)
#if defined(OS_LINUX)
} else if (process_type == kProcessTypeXSessionChooser) {
main_routine = &XSessionChooserMain;
#endif // defined(OS_LINUX)
} }
return main_routine; return main_routine;
......
...@@ -909,29 +909,8 @@ def choose_x_session(): ...@@ -909,29 +909,8 @@ def choose_x_session():
# current user. # current user.
return ["/bin/sh", startup_file] return ["/bin/sh", startup_file]
# Choose a session wrapper script to run the session. On some systems, # If there's no configuration, show the user a session chooser.
# /etc/X11/Xsession fails to load the user's .profile, so look for an return [HOST_BINARY_PATH, "--type=xsession_chooser"]
# alternative wrapper that is more likely to match the script that the
# system actually uses for console desktop sessions.
SESSION_WRAPPERS = [
"/usr/sbin/lightdm-session",
"/etc/gdm/Xsession",
"/etc/X11/Xsession" ]
for session_wrapper in SESSION_WRAPPERS:
if os.path.exists(session_wrapper):
if os.path.exists("/usr/bin/unity-2d-panel"):
# On Ubuntu 12.04, the default session relies on 3D-accelerated
# hardware. Trying to run this with a virtual X display produces
# weird results on some systems (for example, upside-down and
# corrupt displays). So if the ubuntu-2d session is available,
# choose it explicitly.
return [session_wrapper, "/usr/bin/gnome-session --session=ubuntu-2d"]
else:
# Use the session wrapper by itself, and let the system choose a
# session.
return [session_wrapper]
return None
class ParentProcessLogger(object): class ParentProcessLogger(object):
"""Redirects logs to the parent process, until the host is ready or quits. """Redirects logs to the parent process, until the host is ready or quits.
......
...@@ -21,6 +21,9 @@ const char kProcessTypeHost[] = "host"; ...@@ -21,6 +21,9 @@ const char kProcessTypeHost[] = "host";
const char kProcessTypeRdpDesktopSession[] = "rdp_desktop_session"; const char kProcessTypeRdpDesktopSession[] = "rdp_desktop_session";
const char kProcessTypeEvaluateCapability[] = "evaluate_capability"; const char kProcessTypeEvaluateCapability[] = "evaluate_capability";
const char kProcessTypeFileChooser[] = "file_chooser"; const char kProcessTypeFileChooser[] = "file_chooser";
#if defined(OS_LINUX)
const char kProcessTypeXSessionChooser[] = "xsession_chooser";
#endif // defined(OS_LINUX)
const char kEvaluateCapabilitySwitchName[] = "evaluate-type"; const char kEvaluateCapabilitySwitchName[] = "evaluate-type";
......
...@@ -34,6 +34,9 @@ extern const char kProcessTypeHost[]; ...@@ -34,6 +34,9 @@ extern const char kProcessTypeHost[];
extern const char kProcessTypeRdpDesktopSession[]; extern const char kProcessTypeRdpDesktopSession[];
extern const char kProcessTypeEvaluateCapability[]; extern const char kProcessTypeEvaluateCapability[];
extern const char kProcessTypeFileChooser[]; extern const char kProcessTypeFileChooser[];
#if defined(OS_LINUX)
extern const char kProcessTypeXSessionChooser[];
#endif // defined(OS_LINUX)
extern const char kEvaluateCapabilitySwitchName[]; extern const char kEvaluateCapabilitySwitchName[];
......
This diff is collapsed.
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// The user interface definition used for the session chooser.
namespace remoting {
namespace {
const char UI[] = R"UI_Definition(
<interface>
<requires lib="gtk+" version="3.2"/>
<object class="GtkListStore" id="session_store">
<columns>
<column type="guint"/>
<column type="gchararray"/>
<column type="gchararray"/>
</columns>
</object>
<object class="GtkDialog" id="dialog">
<property name="can_focus">False</property>
<property name="default_width">600</property>
<property name="default_height">400</property>
<property name="type_hint">dialog</property>
<child>
<placeholder/>
</child>
<child internal-child="vbox">
<object class="GtkBox">
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<property name="spacing">2</property>
<child internal-child="action_area">
<object class="GtkButtonBox">
<property name="can_focus">False</property>
<property name="layout_style">end</property>
<child>
<object class="GtkButton" id="ok_button">
<property name="label">gtk-ok</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_stock">True</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="message">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="wrap">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkScrolledWindow">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="shadow_type">in</property>
<child>
<object class="GtkTreeView" id="session_list">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="model">session_store</property>
<child internal-child="selection">
<object class="GtkTreeSelection">
<property name="mode">browse</property>
</object>
</child>
<child>
<object class="GtkTreeViewColumn" id="name_column">
<child>
<object class="GtkCellRendererText"/>
<attributes>
<attribute name="text">1</attribute>
</attributes>
</child>
</object>
</child>
<child>
<object class="GtkTreeViewColumn" id="comment_column">
<child>
<object class="GtkCellRendererText"/>
<attributes>
<attribute name="text">2</attribute>
</attributes>
</child>
</object>
</child>
</object>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
</object>
</child>
</object>
</interface>
)UI_Definition";
} // namespace
} // namespace remoting
...@@ -1332,6 +1332,23 @@ If '<ph name="SERVICE_SCRIPT_NAME">$3<ex>org.chromium.chromoting.me2me.sh</ex></ ...@@ -1332,6 +1332,23 @@ If '<ph name="SERVICE_SCRIPT_NAME">$3<ex>org.chromium.chromoting.me2me.sh</ex></
Not Now Not Now
</message> </message>
</if> </if>
<if expr="is_linux">
<message name="IDS_SESSION_DIALOG_MESSAGE" desc="The message to show at the top of the session-selection dialog.">
Select a session to launch within your Chrome Remote Desktop environment. (Note that some session types may not support running within Chrome Remote Desktop and on the local console simultaneously.)
</message>
<message name="IDS_SESSION_DIALOG_NAME_COLUMN" desc="The title of the column containing the names of potential sessions.">
Name
</message>
<message name="IDS_SESSION_DIALOG_COMMENT_COLUMN" desc="The title of the column containing the comment/description of potential sessions.">
Comment
</message>
<message name="IDS_SESSION_DIALOG_DEFAULT_SESSION_NAME" desc="The name of the entry to launch the default session.">
(default)
</message>
<message name="IDS_SESSION_DIALOG_DEFAULT_SESSION_COMMENT" desc="The comment for the entry to launch the default session.">
Launch the default XSession
</message>
</if> <!-- is_linux -->
</messages> </messages>
</release> </release>
</grit> </grit>
bbb2a1814aec1f4862f443ff4c7b5f899ecbf58d
\ No newline at end of file
bbb2a1814aec1f4862f443ff4c7b5f899ecbf58d
\ No newline at end of file
bbb2a1814aec1f4862f443ff4c7b5f899ecbf58d
\ No newline at end of file
bbb2a1814aec1f4862f443ff4c7b5f899ecbf58d
\ No newline at end of file
bbb2a1814aec1f4862f443ff4c7b5f899ecbf58d
\ No newline at end of file
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment