// Copyright 2015 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 "chromeos/dbus/privet_daemon_manager_client.h" #include #include #include "base/bind.h" #include "base/location.h" #include "base/logging.h" #include "base/macros.h" #include "base/memory/weak_ptr.h" #include "base/observer_list.h" #include "base/single_thread_task_runner.h" #include "base/thread_task_runner_handle.h" #include "dbus/bus.h" #include "dbus/message.h" #include "dbus/object_manager.h" #include "dbus/object_proxy.h" namespace chromeos { namespace { // TODO(benchan): Move these constants to system_api. const char kManagerInterfaceName[] = "org.chromium.privetd.Manager"; const char kPrivetdManagerPath[] = "/org/chromium/privetd/Manager"; const char kPrivetdServiceName[] = "org.chromium.privetd"; const char kPrivetdServicePath[] = "/org/chromium/privetd"; const char kSetDescriptionMethod[] = "SetDescription"; const char kDescriptionProperty[] = "Description"; const char kGCDBootstrapStateProperty[] = "GCDBootstrapState"; const char kNameProperty[] = "Name"; const char kPairingInfoCodeProperty[] = "code"; const char kPairingInfoModeProperty[] = "mode"; const char kPairingInfoProperty[] = "PairingInfo"; const char kPairingInfoSessionIdProperty[] = "sessionId"; const char kWiFiBootstrapStateProperty[] = "WiFiBootstrapState"; // The PrivetDaemonManagerClient implementation used in production. class PrivetDaemonManagerClientImpl : public PrivetDaemonManagerClient, public dbus::ObjectManager::Interface { public: PrivetDaemonManagerClientImpl(); ~PrivetDaemonManagerClientImpl() override; // PrivetDaemonManagerClient overrides. void AddObserver(Observer* observer) override; void RemoveObserver(Observer* observer) override; void SetDescription(const std::string& description, const VoidDBusMethodCallback& callback) override; const Properties* GetProperties() override; // DBusClient overrides. void Init(dbus::Bus* bus) override; // dbus::ObjectManager::Interface overrides. dbus::PropertySet* CreateProperties( dbus::ObjectProxy* object_proxy, const dbus::ObjectPath& object_path, const std::string& interface_name) override; void ObjectAdded(const dbus::ObjectPath& object_path, const std::string& interface_name) override; void ObjectRemoved(const dbus::ObjectPath& object_path, const std::string& interface_name) override; private: // Called by dbus::PropertySet when a property value is changed, // either by result of a signal or response to a GetAll() or Get() // call. Informs observers. void OnManagerPropertyChanged(const std::string& property_name); void OnVoidDBusMethod(const VoidDBusMethodCallback& callback, dbus::Response* response); // List of observers interested in event notifications from us. base::ObserverList observers_; dbus::ObjectManager* object_manager_; base::WeakPtrFactory weak_ptr_factory_; DISALLOW_COPY_AND_ASSIGN(PrivetDaemonManagerClientImpl); }; PrivetDaemonManagerClientImpl::PrivetDaemonManagerClientImpl() : object_manager_(nullptr), weak_ptr_factory_(this) { } PrivetDaemonManagerClientImpl::~PrivetDaemonManagerClientImpl() { if (object_manager_) { object_manager_->UnregisterInterface(kManagerInterfaceName); } } void PrivetDaemonManagerClientImpl::AddObserver(Observer* observer) { DCHECK(observer); observers_.AddObserver(observer); } void PrivetDaemonManagerClientImpl::RemoveObserver(Observer* observer) { DCHECK(observer); observers_.RemoveObserver(observer); } void PrivetDaemonManagerClientImpl::SetDescription( const std::string& description, const VoidDBusMethodCallback& callback) { dbus::ObjectProxy* object_proxy = object_manager_->GetObjectProxy(dbus::ObjectPath(kPrivetdManagerPath)); if (!object_proxy) { base::ThreadTaskRunnerHandle::Get()->PostTask( FROM_HERE, base::Bind(&PrivetDaemonManagerClientImpl::OnVoidDBusMethod, weak_ptr_factory_.GetWeakPtr(), callback, nullptr)); return; } dbus::MethodCall method_call(kManagerInterfaceName, kSetDescriptionMethod); dbus::MessageWriter writer(&method_call); writer.AppendString(description); object_proxy->CallMethod( &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, base::Bind(&PrivetDaemonManagerClientImpl::OnVoidDBusMethod, weak_ptr_factory_.GetWeakPtr(), callback)); } const PrivetDaemonManagerClient::Properties* PrivetDaemonManagerClientImpl::GetProperties() { return static_cast(object_manager_->GetProperties( dbus::ObjectPath(kPrivetdManagerPath), kManagerInterfaceName)); } void PrivetDaemonManagerClientImpl::Init(dbus::Bus* bus) { object_manager_ = bus->GetObjectManager( kPrivetdServiceName, dbus::ObjectPath(kPrivetdServicePath)); object_manager_->RegisterInterface(kManagerInterfaceName, this); } dbus::PropertySet* PrivetDaemonManagerClientImpl::CreateProperties( dbus::ObjectProxy* object_proxy, const dbus::ObjectPath& object_path, const std::string& interface_name) { dbus::PropertySet* properties = nullptr; if (interface_name == kManagerInterfaceName) { properties = new Properties( object_proxy, interface_name, base::Bind(&PrivetDaemonManagerClientImpl::OnManagerPropertyChanged, weak_ptr_factory_.GetWeakPtr())); } else { NOTREACHED() << "Unhandled interface name " << interface_name; } return properties; } void PrivetDaemonManagerClientImpl::ObjectAdded( const dbus::ObjectPath& object_path, const std::string& interface_name) { if (interface_name == kManagerInterfaceName) { FOR_EACH_OBSERVER(Observer, observers_, ManagerAdded()); } else { NOTREACHED() << "Unhandled interface name " << interface_name; } } void PrivetDaemonManagerClientImpl::ObjectRemoved( const dbus::ObjectPath& object_path, const std::string& interface_name) { if (interface_name == kManagerInterfaceName) { FOR_EACH_OBSERVER(Observer, observers_, ManagerRemoved()); } else { NOTREACHED() << "Unhandled interface name " << interface_name; } } void PrivetDaemonManagerClientImpl::OnManagerPropertyChanged( const std::string& property_name) { FOR_EACH_OBSERVER(Observer, observers_, ManagerPropertyChanged(property_name)); } void PrivetDaemonManagerClientImpl::OnVoidDBusMethod( const VoidDBusMethodCallback& callback, dbus::Response* response) { callback.Run(response ? DBUS_METHOD_CALL_SUCCESS : DBUS_METHOD_CALL_FAILURE); } } // namespace void PrivetDaemonManagerClient::PairingInfo::Clear() { code_.clear(); mode_.clear(); session_id_.clear(); } bool PrivetDaemonManagerClient::PairingInfoProperty::PopValueFromReader( dbus::MessageReader* reader) { dbus::MessageReader variant_reader(nullptr); dbus::MessageReader array_reader(nullptr); value_.Clear(); if (!reader->PopVariant(&variant_reader) || !variant_reader.PopArray(&array_reader)) { return false; } while (array_reader.HasMoreData()) { dbus::MessageReader dict_entry_reader(nullptr); if (!array_reader.PopDictEntry(&dict_entry_reader)) return false; std::string key; if (!dict_entry_reader.PopString(&key)) return false; dbus::MessageReader field_reader(nullptr); if (!dict_entry_reader.PopVariant(&field_reader)) return false; if (field_reader.GetDataSignature() == "s") { std::string string_value; if (!field_reader.PopString(&string_value)) return false; if (key == kPairingInfoSessionIdProperty) { value_.set_session_id(string_value); } else if (key == kPairingInfoModeProperty) { value_.set_mode(string_value); } } else if (field_reader.GetDataSignature() == "ay") { const uint8_t* bytes = nullptr; size_t length = 0; if (!field_reader.PopArrayOfBytes(&bytes, &length)) return false; if (key == kPairingInfoCodeProperty) value_.set_code(bytes, length); } } return true; } PrivetDaemonManagerClient::PairingInfo::PairingInfo() { } PrivetDaemonManagerClient::PairingInfo::~PairingInfo() { } void PrivetDaemonManagerClient::PairingInfoProperty::AppendSetValueToWriter( dbus::MessageWriter* writer) { NOTIMPLEMENTED(); } void PrivetDaemonManagerClient::PairingInfoProperty:: ReplaceValueWithSetValue() { NOTIMPLEMENTED(); } PrivetDaemonManagerClient::Properties::Properties( dbus::ObjectProxy* object_proxy, const std::string& interface_name, const PropertyChangedCallback& callback) : dbus::PropertySet(object_proxy, interface_name, callback) { RegisterProperty(kWiFiBootstrapStateProperty, &wifi_bootstrap_state_); RegisterProperty(kGCDBootstrapStateProperty, &gcd_bootstrap_state_); RegisterProperty(kPairingInfoProperty, &pairing_info_); RegisterProperty(kDescriptionProperty, &description_); RegisterProperty(kNameProperty, &name_); } PrivetDaemonManagerClient::Properties::~Properties() { } PrivetDaemonManagerClient::Observer::~Observer() { } PrivetDaemonManagerClient::PrivetDaemonManagerClient() { } PrivetDaemonManagerClient::~PrivetDaemonManagerClient() { } // static PrivetDaemonManagerClient* PrivetDaemonManagerClient::Create() { return new PrivetDaemonManagerClientImpl(); } } // namespace chromeos