blob: c82105030ad45ddc56748081b8020a2068716d7c [file] [log] [blame]
// Copyright 2022 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "vm_tools/garcon/screensaver_dbus_service.h"
#include <map>
#include <string>
#include <utility>
#include <vector>
#include "base/process/launch.h"
#include <base/functional/bind.h>
#include <base/logging.h>
#include <base/memory/ptr_util.h>
#include "vm_tools/garcon/host_notifier.h"
namespace {
const char kScreenSaverServiceName[] = "org.freedesktop.ScreenSaver";
const char kScreenSaverServicePath[] = "/org/freedesktop/ScreenSaver";
void HandleSynchronousDBusMethodCall(
base::RepeatingCallback<std::unique_ptr<dbus::Response>(dbus::MethodCall*)>
handler,
dbus::MethodCall* method_call,
dbus::ExportedObject::ResponseSender response_sender) {
auto response = handler.Run(method_call);
if (!response)
response = dbus::Response::FromMethodCall(method_call);
std::move(response_sender).Run(std::move(response));
}
} // namespace
namespace vm_tools {
namespace garcon {
ScreenSaverDBusService::ScreenSaverDBusService(
vm_tools::garcon::HostNotifier* host_notifier)
: host_notifier_(host_notifier) {}
// static
std::unique_ptr<ScreenSaverDBusService> ScreenSaverDBusService::Create(
vm_tools::garcon::HostNotifier* host_notifier) {
auto service = base::WrapUnique(new ScreenSaverDBusService(host_notifier));
if (!service->Init())
return nullptr;
return service;
}
bool ScreenSaverDBusService::RegisterMethods() {
using ServiceMethod = std::unique_ptr<dbus::Response> (
ScreenSaverDBusService::*)(dbus::MethodCall*);
const std::map<const char*, ServiceMethod> kServiceMethods = {
{"Inhibit", &ScreenSaverDBusService::Inhibit},
{"UnInhibit", &ScreenSaverDBusService::Uninhibit},
};
for (const auto& iter : kServiceMethods) {
const bool ret = exported_object_->ExportMethodAndBlock(
kScreenSaverServiceName, iter.first,
base::BindRepeating(
&HandleSynchronousDBusMethodCall,
base::BindRepeating(iter.second, base::Unretained(this))));
if (!ret) {
LOG(ERROR) << "Failed to export method " << iter.first;
return false;
}
}
return true;
}
std::unique_ptr<dbus::Response> ScreenSaverDBusService::Inhibit(
dbus::MethodCall* method_call) {
uint32_t cookie = cookie_counter_++;
dbus::MessageReader reader(method_call);
std::string client;
reader.PopString(&client);
std::string reason;
reader.PopString(&reason);
vm_tools::container::InhibitScreensaverInfo info;
info.set_client(client);
info.set_reason(reason);
info.set_cookie(cookie);
if (!host_notifier_->InhibitScreensaver(std::move(info))) {
LOG(ERROR) << "Failed to inhibit screensaver";
}
std::unique_ptr<dbus::Response> dbus_response(
dbus::Response::FromMethodCall(method_call));
dbus::MessageWriter writer(dbus_response.get());
writer.AppendUint32(cookie);
return dbus_response;
}
std::unique_ptr<dbus::Response> ScreenSaverDBusService::Uninhibit(
dbus::MethodCall* method_call) {
dbus::MessageReader reader(method_call);
uint32_t cookie;
reader.PopUint32(&cookie);
vm_tools::container::UninhibitScreensaverInfo info;
info.set_cookie(cookie);
if (!host_notifier_->UninhibitScreensaver(std::move(info))) {
LOG(ERROR) << "Failed to uninhibit screensaver";
}
std::unique_ptr<dbus::Response> dbus_response(
dbus::Response::FromMethodCall(method_call));
return dbus_response;
}
bool ScreenSaverDBusService::Init() {
dbus::Bus::Options options;
bus_ = new dbus::Bus(options);
if (!bus_->Connect()) {
LOG(ERROR) << "Failed to connect to session bus";
return false;
}
exported_object_ =
bus_->GetExportedObject(dbus::ObjectPath(kScreenSaverServicePath));
if (!exported_object_) {
LOG(ERROR) << "Failed to export " << kScreenSaverServicePath << " object";
return false;
}
if (!RegisterMethods()) {
LOG(ERROR) << "Failed to export methods";
return false;
}
if (!bus_->RequestOwnershipAndBlock(kScreenSaverServiceName,
dbus::Bus::REQUIRE_PRIMARY)) {
LOG(ERROR) << "Unable to take ownership of " << kScreenSaverServiceName;
return false;
}
return true;
}
} // namespace garcon
} // namespace vm_tools