blob: 8f2addef3687f034101407b16002d502f8ade438 [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_);
Christopher Wiley982f6d42015-02-23 09:34:32 -080057 actions.push_back(
58 base::Bind(&DBusInterface::ClaimInterface,
59 weak_factory_.GetWeakPtr(),
Alex Vakulenko30477dd2014-08-15 11:44:26 -070060 object_manager->AsWeakPtr(),
61 object_path,
Christopher Wiley982f6d42015-02-23 09:34:32 -080062 property_writer_callback));
Alex Vakulenko30477dd2014-08-15 11:44:26 -070063 }
64 actions.push_back(completion_callback);
65 sequencer->OnAllTasksCompletedCall(actions);
66}
67
Christopher Wiley982f6d42015-02-23 09:34:32 -080068void DBusInterface::ClaimInterface(
69 base::WeakPtr<ExportedObjectManager> object_manager,
70 const dbus::ObjectPath& object_path,
71 const ExportedPropertySet::PropertyWriter& writer,
72 bool all_succeeded) {
73 if (!all_succeeded || !object_manager) {
74 LOG(ERROR) << "Skipping claiming interface: " << interface_name_;
75 return;
76 }
77 object_manager->ClaimInterface(object_path, interface_name_, writer);
78 release_interface_cb_.Reset(
79 base::Bind(&ExportedObjectManager::ReleaseInterface,
80 object_manager, object_path, interface_name_));
81}
82
Alex Vakulenko05d29042015-01-13 09:39:25 -080083void DBusInterface::HandleMethodCall(dbus::MethodCall* method_call,
84 ResponseSender sender) {
Alex Vakulenko30477dd2014-08-15 11:44:26 -070085 std::string method_name = method_call->GetMember();
Alex Vakulenko3e007ac2014-09-11 15:56:19 -070086 // Make a local copy of |interface_name_| because calling HandleMethod()
87 // can potentially kill this interface object...
88 std::string interface_name = interface_name_;
Alex Vakulenko05d29042015-01-13 09:39:25 -080089 VLOG(1) << "Received method call request: " << interface_name << "."
90 << method_name << "(" << method_call->GetSignature() << ")";
Alex Vakulenko30477dd2014-08-15 11:44:26 -070091 auto pair = handlers_.find(method_name);
Alex Vakulenkoc60df902014-11-07 07:31:07 -080092 if (pair == handlers_.end()) {
Alex Vakulenko05d29042015-01-13 09:39:25 -080093 auto response =
94 dbus::ErrorResponse::FromMethodCall(method_call,
95 DBUS_ERROR_UNKNOWN_METHOD,
96 "Unknown method: " + method_name);
Alex Vakulenko7fb5e542014-12-10 12:52:31 -080097 sender.Run(response.Pass());
Alex Vakulenkof437e3b2014-10-30 16:28:38 -070098 return;
Alex Vakulenko30477dd2014-08-15 11:44:26 -070099 }
Alex Vakulenko3e007ac2014-09-11 15:56:19 -0700100 LOG(INFO) << "Dispatching DBus method call: " << method_name;
Alex Vakulenkof437e3b2014-10-30 16:28:38 -0700101 pair->second->HandleMethod(method_call, sender);
Alex Vakulenko30477dd2014-08-15 11:44:26 -0700102}
103
104void DBusInterface::AddHandlerImpl(
105 const std::string& method_name,
Alex Vakulenkof437e3b2014-10-30 16:28:38 -0700106 std::unique_ptr<DBusInterfaceMethodHandlerInterface> handler) {
Alex Vakulenko05d29042015-01-13 09:39:25 -0800107 VLOG(1) << "Declaring method handler: " << interface_name_ << "."
108 << method_name;
Alex Vakulenko30477dd2014-08-15 11:44:26 -0700109 auto res = handlers_.insert(std::make_pair(method_name, std::move(handler)));
110 CHECK(res.second) << "Method '" << method_name << "' already exists";
111}
112
Alex Vakulenko3e007ac2014-09-11 15:56:19 -0700113void DBusInterface::AddSignalImpl(
114 const std::string& signal_name,
115 const std::shared_ptr<DBusSignalBase>& signal) {
Alex Vakulenko05d29042015-01-13 09:39:25 -0800116 VLOG(1) << "Declaring a signal sink: " << interface_name_ << "."
117 << signal_name;
Alex Vakulenko3e007ac2014-09-11 15:56:19 -0700118 CHECK(signals_.insert(std::make_pair(signal_name, signal)).second)
119 << "The signal '" << signal_name << "' is already registered";
120}
121
Alex Vakulenko30477dd2014-08-15 11:44:26 -0700122///////////////////////////////////////////////////////////////////////////////
123
124DBusObject::DBusObject(ExportedObjectManager* object_manager,
125 const scoped_refptr<dbus::Bus>& bus,
126 const dbus::ObjectPath& object_path)
Alex Vakulenko05d29042015-01-13 09:39:25 -0800127 : property_set_(bus.get()), bus_(bus), object_path_(object_path) {
Alex Vakulenko30477dd2014-08-15 11:44:26 -0700128 if (object_manager)
129 object_manager_ = object_manager->AsWeakPtr();
130}
131
132DBusObject::~DBusObject() {
Alex Vakulenko30477dd2014-08-15 11:44:26 -0700133 if (exported_object_)
134 exported_object_->Unregister();
135}
136
137DBusInterface* DBusObject::AddOrGetInterface(
138 const std::string& interface_name) {
139 auto iter = interfaces_.find(interface_name);
140 if (iter == interfaces_.end()) {
Alex Vakulenko3e007ac2014-09-11 15:56:19 -0700141 VLOG(1) << "Adding an interface '" << interface_name << "' to object '"
142 << object_path_.value() << "'.";
Alex Vakulenko30477dd2014-08-15 11:44:26 -0700143 // Interface doesn't exist yet. Create one...
144 std::unique_ptr<DBusInterface> new_itf(
145 new DBusInterface(this, interface_name));
Alex Vakulenko05d29042015-01-13 09:39:25 -0800146 iter = interfaces_.insert(std::make_pair(interface_name,
147 std::move(new_itf))).first;
Alex Vakulenko30477dd2014-08-15 11:44:26 -0700148 }
149 return iter->second.get();
150}
151
Alex Vakulenkof02e3792014-11-07 08:01:35 -0800152DBusInterface* DBusObject::FindInterface(
Alex Vakulenko05d29042015-01-13 09:39:25 -0800153 const std::string& interface_name) const {
Alex Vakulenko30477dd2014-08-15 11:44:26 -0700154 auto itf_iter = interfaces_.find(interface_name);
Alex Vakulenkof02e3792014-11-07 08:01:35 -0800155 return (itf_iter == interfaces_.end()) ? nullptr : itf_iter->second.get();
Alex Vakulenko30477dd2014-08-15 11:44:26 -0700156}
157
158void DBusObject::RegisterAsync(
159 const AsyncEventSequencer::CompletionAction& completion_callback) {
Alex Vakulenko05d29042015-01-13 09:39:25 -0800160 VLOG(1) << "Registering D-Bus object '" << object_path_.value() << "'.";
Alex Vakulenko30477dd2014-08-15 11:44:26 -0700161 CHECK(exported_object_ == nullptr) << "Object already registered.";
162 scoped_refptr<AsyncEventSequencer> sequencer(new AsyncEventSequencer());
163 exported_object_ = bus_->GetExportedObject(object_path_);
Alex Vakulenko520fc152014-08-19 10:31:54 -0700164
165 // Add the org.freedesktop.DBus.Properties interface to the object.
166 DBusInterface* prop_interface = AddOrGetInterface(dbus::kPropertiesInterface);
Alex Vakulenkof437e3b2014-10-30 16:28:38 -0700167 prop_interface->AddSimpleMethodHandler(
168 dbus::kPropertiesGetAll,
169 base::Unretained(&property_set_),
170 &ExportedPropertySet::HandleGetAll);
171 prop_interface->AddSimpleMethodHandlerWithError(
172 dbus::kPropertiesGet,
173 base::Unretained(&property_set_),
174 &ExportedPropertySet::HandleGet);
175 prop_interface->AddSimpleMethodHandlerWithError(
176 dbus::kPropertiesSet,
177 base::Unretained(&property_set_),
178 &ExportedPropertySet::HandleSet);
Alex Vakulenkofa8f9442014-08-27 14:50:36 -0700179 property_set_.OnPropertiesInterfaceExported(prop_interface);
Alex Vakulenko30477dd2014-08-15 11:44:26 -0700180
181 // Export interface methods
182 for (const auto& pair : interfaces_) {
183 pair.second->ExportAsync(
184 object_manager_.get(),
185 bus_.get(),
186 exported_object_,
187 object_path_,
188 sequencer->GetHandler("Failed to export interface " + pair.first,
189 false));
190 }
191
192 sequencer->OnAllTasksCompletedCall({completion_callback});
193}
194
Alex Vakulenkofa8f9442014-08-27 14:50:36 -0700195bool DBusObject::SendSignal(dbus::Signal* signal) {
Alex Vakulenkoe2f969f2014-08-24 15:05:06 -0700196 if (exported_object_) {
Alex Vakulenkoe2f969f2014-08-24 15:05:06 -0700197 exported_object_->SendSignal(signal);
Alex Vakulenkofa8f9442014-08-27 14:50:36 -0700198 return true;
Alex Vakulenkoe2f969f2014-08-24 15:05:06 -0700199 }
Alex Vakulenkofa8f9442014-08-27 14:50:36 -0700200 LOG(ERROR) << "Trying to send a signal from an object that is not exported";
201 return false;
Alex Vakulenkoe2f969f2014-08-24 15:05:06 -0700202}
203
Alex Vakulenko30477dd2014-08-15 11:44:26 -0700204} // namespace dbus_utils
205} // namespace chromeos