Home | History | Annotate | Download | only in dbus
      1 // Copyright 2014 The Chromium OS Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include <brillo/dbus/exported_property_set.h>
      6 
      7 #include <base/bind.h>
      8 #include <dbus/bus.h>
      9 #include <dbus/property.h>  // For kPropertyInterface
     10 
     11 #include <brillo/dbus/async_event_sequencer.h>
     12 #include <brillo/dbus/dbus_object.h>
     13 #include <brillo/errors/error_codes.h>
     14 
     15 using brillo::dbus_utils::AsyncEventSequencer;
     16 
     17 namespace brillo {
     18 
     19 namespace dbus_utils {
     20 
     21 ExportedPropertySet::ExportedPropertySet(dbus::Bus* bus)
     22     : bus_(bus), weak_ptr_factory_(this) {
     23 }
     24 
     25 void ExportedPropertySet::OnPropertiesInterfaceExported(
     26     DBusInterface* prop_interface) {
     27   signal_properties_changed_ =
     28       prop_interface->RegisterSignalOfType<SignalPropertiesChanged>(
     29           dbus::kPropertiesChanged);
     30 }
     31 
     32 ExportedPropertySet::PropertyWriter ExportedPropertySet::GetPropertyWriter(
     33     const std::string& interface_name) {
     34   return base::Bind(&ExportedPropertySet::WritePropertiesToDict,
     35                     weak_ptr_factory_.GetWeakPtr(),
     36                     interface_name);
     37 }
     38 
     39 void ExportedPropertySet::RegisterProperty(
     40     const std::string& interface_name,
     41     const std::string& property_name,
     42     ExportedPropertyBase* exported_property) {
     43   bus_->AssertOnOriginThread();
     44   auto& prop_map = properties_[interface_name];
     45   auto res = prop_map.insert(std::make_pair(property_name, exported_property));
     46   CHECK(res.second) << "Property '" << property_name << "' already exists";
     47   // Technically, the property set exists longer than the properties themselves,
     48   // so we could use Unretained here rather than a weak pointer.
     49   ExportedPropertyBase::OnUpdateCallback cb =
     50       base::Bind(&ExportedPropertySet::HandlePropertyUpdated,
     51                  weak_ptr_factory_.GetWeakPtr(),
     52                  interface_name,
     53                  property_name);
     54   exported_property->SetUpdateCallback(cb);
     55 }
     56 
     57 VariantDictionary ExportedPropertySet::HandleGetAll(
     58     const std::string& interface_name) {
     59   bus_->AssertOnOriginThread();
     60   return GetInterfaceProperties(interface_name);
     61 }
     62 
     63 VariantDictionary ExportedPropertySet::GetInterfaceProperties(
     64     const std::string& interface_name) const {
     65   VariantDictionary properties;
     66   auto property_map_itr = properties_.find(interface_name);
     67   if (property_map_itr != properties_.end()) {
     68     for (const auto& kv : property_map_itr->second)
     69       properties.insert(std::make_pair(kv.first, kv.second->GetValue()));
     70   }
     71   return properties;
     72 }
     73 
     74 void ExportedPropertySet::WritePropertiesToDict(
     75     const std::string& interface_name,
     76     VariantDictionary* dict) {
     77   *dict = GetInterfaceProperties(interface_name);
     78 }
     79 
     80 bool ExportedPropertySet::HandleGet(brillo::ErrorPtr* error,
     81                                     const std::string& interface_name,
     82                                     const std::string& property_name,
     83                                     brillo::Any* result) {
     84   bus_->AssertOnOriginThread();
     85   auto property_map_itr = properties_.find(interface_name);
     86   if (property_map_itr == properties_.end()) {
     87     brillo::Error::AddTo(error, FROM_HERE, errors::dbus::kDomain,
     88                          DBUS_ERROR_UNKNOWN_INTERFACE,
     89                          "No such interface on object.");
     90     return false;
     91   }
     92   LOG(INFO) << "Looking for " << property_name << " on " << interface_name;
     93   auto property_itr = property_map_itr->second.find(property_name);
     94   if (property_itr == property_map_itr->second.end()) {
     95     brillo::Error::AddTo(error, FROM_HERE, errors::dbus::kDomain,
     96                          DBUS_ERROR_UNKNOWN_PROPERTY,
     97                          "No such property on interface.");
     98     return false;
     99   }
    100   *result = property_itr->second->GetValue();
    101   return true;
    102 }
    103 
    104 bool ExportedPropertySet::HandleSet(brillo::ErrorPtr* error,
    105                                     const std::string& interface_name,
    106                                     const std::string& property_name,
    107                                     const brillo::Any& value) {
    108   bus_->AssertOnOriginThread();
    109   auto property_map_itr = properties_.find(interface_name);
    110   if (property_map_itr == properties_.end()) {
    111     brillo::Error::AddTo(error, FROM_HERE, errors::dbus::kDomain,
    112                          DBUS_ERROR_UNKNOWN_INTERFACE,
    113                          "No such interface on object.");
    114     return false;
    115   }
    116   LOG(INFO) << "Looking for " << property_name << " on " << interface_name;
    117   auto property_itr = property_map_itr->second.find(property_name);
    118   if (property_itr == property_map_itr->second.end()) {
    119     brillo::Error::AddTo(error, FROM_HERE, errors::dbus::kDomain,
    120                          DBUS_ERROR_UNKNOWN_PROPERTY,
    121                          "No such property on interface.");
    122     return false;
    123   }
    124 
    125   return property_itr->second->SetValue(error, value);
    126 }
    127 
    128 void ExportedPropertySet::HandlePropertyUpdated(
    129     const std::string& interface_name,
    130     const std::string& property_name,
    131     const ExportedPropertyBase* exported_property) {
    132   bus_->AssertOnOriginThread();
    133   // Send signal only if the object has been exported successfully.
    134   // This could happen when a property value is changed (which triggers
    135   // the notification) before D-Bus interface is completely exported/claimed.
    136   auto signal = signal_properties_changed_.lock();
    137   if (!signal)
    138     return;
    139   VariantDictionary changed_properties{
    140       {property_name, exported_property->GetValue()}};
    141   // The interface specification tells us to include this list of properties
    142   // which have changed, but for whom no value is conveyed.  Currently, we
    143   // don't do anything interesting here.
    144   std::vector<std::string> invalidated_properties;  // empty.
    145   signal->Send(interface_name, changed_properties, invalidated_properties);
    146 }
    147 
    148 void ExportedPropertyBase::NotifyPropertyChanged() {
    149   // These is a brief period after the construction of an ExportedProperty
    150   // when this callback is not initialized because the property has not
    151   // been registered with the parent ExportedPropertySet.  During this period
    152   // users should be initializing values via SetValue, and no notifications
    153   // should be triggered by the ExportedPropertySet.
    154   if (!on_update_callback_.is_null()) {
    155     on_update_callback_.Run(this);
    156   }
    157 }
    158 
    159 void ExportedPropertyBase::SetUpdateCallback(const OnUpdateCallback& cb) {
    160   on_update_callback_ = cb;
    161 }
    162 
    163 void ExportedPropertyBase::SetAccessMode(
    164     ExportedPropertyBase::Access access_mode) {
    165   access_mode_ = access_mode;
    166 }
    167 
    168 ExportedPropertyBase::Access ExportedPropertyBase::GetAccessMode() const {
    169   return access_mode_;
    170 }
    171 
    172 }  // namespace dbus_utils
    173 
    174 }  // namespace brillo
    175