You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
189 lines
7.0 KiB
189 lines
7.0 KiB
// Copyright 2014 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 <brillo/dbus/exported_property_set.h>
|
|
|
|
#include <utility>
|
|
|
|
#include <base/bind.h>
|
|
#include <dbus/bus.h>
|
|
#include <dbus/property.h> // For kPropertyInterface
|
|
|
|
#include <brillo/dbus/dbus_object.h>
|
|
#include <brillo/errors/error_codes.h>
|
|
|
|
namespace brillo {
|
|
|
|
namespace dbus_utils {
|
|
|
|
ExportedPropertySet::ExportedPropertySet(dbus::Bus* bus)
|
|
: bus_(bus), weak_ptr_factory_(this) {
|
|
}
|
|
|
|
void ExportedPropertySet::OnPropertiesInterfaceExported(
|
|
DBusInterface* prop_interface) {
|
|
signal_properties_changed_ =
|
|
prop_interface->RegisterSignalOfType<SignalPropertiesChanged>(
|
|
dbus::kPropertiesChanged);
|
|
}
|
|
|
|
ExportedPropertySet::PropertyWriter ExportedPropertySet::GetPropertyWriter(
|
|
const std::string& interface_name) {
|
|
return base::Bind(&ExportedPropertySet::WritePropertiesToDict,
|
|
weak_ptr_factory_.GetWeakPtr(),
|
|
interface_name);
|
|
}
|
|
|
|
void ExportedPropertySet::RegisterProperty(
|
|
const std::string& interface_name,
|
|
const std::string& property_name,
|
|
ExportedPropertyBase* exported_property) {
|
|
bus_->AssertOnOriginThread();
|
|
auto& prop_map = properties_[interface_name];
|
|
auto res = prop_map.insert(std::make_pair(property_name, exported_property));
|
|
CHECK(res.second) << "Property '" << property_name << "' already exists";
|
|
// Technically, the property set exists longer than the properties themselves,
|
|
// so we could use Unretained here rather than a weak pointer.
|
|
ExportedPropertyBase::OnUpdateCallback cb =
|
|
base::Bind(&ExportedPropertySet::HandlePropertyUpdated,
|
|
weak_ptr_factory_.GetWeakPtr(),
|
|
interface_name,
|
|
property_name);
|
|
exported_property->SetUpdateCallback(cb);
|
|
}
|
|
|
|
void ExportedPropertySet::UnregisterProperty(const std::string& interface_name,
|
|
const std::string& property_name) {
|
|
bus_->AssertOnOriginThread();
|
|
auto& prop_map = properties_[interface_name];
|
|
auto prop_iter = prop_map.find(property_name);
|
|
CHECK(prop_iter != prop_map.end())
|
|
<< "Property '" << property_name << "' doesn't exist";
|
|
prop_iter->second->ClearUpdateCallback();
|
|
prop_map.erase(prop_iter);
|
|
}
|
|
|
|
VariantDictionary ExportedPropertySet::HandleGetAll(
|
|
const std::string& interface_name) {
|
|
bus_->AssertOnOriginThread();
|
|
return GetInterfaceProperties(interface_name);
|
|
}
|
|
|
|
VariantDictionary ExportedPropertySet::GetInterfaceProperties(
|
|
const std::string& interface_name) const {
|
|
VariantDictionary properties;
|
|
auto property_map_itr = properties_.find(interface_name);
|
|
if (property_map_itr != properties_.end()) {
|
|
for (const auto& kv : property_map_itr->second)
|
|
properties.insert(std::make_pair(kv.first, kv.second->GetValue()));
|
|
}
|
|
return properties;
|
|
}
|
|
|
|
void ExportedPropertySet::WritePropertiesToDict(
|
|
const std::string& interface_name,
|
|
VariantDictionary* dict) {
|
|
*dict = GetInterfaceProperties(interface_name);
|
|
}
|
|
|
|
bool ExportedPropertySet::HandleGet(brillo::ErrorPtr* error,
|
|
const std::string& interface_name,
|
|
const std::string& property_name,
|
|
brillo::Any* result) {
|
|
bus_->AssertOnOriginThread();
|
|
auto property_map_itr = properties_.find(interface_name);
|
|
if (property_map_itr == properties_.end()) {
|
|
brillo::Error::AddTo(error, FROM_HERE, errors::dbus::kDomain,
|
|
DBUS_ERROR_UNKNOWN_INTERFACE,
|
|
"No such interface on object.");
|
|
return false;
|
|
}
|
|
LOG(INFO) << "Looking for " << property_name << " on " << interface_name;
|
|
auto property_itr = property_map_itr->second.find(property_name);
|
|
if (property_itr == property_map_itr->second.end()) {
|
|
brillo::Error::AddTo(error, FROM_HERE, errors::dbus::kDomain,
|
|
DBUS_ERROR_UNKNOWN_PROPERTY,
|
|
"No such property on interface.");
|
|
return false;
|
|
}
|
|
*result = property_itr->second->GetValue();
|
|
return true;
|
|
}
|
|
|
|
bool ExportedPropertySet::HandleSet(brillo::ErrorPtr* error,
|
|
const std::string& interface_name,
|
|
const std::string& property_name,
|
|
const brillo::Any& value) {
|
|
bus_->AssertOnOriginThread();
|
|
auto property_map_itr = properties_.find(interface_name);
|
|
if (property_map_itr == properties_.end()) {
|
|
brillo::Error::AddTo(error, FROM_HERE, errors::dbus::kDomain,
|
|
DBUS_ERROR_UNKNOWN_INTERFACE,
|
|
"No such interface on object.");
|
|
return false;
|
|
}
|
|
LOG(INFO) << "Looking for " << property_name << " on " << interface_name;
|
|
auto property_itr = property_map_itr->second.find(property_name);
|
|
if (property_itr == property_map_itr->second.end()) {
|
|
brillo::Error::AddTo(error, FROM_HERE, errors::dbus::kDomain,
|
|
DBUS_ERROR_UNKNOWN_PROPERTY,
|
|
"No such property on interface.");
|
|
return false;
|
|
}
|
|
|
|
return property_itr->second->SetValue(error, value);
|
|
}
|
|
|
|
void ExportedPropertySet::HandlePropertyUpdated(
|
|
const std::string& interface_name,
|
|
const std::string& property_name,
|
|
const ExportedPropertyBase* exported_property) {
|
|
bus_->AssertOnOriginThread();
|
|
// Send signal only if the object has been exported successfully.
|
|
// This could happen when a property value is changed (which triggers
|
|
// the notification) before D-Bus interface is completely exported/claimed.
|
|
auto signal = signal_properties_changed_.lock();
|
|
if (!signal)
|
|
return;
|
|
VariantDictionary changed_properties{
|
|
{property_name, exported_property->GetValue()}};
|
|
// The interface specification tells us to include this list of properties
|
|
// which have changed, but for whom no value is conveyed. Currently, we
|
|
// don't do anything interesting here.
|
|
std::vector<std::string> invalidated_properties; // empty.
|
|
signal->Send(interface_name, changed_properties, invalidated_properties);
|
|
}
|
|
|
|
void ExportedPropertyBase::NotifyPropertyChanged() {
|
|
// These is a brief period after the construction of an ExportedProperty
|
|
// when this callback is not initialized because the property has not
|
|
// been registered with the parent ExportedPropertySet. During this period
|
|
// users should be initializing values via SetValue, and no notifications
|
|
// should be triggered by the ExportedPropertySet.
|
|
if (!on_update_callback_.is_null()) {
|
|
on_update_callback_.Run(this);
|
|
}
|
|
}
|
|
|
|
void ExportedPropertyBase::SetUpdateCallback(const OnUpdateCallback& cb) {
|
|
on_update_callback_ = cb;
|
|
}
|
|
|
|
void ExportedPropertyBase::ClearUpdateCallback() {
|
|
on_update_callback_.Reset();
|
|
}
|
|
|
|
void ExportedPropertyBase::SetAccessMode(
|
|
ExportedPropertyBase::Access access_mode) {
|
|
access_mode_ = access_mode;
|
|
}
|
|
|
|
ExportedPropertyBase::Access ExportedPropertyBase::GetAccessMode() const {
|
|
return access_mode_;
|
|
}
|
|
|
|
} // namespace dbus_utils
|
|
|
|
} // namespace brillo
|