• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2012 The Chromium 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 "dbus/bus.h"
6 
7 #include <stddef.h>
8 
9 #include <memory>
10 
11 #include "base/bind.h"
12 #include "base/files/file_descriptor_watcher_posix.h"
13 #include "base/logging.h"
14 #include "base/memory/weak_ptr.h"
15 #include "base/stl_util.h"
16 #include "base/strings/stringprintf.h"
17 #include "base/threading/thread.h"
18 #include "base/threading/thread_restrictions.h"
19 #include "base/threading/thread_task_runner_handle.h"
20 #include "base/time/time.h"
21 #include "dbus/exported_object.h"
22 #include "dbus/message.h"
23 #include "dbus/object_manager.h"
24 #include "dbus/object_path.h"
25 #include "dbus/object_proxy.h"
26 #include "dbus/scoped_dbus_error.h"
27 
28 namespace dbus {
29 
30 namespace {
31 
32 const char kDisconnectedSignal[] = "Disconnected";
33 const char kDisconnectedMatchRule[] =
34     "type='signal', path='/org/freedesktop/DBus/Local',"
35     "interface='org.freedesktop.DBus.Local', member='Disconnected'";
36 
37 // The NameOwnerChanged member in org.freedesktop.DBus
38 const char kNameOwnerChangedSignal[] = "NameOwnerChanged";
39 
40 // The match rule used to filter for changes to a given service name owner.
41 const char kServiceNameOwnerChangeMatchRule[] =
42     "type='signal',interface='org.freedesktop.DBus',"
43     "member='NameOwnerChanged',path='/org/freedesktop/DBus',"
44     "sender='org.freedesktop.DBus',arg0='%s'";
45 
46 // The class is used for watching the file descriptor used for D-Bus
47 // communication.
48 class Watch {
49  public:
Watch(DBusWatch * watch)50   explicit Watch(DBusWatch* watch) : raw_watch_(watch) {
51     dbus_watch_set_data(raw_watch_, this, nullptr);
52   }
53 
~Watch()54   ~Watch() { dbus_watch_set_data(raw_watch_, nullptr, nullptr); }
55 
56   // Returns true if the underlying file descriptor is ready to be watched.
IsReadyToBeWatched()57   bool IsReadyToBeWatched() {
58     return dbus_watch_get_enabled(raw_watch_);
59   }
60 
61   // Starts watching the underlying file descriptor.
StartWatching()62   void StartWatching() {
63     const int file_descriptor = dbus_watch_get_unix_fd(raw_watch_);
64     const unsigned int flags = dbus_watch_get_flags(raw_watch_);
65 
66     // Using base::Unretained(this) is safe because watches are automatically
67     // canceled when |read_watcher_| and |write_watcher_| are destroyed.
68     if (flags & DBUS_WATCH_READABLE) {
69       read_watcher_ = base::FileDescriptorWatcher::WatchReadable(
70           file_descriptor,
71           base::Bind(&Watch::OnFileReady, base::Unretained(this),
72                      DBUS_WATCH_READABLE));
73     }
74     if (flags & DBUS_WATCH_WRITABLE) {
75       write_watcher_ = base::FileDescriptorWatcher::WatchWritable(
76           file_descriptor,
77           base::Bind(&Watch::OnFileReady, base::Unretained(this),
78                      DBUS_WATCH_WRITABLE));
79     }
80   }
81 
82   // Stops watching the underlying file descriptor.
StopWatching()83   void StopWatching() {
84     read_watcher_.reset();
85     write_watcher_.reset();
86   }
87 
88  private:
OnFileReady(unsigned int flags)89   void OnFileReady(unsigned int flags) {
90     CHECK(dbus_watch_handle(raw_watch_, flags)) << "Unable to allocate memory";
91   }
92 
93   DBusWatch* raw_watch_;
94   std::unique_ptr<base::FileDescriptorWatcher::Controller> read_watcher_;
95   std::unique_ptr<base::FileDescriptorWatcher::Controller> write_watcher_;
96 
97   DISALLOW_COPY_AND_ASSIGN(Watch);
98 };
99 
100 // The class is used for monitoring the timeout used for D-Bus method
101 // calls.
102 class Timeout {
103  public:
Timeout(DBusTimeout * timeout)104   explicit Timeout(DBusTimeout* timeout)
105       : raw_timeout_(timeout), weak_ptr_factory_(this) {
106     // Associated |this| with the underlying DBusTimeout.
107     dbus_timeout_set_data(raw_timeout_, this, nullptr);
108   }
109 
~Timeout()110   ~Timeout() {
111     // Remove the association between |this| and the |raw_timeout_|.
112     dbus_timeout_set_data(raw_timeout_, nullptr, nullptr);
113   }
114 
115   // Returns true if the timeout is ready to be monitored.
IsReadyToBeMonitored()116   bool IsReadyToBeMonitored() {
117     return dbus_timeout_get_enabled(raw_timeout_);
118   }
119 
120   // Starts monitoring the timeout.
StartMonitoring(Bus * bus)121   void StartMonitoring(Bus* bus) {
122     bus->GetDBusTaskRunner()->PostDelayedTask(
123         FROM_HERE,
124         base::Bind(&Timeout::HandleTimeout, weak_ptr_factory_.GetWeakPtr()),
125         GetInterval());
126   }
127 
128   // Stops monitoring the timeout.
StopMonitoring()129   void StopMonitoring() { weak_ptr_factory_.InvalidateWeakPtrs(); }
130 
GetInterval()131   base::TimeDelta GetInterval() {
132     return base::TimeDelta::FromMilliseconds(
133         dbus_timeout_get_interval(raw_timeout_));
134   }
135 
136  private:
137   // Calls DBus to handle the timeout.
HandleTimeout()138   void HandleTimeout() { CHECK(dbus_timeout_handle(raw_timeout_)); }
139 
140   DBusTimeout* raw_timeout_;
141 
142   base::WeakPtrFactory<Timeout> weak_ptr_factory_;
143 
144   DISALLOW_COPY_AND_ASSIGN(Timeout);
145 };
146 
147 }  // namespace
148 
Options()149 Bus::Options::Options()
150   : bus_type(SESSION),
151     connection_type(PRIVATE) {
152 }
153 
154 Bus::Options::~Options() = default;
155 
Bus(const Options & options)156 Bus::Bus(const Options& options)
157     : bus_type_(options.bus_type),
158       connection_type_(options.connection_type),
159       dbus_task_runner_(options.dbus_task_runner),
160       on_shutdown_(base::WaitableEvent::ResetPolicy::AUTOMATIC,
161                    base::WaitableEvent::InitialState::NOT_SIGNALED),
162       connection_(nullptr),
163       origin_thread_id_(base::PlatformThread::CurrentId()),
164       async_operations_set_up_(false),
165       shutdown_completed_(false),
166       num_pending_watches_(0),
167       num_pending_timeouts_(0),
168       address_(options.address) {
169   // This is safe to call multiple times.
170   dbus_threads_init_default();
171   // The origin message loop is unnecessary if the client uses synchronous
172   // functions only.
173   if (base::ThreadTaskRunnerHandle::IsSet())
174     origin_task_runner_ = base::ThreadTaskRunnerHandle::Get();
175 }
176 
~Bus()177 Bus::~Bus() {
178   DCHECK(!connection_);
179   DCHECK(owned_service_names_.empty());
180   DCHECK(match_rules_added_.empty());
181   DCHECK(filter_functions_added_.empty());
182   DCHECK(registered_object_paths_.empty());
183   DCHECK_EQ(0, num_pending_watches_);
184   // TODO(satorux): This check fails occasionally in browser_tests for tests
185   // that run very quickly. Perhaps something does not have time to clean up.
186   // Despite the check failing, the tests seem to run fine. crosbug.com/23416
187   // DCHECK_EQ(0, num_pending_timeouts_);
188 }
189 
GetObjectProxy(const std::string & service_name,const ObjectPath & object_path)190 ObjectProxy* Bus::GetObjectProxy(const std::string& service_name,
191                                  const ObjectPath& object_path) {
192   return GetObjectProxyWithOptions(service_name, object_path,
193                                    ObjectProxy::DEFAULT_OPTIONS);
194 }
195 
GetObjectProxyWithOptions(const std::string & service_name,const ObjectPath & object_path,int options)196 ObjectProxy* Bus::GetObjectProxyWithOptions(const std::string& service_name,
197                                             const ObjectPath& object_path,
198                                             int options) {
199   AssertOnOriginThread();
200 
201   // Check if we already have the requested object proxy.
202   const ObjectProxyTable::key_type key(service_name + object_path.value(),
203                                        options);
204   ObjectProxyTable::iterator iter = object_proxy_table_.find(key);
205   if (iter != object_proxy_table_.end()) {
206     return iter->second.get();
207   }
208 
209   scoped_refptr<ObjectProxy> object_proxy =
210       new ObjectProxy(this, service_name, object_path, options);
211   object_proxy_table_[key] = object_proxy;
212 
213   return object_proxy.get();
214 }
215 
RemoveObjectProxy(const std::string & service_name,const ObjectPath & object_path,const base::Closure & callback)216 bool Bus::RemoveObjectProxy(const std::string& service_name,
217                             const ObjectPath& object_path,
218                             const base::Closure& callback) {
219   return RemoveObjectProxyWithOptions(service_name, object_path,
220                                       ObjectProxy::DEFAULT_OPTIONS,
221                                       callback);
222 }
223 
RemoveObjectProxyWithOptions(const std::string & service_name,const ObjectPath & object_path,int options,const base::Closure & callback)224 bool Bus::RemoveObjectProxyWithOptions(const std::string& service_name,
225                                        const ObjectPath& object_path,
226                                        int options,
227                                        const base::Closure& callback) {
228   AssertOnOriginThread();
229 
230   // Check if we have the requested object proxy.
231   const ObjectProxyTable::key_type key(service_name + object_path.value(),
232                                        options);
233   ObjectProxyTable::iterator iter = object_proxy_table_.find(key);
234   if (iter != object_proxy_table_.end()) {
235     scoped_refptr<ObjectProxy> object_proxy = iter->second;
236     object_proxy_table_.erase(iter);
237     // Object is present. Remove it now and Detach on the DBus thread.
238     GetDBusTaskRunner()->PostTask(
239         FROM_HERE,
240         base::Bind(&Bus::RemoveObjectProxyInternal,
241                    this, object_proxy, callback));
242     return true;
243   }
244   return false;
245 }
246 
RemoveObjectProxyInternal(scoped_refptr<ObjectProxy> object_proxy,const base::Closure & callback)247 void Bus::RemoveObjectProxyInternal(scoped_refptr<ObjectProxy> object_proxy,
248                                     const base::Closure& callback) {
249   AssertOnDBusThread();
250 
251   object_proxy->Detach();
252 
253   GetOriginTaskRunner()->PostTask(FROM_HERE, callback);
254 }
255 
GetExportedObject(const ObjectPath & object_path)256 ExportedObject* Bus::GetExportedObject(const ObjectPath& object_path) {
257   AssertOnOriginThread();
258 
259   // Check if we already have the requested exported object.
260   ExportedObjectTable::iterator iter = exported_object_table_.find(object_path);
261   if (iter != exported_object_table_.end()) {
262     return iter->second.get();
263   }
264 
265   scoped_refptr<ExportedObject> exported_object =
266       new ExportedObject(this, object_path);
267   exported_object_table_[object_path] = exported_object;
268 
269   return exported_object.get();
270 }
271 
UnregisterExportedObject(const ObjectPath & object_path)272 void Bus::UnregisterExportedObject(const ObjectPath& object_path) {
273   AssertOnOriginThread();
274 
275   // Remove the registered object from the table first, to allow a new
276   // GetExportedObject() call to return a new object, rather than this one.
277   ExportedObjectTable::iterator iter = exported_object_table_.find(object_path);
278   if (iter == exported_object_table_.end())
279     return;
280 
281   scoped_refptr<ExportedObject> exported_object = iter->second;
282   exported_object_table_.erase(iter);
283 
284   // Post the task to perform the final unregistration to the D-Bus thread.
285   // Since the registration also happens on the D-Bus thread in
286   // TryRegisterObjectPath(), and the task runner we post to is a
287   // SequencedTaskRunner, there is a guarantee that this will happen before any
288   // future registration call.
289   GetDBusTaskRunner()->PostTask(
290       FROM_HERE,
291       base::Bind(&Bus::UnregisterExportedObjectInternal,
292                  this, exported_object));
293 }
294 
UnregisterExportedObjectInternal(scoped_refptr<ExportedObject> exported_object)295 void Bus::UnregisterExportedObjectInternal(
296     scoped_refptr<ExportedObject> exported_object) {
297   AssertOnDBusThread();
298 
299   exported_object->Unregister();
300 }
301 
GetObjectManager(const std::string & service_name,const ObjectPath & object_path)302 ObjectManager* Bus::GetObjectManager(const std::string& service_name,
303                                      const ObjectPath& object_path) {
304   AssertOnOriginThread();
305 
306   // Check if we already have the requested object manager.
307   const ObjectManagerTable::key_type key(service_name + object_path.value());
308   ObjectManagerTable::iterator iter = object_manager_table_.find(key);
309   if (iter != object_manager_table_.end()) {
310     return iter->second.get();
311   }
312 
313   scoped_refptr<ObjectManager> object_manager =
314       new ObjectManager(this, service_name, object_path);
315   object_manager_table_[key] = object_manager;
316 
317   return object_manager.get();
318 }
319 
RemoveObjectManager(const std::string & service_name,const ObjectPath & object_path,const base::Closure & callback)320 bool Bus::RemoveObjectManager(const std::string& service_name,
321                               const ObjectPath& object_path,
322                               const base::Closure& callback) {
323   AssertOnOriginThread();
324   DCHECK(!callback.is_null());
325 
326   const ObjectManagerTable::key_type key(service_name + object_path.value());
327   ObjectManagerTable::iterator iter = object_manager_table_.find(key);
328   if (iter == object_manager_table_.end())
329     return false;
330 
331   // ObjectManager is present. Remove it now and CleanUp on the DBus thread.
332   scoped_refptr<ObjectManager> object_manager = iter->second;
333   object_manager_table_.erase(iter);
334 
335   GetDBusTaskRunner()->PostTask(
336       FROM_HERE,
337       base::Bind(&Bus::RemoveObjectManagerInternal,
338                  this, object_manager, callback));
339 
340   return true;
341 }
342 
RemoveObjectManagerInternal(scoped_refptr<dbus::ObjectManager> object_manager,const base::Closure & callback)343 void Bus::RemoveObjectManagerInternal(
344       scoped_refptr<dbus::ObjectManager> object_manager,
345       const base::Closure& callback) {
346   AssertOnDBusThread();
347   DCHECK(object_manager.get());
348 
349   object_manager->CleanUp();
350 
351   // The ObjectManager has to be deleted on the origin thread since it was
352   // created there.
353   GetOriginTaskRunner()->PostTask(
354       FROM_HERE,
355       base::Bind(&Bus::RemoveObjectManagerInternalHelper,
356                  this, object_manager, callback));
357 }
358 
RemoveObjectManagerInternalHelper(scoped_refptr<dbus::ObjectManager> object_manager,const base::Closure & callback)359 void Bus::RemoveObjectManagerInternalHelper(
360       scoped_refptr<dbus::ObjectManager> object_manager,
361       const base::Closure& callback) {
362   AssertOnOriginThread();
363   DCHECK(object_manager);
364 
365   // Release the object manager and run the callback.
366   object_manager = nullptr;
367   callback.Run();
368 }
369 
Connect()370 bool Bus::Connect() {
371   // dbus_bus_get_private() and dbus_bus_get() are blocking calls.
372   AssertOnDBusThread();
373 
374   // Check if it's already initialized.
375   if (connection_)
376     return true;
377 
378   ScopedDBusError error;
379   if (bus_type_ == CUSTOM_ADDRESS) {
380     if (connection_type_ == PRIVATE) {
381       connection_ = dbus_connection_open_private(address_.c_str(), error.get());
382     } else {
383       connection_ = dbus_connection_open(address_.c_str(), error.get());
384     }
385   } else {
386     const DBusBusType dbus_bus_type = static_cast<DBusBusType>(bus_type_);
387     if (connection_type_ == PRIVATE) {
388       connection_ = dbus_bus_get_private(dbus_bus_type, error.get());
389     } else {
390       connection_ = dbus_bus_get(dbus_bus_type, error.get());
391     }
392   }
393   if (!connection_) {
394     LOG(ERROR) << "Failed to connect to the bus: "
395                << (error.is_set() ? error.message() : "");
396     return false;
397   }
398 
399   if (bus_type_ == CUSTOM_ADDRESS) {
400     // We should call dbus_bus_register here, otherwise unique name can not be
401     // acquired. According to dbus specification, it is responsible to call
402     // org.freedesktop.DBus.Hello method at the beging of bus connection to
403     // acquire unique name. In the case of dbus_bus_get, dbus_bus_register is
404     // called internally.
405     if (!dbus_bus_register(connection_, error.get())) {
406       LOG(ERROR) << "Failed to register the bus component: "
407                  << (error.is_set() ? error.message() : "");
408       return false;
409     }
410   }
411   // We shouldn't exit on the disconnected signal.
412   dbus_connection_set_exit_on_disconnect(connection_, false);
413 
414   // Watch Disconnected signal.
415   AddFilterFunction(Bus::OnConnectionDisconnectedFilter, this);
416   AddMatch(kDisconnectedMatchRule, error.get());
417 
418   return true;
419 }
420 
ClosePrivateConnection()421 void Bus::ClosePrivateConnection() {
422   // dbus_connection_close is blocking call.
423   AssertOnDBusThread();
424   DCHECK_EQ(PRIVATE, connection_type_)
425       << "non-private connection should not be closed";
426   dbus_connection_close(connection_);
427 }
428 
ShutdownAndBlock()429 void Bus::ShutdownAndBlock() {
430   AssertOnDBusThread();
431 
432   if (shutdown_completed_)
433     return;  // Already shutdowned, just return.
434 
435   // Unregister the exported objects.
436   for (ExportedObjectTable::iterator iter = exported_object_table_.begin();
437        iter != exported_object_table_.end(); ++iter) {
438     iter->second->Unregister();
439   }
440 
441   // Release all service names.
442   for (std::set<std::string>::iterator iter = owned_service_names_.begin();
443        iter != owned_service_names_.end();) {
444     // This is a bit tricky but we should increment the iter here as
445     // ReleaseOwnership() may remove |service_name| from the set.
446     const std::string& service_name = *iter++;
447     ReleaseOwnership(service_name);
448   }
449   if (!owned_service_names_.empty()) {
450     LOG(ERROR) << "Failed to release all service names. # of services left: "
451                << owned_service_names_.size();
452   }
453 
454   // Detach from the remote objects.
455   for (ObjectProxyTable::iterator iter = object_proxy_table_.begin();
456        iter != object_proxy_table_.end(); ++iter) {
457     iter->second->Detach();
458   }
459 
460   // Clean up the object managers.
461   for (ObjectManagerTable::iterator iter = object_manager_table_.begin();
462        iter != object_manager_table_.end(); ++iter) {
463     iter->second->CleanUp();
464   }
465 
466   // Release object proxies and exported objects here. We should do this
467   // here rather than in the destructor to avoid memory leaks due to
468   // cyclic references.
469   object_proxy_table_.clear();
470   exported_object_table_.clear();
471 
472   // Private connection should be closed.
473   if (connection_) {
474     // Remove Disconnected watcher.
475     ScopedDBusError error;
476     RemoveFilterFunction(Bus::OnConnectionDisconnectedFilter, this);
477     RemoveMatch(kDisconnectedMatchRule, error.get());
478 
479     if (connection_type_ == PRIVATE)
480       ClosePrivateConnection();
481     // dbus_connection_close() won't unref.
482     dbus_connection_unref(connection_);
483   }
484 
485   connection_ = nullptr;
486   shutdown_completed_ = true;
487 }
488 
ShutdownOnDBusThreadAndBlock()489 void Bus::ShutdownOnDBusThreadAndBlock() {
490   AssertOnOriginThread();
491   DCHECK(dbus_task_runner_);
492 
493   GetDBusTaskRunner()->PostTask(
494       FROM_HERE,
495       base::Bind(&Bus::ShutdownOnDBusThreadAndBlockInternal, this));
496 
497   // http://crbug.com/125222
498   base::ThreadRestrictions::ScopedAllowWait allow_wait;
499 
500   // Wait until the shutdown is complete on the D-Bus thread.
501   // The shutdown should not hang, but set timeout just in case.
502   const int kTimeoutSecs = 3;
503   const base::TimeDelta timeout(base::TimeDelta::FromSeconds(kTimeoutSecs));
504   const bool signaled = on_shutdown_.TimedWait(timeout);
505   LOG_IF(ERROR, !signaled) << "Failed to shutdown the bus";
506 }
507 
RequestOwnership(const std::string & service_name,ServiceOwnershipOptions options,OnOwnershipCallback on_ownership_callback)508 void Bus::RequestOwnership(const std::string& service_name,
509                            ServiceOwnershipOptions options,
510                            OnOwnershipCallback on_ownership_callback) {
511   AssertOnOriginThread();
512 
513   GetDBusTaskRunner()->PostTask(
514       FROM_HERE,
515       base::Bind(&Bus::RequestOwnershipInternal,
516                  this, service_name, options, on_ownership_callback));
517 }
518 
RequestOwnershipInternal(const std::string & service_name,ServiceOwnershipOptions options,OnOwnershipCallback on_ownership_callback)519 void Bus::RequestOwnershipInternal(const std::string& service_name,
520                                    ServiceOwnershipOptions options,
521                                    OnOwnershipCallback on_ownership_callback) {
522   AssertOnDBusThread();
523 
524   bool success = Connect();
525   if (success)
526     success = RequestOwnershipAndBlock(service_name, options);
527 
528   GetOriginTaskRunner()->PostTask(FROM_HERE,
529                                   base::Bind(on_ownership_callback,
530                                              service_name,
531                                              success));
532 }
533 
RequestOwnershipAndBlock(const std::string & service_name,ServiceOwnershipOptions options)534 bool Bus::RequestOwnershipAndBlock(const std::string& service_name,
535                                    ServiceOwnershipOptions options) {
536   DCHECK(connection_);
537   // dbus_bus_request_name() is a blocking call.
538   AssertOnDBusThread();
539 
540   // Check if we already own the service name.
541   if (owned_service_names_.find(service_name) != owned_service_names_.end()) {
542     return true;
543   }
544 
545   ScopedDBusError error;
546   const int result = dbus_bus_request_name(connection_,
547                                            service_name.c_str(),
548                                            options,
549                                            error.get());
550   if (result != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {
551     LOG(ERROR) << "Failed to get the ownership of " << service_name << ": "
552                << (error.is_set() ? error.message() : "");
553     return false;
554   }
555   owned_service_names_.insert(service_name);
556   return true;
557 }
558 
ReleaseOwnership(const std::string & service_name)559 bool Bus::ReleaseOwnership(const std::string& service_name) {
560   DCHECK(connection_);
561   // dbus_bus_request_name() is a blocking call.
562   AssertOnDBusThread();
563 
564   // Check if we already own the service name.
565   std::set<std::string>::iterator found =
566       owned_service_names_.find(service_name);
567   if (found == owned_service_names_.end()) {
568     LOG(ERROR) << service_name << " is not owned by the bus";
569     return false;
570   }
571 
572   ScopedDBusError error;
573   const int result = dbus_bus_release_name(connection_, service_name.c_str(),
574                                            error.get());
575   if (result == DBUS_RELEASE_NAME_REPLY_RELEASED) {
576     owned_service_names_.erase(found);
577     return true;
578   } else {
579     LOG(ERROR) << "Failed to release the ownership of " << service_name << ": "
580                << (error.is_set() ? error.message() : "")
581                << ", result code: " << result;
582     return false;
583   }
584 }
585 
SetUpAsyncOperations()586 bool Bus::SetUpAsyncOperations() {
587   DCHECK(connection_);
588   AssertOnDBusThread();
589 
590   if (async_operations_set_up_)
591     return true;
592 
593   // Process all the incoming data if any, so that OnDispatchStatus() will
594   // be called when the incoming data is ready.
595   ProcessAllIncomingDataIfAny();
596 
597   bool success = dbus_connection_set_watch_functions(
598       connection_, &Bus::OnAddWatchThunk, &Bus::OnRemoveWatchThunk,
599       &Bus::OnToggleWatchThunk, this, nullptr);
600   CHECK(success) << "Unable to allocate memory";
601 
602   success = dbus_connection_set_timeout_functions(
603       connection_, &Bus::OnAddTimeoutThunk, &Bus::OnRemoveTimeoutThunk,
604       &Bus::OnToggleTimeoutThunk, this, nullptr);
605   CHECK(success) << "Unable to allocate memory";
606 
607   dbus_connection_set_dispatch_status_function(
608       connection_, &Bus::OnDispatchStatusChangedThunk, this, nullptr);
609 
610   async_operations_set_up_ = true;
611 
612   return true;
613 }
614 
SendWithReplyAndBlock(DBusMessage * request,int timeout_ms,DBusError * error)615 DBusMessage* Bus::SendWithReplyAndBlock(DBusMessage* request,
616                                         int timeout_ms,
617                                         DBusError* error) {
618   DCHECK(connection_);
619   AssertOnDBusThread();
620 
621   return dbus_connection_send_with_reply_and_block(
622       connection_, request, timeout_ms, error);
623 }
624 
SendWithReply(DBusMessage * request,DBusPendingCall ** pending_call,int timeout_ms)625 void Bus::SendWithReply(DBusMessage* request,
626                         DBusPendingCall** pending_call,
627                         int timeout_ms) {
628   DCHECK(connection_);
629   AssertOnDBusThread();
630 
631   const bool success = dbus_connection_send_with_reply(
632       connection_, request, pending_call, timeout_ms);
633   CHECK(success) << "Unable to allocate memory";
634 }
635 
Send(DBusMessage * request,uint32_t * serial)636 void Bus::Send(DBusMessage* request, uint32_t* serial) {
637   DCHECK(connection_);
638   AssertOnDBusThread();
639 
640   const bool success = dbus_connection_send(connection_, request, serial);
641   CHECK(success) << "Unable to allocate memory";
642 }
643 
AddFilterFunction(DBusHandleMessageFunction filter_function,void * user_data)644 void Bus::AddFilterFunction(DBusHandleMessageFunction filter_function,
645                             void* user_data) {
646   DCHECK(connection_);
647   AssertOnDBusThread();
648 
649   std::pair<DBusHandleMessageFunction, void*> filter_data_pair =
650       std::make_pair(filter_function, user_data);
651   if (filter_functions_added_.find(filter_data_pair) !=
652       filter_functions_added_.end()) {
653     VLOG(1) << "Filter function already exists: " << filter_function
654             << " with associated data: " << user_data;
655     return;
656   }
657 
658   const bool success = dbus_connection_add_filter(connection_, filter_function,
659                                                   user_data, nullptr);
660   CHECK(success) << "Unable to allocate memory";
661   filter_functions_added_.insert(filter_data_pair);
662 }
663 
RemoveFilterFunction(DBusHandleMessageFunction filter_function,void * user_data)664 void Bus::RemoveFilterFunction(DBusHandleMessageFunction filter_function,
665                                void* user_data) {
666   DCHECK(connection_);
667   AssertOnDBusThread();
668 
669   std::pair<DBusHandleMessageFunction, void*> filter_data_pair =
670       std::make_pair(filter_function, user_data);
671   if (filter_functions_added_.find(filter_data_pair) ==
672       filter_functions_added_.end()) {
673     VLOG(1) << "Requested to remove an unknown filter function: "
674             << filter_function
675             << " with associated data: " << user_data;
676     return;
677   }
678 
679   dbus_connection_remove_filter(connection_, filter_function, user_data);
680   filter_functions_added_.erase(filter_data_pair);
681 }
682 
AddMatch(const std::string & match_rule,DBusError * error)683 void Bus::AddMatch(const std::string& match_rule, DBusError* error) {
684   DCHECK(connection_);
685   AssertOnDBusThread();
686 
687   std::map<std::string, int>::iterator iter =
688       match_rules_added_.find(match_rule);
689   if (iter != match_rules_added_.end()) {
690     // The already existing rule's counter is incremented.
691     iter->second++;
692 
693     VLOG(1) << "Match rule already exists: " << match_rule;
694     return;
695   }
696 
697   dbus_bus_add_match(connection_, match_rule.c_str(), error);
698   match_rules_added_[match_rule] = 1;
699 }
700 
RemoveMatch(const std::string & match_rule,DBusError * error)701 bool Bus::RemoveMatch(const std::string& match_rule, DBusError* error) {
702   DCHECK(connection_);
703   AssertOnDBusThread();
704 
705   std::map<std::string, int>::iterator iter =
706       match_rules_added_.find(match_rule);
707   if (iter == match_rules_added_.end()) {
708     LOG(ERROR) << "Requested to remove an unknown match rule: " << match_rule;
709     return false;
710   }
711 
712   // The rule's counter is decremented and the rule is deleted when reachs 0.
713   iter->second--;
714   if (iter->second == 0) {
715     dbus_bus_remove_match(connection_, match_rule.c_str(), error);
716     match_rules_added_.erase(match_rule);
717   }
718   return true;
719 }
720 
TryRegisterObjectPath(const ObjectPath & object_path,const DBusObjectPathVTable * vtable,void * user_data,DBusError * error)721 bool Bus::TryRegisterObjectPath(const ObjectPath& object_path,
722                                 const DBusObjectPathVTable* vtable,
723                                 void* user_data,
724                                 DBusError* error) {
725   DCHECK(connection_);
726   AssertOnDBusThread();
727 
728   if (registered_object_paths_.find(object_path) !=
729       registered_object_paths_.end()) {
730     LOG(ERROR) << "Object path already registered: " << object_path.value();
731     return false;
732   }
733 
734   const bool success = dbus_connection_try_register_object_path(
735       connection_,
736       object_path.value().c_str(),
737       vtable,
738       user_data,
739       error);
740   if (success)
741     registered_object_paths_.insert(object_path);
742   return success;
743 }
744 
UnregisterObjectPath(const ObjectPath & object_path)745 void Bus::UnregisterObjectPath(const ObjectPath& object_path) {
746   DCHECK(connection_);
747   AssertOnDBusThread();
748 
749   if (registered_object_paths_.find(object_path) ==
750       registered_object_paths_.end()) {
751     LOG(ERROR) << "Requested to unregister an unknown object path: "
752                << object_path.value();
753     return;
754   }
755 
756   const bool success = dbus_connection_unregister_object_path(
757       connection_,
758       object_path.value().c_str());
759   CHECK(success) << "Unable to allocate memory";
760   registered_object_paths_.erase(object_path);
761 }
762 
ShutdownOnDBusThreadAndBlockInternal()763 void Bus::ShutdownOnDBusThreadAndBlockInternal() {
764   AssertOnDBusThread();
765 
766   ShutdownAndBlock();
767   on_shutdown_.Signal();
768 }
769 
ProcessAllIncomingDataIfAny()770 void Bus::ProcessAllIncomingDataIfAny() {
771   AssertOnDBusThread();
772 
773   // As mentioned at the class comment in .h file, connection_ can be NULL.
774   if (!connection_)
775     return;
776 
777   // It is safe and necessary to call dbus_connection_get_dispatch_status even
778   // if the connection is lost.
779   if (dbus_connection_get_dispatch_status(connection_) ==
780       DBUS_DISPATCH_DATA_REMAINS) {
781     while (dbus_connection_dispatch(connection_) ==
782            DBUS_DISPATCH_DATA_REMAINS) {
783     }
784   }
785 }
786 
GetDBusTaskRunner()787 base::TaskRunner* Bus::GetDBusTaskRunner() {
788   if (dbus_task_runner_)
789     return dbus_task_runner_.get();
790   else
791     return GetOriginTaskRunner();
792 }
793 
GetOriginTaskRunner()794 base::TaskRunner* Bus::GetOriginTaskRunner() {
795   DCHECK(origin_task_runner_);
796   return origin_task_runner_.get();
797 }
798 
HasDBusThread()799 bool Bus::HasDBusThread() {
800   return dbus_task_runner_ != nullptr;
801 }
802 
AssertOnOriginThread()803 void Bus::AssertOnOriginThread() {
804   DCHECK_EQ(origin_thread_id_, base::PlatformThread::CurrentId());
805 }
806 
AssertOnDBusThread()807 void Bus::AssertOnDBusThread() {
808   base::AssertBlockingAllowed();
809 
810   if (dbus_task_runner_) {
811     DCHECK(dbus_task_runner_->RunsTasksInCurrentSequence());
812   } else {
813     AssertOnOriginThread();
814   }
815 }
816 
GetServiceOwnerAndBlock(const std::string & service_name,GetServiceOwnerOption options)817 std::string Bus::GetServiceOwnerAndBlock(const std::string& service_name,
818                                          GetServiceOwnerOption options) {
819   AssertOnDBusThread();
820 
821   MethodCall get_name_owner_call("org.freedesktop.DBus", "GetNameOwner");
822   MessageWriter writer(&get_name_owner_call);
823   writer.AppendString(service_name);
824   VLOG(1) << "Method call: " << get_name_owner_call.ToString();
825 
826   const ObjectPath obj_path("/org/freedesktop/DBus");
827   if (!get_name_owner_call.SetDestination("org.freedesktop.DBus") ||
828       !get_name_owner_call.SetPath(obj_path)) {
829     if (options == REPORT_ERRORS)
830       LOG(ERROR) << "Failed to get name owner.";
831     return "";
832   }
833 
834   ScopedDBusError error;
835   DBusMessage* response_message =
836       SendWithReplyAndBlock(get_name_owner_call.raw_message(),
837                             ObjectProxy::TIMEOUT_USE_DEFAULT,
838                             error.get());
839   if (!response_message) {
840     if (options == REPORT_ERRORS) {
841       LOG(ERROR) << "Failed to get name owner. Got " << error.name() << ": "
842                  << error.message();
843     }
844     return "";
845   }
846 
847   std::unique_ptr<Response> response(
848       Response::FromRawMessage(response_message));
849   MessageReader reader(response.get());
850 
851   std::string service_owner;
852   if (!reader.PopString(&service_owner))
853     service_owner.clear();
854   return service_owner;
855 }
856 
GetServiceOwner(const std::string & service_name,const GetServiceOwnerCallback & callback)857 void Bus::GetServiceOwner(const std::string& service_name,
858                           const GetServiceOwnerCallback& callback) {
859   AssertOnOriginThread();
860 
861   GetDBusTaskRunner()->PostTask(
862       FROM_HERE,
863       base::Bind(&Bus::GetServiceOwnerInternal, this, service_name, callback));
864 }
865 
GetServiceOwnerInternal(const std::string & service_name,const GetServiceOwnerCallback & callback)866 void Bus::GetServiceOwnerInternal(const std::string& service_name,
867                                   const GetServiceOwnerCallback& callback) {
868   AssertOnDBusThread();
869 
870   std::string service_owner;
871   if (Connect())
872     service_owner = GetServiceOwnerAndBlock(service_name, SUPPRESS_ERRORS);
873   GetOriginTaskRunner()->PostTask(FROM_HERE,
874                                   base::Bind(callback, service_owner));
875 }
876 
ListenForServiceOwnerChange(const std::string & service_name,const GetServiceOwnerCallback & callback)877 void Bus::ListenForServiceOwnerChange(
878     const std::string& service_name,
879     const GetServiceOwnerCallback& callback) {
880   AssertOnOriginThread();
881   DCHECK(!service_name.empty());
882   DCHECK(!callback.is_null());
883 
884   GetDBusTaskRunner()->PostTask(
885       FROM_HERE,
886       base::Bind(&Bus::ListenForServiceOwnerChangeInternal,
887                  this, service_name, callback));
888 }
889 
ListenForServiceOwnerChangeInternal(const std::string & service_name,const GetServiceOwnerCallback & callback)890 void Bus::ListenForServiceOwnerChangeInternal(
891     const std::string& service_name,
892     const GetServiceOwnerCallback& callback) {
893   AssertOnDBusThread();
894   DCHECK(!service_name.empty());
895   DCHECK(!callback.is_null());
896 
897   if (!Connect() || !SetUpAsyncOperations())
898     return;
899 
900   if (service_owner_changed_listener_map_.empty())
901     AddFilterFunction(Bus::OnServiceOwnerChangedFilter, this);
902 
903   ServiceOwnerChangedListenerMap::iterator it =
904       service_owner_changed_listener_map_.find(service_name);
905   if (it == service_owner_changed_listener_map_.end()) {
906     // Add a match rule for the new service name.
907     const std::string name_owner_changed_match_rule =
908         base::StringPrintf(kServiceNameOwnerChangeMatchRule,
909                            service_name.c_str());
910     ScopedDBusError error;
911     AddMatch(name_owner_changed_match_rule, error.get());
912     if (error.is_set()) {
913       LOG(ERROR) << "Failed to add match rule for " << service_name
914                  << ". Got " << error.name() << ": " << error.message();
915       return;
916     }
917 
918     service_owner_changed_listener_map_[service_name].push_back(callback);
919     return;
920   }
921 
922   // Check if the callback has already been added.
923   std::vector<GetServiceOwnerCallback>& callbacks = it->second;
924   for (size_t i = 0; i < callbacks.size(); ++i) {
925     if (callbacks[i].Equals(callback))
926       return;
927   }
928   callbacks.push_back(callback);
929 }
930 
UnlistenForServiceOwnerChange(const std::string & service_name,const GetServiceOwnerCallback & callback)931 void Bus::UnlistenForServiceOwnerChange(
932     const std::string& service_name,
933     const GetServiceOwnerCallback& callback) {
934   AssertOnOriginThread();
935   DCHECK(!service_name.empty());
936   DCHECK(!callback.is_null());
937 
938   GetDBusTaskRunner()->PostTask(
939       FROM_HERE,
940       base::Bind(&Bus::UnlistenForServiceOwnerChangeInternal,
941                  this, service_name, callback));
942 }
943 
UnlistenForServiceOwnerChangeInternal(const std::string & service_name,const GetServiceOwnerCallback & callback)944 void Bus::UnlistenForServiceOwnerChangeInternal(
945     const std::string& service_name,
946     const GetServiceOwnerCallback& callback) {
947   AssertOnDBusThread();
948   DCHECK(!service_name.empty());
949   DCHECK(!callback.is_null());
950 
951   ServiceOwnerChangedListenerMap::iterator it =
952       service_owner_changed_listener_map_.find(service_name);
953   if (it == service_owner_changed_listener_map_.end())
954     return;
955 
956   std::vector<GetServiceOwnerCallback>& callbacks = it->second;
957   for (size_t i = 0; i < callbacks.size(); ++i) {
958     if (callbacks[i].Equals(callback)) {
959       callbacks.erase(callbacks.begin() + i);
960       break;  // There can be only one.
961     }
962   }
963   if (!callbacks.empty())
964     return;
965 
966   // Last callback for |service_name| has been removed, remove match rule.
967   const std::string name_owner_changed_match_rule =
968       base::StringPrintf(kServiceNameOwnerChangeMatchRule,
969                          service_name.c_str());
970   ScopedDBusError error;
971   RemoveMatch(name_owner_changed_match_rule, error.get());
972   // And remove |service_owner_changed_listener_map_| entry.
973   service_owner_changed_listener_map_.erase(it);
974 
975   if (service_owner_changed_listener_map_.empty())
976     RemoveFilterFunction(Bus::OnServiceOwnerChangedFilter, this);
977 }
978 
GetConnectionName()979 std::string Bus::GetConnectionName() {
980   if (!connection_)
981     return "";
982   return dbus_bus_get_unique_name(connection_);
983 }
984 
OnAddWatch(DBusWatch * raw_watch)985 dbus_bool_t Bus::OnAddWatch(DBusWatch* raw_watch) {
986   AssertOnDBusThread();
987 
988   // watch will be deleted when raw_watch is removed in OnRemoveWatch().
989   Watch* watch = new Watch(raw_watch);
990   if (watch->IsReadyToBeWatched()) {
991     watch->StartWatching();
992   }
993   ++num_pending_watches_;
994   return true;
995 }
996 
OnRemoveWatch(DBusWatch * raw_watch)997 void Bus::OnRemoveWatch(DBusWatch* raw_watch) {
998   AssertOnDBusThread();
999 
1000   Watch* watch = static_cast<Watch*>(dbus_watch_get_data(raw_watch));
1001   delete watch;
1002   --num_pending_watches_;
1003 }
1004 
OnToggleWatch(DBusWatch * raw_watch)1005 void Bus::OnToggleWatch(DBusWatch* raw_watch) {
1006   AssertOnDBusThread();
1007 
1008   Watch* watch = static_cast<Watch*>(dbus_watch_get_data(raw_watch));
1009   if (watch->IsReadyToBeWatched())
1010     watch->StartWatching();
1011   else
1012     watch->StopWatching();
1013 }
1014 
OnAddTimeout(DBusTimeout * raw_timeout)1015 dbus_bool_t Bus::OnAddTimeout(DBusTimeout* raw_timeout) {
1016   AssertOnDBusThread();
1017 
1018   // |timeout| will be deleted by OnRemoveTimeoutThunk().
1019   Timeout* timeout = new Timeout(raw_timeout);
1020   if (timeout->IsReadyToBeMonitored()) {
1021     timeout->StartMonitoring(this);
1022   }
1023   ++num_pending_timeouts_;
1024   return true;
1025 }
1026 
OnRemoveTimeout(DBusTimeout * raw_timeout)1027 void Bus::OnRemoveTimeout(DBusTimeout* raw_timeout) {
1028   AssertOnDBusThread();
1029 
1030   Timeout* timeout = static_cast<Timeout*>(dbus_timeout_get_data(raw_timeout));
1031   delete timeout;
1032   --num_pending_timeouts_;
1033 }
1034 
OnToggleTimeout(DBusTimeout * raw_timeout)1035 void Bus::OnToggleTimeout(DBusTimeout* raw_timeout) {
1036   AssertOnDBusThread();
1037 
1038   Timeout* timeout = static_cast<Timeout*>(dbus_timeout_get_data(raw_timeout));
1039   if (timeout->IsReadyToBeMonitored()) {
1040     timeout->StartMonitoring(this);
1041   } else {
1042     timeout->StopMonitoring();
1043   }
1044 }
1045 
OnDispatchStatusChanged(DBusConnection * connection,DBusDispatchStatus status)1046 void Bus::OnDispatchStatusChanged(DBusConnection* connection,
1047                                   DBusDispatchStatus status) {
1048   DCHECK_EQ(connection, connection_);
1049   AssertOnDBusThread();
1050 
1051   // We cannot call ProcessAllIncomingDataIfAny() here, as calling
1052   // dbus_connection_dispatch() inside DBusDispatchStatusFunction is
1053   // prohibited by the D-Bus library. Hence, we post a task here instead.
1054   // See comments for dbus_connection_set_dispatch_status_function().
1055   GetDBusTaskRunner()->PostTask(FROM_HERE,
1056                                 base::Bind(&Bus::ProcessAllIncomingDataIfAny,
1057                                            this));
1058 }
1059 
OnServiceOwnerChanged(DBusMessage * message)1060 void Bus::OnServiceOwnerChanged(DBusMessage* message) {
1061   DCHECK(message);
1062   AssertOnDBusThread();
1063 
1064   // |message| will be unrefed on exit of the function. Increment the
1065   // reference so we can use it in Signal::FromRawMessage() below.
1066   dbus_message_ref(message);
1067   std::unique_ptr<Signal> signal(Signal::FromRawMessage(message));
1068 
1069   // Confirm the validity of the NameOwnerChanged signal.
1070   if (signal->GetMember() != kNameOwnerChangedSignal ||
1071       signal->GetInterface() != DBUS_INTERFACE_DBUS ||
1072       signal->GetSender() != DBUS_SERVICE_DBUS) {
1073     return;
1074   }
1075 
1076   MessageReader reader(signal.get());
1077   std::string service_name;
1078   std::string old_owner;
1079   std::string new_owner;
1080   if (!reader.PopString(&service_name) ||
1081       !reader.PopString(&old_owner) ||
1082       !reader.PopString(&new_owner)) {
1083     return;
1084   }
1085 
1086   ServiceOwnerChangedListenerMap::const_iterator it =
1087       service_owner_changed_listener_map_.find(service_name);
1088   if (it == service_owner_changed_listener_map_.end())
1089     return;
1090 
1091   const std::vector<GetServiceOwnerCallback>& callbacks = it->second;
1092   for (size_t i = 0; i < callbacks.size(); ++i) {
1093     GetOriginTaskRunner()->PostTask(FROM_HERE,
1094                                     base::Bind(callbacks[i], new_owner));
1095   }
1096 }
1097 
1098 // static
OnAddWatchThunk(DBusWatch * raw_watch,void * data)1099 dbus_bool_t Bus::OnAddWatchThunk(DBusWatch* raw_watch, void* data) {
1100   Bus* self = static_cast<Bus*>(data);
1101   return self->OnAddWatch(raw_watch);
1102 }
1103 
1104 // static
OnRemoveWatchThunk(DBusWatch * raw_watch,void * data)1105 void Bus::OnRemoveWatchThunk(DBusWatch* raw_watch, void* data) {
1106   Bus* self = static_cast<Bus*>(data);
1107   self->OnRemoveWatch(raw_watch);
1108 }
1109 
1110 // static
OnToggleWatchThunk(DBusWatch * raw_watch,void * data)1111 void Bus::OnToggleWatchThunk(DBusWatch* raw_watch, void* data) {
1112   Bus* self = static_cast<Bus*>(data);
1113   self->OnToggleWatch(raw_watch);
1114 }
1115 
1116 // static
OnAddTimeoutThunk(DBusTimeout * raw_timeout,void * data)1117 dbus_bool_t Bus::OnAddTimeoutThunk(DBusTimeout* raw_timeout, void* data) {
1118   Bus* self = static_cast<Bus*>(data);
1119   return self->OnAddTimeout(raw_timeout);
1120 }
1121 
1122 // static
OnRemoveTimeoutThunk(DBusTimeout * raw_timeout,void * data)1123 void Bus::OnRemoveTimeoutThunk(DBusTimeout* raw_timeout, void* data) {
1124   Bus* self = static_cast<Bus*>(data);
1125   self->OnRemoveTimeout(raw_timeout);
1126 }
1127 
1128 // static
OnToggleTimeoutThunk(DBusTimeout * raw_timeout,void * data)1129 void Bus::OnToggleTimeoutThunk(DBusTimeout* raw_timeout, void* data) {
1130   Bus* self = static_cast<Bus*>(data);
1131   self->OnToggleTimeout(raw_timeout);
1132 }
1133 
1134 // static
OnDispatchStatusChangedThunk(DBusConnection * connection,DBusDispatchStatus status,void * data)1135 void Bus::OnDispatchStatusChangedThunk(DBusConnection* connection,
1136                                        DBusDispatchStatus status,
1137                                        void* data) {
1138   Bus* self = static_cast<Bus*>(data);
1139   self->OnDispatchStatusChanged(connection, status);
1140 }
1141 
1142 // static
OnConnectionDisconnectedFilter(DBusConnection * connection,DBusMessage * message,void * data)1143 DBusHandlerResult Bus::OnConnectionDisconnectedFilter(
1144     DBusConnection* connection,
1145     DBusMessage* message,
1146     void* data) {
1147   if (dbus_message_is_signal(message,
1148                              DBUS_INTERFACE_LOCAL,
1149                              kDisconnectedSignal)) {
1150     // Abort when the connection is lost.
1151     LOG(FATAL) << "D-Bus connection was disconnected. Aborting.";
1152   }
1153   return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1154 }
1155 
1156 // static
OnServiceOwnerChangedFilter(DBusConnection * connection,DBusMessage * message,void * data)1157 DBusHandlerResult Bus::OnServiceOwnerChangedFilter(
1158     DBusConnection* connection,
1159     DBusMessage* message,
1160     void* data) {
1161   if (dbus_message_is_signal(message,
1162                              DBUS_INTERFACE_DBUS,
1163                              kNameOwnerChangedSignal)) {
1164     Bus* self = static_cast<Bus*>(data);
1165     self->OnServiceOwnerChanged(message);
1166   }
1167   // Always return unhandled to let others, e.g. ObjectProxies, handle the same
1168   // signal.
1169   return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1170 }
1171 
1172 }  // namespace dbus
1173