blob: 4e8cdc2a138f711d4e5d514746b91a7f01cbf3dd [file] [log] [blame]
Alex Vakulenko30477dd2014-08-15 11:44:26 -07001// 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 <chromeos/dbus/dbus_object.h>
6
7#include <vector>
8
9#include <base/bind.h>
Alex Vakulenkoe2f969f2014-08-24 15:05:06 -070010#include <base/logging.h>
Alex Vakulenko15104662014-08-27 11:00:57 -070011#include <chromeos/dbus/async_event_sequencer.h>
12#include <chromeos/dbus/exported_object_manager.h>
13#include <chromeos/dbus/exported_property_set.h>
Alex Vakulenko520fc152014-08-19 10:31:54 -070014#include <dbus/property.h>
Alex Vakulenko30477dd2014-08-15 11:44:26 -070015
16namespace chromeos {
17namespace dbus_utils {
18
Alex Vakulenko30477dd2014-08-15 11:44:26 -070019//////////////////////////////////////////////////////////////////////////////
20
21DBusInterface::DBusInterface(DBusObject* dbus_object,
22 const std::string& interface_name)
Alex Vakulenko05d29042015-01-13 09:39:25 -080023 : dbus_object_(dbus_object), interface_name_(interface_name) {
24}
Alex Vakulenko30477dd2014-08-15 11:44:26 -070025
26void DBusInterface::AddProperty(const std::string& property_name,
27 ExportedPropertyBase* prop_base) {
Alex Vakulenko05d29042015-01-13 09:39:25 -080028 dbus_object_->property_set_.RegisterProperty(
29 interface_name_, property_name, prop_base);
Alex Vakulenko30477dd2014-08-15 11:44:26 -070030}
31
32void DBusInterface::ExportAsync(
33 ExportedObjectManager* object_manager,
34 dbus::Bus* bus,
35 dbus::ExportedObject* exported_object,
36 const dbus::ObjectPath& object_path,
37 const AsyncEventSequencer::CompletionAction& completion_callback) {
Alex Vakulenko3e007ac2014-09-11 15:56:19 -070038 VLOG(1) << "Registering D-Bus interface '" << interface_name_ << "' for '"
39 << object_path.value() << "'";
Alex Vakulenko30477dd2014-08-15 11:44:26 -070040 scoped_refptr<AsyncEventSequencer> sequencer(new AsyncEventSequencer());
41 for (const auto& pair : handlers_) {
42 std::string method_name = pair.first;
Alex Vakulenko3e007ac2014-09-11 15:56:19 -070043 VLOG(1) << "Exporting method: " << interface_name_ << "." << method_name;
Alex Vakulenko30477dd2014-08-15 11:44:26 -070044 std::string export_error = "Failed exporting " + method_name + " method";
45 auto export_handler = sequencer->GetExportHandler(
46 interface_name_, method_name, export_error, true);
Alex Vakulenko05d29042015-01-13 09:39:25 -080047 auto method_handler =
48 base::Bind(&DBusInterface::HandleMethodCall, base::Unretained(this));
Alex Vakulenko30477dd2014-08-15 11:44:26 -070049 exported_object->ExportMethod(
50 interface_name_, method_name, method_handler, export_handler);
51 }
52
Alex Vakulenko30477dd2014-08-15 11:44:26 -070053 std::vector<AsyncEventSequencer::CompletionAction> actions;
54 if (object_manager) {
Alex Vakulenko520fc152014-08-19 10:31:54 -070055 auto property_writer_callback =
56 dbus_object_->property_set_.GetPropertyWriter(interface_name_);
Alex Vakulenko30477dd2014-08-15 11:44:26 -070057 actions.push_back(sequencer->WrapCompletionTask(
58 base::Bind(&ExportedObjectManager::ClaimInterface,
59 object_manager->AsWeakPtr(),
60 object_path,
61 interface_name_,
Alex Vakulenko520fc152014-08-19 10:31:54 -070062 property_writer_callback)));
Alex Vakulenko30477dd2014-08-15 11:44:26 -070063 }
64 actions.push_back(completion_callback);
65 sequencer->OnAllTasksCompletedCall(actions);
66}
67
Alex Vakulenko05d29042015-01-13 09:39:25 -080068void DBusInterface::HandleMethodCall(dbus::MethodCall* method_call,
69 ResponseSender sender) {
Alex Vakulenko30477dd2014-08-15 11:44:26 -070070 std::string method_name = method_call->GetMember();
Alex Vakulenko3e007ac2014-09-11 15:56:19 -070071 // Make a local copy of |interface_name_| because calling HandleMethod()
72 // can potentially kill this interface object...
73 std::string interface_name = interface_name_;
Alex Vakulenko05d29042015-01-13 09:39:25 -080074 VLOG(1) << "Received method call request: " << interface_name << "."
75 << method_name << "(" << method_call->GetSignature() << ")";
Alex Vakulenko30477dd2014-08-15 11:44:26 -070076 auto pair = handlers_.find(method_name);
Alex Vakulenkoc60df902014-11-07 07:31:07 -080077 if (pair == handlers_.end()) {
Alex Vakulenko05d29042015-01-13 09:39:25 -080078 auto response =
79 dbus::ErrorResponse::FromMethodCall(method_call,
80 DBUS_ERROR_UNKNOWN_METHOD,
81 "Unknown method: " + method_name);
Alex Vakulenko7fb5e542014-12-10 12:52:31 -080082 sender.Run(response.Pass());
Alex Vakulenkof437e3b2014-10-30 16:28:38 -070083 return;
Alex Vakulenko30477dd2014-08-15 11:44:26 -070084 }
Alex Vakulenko3e007ac2014-09-11 15:56:19 -070085 LOG(INFO) << "Dispatching DBus method call: " << method_name;
Alex Vakulenkof437e3b2014-10-30 16:28:38 -070086 pair->second->HandleMethod(method_call, sender);
Alex Vakulenko30477dd2014-08-15 11:44:26 -070087}
88
89void DBusInterface::AddHandlerImpl(
90 const std::string& method_name,
Alex Vakulenkof437e3b2014-10-30 16:28:38 -070091 std::unique_ptr<DBusInterfaceMethodHandlerInterface> handler) {
Alex Vakulenko05d29042015-01-13 09:39:25 -080092 VLOG(1) << "Declaring method handler: " << interface_name_ << "."
93 << method_name;
Alex Vakulenko30477dd2014-08-15 11:44:26 -070094 auto res = handlers_.insert(std::make_pair(method_name, std::move(handler)));
95 CHECK(res.second) << "Method '" << method_name << "' already exists";
96}
97
Alex Vakulenko3e007ac2014-09-11 15:56:19 -070098void DBusInterface::AddSignalImpl(
99 const std::string& signal_name,
100 const std::shared_ptr<DBusSignalBase>& signal) {
Alex Vakulenko05d29042015-01-13 09:39:25 -0800101 VLOG(1) << "Declaring a signal sink: " << interface_name_ << "."
102 << signal_name;
Alex Vakulenko3e007ac2014-09-11 15:56:19 -0700103 CHECK(signals_.insert(std::make_pair(signal_name, signal)).second)
104 << "The signal '" << signal_name << "' is already registered";
105}
106
Alex Vakulenko30477dd2014-08-15 11:44:26 -0700107///////////////////////////////////////////////////////////////////////////////
108
109DBusObject::DBusObject(ExportedObjectManager* object_manager,
110 const scoped_refptr<dbus::Bus>& bus,
111 const dbus::ObjectPath& object_path)
Alex Vakulenko05d29042015-01-13 09:39:25 -0800112 : property_set_(bus.get()), bus_(bus), object_path_(object_path) {
Alex Vakulenko30477dd2014-08-15 11:44:26 -0700113 if (object_manager)
114 object_manager_ = object_manager->AsWeakPtr();
115}
116
117DBusObject::~DBusObject() {
118 if (object_manager_) {
119 for (const auto& pair : interfaces_)
120 object_manager_->ReleaseInterface(object_path_, pair.first);
121 }
122
123 if (exported_object_)
124 exported_object_->Unregister();
125}
126
127DBusInterface* DBusObject::AddOrGetInterface(
128 const std::string& interface_name) {
129 auto iter = interfaces_.find(interface_name);
130 if (iter == interfaces_.end()) {
Alex Vakulenko3e007ac2014-09-11 15:56:19 -0700131 VLOG(1) << "Adding an interface '" << interface_name << "' to object '"
132 << object_path_.value() << "'.";
Alex Vakulenko30477dd2014-08-15 11:44:26 -0700133 // Interface doesn't exist yet. Create one...
134 std::unique_ptr<DBusInterface> new_itf(
135 new DBusInterface(this, interface_name));
Alex Vakulenko05d29042015-01-13 09:39:25 -0800136 iter = interfaces_.insert(std::make_pair(interface_name,
137 std::move(new_itf))).first;
Alex Vakulenko30477dd2014-08-15 11:44:26 -0700138 }
139 return iter->second.get();
140}
141
Alex Vakulenkof02e3792014-11-07 08:01:35 -0800142DBusInterface* DBusObject::FindInterface(
Alex Vakulenko05d29042015-01-13 09:39:25 -0800143 const std::string& interface_name) const {
Alex Vakulenko30477dd2014-08-15 11:44:26 -0700144 auto itf_iter = interfaces_.find(interface_name);
Alex Vakulenkof02e3792014-11-07 08:01:35 -0800145 return (itf_iter == interfaces_.end()) ? nullptr : itf_iter->second.get();
Alex Vakulenko30477dd2014-08-15 11:44:26 -0700146}
147
148void DBusObject::RegisterAsync(
149 const AsyncEventSequencer::CompletionAction& completion_callback) {
Alex Vakulenko05d29042015-01-13 09:39:25 -0800150 VLOG(1) << "Registering D-Bus object '" << object_path_.value() << "'.";
Alex Vakulenko30477dd2014-08-15 11:44:26 -0700151 CHECK(exported_object_ == nullptr) << "Object already registered.";
152 scoped_refptr<AsyncEventSequencer> sequencer(new AsyncEventSequencer());
153 exported_object_ = bus_->GetExportedObject(object_path_);
Alex Vakulenko520fc152014-08-19 10:31:54 -0700154
155 // Add the org.freedesktop.DBus.Properties interface to the object.
156 DBusInterface* prop_interface = AddOrGetInterface(dbus::kPropertiesInterface);
Alex Vakulenkof437e3b2014-10-30 16:28:38 -0700157 prop_interface->AddSimpleMethodHandler(
158 dbus::kPropertiesGetAll,
159 base::Unretained(&property_set_),
160 &ExportedPropertySet::HandleGetAll);
161 prop_interface->AddSimpleMethodHandlerWithError(
162 dbus::kPropertiesGet,
163 base::Unretained(&property_set_),
164 &ExportedPropertySet::HandleGet);
165 prop_interface->AddSimpleMethodHandlerWithError(
166 dbus::kPropertiesSet,
167 base::Unretained(&property_set_),
168 &ExportedPropertySet::HandleSet);
Alex Vakulenkofa8f9442014-08-27 14:50:36 -0700169 property_set_.OnPropertiesInterfaceExported(prop_interface);
Alex Vakulenko30477dd2014-08-15 11:44:26 -0700170
171 // Export interface methods
172 for (const auto& pair : interfaces_) {
173 pair.second->ExportAsync(
174 object_manager_.get(),
175 bus_.get(),
176 exported_object_,
177 object_path_,
178 sequencer->GetHandler("Failed to export interface " + pair.first,
179 false));
180 }
181
182 sequencer->OnAllTasksCompletedCall({completion_callback});
183}
184
Alex Vakulenkofa8f9442014-08-27 14:50:36 -0700185bool DBusObject::SendSignal(dbus::Signal* signal) {
Alex Vakulenkoe2f969f2014-08-24 15:05:06 -0700186 if (exported_object_) {
Alex Vakulenkoe2f969f2014-08-24 15:05:06 -0700187 exported_object_->SendSignal(signal);
Alex Vakulenkofa8f9442014-08-27 14:50:36 -0700188 return true;
Alex Vakulenkoe2f969f2014-08-24 15:05:06 -0700189 }
Alex Vakulenkofa8f9442014-08-27 14:50:36 -0700190 LOG(ERROR) << "Trying to send a signal from an object that is not exported";
191 return false;
Alex Vakulenkoe2f969f2014-08-24 15:05:06 -0700192}
193
Alex Vakulenko30477dd2014-08-15 11:44:26 -0700194} // namespace dbus_utils
195} // namespace chromeos