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