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