blob: 2e06230293a08b7f0ee7133a5062de265eea236a [file] [log] [blame]
// Copyright 2016 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "power_manager/powerd/system/dbus_wrapper.h"
#include <memory>
#include <utility>
#include <base/bind.h>
#include <base/logging.h>
#include <base/memory/ptr_util.h>
#include <chromeos/dbus/service_constants.h>
#include <dbus/bus.h>
#include <dbus/message.h>
#include <google/protobuf/message_lite.h>
#include "power_manager/common/power_constants.h"
namespace power_manager {
namespace system {
namespace {
// Handles the result of an attempt to connect to a D-Bus signal, logging an
// error on failure.
void HandleSignalConnected(const std::string& interface,
const std::string& signal,
bool success) {
if (!success)
LOG(ERROR) << "Failed to connect to signal " << interface << "." << signal;
}
} // namespace
DBusWrapper::DBusWrapper(scoped_refptr<dbus::Bus> bus,
dbus::ExportedObject* exported_object)
: bus_(bus), exported_object_(exported_object), weak_ptr_factory_(this) {
// Listen for NameOwnerChanged signals from the bus itself.
dbus::ObjectProxy* bus_proxy =
bus->GetObjectProxy(kBusServiceName, dbus::ObjectPath(kBusServicePath));
bus_proxy->ConnectToSignal(
kBusInterface, kBusNameOwnerChangedSignal,
base::Bind(&DBusWrapper::HandleNameOwnerChangedSignal,
weak_ptr_factory_.GetWeakPtr()),
base::Bind(&HandleSignalConnected));
}
DBusWrapper::~DBusWrapper() = default;
// static
std::unique_ptr<DBusWrapper> DBusWrapper::Create() {
dbus::Bus::Options options;
options.bus_type = dbus::Bus::SYSTEM;
scoped_refptr<dbus::Bus> bus(new dbus::Bus(options));
if (!bus->Connect()) {
LOG(ERROR) << "Failed to connect to system bus";
return nullptr;
}
dbus::ExportedObject* exported_object =
bus->GetExportedObject(dbus::ObjectPath(kPowerManagerServicePath));
if (!exported_object) {
LOG(ERROR) << "Failed to export " << kPowerManagerServicePath << " object";
return nullptr;
}
return base::WrapUnique(new DBusWrapper(bus, exported_object));
}
void DBusWrapper::AddObserver(Observer* observer) {
DCHECK(observer);
observers_.AddObserver(observer);
}
void DBusWrapper::RemoveObserver(Observer* observer) {
DCHECK(observer);
observers_.RemoveObserver(observer);
}
dbus::Bus* DBusWrapper::GetBus() {
return bus_.get();
}
dbus::ObjectProxy* DBusWrapper::GetObjectProxy(const std::string& service_name,
const std::string& object_path) {
return bus_->GetObjectProxy(service_name, dbus::ObjectPath(object_path));
}
void DBusWrapper::RegisterForServiceAvailability(
dbus::ObjectProxy* proxy,
dbus::ObjectProxy::WaitForServiceToBeAvailableCallback callback) {
DCHECK(proxy);
proxy->WaitForServiceToBeAvailable(std::move(callback));
}
void DBusWrapper::RegisterForSignal(
dbus::ObjectProxy* proxy,
const std::string& interface_name,
const std::string& signal_name,
dbus::ObjectProxy::SignalCallback callback) {
DCHECK(proxy);
proxy->ConnectToSignal(interface_name, signal_name, callback,
base::Bind(&HandleSignalConnected));
}
void DBusWrapper::ExportMethod(
const std::string& method_name,
dbus::ExportedObject::MethodCallCallback callback) {
CHECK(exported_object_->ExportMethodAndBlock(kPowerManagerInterface,
method_name, callback));
}
bool DBusWrapper::PublishService() {
return bus_->RequestOwnershipAndBlock(kPowerManagerServiceName,
dbus::Bus::REQUIRE_PRIMARY);
}
void DBusWrapper::EmitSignal(dbus::Signal* signal) {
DCHECK(exported_object_);
DCHECK(signal);
exported_object_->SendSignal(signal);
}
void DBusWrapper::EmitBareSignal(const std::string& signal_name) {
dbus::Signal signal(kPowerManagerInterface, signal_name);
EmitSignal(&signal);
}
void DBusWrapper::EmitSignalWithProtocolBuffer(
const std::string& signal_name,
const google::protobuf::MessageLite& protobuf) {
dbus::Signal signal(kPowerManagerInterface, signal_name);
dbus::MessageWriter writer(&signal);
writer.AppendProtoAsArrayOfBytes(protobuf);
EmitSignal(&signal);
}
std::unique_ptr<dbus::Response> DBusWrapper::CallMethodSync(
dbus::ObjectProxy* proxy,
dbus::MethodCall* method_call,
base::TimeDelta timeout) {
DCHECK(proxy);
DCHECK(method_call);
return std::unique_ptr<dbus::Response>(
proxy->CallMethodAndBlock(method_call, timeout.InMilliseconds()));
}
void DBusWrapper::CallMethodAsync(
dbus::ObjectProxy* proxy,
dbus::MethodCall* method_call,
base::TimeDelta timeout,
dbus::ObjectProxy::ResponseCallback callback) {
DCHECK(proxy);
DCHECK(method_call);
proxy->CallMethod(method_call, timeout.InMilliseconds(), std::move(callback));
}
void DBusWrapper::HandleNameOwnerChangedSignal(dbus::Signal* signal) {
DCHECK(signal);
dbus::MessageReader reader(signal);
std::string name, old_owner, new_owner;
if (!reader.PopString(&name) || !reader.PopString(&old_owner) ||
!reader.PopString(&new_owner)) {
LOG(ERROR) << "Unable to parse " << kBusNameOwnerChangedSignal << " signal";
return;
}
for (DBusWrapper::Observer& observer : observers_)
observer.OnDBusNameOwnerChanged(name, old_owner, new_owner);
}
} // namespace system
} // namespace power_manager