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