| // Copyright (c) 2012 The Chromium 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 "dbus/property.h" |
| |
| #include "base/basictypes.h" |
| #include "base/bind.h" |
| #include "base/logging.h" |
| |
| #include "dbus/message.h" |
| #include "dbus/object_path.h" |
| #include "dbus/object_proxy.h" |
| |
| namespace dbus { |
| |
| // |
| // PropertyBase implementation. |
| // |
| |
| PropertyBase::PropertyBase() : property_set_(nullptr), is_valid_(false) {} |
| |
| PropertyBase::~PropertyBase() {} |
| |
| void PropertyBase::Init(PropertySet* property_set, const std::string& name) { |
| DCHECK(!property_set_); |
| property_set_ = property_set; |
| is_valid_ = false; |
| name_ = name; |
| } |
| |
| // |
| // PropertySet implementation. |
| // |
| |
| PropertySet::PropertySet( |
| ObjectProxy* object_proxy, |
| const std::string& interface, |
| const PropertyChangedCallback& property_changed_callback) |
| : object_proxy_(object_proxy), |
| interface_(interface), |
| property_changed_callback_(property_changed_callback), |
| weak_ptr_factory_(this) {} |
| |
| PropertySet::~PropertySet() { |
| } |
| |
| void PropertySet::RegisterProperty(const std::string& name, |
| PropertyBase* property) { |
| property->Init(this, name); |
| properties_map_[name] = property; |
| } |
| |
| void PropertySet::ConnectSignals() { |
| DCHECK(object_proxy_); |
| object_proxy_->ConnectToSignal( |
| kPropertiesInterface, |
| kPropertiesChanged, |
| base::Bind(&PropertySet::ChangedReceived, |
| weak_ptr_factory_.GetWeakPtr()), |
| base::Bind(&PropertySet::ChangedConnected, |
| weak_ptr_factory_.GetWeakPtr())); |
| } |
| |
| |
| void PropertySet::ChangedReceived(Signal* signal) { |
| DCHECK(signal); |
| MessageReader reader(signal); |
| |
| std::string interface; |
| if (!reader.PopString(&interface)) { |
| LOG(WARNING) << "Property changed signal has wrong parameters: " |
| << "expected interface name: " << signal->ToString(); |
| return; |
| } |
| |
| if (interface != this->interface()) |
| return; |
| |
| if (!UpdatePropertiesFromReader(&reader)) { |
| LOG(WARNING) << "Property changed signal has wrong parameters: " |
| << "expected dictionary: " << signal->ToString(); |
| } |
| |
| if (!InvalidatePropertiesFromReader(&reader)) { |
| LOG(WARNING) << "Property changed signal has wrong parameters: " |
| << "expected array to invalidate: " << signal->ToString(); |
| } |
| } |
| |
| void PropertySet::ChangedConnected(const std::string& interface_name, |
| const std::string& signal_name, |
| bool success) { |
| LOG_IF(WARNING, !success) << "Failed to connect to " << signal_name |
| << "signal."; |
| } |
| |
| |
| void PropertySet::Get(PropertyBase* property, GetCallback callback) { |
| MethodCall method_call(kPropertiesInterface, kPropertiesGet); |
| MessageWriter writer(&method_call); |
| writer.AppendString(interface()); |
| writer.AppendString(property->name()); |
| |
| DCHECK(object_proxy_); |
| object_proxy_->CallMethod(&method_call, |
| ObjectProxy::TIMEOUT_USE_DEFAULT, |
| base::Bind(&PropertySet::OnGet, |
| GetWeakPtr(), |
| property, |
| callback)); |
| } |
| |
| void PropertySet::OnGet(PropertyBase* property, GetCallback callback, |
| Response* response) { |
| if (!response) { |
| LOG(WARNING) << property->name() << ": Get: failed."; |
| return; |
| } |
| |
| MessageReader reader(response); |
| if (property->PopValueFromReader(&reader)) { |
| property->set_valid(true); |
| NotifyPropertyChanged(property->name()); |
| } else { |
| if (property->is_valid()) { |
| property->set_valid(false); |
| NotifyPropertyChanged(property->name()); |
| } |
| } |
| |
| if (!callback.is_null()) |
| callback.Run(response); |
| } |
| |
| bool PropertySet::GetAndBlock(PropertyBase* property) { |
| MethodCall method_call(kPropertiesInterface, kPropertiesGet); |
| MessageWriter writer(&method_call); |
| writer.AppendString(interface()); |
| writer.AppendString(property->name()); |
| |
| DCHECK(object_proxy_); |
| scoped_ptr<dbus::Response> response( |
| object_proxy_->CallMethodAndBlock(&method_call, |
| ObjectProxy::TIMEOUT_USE_DEFAULT)); |
| |
| if (!response.get()) { |
| LOG(WARNING) << property->name() << ": GetAndBlock: failed."; |
| return false; |
| } |
| |
| MessageReader reader(response.get()); |
| if (property->PopValueFromReader(&reader)) { |
| property->set_valid(true); |
| NotifyPropertyChanged(property->name()); |
| } else { |
| if (property->is_valid()) { |
| property->set_valid(false); |
| NotifyPropertyChanged(property->name()); |
| } |
| } |
| return true; |
| } |
| |
| void PropertySet::GetAll() { |
| MethodCall method_call(kPropertiesInterface, kPropertiesGetAll); |
| MessageWriter writer(&method_call); |
| writer.AppendString(interface()); |
| |
| DCHECK(object_proxy_); |
| object_proxy_->CallMethod(&method_call, |
| ObjectProxy::TIMEOUT_USE_DEFAULT, |
| base::Bind(&PropertySet::OnGetAll, |
| weak_ptr_factory_.GetWeakPtr())); |
| } |
| |
| void PropertySet::OnGetAll(Response* response) { |
| if (!response) { |
| LOG(WARNING) << "GetAll request failed for: " << interface_; |
| return; |
| } |
| |
| MessageReader reader(response); |
| if (!UpdatePropertiesFromReader(&reader)) { |
| LOG(WARNING) << "GetAll response has wrong parameters: " |
| << "expected dictionary: " << response->ToString(); |
| } |
| } |
| |
| void PropertySet::Set(PropertyBase* property, SetCallback callback) { |
| MethodCall method_call(kPropertiesInterface, kPropertiesSet); |
| MessageWriter writer(&method_call); |
| writer.AppendString(interface()); |
| writer.AppendString(property->name()); |
| property->AppendSetValueToWriter(&writer); |
| |
| DCHECK(object_proxy_); |
| object_proxy_->CallMethod(&method_call, |
| ObjectProxy::TIMEOUT_USE_DEFAULT, |
| base::Bind(&PropertySet::OnSet, |
| GetWeakPtr(), |
| property, |
| callback)); |
| } |
| |
| bool PropertySet::SetAndBlock(PropertyBase* property) { |
| MethodCall method_call(kPropertiesInterface, kPropertiesSet); |
| MessageWriter writer(&method_call); |
| writer.AppendString(interface()); |
| writer.AppendString(property->name()); |
| property->AppendSetValueToWriter(&writer); |
| |
| DCHECK(object_proxy_); |
| scoped_ptr<dbus::Response> response( |
| object_proxy_->CallMethodAndBlock(&method_call, |
| ObjectProxy::TIMEOUT_USE_DEFAULT)); |
| if (response.get()) |
| return true; |
| return false; |
| } |
| |
| void PropertySet::OnSet(PropertyBase* property, |
| SetCallback callback, |
| Response* response) { |
| LOG_IF(WARNING, !response) << property->name() << ": Set: failed."; |
| if (!callback.is_null()) |
| callback.Run(response); |
| } |
| |
| bool PropertySet::UpdatePropertiesFromReader(MessageReader* reader) { |
| DCHECK(reader); |
| MessageReader array_reader(NULL); |
| if (!reader->PopArray(&array_reader)) |
| return false; |
| |
| while (array_reader.HasMoreData()) { |
| MessageReader dict_entry_reader(NULL); |
| if (array_reader.PopDictEntry(&dict_entry_reader)) |
| UpdatePropertyFromReader(&dict_entry_reader); |
| } |
| |
| return true; |
| } |
| |
| bool PropertySet::UpdatePropertyFromReader(MessageReader* reader) { |
| DCHECK(reader); |
| |
| std::string name; |
| if (!reader->PopString(&name)) |
| return false; |
| |
| PropertiesMap::iterator it = properties_map_.find(name); |
| if (it == properties_map_.end()) |
| return false; |
| |
| PropertyBase* property = it->second; |
| if (property->PopValueFromReader(reader)) { |
| property->set_valid(true); |
| NotifyPropertyChanged(name); |
| return true; |
| } else { |
| if (property->is_valid()) { |
| property->set_valid(false); |
| NotifyPropertyChanged(property->name()); |
| } |
| return false; |
| } |
| } |
| |
| bool PropertySet::InvalidatePropertiesFromReader(MessageReader* reader) { |
| DCHECK(reader); |
| MessageReader array_reader(NULL); |
| if (!reader->PopArray(&array_reader)) |
| return false; |
| |
| while (array_reader.HasMoreData()) { |
| std::string name; |
| if (!array_reader.PopString(&name)) |
| return false; |
| |
| PropertiesMap::iterator it = properties_map_.find(name); |
| if (it == properties_map_.end()) |
| continue; |
| |
| PropertyBase* property = it->second; |
| if (property->is_valid()) { |
| property->set_valid(false); |
| NotifyPropertyChanged(property->name()); |
| } |
| } |
| |
| return true; |
| } |
| |
| void PropertySet::NotifyPropertyChanged(const std::string& name) { |
| if (!property_changed_callback_.is_null()) |
| property_changed_callback_.Run(name); |
| } |
| |
| // |
| // Property<Byte> specialization. |
| // |
| |
| template <> |
| Property<uint8>::Property() : value_(0) { |
| } |
| |
| template <> |
| bool Property<uint8>::PopValueFromReader(MessageReader* reader) { |
| return reader->PopVariantOfByte(&value_); |
| } |
| |
| template <> |
| void Property<uint8>::AppendSetValueToWriter(MessageWriter* writer) { |
| writer->AppendVariantOfByte(set_value_); |
| } |
| |
| // |
| // Property<bool> specialization. |
| // |
| |
| template <> |
| Property<bool>::Property() : value_(false) { |
| } |
| |
| template <> |
| bool Property<bool>::PopValueFromReader(MessageReader* reader) { |
| return reader->PopVariantOfBool(&value_); |
| } |
| |
| template <> |
| void Property<bool>::AppendSetValueToWriter(MessageWriter* writer) { |
| writer->AppendVariantOfBool(set_value_); |
| } |
| |
| // |
| // Property<int16> specialization. |
| // |
| |
| template <> |
| Property<int16>::Property() : value_(0) { |
| } |
| |
| template <> |
| bool Property<int16>::PopValueFromReader(MessageReader* reader) { |
| return reader->PopVariantOfInt16(&value_); |
| } |
| |
| template <> |
| void Property<int16>::AppendSetValueToWriter(MessageWriter* writer) { |
| writer->AppendVariantOfInt16(set_value_); |
| } |
| |
| // |
| // Property<uint16> specialization. |
| // |
| |
| template <> |
| Property<uint16>::Property() : value_(0) { |
| } |
| |
| template <> |
| bool Property<uint16>::PopValueFromReader(MessageReader* reader) { |
| return reader->PopVariantOfUint16(&value_); |
| } |
| |
| template <> |
| void Property<uint16>::AppendSetValueToWriter(MessageWriter* writer) { |
| writer->AppendVariantOfUint16(set_value_); |
| } |
| |
| // |
| // Property<int32> specialization. |
| // |
| |
| template <> |
| Property<int32>::Property() : value_(0) { |
| } |
| |
| template <> |
| bool Property<int32>::PopValueFromReader(MessageReader* reader) { |
| return reader->PopVariantOfInt32(&value_); |
| } |
| |
| template <> |
| void Property<int32>::AppendSetValueToWriter(MessageWriter* writer) { |
| writer->AppendVariantOfInt32(set_value_); |
| } |
| |
| // |
| // Property<uint32> specialization. |
| // |
| |
| template <> |
| Property<uint32>::Property() : value_(0) { |
| } |
| |
| template <> |
| bool Property<uint32>::PopValueFromReader(MessageReader* reader) { |
| return reader->PopVariantOfUint32(&value_); |
| } |
| |
| template <> |
| void Property<uint32>::AppendSetValueToWriter(MessageWriter* writer) { |
| writer->AppendVariantOfUint32(set_value_); |
| } |
| |
| // |
| // Property<int64> specialization. |
| // |
| |
| template <> |
| Property<int64>::Property() : value_(0), set_value_(0) { |
| } |
| |
| template <> |
| bool Property<int64>::PopValueFromReader(MessageReader* reader) { |
| return reader->PopVariantOfInt64(&value_); |
| } |
| |
| template <> |
| void Property<int64>::AppendSetValueToWriter(MessageWriter* writer) { |
| writer->AppendVariantOfInt64(set_value_); |
| } |
| |
| // |
| // Property<uint64> specialization. |
| // |
| |
| template <> |
| Property<uint64>::Property() : value_(0) { |
| } |
| |
| template <> |
| bool Property<uint64>::PopValueFromReader(MessageReader* reader) { |
| return reader->PopVariantOfUint64(&value_); |
| } |
| |
| template <> |
| void Property<uint64>::AppendSetValueToWriter(MessageWriter* writer) { |
| writer->AppendVariantOfUint64(set_value_); |
| } |
| |
| // |
| // Property<double> specialization. |
| // |
| |
| template <> |
| Property<double>::Property() : value_(0.0) { |
| } |
| |
| template <> |
| bool Property<double>::PopValueFromReader(MessageReader* reader) { |
| return reader->PopVariantOfDouble(&value_); |
| } |
| |
| template <> |
| void Property<double>::AppendSetValueToWriter(MessageWriter* writer) { |
| writer->AppendVariantOfDouble(set_value_); |
| } |
| |
| // |
| // Property<std::string> specialization. |
| // |
| |
| template <> |
| bool Property<std::string>::PopValueFromReader(MessageReader* reader) { |
| return reader->PopVariantOfString(&value_); |
| } |
| |
| template <> |
| void Property<std::string>::AppendSetValueToWriter(MessageWriter* writer) { |
| writer->AppendVariantOfString(set_value_); |
| } |
| |
| // |
| // Property<ObjectPath> specialization. |
| // |
| |
| template <> |
| bool Property<ObjectPath>::PopValueFromReader(MessageReader* reader) { |
| return reader->PopVariantOfObjectPath(&value_); |
| } |
| |
| template <> |
| void Property<ObjectPath>::AppendSetValueToWriter(MessageWriter* writer) { |
| writer->AppendVariantOfObjectPath(set_value_); |
| } |
| |
| // |
| // Property<std::vector<std::string> > specialization. |
| // |
| |
| template <> |
| bool Property<std::vector<std::string> >::PopValueFromReader( |
| MessageReader* reader) { |
| MessageReader variant_reader(NULL); |
| if (!reader->PopVariant(&variant_reader)) |
| return false; |
| |
| value_.clear(); |
| return variant_reader.PopArrayOfStrings(&value_); |
| } |
| |
| template <> |
| void Property<std::vector<std::string> >::AppendSetValueToWriter( |
| MessageWriter* writer) { |
| MessageWriter variant_writer(NULL); |
| writer->OpenVariant("as", &variant_writer); |
| variant_writer.AppendArrayOfStrings(set_value_); |
| writer->CloseContainer(&variant_writer); |
| } |
| |
| // |
| // Property<std::vector<ObjectPath> > specialization. |
| // |
| |
| template <> |
| bool Property<std::vector<ObjectPath> >::PopValueFromReader( |
| MessageReader* reader) { |
| MessageReader variant_reader(NULL); |
| if (!reader->PopVariant(&variant_reader)) |
| return false; |
| |
| value_.clear(); |
| return variant_reader.PopArrayOfObjectPaths(&value_); |
| } |
| |
| template <> |
| void Property<std::vector<ObjectPath> >::AppendSetValueToWriter( |
| MessageWriter* writer) { |
| MessageWriter variant_writer(NULL); |
| writer->OpenVariant("ao", &variant_writer); |
| variant_writer.AppendArrayOfObjectPaths(set_value_); |
| writer->CloseContainer(&variant_writer); |
| } |
| |
| // |
| // Property<std::vector<uint8> > specialization. |
| // |
| |
| template <> |
| bool Property<std::vector<uint8> >::PopValueFromReader(MessageReader* reader) { |
| MessageReader variant_reader(NULL); |
| if (!reader->PopVariant(&variant_reader)) |
| return false; |
| |
| value_.clear(); |
| const uint8* bytes = NULL; |
| size_t length = 0; |
| if (!variant_reader.PopArrayOfBytes(&bytes, &length)) |
| return false; |
| value_.assign(bytes, bytes + length); |
| return true; |
| } |
| |
| template <> |
| void Property<std::vector<uint8> >::AppendSetValueToWriter( |
| MessageWriter* writer) { |
| MessageWriter variant_writer(NULL); |
| writer->OpenVariant("ay", &variant_writer); |
| variant_writer.AppendArrayOfBytes(set_value_.data(), set_value_.size()); |
| writer->CloseContainer(&variant_writer); |
| } |
| |
| // |
| // Property<std::map<std::string, std::string>> specialization. |
| // |
| |
| template <> |
| bool Property<std::map<std::string, std::string>>::PopValueFromReader( |
| MessageReader* reader) { |
| MessageReader variant_reader(NULL); |
| MessageReader array_reader(NULL); |
| if (!reader->PopVariant(&variant_reader) || |
| !variant_reader.PopArray(&array_reader)) |
| return false; |
| value_.clear(); |
| while (array_reader.HasMoreData()) { |
| dbus::MessageReader dict_entry_reader(NULL); |
| if (!array_reader.PopDictEntry(&dict_entry_reader)) |
| return false; |
| std::string key; |
| std::string value; |
| if (!dict_entry_reader.PopString(&key) || |
| !dict_entry_reader.PopString(&value)) |
| return false; |
| value_[key] = value; |
| } |
| return true; |
| } |
| |
| template <> |
| void Property<std::map<std::string, std::string>>::AppendSetValueToWriter( |
| MessageWriter* writer) { |
| MessageWriter variant_writer(NULL); |
| MessageWriter dict_writer(NULL); |
| writer->OpenVariant("a{ss}", &variant_writer); |
| variant_writer.OpenArray("{ss}", &dict_writer); |
| for (const auto& pair : set_value_) { |
| dbus::MessageWriter entry_writer(NULL); |
| dict_writer.OpenDictEntry(&entry_writer); |
| entry_writer.AppendString(pair.first); |
| entry_writer.AppendString(pair.second); |
| dict_writer.CloseContainer(&entry_writer); |
| } |
| variant_writer.CloseContainer(&dict_writer); |
| writer->CloseContainer(&variant_writer); |
| } |
| |
| // |
| // Property<std::vector<std::pair<std::vector<uint8_t>, uint16_t>>> |
| // specialization. |
| // |
| |
| template <> |
| bool Property<std::vector<std::pair<std::vector<uint8_t>, uint16_t>>>:: |
| PopValueFromReader(MessageReader* reader) { |
| MessageReader variant_reader(NULL); |
| MessageReader array_reader(NULL); |
| if (!reader->PopVariant(&variant_reader) || |
| !variant_reader.PopArray(&array_reader)) |
| return false; |
| |
| value_.clear(); |
| while (array_reader.HasMoreData()) { |
| dbus::MessageReader struct_reader(NULL); |
| if (!array_reader.PopStruct(&struct_reader)) |
| return false; |
| |
| std::pair<std::vector<uint8_t>, uint16_t> entry; |
| const uint8* bytes = NULL; |
| size_t length = 0; |
| if (!struct_reader.PopArrayOfBytes(&bytes, &length)) |
| return false; |
| entry.first.assign(bytes, bytes + length); |
| if (!struct_reader.PopUint16(&entry.second)) |
| return false; |
| value_.push_back(entry); |
| } |
| return true; |
| } |
| |
| template <> |
| void Property<std::vector<std::pair<std::vector<uint8_t>, uint16_t>>>:: |
| AppendSetValueToWriter(MessageWriter* writer) { |
| MessageWriter variant_writer(NULL); |
| MessageWriter array_writer(NULL); |
| writer->OpenVariant("a(ayq)", &variant_writer); |
| variant_writer.OpenArray("(ayq)", &array_writer); |
| for (const auto& pair : set_value_) { |
| dbus::MessageWriter struct_writer(nullptr); |
| array_writer.OpenStruct(&struct_writer); |
| struct_writer.AppendArrayOfBytes(std::get<0>(pair).data(), |
| std::get<0>(pair).size()); |
| struct_writer.AppendUint16(std::get<1>(pair)); |
| array_writer.CloseContainer(&struct_writer); |
| } |
| variant_writer.CloseContainer(&array_writer); |
| writer->CloseContainer(&variant_writer); |
| } |
| |
| template class Property<uint8>; |
| template class Property<bool>; |
| template class Property<int16>; |
| template class Property<uint16>; |
| template class Property<int32>; |
| template class Property<uint32>; |
| template class Property<int64>; |
| template class Property<uint64>; |
| template class Property<double>; |
| template class Property<std::string>; |
| template class Property<ObjectPath>; |
| template class Property<std::vector<std::string> >; |
| template class Property<std::vector<ObjectPath> >; |
| template class Property<std::vector<uint8> >; |
| template class Property<std::map<std::string, std::string>>; |
| template class Property<std::vector<std::pair<std::vector<uint8_t>, uint16_t>>>; |
| |
| } // namespace dbus |