• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
ExportedPropertySet(dbus::Bus * bus)21 ExportedPropertySet::ExportedPropertySet(dbus::Bus* bus)
22     : bus_(bus), weak_ptr_factory_(this) {
23 }
24 
OnPropertiesInterfaceExported(DBusInterface * prop_interface)25 void ExportedPropertySet::OnPropertiesInterfaceExported(
26     DBusInterface* prop_interface) {
27   signal_properties_changed_ =
28       prop_interface->RegisterSignalOfType<SignalPropertiesChanged>(
29           dbus::kPropertiesChanged);
30 }
31 
GetPropertyWriter(const std::string & interface_name)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 
RegisterProperty(const std::string & interface_name,const std::string & property_name,ExportedPropertyBase * exported_property)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 
UnregisterProperty(const std::string & interface_name,const std::string & property_name)57 void ExportedPropertySet::UnregisterProperty(const std::string& interface_name,
58                                              const std::string& property_name) {
59   bus_->AssertOnOriginThread();
60   auto& prop_map = properties_[interface_name];
61   auto prop_iter = prop_map.find(property_name);
62   CHECK(prop_iter != prop_map.end())
63       << "Property '" << property_name << "' doesn't exist";
64   prop_iter->second->ClearUpdateCallback();
65   prop_map.erase(prop_iter);
66 }
67 
HandleGetAll(const std::string & interface_name)68 VariantDictionary ExportedPropertySet::HandleGetAll(
69     const std::string& interface_name) {
70   bus_->AssertOnOriginThread();
71   return GetInterfaceProperties(interface_name);
72 }
73 
GetInterfaceProperties(const std::string & interface_name) const74 VariantDictionary ExportedPropertySet::GetInterfaceProperties(
75     const std::string& interface_name) const {
76   VariantDictionary properties;
77   auto property_map_itr = properties_.find(interface_name);
78   if (property_map_itr != properties_.end()) {
79     for (const auto& kv : property_map_itr->second)
80       properties.insert(std::make_pair(kv.first, kv.second->GetValue()));
81   }
82   return properties;
83 }
84 
WritePropertiesToDict(const std::string & interface_name,VariantDictionary * dict)85 void ExportedPropertySet::WritePropertiesToDict(
86     const std::string& interface_name,
87     VariantDictionary* dict) {
88   *dict = GetInterfaceProperties(interface_name);
89 }
90 
HandleGet(brillo::ErrorPtr * error,const std::string & interface_name,const std::string & property_name,brillo::Any * result)91 bool ExportedPropertySet::HandleGet(brillo::ErrorPtr* error,
92                                     const std::string& interface_name,
93                                     const std::string& property_name,
94                                     brillo::Any* result) {
95   bus_->AssertOnOriginThread();
96   auto property_map_itr = properties_.find(interface_name);
97   if (property_map_itr == properties_.end()) {
98     brillo::Error::AddTo(error, FROM_HERE, errors::dbus::kDomain,
99                          DBUS_ERROR_UNKNOWN_INTERFACE,
100                          "No such interface on object.");
101     return false;
102   }
103   LOG(INFO) << "Looking for " << property_name << " on " << interface_name;
104   auto property_itr = property_map_itr->second.find(property_name);
105   if (property_itr == property_map_itr->second.end()) {
106     brillo::Error::AddTo(error, FROM_HERE, errors::dbus::kDomain,
107                          DBUS_ERROR_UNKNOWN_PROPERTY,
108                          "No such property on interface.");
109     return false;
110   }
111   *result = property_itr->second->GetValue();
112   return true;
113 }
114 
HandleSet(brillo::ErrorPtr * error,const std::string & interface_name,const std::string & property_name,const brillo::Any & value)115 bool ExportedPropertySet::HandleSet(brillo::ErrorPtr* error,
116                                     const std::string& interface_name,
117                                     const std::string& property_name,
118                                     const brillo::Any& value) {
119   bus_->AssertOnOriginThread();
120   auto property_map_itr = properties_.find(interface_name);
121   if (property_map_itr == properties_.end()) {
122     brillo::Error::AddTo(error, FROM_HERE, errors::dbus::kDomain,
123                          DBUS_ERROR_UNKNOWN_INTERFACE,
124                          "No such interface on object.");
125     return false;
126   }
127   LOG(INFO) << "Looking for " << property_name << " on " << interface_name;
128   auto property_itr = property_map_itr->second.find(property_name);
129   if (property_itr == property_map_itr->second.end()) {
130     brillo::Error::AddTo(error, FROM_HERE, errors::dbus::kDomain,
131                          DBUS_ERROR_UNKNOWN_PROPERTY,
132                          "No such property on interface.");
133     return false;
134   }
135 
136   return property_itr->second->SetValue(error, value);
137 }
138 
HandlePropertyUpdated(const std::string & interface_name,const std::string & property_name,const ExportedPropertyBase * exported_property)139 void ExportedPropertySet::HandlePropertyUpdated(
140     const std::string& interface_name,
141     const std::string& property_name,
142     const ExportedPropertyBase* exported_property) {
143   bus_->AssertOnOriginThread();
144   // Send signal only if the object has been exported successfully.
145   // This could happen when a property value is changed (which triggers
146   // the notification) before D-Bus interface is completely exported/claimed.
147   auto signal = signal_properties_changed_.lock();
148   if (!signal)
149     return;
150   VariantDictionary changed_properties{
151       {property_name, exported_property->GetValue()}};
152   // The interface specification tells us to include this list of properties
153   // which have changed, but for whom no value is conveyed.  Currently, we
154   // don't do anything interesting here.
155   std::vector<std::string> invalidated_properties;  // empty.
156   signal->Send(interface_name, changed_properties, invalidated_properties);
157 }
158 
NotifyPropertyChanged()159 void ExportedPropertyBase::NotifyPropertyChanged() {
160   // These is a brief period after the construction of an ExportedProperty
161   // when this callback is not initialized because the property has not
162   // been registered with the parent ExportedPropertySet.  During this period
163   // users should be initializing values via SetValue, and no notifications
164   // should be triggered by the ExportedPropertySet.
165   if (!on_update_callback_.is_null()) {
166     on_update_callback_.Run(this);
167   }
168 }
169 
SetUpdateCallback(const OnUpdateCallback & cb)170 void ExportedPropertyBase::SetUpdateCallback(const OnUpdateCallback& cb) {
171   on_update_callback_ = cb;
172 }
173 
ClearUpdateCallback()174 void ExportedPropertyBase::ClearUpdateCallback() {
175   on_update_callback_.Reset();
176 }
177 
SetAccessMode(ExportedPropertyBase::Access access_mode)178 void ExportedPropertyBase::SetAccessMode(
179     ExportedPropertyBase::Access access_mode) {
180   access_mode_ = access_mode;
181 }
182 
GetAccessMode() const183 ExportedPropertyBase::Access ExportedPropertyBase::GetAccessMode() const {
184   return access_mode_;
185 }
186 
187 }  // namespace dbus_utils
188 
189 }  // namespace brillo
190