blob: b32dae6a9e975b1dbc8886bd5da16b7853edb6e7 [file] [log] [blame]
// Copyright 2025 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "remoting/host/linux/gnome_headless_detector.h"
#include <utility>
#include "base/containers/contains.h"
#include "base/functional/bind.h"
#include "remoting/base/logging.h"
#include "remoting/host/linux/dbus_interfaces/org_freedesktop_systemd1_Manager.h"
#include "remoting/host/linux/dbus_interfaces/org_freedesktop_systemd1_Service.h"
#include "remoting/host/linux/dbus_interfaces/org_freedesktop_systemd1_Unit.h"
namespace remoting {
namespace {
constexpr char kSystemdBusName[] = "org.freedesktop.systemd1";
} // namespace
GnomeHeadlessDetector::GnomeHeadlessDetector() = default;
GnomeHeadlessDetector::~GnomeHeadlessDetector() = default;
void GnomeHeadlessDetector::Start(GDBusConnectionRef connection,
Callback callback) {
dbus_connection_ = std::move(connection);
callback_ = std::move(callback);
dbus_connection_.Call<org_freedesktop_systemd1_Manager::GetUnit>(
kSystemdBusName, "/org/freedesktop/systemd1",
std::tuple("org.gnome.Shell@wayland.service"),
base::BindOnce(&GnomeHeadlessDetector::OnGetUnitReply,
weak_factory_.GetWeakPtr()));
}
void GnomeHeadlessDetector::OnGetUnitReply(
base::expected<std::tuple<gvariant::ObjectPath>, Loggable> result) {
if (!result.has_value()) {
LOG(ERROR) << "GetUnit failed: " << result.error();
std::move(callback_).Run(false);
return;
}
systemd_unit_path_ = std::get<0>(result.value());
dbus_connection_.GetProperty<org_freedesktop_systemd1_Unit::ActiveState>(
kSystemdBusName, systemd_unit_path_,
base::BindOnce(&GnomeHeadlessDetector::OnActiveStateReply,
weak_factory_.GetWeakPtr()));
}
void GnomeHeadlessDetector::OnActiveStateReply(
base::expected<std::string, Loggable> result) {
if (!result.has_value()) {
LOG(ERROR) << "Failed to get ActiveState: " << result.error();
std::move(callback_).Run(false);
return;
}
if (result.value() != "active") {
LOG(ERROR) << "GNOME Shell service is not running, ActiveState returned: "
<< result.value();
std::move(callback_).Run(false);
return;
}
dbus_connection_.GetProperty<org_freedesktop_systemd1_Service::ExecStart>(
kSystemdBusName, systemd_unit_path_,
base::BindOnce(&GnomeHeadlessDetector::OnExecStartReply,
weak_factory_.GetWeakPtr()));
}
void GnomeHeadlessDetector::OnExecStartReply(
base::expected<std::vector<GVariantRef<"(sasbttttuii)">>, Loggable>
result) {
if (!result.has_value()) {
LOG(ERROR) << "Failed to get ExecStart: " << result.error();
std::move(callback_).Run(false);
return;
}
if (result.value().size() != 1) {
LOG(ERROR) << "Expected ExecStart to have 1 element, got "
<< result.value().size();
std::move(callback_).Run(false);
return;
}
const auto& exec_start = result.value()[0];
auto exe = exec_start.get<0>().Into<std::string>();
constexpr char kGnomeShellPath[] = "/usr/bin/gnome-shell";
if (exe != kGnomeShellPath) {
LOG(ERROR) << "Expected " << kGnomeShellPath << ", but got " << exe;
std::move(callback_).Run(false);
return;
}
auto args = exec_start.get<1>().Into<std::vector<std::string>>();
constexpr char kHeadlessArg[] = "--headless";
if (!base::Contains(args, kHeadlessArg)) {
HOST_LOG << "Did not find '" << kHeadlessArg << "' in gnome-shell args";
std::move(callback_).Run(false);
return;
}
HOST_LOG << "GNOME Wayland session is headless.";
std::move(callback_).Run(true);
}
} // namespace remoting