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