• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/dbus_object.h>
6 
7 #include <vector>
8 
9 #include <base/bind.h>
10 #include <base/logging.h>
11 #include <brillo/dbus/async_event_sequencer.h>
12 #include <brillo/dbus/exported_object_manager.h>
13 #include <brillo/dbus/exported_property_set.h>
14 #include <dbus/property.h>
15 
16 namespace brillo {
17 namespace dbus_utils {
18 
19 namespace {
20 
SetupDefaultPropertyHandlers(DBusInterface * prop_interface,ExportedPropertySet * property_set)21 void SetupDefaultPropertyHandlers(DBusInterface* prop_interface,
22                                   ExportedPropertySet* property_set) {
23   prop_interface->AddSimpleMethodHandler(dbus::kPropertiesGetAll,
24                                          base::Unretained(property_set),
25                                          &ExportedPropertySet::HandleGetAll);
26   prop_interface->AddSimpleMethodHandlerWithError(
27       dbus::kPropertiesGet, base::Unretained(property_set),
28       &ExportedPropertySet::HandleGet);
29   prop_interface->AddSimpleMethodHandlerWithError(
30       dbus::kPropertiesSet, base::Unretained(property_set),
31       &ExportedPropertySet::HandleSet);
32 }
33 
34 }  // namespace
35 
36 //////////////////////////////////////////////////////////////////////////////
37 
DBusInterface(DBusObject * dbus_object,const std::string & interface_name)38 DBusInterface::DBusInterface(DBusObject* dbus_object,
39                              const std::string& interface_name)
40     : dbus_object_(dbus_object), interface_name_(interface_name) {
41 }
42 
AddProperty(const std::string & property_name,ExportedPropertyBase * prop_base)43 void DBusInterface::AddProperty(const std::string& property_name,
44                                 ExportedPropertyBase* prop_base) {
45   dbus_object_->property_set_.RegisterProperty(
46       interface_name_, property_name, prop_base);
47 }
48 
RemoveProperty(const std::string & property_name)49 void DBusInterface::RemoveProperty(const std::string& property_name) {
50   dbus_object_->property_set_.UnregisterProperty(interface_name_,
51                                                  property_name);
52 }
53 
ExportAsync(ExportedObjectManager * object_manager,dbus::Bus *,dbus::ExportedObject * exported_object,const dbus::ObjectPath & object_path,const AsyncEventSequencer::CompletionAction & completion_callback)54 void DBusInterface::ExportAsync(
55     ExportedObjectManager* object_manager,
56     dbus::Bus* /* bus */,
57     dbus::ExportedObject* exported_object,
58     const dbus::ObjectPath& object_path,
59     const AsyncEventSequencer::CompletionAction& completion_callback) {
60   VLOG(1) << "Registering D-Bus interface '" << interface_name_ << "' for '"
61           << object_path.value() << "'";
62   scoped_refptr<AsyncEventSequencer> sequencer(new AsyncEventSequencer());
63   for (const auto& pair : handlers_) {
64     std::string method_name = pair.first;
65     VLOG(1) << "Exporting method: " << interface_name_ << "." << method_name;
66     std::string export_error = "Failed exporting " + method_name + " method";
67     auto export_handler = sequencer->GetExportHandler(
68         interface_name_, method_name, export_error, true);
69     auto method_handler =
70         base::Bind(&DBusInterface::HandleMethodCall, base::Unretained(this));
71     exported_object->ExportMethod(
72         interface_name_, method_name, method_handler, export_handler);
73   }
74 
75   std::vector<AsyncEventSequencer::CompletionAction> actions;
76   if (object_manager) {
77     auto property_writer_callback =
78         dbus_object_->property_set_.GetPropertyWriter(interface_name_);
79     actions.push_back(
80         base::Bind(&DBusInterface::ClaimInterface,
81                    weak_factory_.GetWeakPtr(),
82                    object_manager->AsWeakPtr(),
83                    object_path,
84                    property_writer_callback));
85   }
86   actions.push_back(completion_callback);
87   sequencer->OnAllTasksCompletedCall(actions);
88 }
89 
ExportAndBlock(ExportedObjectManager * object_manager,dbus::Bus *,dbus::ExportedObject * exported_object,const dbus::ObjectPath & object_path)90 void DBusInterface::ExportAndBlock(
91     ExportedObjectManager* object_manager,
92     dbus::Bus* /* bus */,
93     dbus::ExportedObject* exported_object,
94     const dbus::ObjectPath& object_path) {
95   VLOG(1) << "Registering D-Bus interface '" << interface_name_ << "' for '"
96           << object_path.value() << "'";
97   for (const auto& pair : handlers_) {
98     std::string method_name = pair.first;
99     VLOG(1) << "Exporting method: " << interface_name_ << "." << method_name;
100     auto method_handler =
101         base::Bind(&DBusInterface::HandleMethodCall, base::Unretained(this));
102     if (!exported_object->ExportMethodAndBlock(
103             interface_name_, method_name, method_handler)) {
104         LOG(FATAL) << "Failed exporting " << method_name << " method";
105     }
106   }
107 
108   if (object_manager) {
109     auto property_writer_callback =
110         dbus_object_->property_set_.GetPropertyWriter(interface_name_);
111     ClaimInterface(object_manager->AsWeakPtr(),
112                    object_path,
113                    property_writer_callback,
114                    true);
115   }
116 }
117 
ClaimInterface(base::WeakPtr<ExportedObjectManager> object_manager,const dbus::ObjectPath & object_path,const ExportedPropertySet::PropertyWriter & writer,bool all_succeeded)118 void DBusInterface::ClaimInterface(
119       base::WeakPtr<ExportedObjectManager> object_manager,
120       const dbus::ObjectPath& object_path,
121       const ExportedPropertySet::PropertyWriter& writer,
122       bool all_succeeded) {
123   if (!all_succeeded || !object_manager) {
124     LOG(ERROR) << "Skipping claiming interface: " << interface_name_;
125     return;
126   }
127   object_manager->ClaimInterface(object_path, interface_name_, writer);
128   release_interface_cb_.ReplaceClosure(
129       base::Bind(&ExportedObjectManager::ReleaseInterface,
130                  object_manager, object_path, interface_name_));
131 }
132 
HandleMethodCall(dbus::MethodCall * method_call,ResponseSender sender)133 void DBusInterface::HandleMethodCall(dbus::MethodCall* method_call,
134                                      ResponseSender sender) {
135   std::string method_name = method_call->GetMember();
136   // Make a local copy of |interface_name_| because calling HandleMethod()
137   // can potentially kill this interface object...
138   std::string interface_name = interface_name_;
139   VLOG(1) << "Received method call request: " << interface_name << "."
140           << method_name << "(" << method_call->GetSignature() << ")";
141   auto pair = handlers_.find(method_name);
142   if (pair == handlers_.end()) {
143     auto response =
144         dbus::ErrorResponse::FromMethodCall(method_call,
145                                             DBUS_ERROR_UNKNOWN_METHOD,
146                                             "Unknown method: " + method_name);
147     sender.Run(std::move(response));
148     return;
149   }
150   VLOG(1) << "Dispatching DBus method call: " << method_name;
151   pair->second->HandleMethod(method_call, sender);
152 }
153 
AddHandlerImpl(const std::string & method_name,std::unique_ptr<DBusInterfaceMethodHandlerInterface> handler)154 void DBusInterface::AddHandlerImpl(
155     const std::string& method_name,
156     std::unique_ptr<DBusInterfaceMethodHandlerInterface> handler) {
157   VLOG(1) << "Declaring method handler: " << interface_name_ << "."
158           << method_name;
159   auto res = handlers_.insert(std::make_pair(method_name, std::move(handler)));
160   CHECK(res.second) << "Method '" << method_name << "' already exists";
161 }
162 
AddSignalImpl(const std::string & signal_name,const std::shared_ptr<DBusSignalBase> & signal)163 void DBusInterface::AddSignalImpl(
164     const std::string& signal_name,
165     const std::shared_ptr<DBusSignalBase>& signal) {
166   VLOG(1) << "Declaring a signal sink: " << interface_name_ << "."
167           << signal_name;
168   CHECK(signals_.insert(std::make_pair(signal_name, signal)).second)
169       << "The signal '" << signal_name << "' is already registered";
170 }
171 
172 ///////////////////////////////////////////////////////////////////////////////
173 
DBusObject(ExportedObjectManager * object_manager,const scoped_refptr<dbus::Bus> & bus,const dbus::ObjectPath & object_path)174 DBusObject::DBusObject(ExportedObjectManager* object_manager,
175                        const scoped_refptr<dbus::Bus>& bus,
176                        const dbus::ObjectPath& object_path)
177     : DBusObject::DBusObject(object_manager,
178                              bus,
179                              object_path,
180                              base::Bind(&SetupDefaultPropertyHandlers)) {}
181 
DBusObject(ExportedObjectManager * object_manager,const scoped_refptr<dbus::Bus> & bus,const dbus::ObjectPath & object_path,PropertyHandlerSetupCallback property_handler_setup_callback)182 DBusObject::DBusObject(
183     ExportedObjectManager* object_manager,
184     const scoped_refptr<dbus::Bus>& bus,
185     const dbus::ObjectPath& object_path,
186     PropertyHandlerSetupCallback property_handler_setup_callback)
187     : property_set_(bus.get()),
188       bus_(bus),
189       object_path_(object_path),
190       property_handler_setup_callback_(
191           std::move(property_handler_setup_callback)) {
192   if (object_manager)
193     object_manager_ = object_manager->AsWeakPtr();
194 }
195 
~DBusObject()196 DBusObject::~DBusObject() {
197   if (exported_object_)
198     exported_object_->Unregister();
199 }
200 
AddOrGetInterface(const std::string & interface_name)201 DBusInterface* DBusObject::AddOrGetInterface(
202     const std::string& interface_name) {
203   auto iter = interfaces_.find(interface_name);
204   if (iter == interfaces_.end()) {
205     VLOG(1) << "Adding an interface '" << interface_name << "' to object '"
206             << object_path_.value() << "'.";
207     // Interface doesn't exist yet. Create one...
208     std::unique_ptr<DBusInterface> new_itf(
209         new DBusInterface(this, interface_name));
210     iter = interfaces_.insert(std::make_pair(interface_name,
211                                              std::move(new_itf))).first;
212   }
213   return iter->second.get();
214 }
215 
FindInterface(const std::string & interface_name) const216 DBusInterface* DBusObject::FindInterface(
217     const std::string& interface_name) const {
218   auto itf_iter = interfaces_.find(interface_name);
219   return (itf_iter == interfaces_.end()) ? nullptr : itf_iter->second.get();
220 }
221 
RemoveInterface(const std::string & interface_name)222 void DBusObject::RemoveInterface(const std::string& interface_name) {
223   auto itf_iter = interfaces_.find(interface_name);
224   CHECK(itf_iter != interfaces_.end())
225       << "Interface " << interface_name << " has not been added.";
226   interfaces_.erase(itf_iter);
227 }
228 
ExportInterfaceAsync(const std::string & interface_name,const AsyncEventSequencer::CompletionAction & completion_callback)229 void DBusObject::ExportInterfaceAsync(
230     const std::string& interface_name,
231     const AsyncEventSequencer::CompletionAction& completion_callback) {
232   AddOrGetInterface(interface_name)
233       ->ExportAsync(object_manager_.get(), bus_.get(), exported_object_,
234                     object_path_, completion_callback);
235 }
236 
RegisterAsync(const AsyncEventSequencer::CompletionAction & completion_callback)237 void DBusObject::RegisterAsync(
238     const AsyncEventSequencer::CompletionAction& completion_callback) {
239   VLOG(1) << "Registering D-Bus object '" << object_path_.value() << "'.";
240   CHECK(exported_object_ == nullptr) << "Object already registered.";
241   scoped_refptr<AsyncEventSequencer> sequencer(new AsyncEventSequencer());
242   exported_object_ = bus_->GetExportedObject(object_path_);
243 
244   RegisterPropertiesInterface();
245 
246   // Export interface methods
247   for (const auto& pair : interfaces_) {
248     pair.second->ExportAsync(
249         object_manager_.get(),
250         bus_.get(),
251         exported_object_,
252         object_path_,
253         sequencer->GetHandler("Failed to export interface " + pair.first,
254                               false));
255   }
256 
257   sequencer->OnAllTasksCompletedCall({completion_callback});
258 }
259 
RegisterAndBlock()260 void DBusObject::RegisterAndBlock() {
261   VLOG(1) << "Registering D-Bus object '" << object_path_.value() << "'.";
262   CHECK(exported_object_ == nullptr) << "Object already registered.";
263   exported_object_ = bus_->GetExportedObject(object_path_);
264 
265   RegisterPropertiesInterface();
266 
267   // Export interface methods
268   for (const auto& pair : interfaces_) {
269     pair.second->ExportAndBlock(
270         object_manager_.get(),
271         bus_.get(),
272         exported_object_,
273         object_path_);
274   }
275 }
276 
UnregisterAsync()277 void DBusObject::UnregisterAsync() {
278   VLOG(1) << "Unregistering D-Bus object '" << object_path_.value() << "'.";
279   CHECK(exported_object_ != nullptr) << "Object not registered.";
280 
281   // This will unregister the object path from the bus.
282   exported_object_->Unregister();
283   // This will remove |exported_object_| from bus's object table. This function
284   // will also post a task to unregister |exported_object_| (same as the call
285   // above), which will be a no-op since it is already done by then.
286   // By doing both in here, the object path is guarantee to be reusable upon
287   // return from this function.
288   bus_->UnregisterExportedObject(object_path_);
289   exported_object_ = nullptr;
290 }
291 
SendSignal(dbus::Signal * signal)292 bool DBusObject::SendSignal(dbus::Signal* signal) {
293   if (exported_object_) {
294     exported_object_->SendSignal(signal);
295     return true;
296   }
297   LOG(ERROR) << "Trying to send a signal from an object that is not exported";
298   return false;
299 }
300 
RegisterPropertiesInterface()301 void DBusObject::RegisterPropertiesInterface() {
302   DBusInterface* prop_interface = AddOrGetInterface(dbus::kPropertiesInterface);
303   property_handler_setup_callback_.Run(prop_interface, &property_set_);
304   property_set_.OnPropertiesInterfaceExported(prop_interface);
305 }
306 
307 }  // namespace dbus_utils
308 }  // namespace brillo
309