[go: nahoru, domu]

blob: f15fbceb4294796f3b75ea59e33a21c0bcdaee4f [file] [log] [blame]
Avi Drissmanf75e37f2022-09-13 19:40:311// Copyright 2012 The Chromium Authors
satorux@chromium.orga51076112011-08-17 20:58:122// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
satorux@chromium.orga51076112011-08-17 20:58:124
5#include "dbus/bus.h"
6
avi22437c692015-12-22 18:12:457#include <stddef.h>
8
fdorayebc379c2017-04-18 13:40:219#include <memory>
10
Ho Cheung361ebe32023-08-16 16:29:2711#include "base/containers/contains.h"
fdorayebc379c2017-04-18 13:40:2112#include "base/files/file_descriptor_watcher_posix.h"
Avi Drissmanbb9cd022023-01-11 01:03:2913#include "base/functional/bind.h"
satorux@chromium.orga51076112011-08-17 20:58:1214#include "base/logging.h"
Keishi Hattorif28f4f82022-06-21 11:32:1515#include "base/memory/raw_ptr.h"
Wez811f6da42017-07-12 02:50:1716#include "base/memory/weak_ptr.h"
avi@chromium.orgc3d4a0d2013-06-20 19:40:1217#include "base/strings/stringprintf.h"
David Sanders10242c12022-03-17 07:36:4418#include "base/synchronization/waitable_event.h"
Sean Maher52fa5a72022-11-14 15:53:2519#include "base/task/sequenced_task_runner.h"
Etienne Pierre-Doray7f1f6062018-09-21 14:41:4320#include "base/threading/scoped_blocking_call.h"
satorux@chromium.orga51076112011-08-17 20:58:1221#include "base/threading/thread.h"
22#include "base/threading/thread_restrictions.h"
avi@chromium.orgb43e5562013-06-28 15:20:0223#include "base/time/time.h"
Xiyuan Xiabbe93b12019-05-08 14:15:2724#include "base/timer/elapsed_timer.h"
Hidehiko Abe3afb59a2023-07-06 07:34:3825#include "dbus/error.h"
satorux@chromium.orga51076112011-08-17 20:58:1226#include "dbus/exported_object.h"
thestig@chromium.org049616e2013-06-10 22:52:3427#include "dbus/message.h"
keybuk@chromium.org9cc40cb2013-03-25 18:20:0828#include "dbus/object_manager.h"
29#include "dbus/object_path.h"
satorux@chromium.orga51076112011-08-17 20:58:1230#include "dbus/object_proxy.h"
31#include "dbus/scoped_dbus_error.h"
32
33namespace dbus {
34
35namespace {
36
nona@chromium.org7c8f3ef2013-02-08 10:53:3937const char kDisconnectedSignal[] = "Disconnected";
38const char kDisconnectedMatchRule[] =
39 "type='signal', path='/org/freedesktop/DBus/Local',"
40 "interface='org.freedesktop.DBus.Local', member='Disconnected'";
41
thestig@chromium.org049616e2013-06-10 22:52:3442// The NameOwnerChanged member in org.freedesktop.DBus
43const char kNameOwnerChangedSignal[] = "NameOwnerChanged";
44
45// The match rule used to filter for changes to a given service name owner.
46const char kServiceNameOwnerChangeMatchRule[] =
47 "type='signal',interface='org.freedesktop.DBus',"
48 "member='NameOwnerChanged',path='/org/freedesktop/DBus',"
49 "sender='org.freedesktop.DBus',arg0='%s'";
50
satorux@chromium.orga51076112011-08-17 20:58:1251// The class is used for watching the file descriptor used for D-Bus
52// communication.
fdorayebc379c2017-04-18 13:40:2153class Watch {
satorux@chromium.orga51076112011-08-17 20:58:1254 public:
fdorayebc379c2017-04-18 13:40:2155 explicit Watch(DBusWatch* watch) : raw_watch_(watch) {
Wez811f6da42017-07-12 02:50:1756 dbus_watch_set_data(raw_watch_, this, nullptr);
satorux@chromium.orga51076112011-08-17 20:58:1257 }
58
Peter Boströmc68c5aa2021-09-28 00:28:0059 Watch(const Watch&) = delete;
60 Watch& operator=(const Watch&) = delete;
61
Wez811f6da42017-07-12 02:50:1762 ~Watch() { dbus_watch_set_data(raw_watch_, nullptr, nullptr); }
satorux@chromium.orga51076112011-08-17 20:58:1263
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_);
fdorayebc379c2017-04-18 13:40:2172 const unsigned int flags = dbus_watch_get_flags(raw_watch_);
satorux@chromium.orga51076112011-08-17 20:58:1273
fdorayebc379c2017-04-18 13:40:2174 // 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,
Reilly Grantd4e66132019-11-22 17:14:5079 base::BindRepeating(&Watch::OnFileReady, base::Unretained(this),
80 DBUS_WATCH_READABLE));
fdorayebc379c2017-04-18 13:40:2181 }
82 if (flags & DBUS_WATCH_WRITABLE) {
83 write_watcher_ = base::FileDescriptorWatcher::WatchWritable(
84 file_descriptor,
Reilly Grantd4e66132019-11-22 17:14:5085 base::BindRepeating(&Watch::OnFileReady, base::Unretained(this),
86 DBUS_WATCH_WRITABLE));
fdorayebc379c2017-04-18 13:40:2187 }
satorux@chromium.orga51076112011-08-17 20:58:1288 }
89
90 // Stops watching the underlying file descriptor.
91 void StopWatching() {
fdorayebc379c2017-04-18 13:40:2192 read_watcher_.reset();
93 write_watcher_.reset();
satorux@chromium.orga51076112011-08-17 20:58:1294 }
95
96 private:
fdorayebc379c2017-04-18 13:40:2197 void OnFileReady(unsigned int flags) {
98 CHECK(dbus_watch_handle(raw_watch_, flags)) << "Unable to allocate memory";
satorux@chromium.orga51076112011-08-17 20:58:1299 }
100
Keishi Hattorif28f4f82022-06-21 11:32:15101 raw_ptr<DBusWatch> raw_watch_;
fdorayebc379c2017-04-18 13:40:21102 std::unique_ptr<base::FileDescriptorWatcher::Controller> read_watcher_;
103 std::unique_ptr<base::FileDescriptorWatcher::Controller> write_watcher_;
satorux@chromium.orga51076112011-08-17 20:58:12104};
105
106// The class is used for monitoring the timeout used for D-Bus method
107// calls.
Wez811f6da42017-07-12 02:50:17108class Timeout {
satorux@chromium.orga51076112011-08-17 20:58:12109 public:
Jeremy Roman7c5cfabd2019-08-12 15:45:27110 explicit Timeout(DBusTimeout* timeout) : raw_timeout_(timeout) {
Wez811f6da42017-07-12 02:50:17111 // Associated |this| with the underlying DBusTimeout.
112 dbus_timeout_set_data(raw_timeout_, this, nullptr);
113 }
114
Peter Boströmc68c5aa2021-09-28 00:28:00115 Timeout(const Timeout&) = delete;
116 Timeout& operator=(const Timeout&) = delete;
117
Wez811f6da42017-07-12 02:50:17118 ~Timeout() {
119 // Remove the association between |this| and the |raw_timeout_|.
120 dbus_timeout_set_data(raw_timeout_, nullptr, nullptr);
satorux@chromium.orga51076112011-08-17 20:58:12121 }
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.
thestig@chromium.org2a57ca642013-06-13 06:37:19129 void StartMonitoring(Bus* bus) {
hashimoto@chromium.org8609be262013-09-26 04:32:29130 bus->GetDBusTaskRunner()->PostDelayedTask(
131 FROM_HERE,
kylechar39c39282019-02-19 19:04:04132 base::BindOnce(&Timeout::HandleTimeout, weak_ptr_factory_.GetWeakPtr()),
hashimoto@chromium.org8609be262013-09-26 04:32:29133 GetInterval());
satorux@chromium.orga51076112011-08-17 20:58:12134 }
135
136 // Stops monitoring the timeout.
Wez811f6da42017-07-12 02:50:17137 void StopMonitoring() { weak_ptr_factory_.InvalidateWeakPtrs(); }
satorux@chromium.orga51076112011-08-17 20:58:12138
tedvessenes@gmail.com4b454262012-03-11 01:12:20139 base::TimeDelta GetInterval() {
Peter Kastinge5a38ed2021-10-02 03:06:35140 return base::Milliseconds(dbus_timeout_get_interval(raw_timeout_));
satorux@chromium.orga51076112011-08-17 20:58:12141 }
142
satorux@chromium.orga51076112011-08-17 20:58:12143 private:
Wez811f6da42017-07-12 02:50:17144 // Calls DBus to handle the timeout.
145 void HandleTimeout() { CHECK(dbus_timeout_handle(raw_timeout_)); }
satorux@chromium.orga51076112011-08-17 20:58:12146
Keishi Hattorif28f4f82022-06-21 11:32:15147 raw_ptr<DBusTimeout> raw_timeout_;
Wez811f6da42017-07-12 02:50:17148
Jeremy Roman7c5cfabd2019-08-12 15:45:27149 base::WeakPtrFactory<Timeout> weak_ptr_factory_{this};
satorux@chromium.orga51076112011-08-17 20:58:12150};
151
Hidehiko Abeac7a3c52023-07-06 11:18:10152// Converts DBusError into dbus::Error.
153Error ToError(const internal::ScopedDBusError& error) {
154 return error.is_set() ? Error(error.name(), error.message()) : Error();
155}
156
satorux@chromium.orga51076112011-08-17 20:58:12157} // namespace
158
159Bus::Options::Options()
160 : bus_type(SESSION),
mdm@chromium.org56d82c9c2011-09-06 20:03:24161 connection_type(PRIVATE) {
satorux@chromium.orga51076112011-08-17 20:58:12162}
163
Chris Watkins3740aae2017-11-29 07:44:11164Bus::Options::~Options() = default;
satorux@chromium.orga51076112011-08-17 20:58:12165
Ryo Hashimoto020d6092021-10-13 03:10:18166Bus::Options::Options(Bus::Options&&) = default;
167
168Bus::Options& Bus::Options::operator=(Bus::Options&&) = default;
169
satorux@chromium.orga51076112011-08-17 20:58:12170Bus::Bus(const Options& options)
171 : bus_type_(options.bus_type),
172 connection_type_(options.connection_type),
thestig@chromium.org200328a2013-02-20 01:36:53173 dbus_task_runner_(options.dbus_task_runner),
gab0faddf482016-06-02 12:26:55174 on_shutdown_(base::WaitableEvent::ResetPolicy::AUTOMATIC,
175 base::WaitableEvent::InitialState::NOT_SIGNALED),
Wez811f6da42017-07-12 02:50:17176 connection_(nullptr),
satorux@chromium.orga51076112011-08-17 20:58:12177 origin_thread_id_(base::PlatformThread::CurrentId()),
satorux@chromium.orgea78b1e2011-08-27 07:26:34178 async_operations_set_up_(false),
satorux@chromium.orge20d39fe2011-09-02 06:56:23179 shutdown_completed_(false),
satorux@chromium.orga51076112011-08-17 20:58:12180 num_pending_watches_(0),
nona@chromium.org7e1942a2012-04-19 03:20:03181 num_pending_timeouts_(0),
hashimotoe8aa0b4e2014-12-09 04:50:23182 address_(options.address) {
satorux@chromium.orga51076112011-08-17 20:58:12183 // This is safe to call multiple times.
184 dbus_threads_init_default();
satorux@chromium.orgb8907a42011-09-08 22:28:42185 // The origin message loop is unnecessary if the client uses synchronous
186 // functions only.
Sean Maher52fa5a72022-11-14 15:53:25187 if (base::SequencedTaskRunner::HasCurrentDefault())
188 origin_task_runner_ = base::SequencedTaskRunner::GetCurrentDefault();
satorux@chromium.orga51076112011-08-17 20:58:12189}
190
191Bus::~Bus() {
192 DCHECK(!connection_);
193 DCHECK(owned_service_names_.empty());
satorux@chromium.org3beaaa4e2011-08-23 07:29:21194 DCHECK(match_rules_added_.empty());
195 DCHECK(filter_functions_added_.empty());
196 DCHECK(registered_object_paths_.empty());
satorux@chromium.orga51076112011-08-17 20:58:12197 DCHECK_EQ(0, num_pending_watches_);
jamescook@chromium.org47e2a0d2011-11-24 07:00:43198 // 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_);
satorux@chromium.orga51076112011-08-17 20:58:12202}
203
204ObjectProxy* Bus::GetObjectProxy(const std::string& service_name,
keybuk@google.com216ed0b2012-02-14 21:29:06205 const ObjectPath& object_path) {
adamk@chromium.org20bed012012-02-10 21:45:23206 return GetObjectProxyWithOptions(service_name, object_path,
207 ObjectProxy::DEFAULT_OPTIONS);
208}
209
210ObjectProxy* Bus::GetObjectProxyWithOptions(const std::string& service_name,
thestig@chromium.org2a57ca642013-06-13 06:37:19211 const ObjectPath& object_path,
adamk@chromium.org20bed012012-02-10 21:45:23212 int options) {
satorux@chromium.orga51076112011-08-17 20:58:12213 AssertOnOriginThread();
214
satorux@chromium.org2ef498f2011-08-23 19:25:20215 // Check if we already have the requested object proxy.
keybuk@google.com216ed0b2012-02-14 21:29:06216 const ObjectProxyTable::key_type key(service_name + object_path.value(),
217 options);
satorux@chromium.org2ef498f2011-08-23 19:25:20218 ObjectProxyTable::iterator iter = object_proxy_table_.find(key);
219 if (iter != object_proxy_table_.end()) {
rsleevi@chromium.orge52df782013-06-02 23:38:09220 return iter->second.get();
satorux@chromium.org2ef498f2011-08-23 19:25:20221 }
222
satorux@chromium.orga51076112011-08-17 20:58:12223 scoped_refptr<ObjectProxy> object_proxy =
adamk@chromium.org20bed012012-02-10 21:45:23224 new ObjectProxy(this, service_name, object_path, options);
satorux@chromium.org2ef498f2011-08-23 19:25:20225 object_proxy_table_[key] = object_proxy;
satorux@chromium.orga51076112011-08-17 20:58:12226
satorux@chromium.org2ef498f2011-08-23 19:25:20227 return object_proxy.get();
satorux@chromium.orga51076112011-08-17 20:58:12228}
229
deymo@chromium.org38ecdc82013-01-29 20:29:12230bool Bus::RemoveObjectProxy(const std::string& service_name,
231 const ObjectPath& object_path,
Reilly Grantd4e66132019-11-22 17:14:50232 base::OnceClosure callback) {
deymo@chromium.org38ecdc82013-01-29 20:29:12233 return RemoveObjectProxyWithOptions(service_name, object_path,
234 ObjectProxy::DEFAULT_OPTIONS,
Reilly Grantd4e66132019-11-22 17:14:50235 std::move(callback));
deymo@chromium.org38ecdc82013-01-29 20:29:12236}
237
238bool Bus::RemoveObjectProxyWithOptions(const std::string& service_name,
thestig@chromium.org2a57ca642013-06-13 06:37:19239 const ObjectPath& object_path,
deymo@chromium.org38ecdc82013-01-29 20:29:12240 int options,
Reilly Grantd4e66132019-11-22 17:14:50241 base::OnceClosure callback) {
deymo@chromium.org38ecdc82013-01-29 20:29:12242 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()) {
stevenjb@chromium.orgee9941382013-10-07 22:56:57249 scoped_refptr<ObjectProxy> object_proxy = iter->second;
250 object_proxy_table_.erase(iter);
armansitoebff093d2014-09-05 17:49:34251 // Object is present. Remove it now and Detach on the DBus thread.
hashimoto@chromium.org8609be262013-09-26 04:32:29252 GetDBusTaskRunner()->PostTask(
kylechar39c39282019-02-19 19:04:04253 FROM_HERE, base::BindOnce(&Bus::RemoveObjectProxyInternal, this,
Reilly Grantd4e66132019-11-22 17:14:50254 object_proxy, std::move(callback)));
deymo@chromium.org38ecdc82013-01-29 20:29:12255 return true;
256 }
257 return false;
258}
259
thestig@chromium.org2a57ca642013-06-13 06:37:19260void Bus::RemoveObjectProxyInternal(scoped_refptr<ObjectProxy> object_proxy,
Reilly Grantd4e66132019-11-22 17:14:50261 base::OnceClosure callback) {
deymo@chromium.org38ecdc82013-01-29 20:29:12262 AssertOnDBusThread();
263
Wez811f6da42017-07-12 02:50:17264 object_proxy->Detach();
deymo@chromium.org38ecdc82013-01-29 20:29:12265
Reilly Grantd4e66132019-11-22 17:14:50266 GetOriginTaskRunner()->PostTask(FROM_HERE, std::move(callback));
deymo@chromium.org38ecdc82013-01-29 20:29:12267}
268
keybuk@chromium.org15e7b162012-03-10 01:12:52269ExportedObject* Bus::GetExportedObject(const ObjectPath& object_path) {
satorux@chromium.orga51076112011-08-17 20:58:12270 AssertOnOriginThread();
271
satorux@chromium.org2ef498f2011-08-23 19:25:20272 // Check if we already have the requested exported object.
keybuk@chromium.org15e7b162012-03-10 01:12:52273 ExportedObjectTable::iterator iter = exported_object_table_.find(object_path);
satorux@chromium.org2ef498f2011-08-23 19:25:20274 if (iter != exported_object_table_.end()) {
rsleevi@chromium.orge52df782013-06-02 23:38:09275 return iter->second.get();
satorux@chromium.org2ef498f2011-08-23 19:25:20276 }
277
satorux@chromium.orga51076112011-08-17 20:58:12278 scoped_refptr<ExportedObject> exported_object =
keybuk@chromium.org15e7b162012-03-10 01:12:52279 new ExportedObject(this, object_path);
280 exported_object_table_[object_path] = exported_object;
satorux@chromium.orga51076112011-08-17 20:58:12281
satorux@chromium.org2ef498f2011-08-23 19:25:20282 return exported_object.get();
satorux@chromium.orga51076112011-08-17 20:58:12283}
284
keybuk@chromium.orgd7361fdc2012-03-14 01:18:35285void 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
thestig@chromium.org200328a2013-02-20 01:36:53299 // 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.
hashimoto@chromium.org8609be262013-09-26 04:32:29302 GetDBusTaskRunner()->PostTask(
kylechar39c39282019-02-19 19:04:04303 FROM_HERE, base::BindOnce(&Bus::UnregisterExportedObjectInternal, this,
304 exported_object));
keybuk@chromium.orgd7361fdc2012-03-14 01:18:35305}
306
307void Bus::UnregisterExportedObjectInternal(
thestig@chromium.org2a57ca642013-06-13 06:37:19308 scoped_refptr<ExportedObject> exported_object) {
keybuk@chromium.orgd7361fdc2012-03-14 01:18:35309 AssertOnDBusThread();
310
311 exported_object->Unregister();
312}
313
keybuk@chromium.org9cc40cb2013-03-25 18:20:08314ObjectManager* 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()) {
rsleevi@chromium.orge52df782013-06-02 23:38:09322 return iter->second.get();
keybuk@chromium.org9cc40cb2013-03-25 18:20:08323 }
324
325 scoped_refptr<ObjectManager> object_manager =
tzik570f47a2018-07-24 09:16:57326 ObjectManager::Create(this, service_name, object_path);
keybuk@chromium.org9cc40cb2013-03-25 18:20:08327 object_manager_table_[key] = object_manager;
328
329 return object_manager.get();
330}
331
armansitoebff093d2014-09-05 17:49:34332bool Bus::RemoveObjectManager(const std::string& service_name,
333 const ObjectPath& object_path,
Reilly Grantd4e66132019-11-22 17:14:50334 base::OnceClosure callback) {
keybuk@chromium.org9cc40cb2013-03-25 18:20:08335 AssertOnOriginThread();
armansitoebff093d2014-09-05 17:49:34336 DCHECK(!callback.is_null());
keybuk@chromium.org9cc40cb2013-03-25 18:20:08337
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())
armansitoebff093d2014-09-05 17:49:34341 return false;
keybuk@chromium.org9cc40cb2013-03-25 18:20:08342
armansitoebff093d2014-09-05 17:49:34343 // ObjectManager is present. Remove it now and CleanUp on the DBus thread.
keybuk@chromium.org9cc40cb2013-03-25 18:20:08344 scoped_refptr<ObjectManager> object_manager = iter->second;
345 object_manager_table_.erase(iter);
armansitoebff093d2014-09-05 17:49:34346
347 GetDBusTaskRunner()->PostTask(
kylechar39c39282019-02-19 19:04:04348 FROM_HERE, base::BindOnce(&Bus::RemoveObjectManagerInternal, this,
Reilly Grantd4e66132019-11-22 17:14:50349 object_manager, std::move(callback)));
armansitoebff093d2014-09-05 17:49:34350
351 return true;
352}
353
354void Bus::RemoveObjectManagerInternal(
Reilly Grantd4e66132019-11-22 17:14:50355 scoped_refptr<dbus::ObjectManager> object_manager,
356 base::OnceClosure callback) {
armansitoebff093d2014-09-05 17:49:34357 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(
kylechar39c39282019-02-19 19:04:04365 FROM_HERE, base::BindOnce(&Bus::RemoveObjectManagerInternalHelper, this,
Reilly Grantd4e66132019-11-22 17:14:50366 object_manager, std::move(callback)));
armansitoebff093d2014-09-05 17:49:34367}
368
369void Bus::RemoveObjectManagerInternalHelper(
Reilly Grantd4e66132019-11-22 17:14:50370 scoped_refptr<dbus::ObjectManager> object_manager,
371 base::OnceClosure callback) {
armansitoebff093d2014-09-05 17:49:34372 AssertOnOriginThread();
Wez811f6da42017-07-12 02:50:17373 DCHECK(object_manager);
armansitoebff093d2014-09-05 17:49:34374
375 // Release the object manager and run the callback.
Wez811f6da42017-07-12 02:50:17376 object_manager = nullptr;
Reilly Grantd4e66132019-11-22 17:14:50377 std::move(callback).Run();
keybuk@chromium.org9cc40cb2013-03-25 18:20:08378}
379
satorux@chromium.orga51076112011-08-17 20:58:12380bool Bus::Connect() {
381 // dbus_bus_get_private() and dbus_bus_get() are blocking calls.
382 AssertOnDBusThread();
Etienne Bergeron436d42212019-02-26 17:15:12383 base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
384 base::BlockingType::MAY_BLOCK);
satorux@chromium.orga51076112011-08-17 20:58:12385
386 // Check if it's already initialized.
387 if (connection_)
388 return true;
389
Hidehiko Abe3afb59a2023-07-06 07:34:38390 internal::ScopedDBusError dbus_error;
nona@chromium.org7e1942a2012-04-19 03:20:03391 if (bus_type_ == CUSTOM_ADDRESS) {
392 if (connection_type_ == PRIVATE) {
Hidehiko Abe3afb59a2023-07-06 07:34:38393 connection_ =
394 dbus_connection_open_private(address_.c_str(), dbus_error.get());
nona@chromium.org7e1942a2012-04-19 03:20:03395 } else {
Hidehiko Abe3afb59a2023-07-06 07:34:38396 connection_ = dbus_connection_open(address_.c_str(), dbus_error.get());
nona@chromium.org7e1942a2012-04-19 03:20:03397 }
satorux@chromium.orga51076112011-08-17 20:58:12398 } else {
nona@chromium.org7e1942a2012-04-19 03:20:03399 const DBusBusType dbus_bus_type = static_cast<DBusBusType>(bus_type_);
400 if (connection_type_ == PRIVATE) {
Hidehiko Abe3afb59a2023-07-06 07:34:38401 connection_ = dbus_bus_get_private(dbus_bus_type, dbus_error.get());
nona@chromium.org7e1942a2012-04-19 03:20:03402 } else {
Hidehiko Abe3afb59a2023-07-06 07:34:38403 connection_ = dbus_bus_get(dbus_bus_type, dbus_error.get());
nona@chromium.org7e1942a2012-04-19 03:20:03404 }
satorux@chromium.orga51076112011-08-17 20:58:12405 }
406 if (!connection_) {
407 LOG(ERROR) << "Failed to connect to the bus: "
Hidehiko Abe3afb59a2023-07-06 07:34:38408 << (dbus_error.is_set() ? dbus_error.message() : "");
satorux@chromium.orga51076112011-08-17 20:58:12409 return false;
410 }
nona@chromium.orgea1aaa92012-11-02 08:04:14411
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.
Hidehiko Abe3afb59a2023-07-06 07:34:38418 if (!dbus_bus_register(connection_, dbus_error.get())) {
nona@chromium.orgea1aaa92012-11-02 08:04:14419 LOG(ERROR) << "Failed to register the bus component: "
Hidehiko Abe3afb59a2023-07-06 07:34:38420 << (dbus_error.is_set() ? dbus_error.message() : "");
nona@chromium.orgea1aaa92012-11-02 08:04:14421 return false;
422 }
423 }
satorux@chromium.orga51076112011-08-17 20:58:12424 // We shouldn't exit on the disconnected signal.
425 dbus_connection_set_exit_on_disconnect(connection_, false);
426
nona@chromium.org7c8f3ef2013-02-08 10:53:39427 // Watch Disconnected signal.
428 AddFilterFunction(Bus::OnConnectionDisconnectedFilter, this);
Hidehiko Abe3afb59a2023-07-06 07:34:38429 Error error;
430 AddMatch(kDisconnectedMatchRule, &error);
nona@chromium.org7c8f3ef2013-02-08 10:53:39431
satorux@chromium.orga51076112011-08-17 20:58:12432 return true;
433}
434
nona@chromium.orgea545192013-02-15 16:44:40435void 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";
Etienne Bergeron436d42212019-02-26 17:15:12440 base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
441 base::BlockingType::MAY_BLOCK);
nona@chromium.orgea545192013-02-15 16:44:40442 dbus_connection_close(connection_);
443}
444
satorux@chromium.orga51076112011-08-17 20:58:12445void Bus::ShutdownAndBlock() {
446 AssertOnDBusThread();
447
nona@chromium.org7c8f3ef2013-02-08 10:53:39448 if (shutdown_completed_)
449 return; // Already shutdowned, just return.
450
satorux@chromium.orga51076112011-08-17 20:58:12451 // Unregister the exported objects.
satorux@chromium.org2ef498f2011-08-23 19:25:20452 for (ExportedObjectTable::iterator iter = exported_object_table_.begin();
453 iter != exported_object_table_.end(); ++iter) {
454 iter->second->Unregister();
satorux@chromium.orga51076112011-08-17 20:58:12455 }
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
satorux@chromium.org3beaaa4e2011-08-23 07:29:21470 // Detach from the remote objects.
satorux@chromium.org2ef498f2011-08-23 19:25:20471 for (ObjectProxyTable::iterator iter = object_proxy_table_.begin();
472 iter != object_proxy_table_.end(); ++iter) {
473 iter->second->Detach();
satorux@chromium.org3beaaa4e2011-08-23 07:29:21474 }
475
armansitoebff093d2014-09-05 17:49:34476 // 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
satorux@chromium.org6477a412011-10-13 00:45:26482 // 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
satorux@chromium.orga51076112011-08-17 20:58:12488 // Private connection should be closed.
satorux@chromium.orge20d39fe2011-09-02 06:56:23489 if (connection_) {
Etienne Pierre-Doray7f1f6062018-09-21 14:41:43490 base::ScopedBlockingCall scoped_blocking_call(
Etienne Bergeron3d58bbd02019-02-27 18:19:21491 FROM_HERE, base::BlockingType::MAY_BLOCK);
Etienne Pierre-Doray7f1f6062018-09-21 14:41:43492
nona@chromium.org7c8f3ef2013-02-08 10:53:39493 // Remove Disconnected watcher.
Hidehiko Abe3afb59a2023-07-06 07:34:38494 Error error;
nona@chromium.org7c8f3ef2013-02-08 10:53:39495 RemoveFilterFunction(Bus::OnConnectionDisconnectedFilter, this);
Hidehiko Abe3afb59a2023-07-06 07:34:38496 RemoveMatch(kDisconnectedMatchRule, &error);
nona@chromium.org7c8f3ef2013-02-08 10:53:39497
satorux@chromium.orge20d39fe2011-09-02 06:56:23498 if (connection_type_ == PRIVATE)
nona@chromium.orgea545192013-02-15 16:44:40499 ClosePrivateConnection();
satorux@chromium.orge20d39fe2011-09-02 06:56:23500 // dbus_connection_close() won't unref.
501 dbus_connection_unref(connection_);
satorux@chromium.orga51076112011-08-17 20:58:12502 }
satorux@chromium.orga51076112011-08-17 20:58:12503
Wez811f6da42017-07-12 02:50:17504 connection_ = nullptr;
satorux@chromium.orge20d39fe2011-09-02 06:56:23505 shutdown_completed_ = true;
satorux@chromium.orga51076112011-08-17 20:58:12506}
507
satorux@chromium.orge20d39fe2011-09-02 06:56:23508void Bus::ShutdownOnDBusThreadAndBlock() {
satorux@chromium.orga51076112011-08-17 20:58:12509 AssertOnOriginThread();
Wez811f6da42017-07-12 02:50:17510 DCHECK(dbus_task_runner_);
satorux@chromium.orga51076112011-08-17 20:58:12511
hashimoto@chromium.org8609be262013-09-26 04:32:29512 GetDBusTaskRunner()->PostTask(
513 FROM_HERE,
kylechar39c39282019-02-19 19:04:04514 base::BindOnce(&Bus::ShutdownOnDBusThreadAndBlockInternal, this));
satorux@chromium.orge20d39fe2011-09-02 06:56:23515
jam@chromium.org0c65b4e2012-04-26 19:08:58516 // http://crbug.com/125222
Etienne Pierre-Dorayb5cc74a2018-11-27 01:10:46517 base::ScopedAllowBaseSyncPrimitivesOutsideBlockingScope allow_wait;
jam@chromium.org0c65b4e2012-04-26 19:08:58518
satorux@chromium.orge20d39fe2011-09-02 06:56:23519 // 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;
Peter Kastinge5a38ed2021-10-02 03:06:35522 const base::TimeDelta timeout(base::Seconds(kTimeoutSecs));
satorux@chromium.orge20d39fe2011-09-02 06:56:23523 const bool signaled = on_shutdown_.TimedWait(timeout);
524 LOG_IF(ERROR, !signaled) << "Failed to shutdown the bus";
satorux@chromium.orga51076112011-08-17 20:58:12525}
526
keybuk@chromium.org15e7b162012-03-10 01:12:52527void Bus::RequestOwnership(const std::string& service_name,
cmasone@chromium.orge2824902013-07-31 06:34:59528 ServiceOwnershipOptions options,
keybuk@chromium.org15e7b162012-03-10 01:12:52529 OnOwnershipCallback on_ownership_callback) {
530 AssertOnOriginThread();
531
hashimoto@chromium.org8609be262013-09-26 04:32:29532 GetDBusTaskRunner()->PostTask(
Reilly Grantd4e66132019-11-22 17:14:50533 FROM_HERE,
534 base::BindOnce(&Bus::RequestOwnershipInternal, this, service_name,
535 options, std::move(on_ownership_callback)));
keybuk@chromium.org15e7b162012-03-10 01:12:52536}
537
538void Bus::RequestOwnershipInternal(const std::string& service_name,
cmasone@chromium.orge2824902013-07-31 06:34:59539 ServiceOwnershipOptions options,
keybuk@chromium.org15e7b162012-03-10 01:12:52540 OnOwnershipCallback on_ownership_callback) {
541 AssertOnDBusThread();
542
543 bool success = Connect();
544 if (success)
cmasone@chromium.orge2824902013-07-31 06:34:59545 success = RequestOwnershipAndBlock(service_name, options);
keybuk@chromium.org15e7b162012-03-10 01:12:52546
kylechar39c39282019-02-19 19:04:04547 GetOriginTaskRunner()->PostTask(
Reilly Grantd4e66132019-11-22 17:14:50548 FROM_HERE,
549 base::BindOnce(std::move(on_ownership_callback), service_name, success));
keybuk@chromium.org15e7b162012-03-10 01:12:52550}
551
cmasone@chromium.orge2824902013-07-31 06:34:59552bool Bus::RequestOwnershipAndBlock(const std::string& service_name,
553 ServiceOwnershipOptions options) {
satorux@chromium.orga51076112011-08-17 20:58:12554 DCHECK(connection_);
555 // dbus_bus_request_name() is a blocking call.
556 AssertOnDBusThread();
557
558 // Check if we already own the service name.
Ho Cheung361ebe32023-08-16 16:29:27559 if (base::Contains(owned_service_names_, service_name)) {
satorux@chromium.orga51076112011-08-17 20:58:12560 return true;
561 }
562
Etienne Bergeron436d42212019-02-26 17:15:12563 base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
564 base::BlockingType::MAY_BLOCK);
Hidehiko Abe3afb59a2023-07-06 07:34:38565 internal::ScopedDBusError error;
satorux@chromium.orga51076112011-08-17 20:58:12566 const int result = dbus_bus_request_name(connection_,
567 service_name.c_str(),
cmasone@chromium.orge2824902013-07-31 06:34:59568 options,
satorux@chromium.orga51076112011-08-17 20:58:12569 error.get());
570 if (result != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {
satorux@chromium.org829f0e4c2011-08-31 18:02:43571 LOG(ERROR) << "Failed to get the ownership of " << service_name << ": "
tfarina@chromium.orgb4a70c32012-10-29 16:43:26572 << (error.is_set() ? error.message() : "");
satorux@chromium.orga51076112011-08-17 20:58:12573 return false;
574 }
575 owned_service_names_.insert(service_name);
576 return true;
577}
578
579bool Bus::ReleaseOwnership(const std::string& service_name) {
580 DCHECK(connection_);
Etienne Pierre-Doray7f1f6062018-09-21 14:41:43581 // dbus_bus_release_name() is a blocking call.
satorux@chromium.orga51076112011-08-17 20:58:12582 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
Etienne Bergeron436d42212019-02-26 17:15:12592 base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
593 base::BlockingType::MAY_BLOCK);
Hidehiko Abe3afb59a2023-07-06 07:34:38594 internal::ScopedDBusError error;
satorux@chromium.orga51076112011-08-17 20:58:12595 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 {
satorux@chromium.org829f0e4c2011-08-31 18:02:43601 LOG(ERROR) << "Failed to release the ownership of " << service_name << ": "
cmasone@chromium.orge2824902013-07-31 06:34:59602 << (error.is_set() ? error.message() : "")
603 << ", result code: " << result;
satorux@chromium.orga51076112011-08-17 20:58:12604 return false;
605 }
606}
607
608bool Bus::SetUpAsyncOperations() {
609 DCHECK(connection_);
610 AssertOnDBusThread();
611
satorux@chromium.orgea78b1e2011-08-27 07:26:34612 if (async_operations_set_up_)
satorux@chromium.orga51076112011-08-17 20:58:12613 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
Etienne Bergeron436d42212019-02-26 17:15:12619 base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
620 base::BlockingType::MAY_BLOCK);
Wez811f6da42017-07-12 02:50:17621 bool success = dbus_connection_set_watch_functions(
622 connection_, &Bus::OnAddWatchThunk, &Bus::OnRemoveWatchThunk,
623 &Bus::OnToggleWatchThunk, this, nullptr);
satorux@chromium.orga51076112011-08-17 20:58:12624 CHECK(success) << "Unable to allocate memory";
625
Wez811f6da42017-07-12 02:50:17626 success = dbus_connection_set_timeout_functions(
627 connection_, &Bus::OnAddTimeoutThunk, &Bus::OnRemoveTimeoutThunk,
628 &Bus::OnToggleTimeoutThunk, this, nullptr);
satorux@chromium.orga51076112011-08-17 20:58:12629 CHECK(success) << "Unable to allocate memory";
630
631 dbus_connection_set_dispatch_status_function(
Wez811f6da42017-07-12 02:50:17632 connection_, &Bus::OnDispatchStatusChangedThunk, this, nullptr);
satorux@chromium.orga51076112011-08-17 20:58:12633
satorux@chromium.orgea78b1e2011-08-27 07:26:34634 async_operations_set_up_ = true;
satorux@chromium.orga51076112011-08-17 20:58:12635
636 return true;
637}
638
Hidehiko Abeac7a3c52023-07-06 11:18:10639base::expected<std::unique_ptr<Response>, Error> Bus::SendWithReplyAndBlock(
640 DBusMessage* request,
641 int timeout_ms) {
satorux@chromium.orga51076112011-08-17 20:58:12642 DCHECK(connection_);
643 AssertOnDBusThread();
644
Xiyuan Xiabbe93b12019-05-08 14:15:27645 base::ElapsedTimer elapsed;
646
Etienne Bergeron436d42212019-02-26 17:15:12647 base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
648 base::BlockingType::MAY_BLOCK);
Hidehiko Abe3afb59a2023-07-06 07:34:38649 internal::ScopedDBusError dbus_error;
Xiyuan Xiabbe93b12019-05-08 14:15:27650 DBusMessage* reply = dbus_connection_send_with_reply_and_block(
Hidehiko Abe3afb59a2023-07-06 07:34:38651 connection_, request, timeout_ms, dbus_error.get());
Peter Kastinge5a38ed2021-10-02 03:06:35652 constexpr base::TimeDelta kLongCall = base::Seconds(1);
Xiyuan Xiabbe93b12019-05-08 14:15:27653 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
Hidehiko Abeac7a3c52023-07-06 11:18:10661 if (!reply) {
662 return base::unexpected(ToError(dbus_error));
663 }
664
665 return base::ok(Response::FromRawMessage(reply));
satorux@chromium.orga51076112011-08-17 20:58:12666}
667
668void Bus::SendWithReply(DBusMessage* request,
669 DBusPendingCall** pending_call,
670 int timeout_ms) {
671 DCHECK(connection_);
672 AssertOnDBusThread();
673
Etienne Bergeron436d42212019-02-26 17:15:12674 base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
675 base::BlockingType::MAY_BLOCK);
satorux@chromium.orga51076112011-08-17 20:58:12676 const bool success = dbus_connection_send_with_reply(
677 connection_, request, pending_call, timeout_ms);
678 CHECK(success) << "Unable to allocate memory";
679}
680
avi22437c692015-12-22 18:12:45681void Bus::Send(DBusMessage* request, uint32_t* serial) {
satorux@chromium.org3beaaa4e2011-08-23 07:29:21682 DCHECK(connection_);
683 AssertOnDBusThread();
684
Etienne Bergeron436d42212019-02-26 17:15:12685 base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
686 base::BlockingType::MAY_BLOCK);
satorux@chromium.org3beaaa4e2011-08-23 07:29:21687 const bool success = dbus_connection_send(connection_, request, serial);
688 CHECK(success) << "Unable to allocate memory";
689}
690
hashimotob3870312014-12-04 07:41:55691void Bus::AddFilterFunction(DBusHandleMessageFunction filter_function,
satorux@chromium.org3beaaa4e2011-08-23 07:29:21692 void* user_data) {
693 DCHECK(connection_);
694 AssertOnDBusThread();
695
satorux@chromium.org12e25992011-10-06 00:20:53696 std::pair<DBusHandleMessageFunction, void*> filter_data_pair =
697 std::make_pair(filter_function, user_data);
Ho Cheung361ebe32023-08-16 16:29:27698 if (base::Contains(filter_functions_added_, filter_data_pair)) {
satorux@chromium.org12e25992011-10-06 00:20:53699 VLOG(1) << "Filter function already exists: " << filter_function
700 << " with associated data: " << user_data;
hashimotob3870312014-12-04 07:41:55701 return;
satorux@chromium.org3beaaa4e2011-08-23 07:29:21702 }
703
Etienne Bergeron436d42212019-02-26 17:15:12704 base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
705 base::BlockingType::MAY_BLOCK);
Wez811f6da42017-07-12 02:50:17706 const bool success = dbus_connection_add_filter(connection_, filter_function,
707 user_data, nullptr);
satorux@chromium.org3beaaa4e2011-08-23 07:29:21708 CHECK(success) << "Unable to allocate memory";
satorux@chromium.org12e25992011-10-06 00:20:53709 filter_functions_added_.insert(filter_data_pair);
satorux@chromium.org3beaaa4e2011-08-23 07:29:21710}
711
hashimotob3870312014-12-04 07:41:55712void Bus::RemoveFilterFunction(DBusHandleMessageFunction filter_function,
satorux@chromium.org3beaaa4e2011-08-23 07:29:21713 void* user_data) {
714 DCHECK(connection_);
715 AssertOnDBusThread();
716
satorux@chromium.org12e25992011-10-06 00:20:53717 std::pair<DBusHandleMessageFunction, void*> filter_data_pair =
718 std::make_pair(filter_function, user_data);
Ho Cheung361ebe32023-08-16 16:29:27719 if (!base::Contains(filter_functions_added_, filter_data_pair)) {
satorux@chromium.org12e25992011-10-06 00:20:53720 VLOG(1) << "Requested to remove an unknown filter function: "
721 << filter_function
722 << " with associated data: " << user_data;
hashimotob3870312014-12-04 07:41:55723 return;
satorux@chromium.org3beaaa4e2011-08-23 07:29:21724 }
725
Etienne Bergeron436d42212019-02-26 17:15:12726 base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
727 base::BlockingType::MAY_BLOCK);
satorux@chromium.org3beaaa4e2011-08-23 07:29:21728 dbus_connection_remove_filter(connection_, filter_function, user_data);
satorux@chromium.org12e25992011-10-06 00:20:53729 filter_functions_added_.erase(filter_data_pair);
satorux@chromium.org3beaaa4e2011-08-23 07:29:21730}
731
Hidehiko Abe3afb59a2023-07-06 07:34:38732void Bus::AddMatch(const std::string& match_rule, Error* error) {
satorux@chromium.org3beaaa4e2011-08-23 07:29:21733 DCHECK(connection_);
Hidehiko Abe3afb59a2023-07-06 07:34:38734 DCHECK(error);
satorux@chromium.org3beaaa4e2011-08-23 07:29:21735 AssertOnDBusThread();
736
deymo@chromium.orgbae0f882013-01-31 06:08:02737 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
satorux@chromium.org5cb8eb22011-10-12 23:47:13743 VLOG(1) << "Match rule already exists: " << match_rule;
satorux@chromium.org3beaaa4e2011-08-23 07:29:21744 return;
745 }
746
Etienne Bergeron436d42212019-02-26 17:15:12747 base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
748 base::BlockingType::MAY_BLOCK);
Hidehiko Abe3afb59a2023-07-06 07:34:38749 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 }
deymo@chromium.orgbae0f882013-01-31 06:08:02754 match_rules_added_[match_rule] = 1;
satorux@chromium.org3beaaa4e2011-08-23 07:29:21755}
756
Hidehiko Abe3afb59a2023-07-06 07:34:38757bool Bus::RemoveMatch(const std::string& match_rule, Error* error) {
satorux@chromium.org3beaaa4e2011-08-23 07:29:21758 DCHECK(connection_);
Hidehiko Abe3afb59a2023-07-06 07:34:38759 DCHECK(error);
satorux@chromium.org3beaaa4e2011-08-23 07:29:21760 AssertOnDBusThread();
761
deymo@chromium.orgbae0f882013-01-31 06:08:02762 std::map<std::string, int>::iterator iter =
763 match_rules_added_.find(match_rule);
764 if (iter == match_rules_added_.end()) {
satorux@chromium.org3beaaa4e2011-08-23 07:29:21765 LOG(ERROR) << "Requested to remove an unknown match rule: " << match_rule;
deymo@chromium.orgbae0f882013-01-31 06:08:02766 return false;
satorux@chromium.org3beaaa4e2011-08-23 07:29:21767 }
768
Etienne Bergeron436d42212019-02-26 17:15:12769 base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
770 base::BlockingType::MAY_BLOCK);
deymo@chromium.orgbae0f882013-01-31 06:08:02771 // The rule's counter is decremented and the rule is deleted when reachs 0.
772 iter->second--;
773 if (iter->second == 0) {
Hidehiko Abe3afb59a2023-07-06 07:34:38774 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 }
deymo@chromium.orgbae0f882013-01-31 06:08:02779 match_rules_added_.erase(match_rule);
780 }
781 return true;
satorux@chromium.org3beaaa4e2011-08-23 07:29:21782}
783
keybuk@google.com216ed0b2012-02-14 21:29:06784bool Bus::TryRegisterObjectPath(const ObjectPath& object_path,
satorux@chromium.orga51076112011-08-17 20:58:12785 const DBusObjectPathVTable* vtable,
786 void* user_data,
Hidehiko Abe3afb59a2023-07-06 07:34:38787 Error* error) {
Sonny Sasaka564474a2018-07-19 18:27:19788 return TryRegisterObjectPathInternal(
789 object_path, vtable, user_data, error,
790 dbus_connection_try_register_object_path);
791}
792
793bool Bus::TryRegisterFallback(const ObjectPath& object_path,
794 const DBusObjectPathVTable* vtable,
795 void* user_data,
Hidehiko Abe3afb59a2023-07-06 07:34:38796 Error* error) {
797 DCHECK(error);
Sonny Sasaka564474a2018-07-19 18:27:19798 return TryRegisterObjectPathInternal(object_path, vtable, user_data, error,
799 dbus_connection_try_register_fallback);
800}
801
802bool Bus::TryRegisterObjectPathInternal(
803 const ObjectPath& object_path,
804 const DBusObjectPathVTable* vtable,
805 void* user_data,
Hidehiko Abe3afb59a2023-07-06 07:34:38806 Error* error,
Sonny Sasaka564474a2018-07-19 18:27:19807 TryRegisterObjectPathFunction* register_function) {
satorux@chromium.orga51076112011-08-17 20:58:12808 DCHECK(connection_);
Hidehiko Abe3afb59a2023-07-06 07:34:38809 DCHECK(error);
satorux@chromium.orga51076112011-08-17 20:58:12810 AssertOnDBusThread();
Etienne Bergeron436d42212019-02-26 17:15:12811 base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
812 base::BlockingType::MAY_BLOCK);
satorux@chromium.orga51076112011-08-17 20:58:12813
Ho Cheung361ebe32023-08-16 16:29:27814 if (base::Contains(registered_object_paths_, object_path)) {
keybuk@google.com216ed0b2012-02-14 21:29:06815 LOG(ERROR) << "Object path already registered: " << object_path.value();
satorux@chromium.orgea78b1e2011-08-27 07:26:34816 return false;
817 }
satorux@chromium.org3beaaa4e2011-08-23 07:29:21818
Hidehiko Abe3afb59a2023-07-06 07:34:38819 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) {
satorux@chromium.org3beaaa4e2011-08-23 07:29:21824 registered_object_paths_.insert(object_path);
Hidehiko Abe3afb59a2023-07-06 07:34:38825 } else if (dbus_error.is_set()) {
826 *error = Error(dbus_error.name(), dbus_error.message());
827 }
satorux@chromium.org3beaaa4e2011-08-23 07:29:21828 return success;
satorux@chromium.orga51076112011-08-17 20:58:12829}
830
keybuk@google.com216ed0b2012-02-14 21:29:06831void Bus::UnregisterObjectPath(const ObjectPath& object_path) {
satorux@chromium.orga51076112011-08-17 20:58:12832 DCHECK(connection_);
833 AssertOnDBusThread();
834
Ho Cheung361ebe32023-08-16 16:29:27835 if (!base::Contains(registered_object_paths_, object_path)) {
satorux@chromium.orgea78b1e2011-08-27 07:26:34836 LOG(ERROR) << "Requested to unregister an unknown object path: "
keybuk@google.com216ed0b2012-02-14 21:29:06837 << object_path.value();
satorux@chromium.orgea78b1e2011-08-27 07:26:34838 return;
839 }
satorux@chromium.org3beaaa4e2011-08-23 07:29:21840
Etienne Bergeron436d42212019-02-26 17:15:12841 base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
842 base::BlockingType::MAY_BLOCK);
satorux@chromium.orga51076112011-08-17 20:58:12843 const bool success = dbus_connection_unregister_object_path(
844 connection_,
keybuk@google.com216ed0b2012-02-14 21:29:06845 object_path.value().c_str());
satorux@chromium.orga51076112011-08-17 20:58:12846 CHECK(success) << "Unable to allocate memory";
satorux@chromium.org3beaaa4e2011-08-23 07:29:21847 registered_object_paths_.erase(object_path);
satorux@chromium.orga51076112011-08-17 20:58:12848}
849
satorux@chromium.orge20d39fe2011-09-02 06:56:23850void Bus::ShutdownOnDBusThreadAndBlockInternal() {
satorux@chromium.orga51076112011-08-17 20:58:12851 AssertOnDBusThread();
852
853 ShutdownAndBlock();
satorux@chromium.orge20d39fe2011-09-02 06:56:23854 on_shutdown_.Signal();
satorux@chromium.orga51076112011-08-17 20:58:12855}
856
857void Bus::ProcessAllIncomingDataIfAny() {
858 AssertOnDBusThread();
859
860 // As mentioned at the class comment in .h file, connection_ can be NULL.
nona@chromium.org7c8f3ef2013-02-08 10:53:39861 if (!connection_)
satorux@chromium.orga51076112011-08-17 20:58:12862 return;
863
Etienne Bergeron436d42212019-02-26 17:15:12864 base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
865 base::BlockingType::MAY_BLOCK);
Etienne Pierre-Doray7f1f6062018-09-21 14:41:43866
nona@chromium.org7c8f3ef2013-02-08 10:53:39867 // It is safe and necessary to call dbus_connection_get_dispatch_status even
hashimotoe8aa0b4e2014-12-09 04:50:23868 // if the connection is lost.
satorux@chromium.orga51076112011-08-17 20:58:12869 if (dbus_connection_get_dispatch_status(connection_) ==
870 DBUS_DISPATCH_DATA_REMAINS) {
871 while (dbus_connection_dispatch(connection_) ==
thestig@chromium.org2a57ca642013-06-13 06:37:19872 DBUS_DISPATCH_DATA_REMAINS) {
873 }
satorux@chromium.orga51076112011-08-17 20:58:12874 }
875}
876
Gabriel Charettee926fc12019-12-16 19:00:02877base::SequencedTaskRunner* Bus::GetDBusTaskRunner() {
Wez811f6da42017-07-12 02:50:17878 if (dbus_task_runner_)
hashimoto@chromium.org8609be262013-09-26 04:32:29879 return dbus_task_runner_.get();
880 else
881 return GetOriginTaskRunner();
haruki@chromium.org45f23e892013-05-08 11:57:14882}
883
Gabriel Charettee926fc12019-12-16 19:00:02884base::SequencedTaskRunner* Bus::GetOriginTaskRunner() {
Wez811f6da42017-07-12 02:50:17885 DCHECK(origin_task_runner_);
hashimoto@chromium.org8609be262013-09-26 04:32:29886 return origin_task_runner_.get();
satorux@chromium.orga51076112011-08-17 20:58:12887}
888
889bool Bus::HasDBusThread() {
Wez811f6da42017-07-12 02:50:17890 return dbus_task_runner_ != nullptr;
satorux@chromium.orga51076112011-08-17 20:58:12891}
892
893void Bus::AssertOnOriginThread() {
Chinglin Yu26e25b82019-09-02 12:05:42894 if (origin_task_runner_) {
895 CHECK(origin_task_runner_->RunsTasksInCurrentSequence());
896 } else {
897 CHECK_EQ(origin_thread_id_, base::PlatformThread::CurrentId());
898 }
satorux@chromium.orga51076112011-08-17 20:58:12899}
900
901void Bus::AssertOnDBusThread() {
Wez811f6da42017-07-12 02:50:17902 if (dbus_task_runner_) {
Xiyuan Xiabbe93b12019-05-08 14:15:27903 CHECK(dbus_task_runner_->RunsTasksInCurrentSequence());
satorux@chromium.orga51076112011-08-17 20:58:12904 } else {
905 AssertOnOriginThread();
906 }
907}
908
thestig@chromium.org1db0b3572013-05-04 15:48:37909std::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
Hidehiko Abeac7a3c52023-07-06 11:18:10926 auto result = SendWithReplyAndBlock(get_name_owner_call.raw_message(),
927 ObjectProxy::TIMEOUT_USE_DEFAULT);
928 if (!result.has_value()) {
thestig@chromium.org1db0b3572013-05-04 15:48:37929 if (options == REPORT_ERRORS) {
Hidehiko Abeac7a3c52023-07-06 11:18:10930 LOG(ERROR) << "Failed to get name owner. Got " << result.error().name()
931 << ": " << result.error().message();
thestig@chromium.org1db0b3572013-05-04 15:48:37932 }
933 return "";
934 }
935
Hidehiko Abeac7a3c52023-07-06 11:18:10936 MessageReader reader(result->get());
thestig@chromium.org1db0b3572013-05-04 15:48:37937 std::string service_owner;
938 if (!reader.PopString(&service_owner))
939 service_owner.clear();
940 return service_owner;
941}
942
943void Bus::GetServiceOwner(const std::string& service_name,
Reilly Grantd4e66132019-11-22 17:14:50944 GetServiceOwnerCallback callback) {
thestig@chromium.org1db0b3572013-05-04 15:48:37945 AssertOnOriginThread();
946
hashimoto@chromium.org8609be262013-09-26 04:32:29947 GetDBusTaskRunner()->PostTask(
kylechar39c39282019-02-19 19:04:04948 FROM_HERE, base::BindOnce(&Bus::GetServiceOwnerInternal, this,
Reilly Grantd4e66132019-11-22 17:14:50949 service_name, std::move(callback)));
thestig@chromium.org1db0b3572013-05-04 15:48:37950}
951
952void Bus::GetServiceOwnerInternal(const std::string& service_name,
Reilly Grantd4e66132019-11-22 17:14:50953 GetServiceOwnerCallback callback) {
thestig@chromium.org1db0b3572013-05-04 15:48:37954 AssertOnDBusThread();
955
956 std::string service_owner;
957 if (Connect())
thestig@chromium.org8a3a8d62013-05-08 20:47:18958 service_owner = GetServiceOwnerAndBlock(service_name, SUPPRESS_ERRORS);
Reilly Grantd4e66132019-11-22 17:14:50959 GetOriginTaskRunner()->PostTask(
960 FROM_HERE, base::BindOnce(std::move(callback), service_owner));
thestig@chromium.org1db0b3572013-05-04 15:48:37961}
962
thestig@chromium.org049616e2013-06-10 22:52:34963void Bus::ListenForServiceOwnerChange(
964 const std::string& service_name,
Reilly Grantd4e66132019-11-22 17:14:50965 const ServiceOwnerChangeCallback& callback) {
thestig@chromium.org049616e2013-06-10 22:52:34966 AssertOnOriginThread();
967 DCHECK(!service_name.empty());
968 DCHECK(!callback.is_null());
969
hashimoto@chromium.org8609be262013-09-26 04:32:29970 GetDBusTaskRunner()->PostTask(
kylechar39c39282019-02-19 19:04:04971 FROM_HERE, base::BindOnce(&Bus::ListenForServiceOwnerChangeInternal, this,
972 service_name, callback));
thestig@chromium.org049616e2013-06-10 22:52:34973}
974
975void Bus::ListenForServiceOwnerChangeInternal(
976 const std::string& service_name,
Reilly Grantd4e66132019-11-22 17:14:50977 const ServiceOwnerChangeCallback& callback) {
thestig@chromium.org049616e2013-06-10 22:52:34978 AssertOnDBusThread();
979 DCHECK(!service_name.empty());
980 DCHECK(!callback.is_null());
981
982 if (!Connect() || !SetUpAsyncOperations())
983 return;
984
hashimotob3870312014-12-04 07:41:55985 if (service_owner_changed_listener_map_.empty())
986 AddFilterFunction(Bus::OnServiceOwnerChangedFilter, this);
thestig@chromium.org049616e2013-06-10 22:52:34987
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());
Hidehiko Abe3afb59a2023-07-06 07:34:38995 dbus::Error error;
996 AddMatch(name_owner_changed_match_rule, &error);
997 if (error.IsValid()) {
thestig@chromium.org049616e2013-06-10 22:52:34998 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.
Reilly Grantd4e66132019-11-22 17:14:501008 std::vector<ServiceOwnerChangeCallback>& callbacks = it->second;
thestig@chromium.org049616e2013-06-10 22:52:341009 for (size_t i = 0; i < callbacks.size(); ++i) {
Robert Liaof5c78372019-06-05 04:03:491010 if (callbacks[i] == callback)
thestig@chromium.org049616e2013-06-10 22:52:341011 return;
1012 }
1013 callbacks.push_back(callback);
1014}
1015
1016void Bus::UnlistenForServiceOwnerChange(
1017 const std::string& service_name,
Reilly Grantd4e66132019-11-22 17:14:501018 const ServiceOwnerChangeCallback& callback) {
thestig@chromium.org049616e2013-06-10 22:52:341019 AssertOnOriginThread();
1020 DCHECK(!service_name.empty());
1021 DCHECK(!callback.is_null());
1022
hashimoto@chromium.org8609be262013-09-26 04:32:291023 GetDBusTaskRunner()->PostTask(
kylechar39c39282019-02-19 19:04:041024 FROM_HERE, base::BindOnce(&Bus::UnlistenForServiceOwnerChangeInternal,
1025 this, service_name, callback));
thestig@chromium.org049616e2013-06-10 22:52:341026}
1027
1028void Bus::UnlistenForServiceOwnerChangeInternal(
1029 const std::string& service_name,
Reilly Grantd4e66132019-11-22 17:14:501030 const ServiceOwnerChangeCallback& callback) {
thestig@chromium.org049616e2013-06-10 22:52:341031 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
Reilly Grantd4e66132019-11-22 17:14:501040 std::vector<ServiceOwnerChangeCallback>& callbacks = it->second;
thestig@chromium.org049616e2013-06-10 22:52:341041 for (size_t i = 0; i < callbacks.size(); ++i) {
Robert Liaof5c78372019-06-05 04:03:491042 if (callbacks[i] == callback) {
thestig@chromium.org049616e2013-06-10 22:52:341043 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());
Hidehiko Abe3afb59a2023-07-06 07:34:381054 Error error;
1055 RemoveMatch(name_owner_changed_match_rule, &error);
1056 // And remove |service_owner_changed_lister_map_| entry.
thestig@chromium.org049616e2013-06-10 22:52:341057 service_owner_changed_listener_map_.erase(it);
1058
hashimotob3870312014-12-04 07:41:551059 if (service_owner_changed_listener_map_.empty())
1060 RemoveFilterFunction(Bus::OnServiceOwnerChangedFilter, this);
thestig@chromium.org049616e2013-06-10 22:52:341061}
1062
zqiuf63bfe5e2015-07-08 02:08:301063std::string Bus::GetConnectionName() {
1064 if (!connection_)
1065 return "";
1066 return dbus_bus_get_unique_name(connection_);
1067}
1068
Sonny Sasaka59bc1c02018-08-16 05:09:201069bool Bus::IsConnected() {
1070 return connection_ != nullptr;
1071}
1072
satorux@chromium.orga51076112011-08-17 20:58:121073dbus_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
1085void Bus::OnRemoveWatch(DBusWatch* raw_watch) {
1086 AssertOnDBusThread();
1087
Etienne Bergeron436d42212019-02-26 17:15:121088 base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
1089 base::BlockingType::MAY_BLOCK);
satorux@chromium.orga51076112011-08-17 20:58:121090 Watch* watch = static_cast<Watch*>(dbus_watch_get_data(raw_watch));
1091 delete watch;
1092 --num_pending_watches_;
1093}
1094
1095void Bus::OnToggleWatch(DBusWatch* raw_watch) {
1096 AssertOnDBusThread();
1097
Etienne Bergeron436d42212019-02-26 17:15:121098 base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
1099 base::BlockingType::MAY_BLOCK);
satorux@chromium.orga51076112011-08-17 20:58:121100 Watch* watch = static_cast<Watch*>(dbus_watch_get_data(raw_watch));
fdorayebc379c2017-04-18 13:40:211101 if (watch->IsReadyToBeWatched())
satorux@chromium.orga51076112011-08-17 20:58:121102 watch->StartWatching();
fdorayebc379c2017-04-18 13:40:211103 else
satorux@chromium.orga51076112011-08-17 20:58:121104 watch->StopWatching();
satorux@chromium.orga51076112011-08-17 20:58:121105}
1106
1107dbus_bool_t Bus::OnAddTimeout(DBusTimeout* raw_timeout) {
1108 AssertOnDBusThread();
1109
Wez811f6da42017-07-12 02:50:171110 // |timeout| will be deleted by OnRemoveTimeoutThunk().
satorux@chromium.orga51076112011-08-17 20:58:121111 Timeout* timeout = new Timeout(raw_timeout);
1112 if (timeout->IsReadyToBeMonitored()) {
1113 timeout->StartMonitoring(this);
1114 }
1115 ++num_pending_timeouts_;
1116 return true;
1117}
1118
1119void Bus::OnRemoveTimeout(DBusTimeout* raw_timeout) {
1120 AssertOnDBusThread();
1121
Etienne Bergeron436d42212019-02-26 17:15:121122 base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
1123 base::BlockingType::MAY_BLOCK);
satorux@chromium.orga51076112011-08-17 20:58:121124 Timeout* timeout = static_cast<Timeout*>(dbus_timeout_get_data(raw_timeout));
Wez811f6da42017-07-12 02:50:171125 delete timeout;
satorux@chromium.orga51076112011-08-17 20:58:121126 --num_pending_timeouts_;
1127}
1128
1129void Bus::OnToggleTimeout(DBusTimeout* raw_timeout) {
1130 AssertOnDBusThread();
1131
Etienne Bergeron436d42212019-02-26 17:15:121132 base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
1133 base::BlockingType::MAY_BLOCK);
satorux@chromium.orga51076112011-08-17 20:58:121134 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
1142void Bus::OnDispatchStatusChanged(DBusConnection* connection,
1143 DBusDispatchStatus status) {
1144 DCHECK_EQ(connection, connection_);
1145 AssertOnDBusThread();
1146
satorux@chromium.orga51076112011-08-17 20:58:121147 // 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().
kylechar39c39282019-02-19 19:04:041151 GetDBusTaskRunner()->PostTask(
1152 FROM_HERE, base::BindOnce(&Bus::ProcessAllIncomingDataIfAny, this));
satorux@chromium.orga51076112011-08-17 20:58:121153}
1154
thestig@chromium.org049616e2013-06-10 22:52:341155void 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);
dcheng2a193282016-04-08 22:55:041162 std::unique_ptr<Signal> signal(Signal::FromRawMessage(message));
thestig@chromium.org049616e2013-06-10 22:52:341163
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
Reilly Grantd4e66132019-11-22 17:14:501186 const std::vector<ServiceOwnerChangeCallback>& callbacks = it->second;
thestig@chromium.org049616e2013-06-10 22:52:341187 for (size_t i = 0; i < callbacks.size(); ++i) {
hashimoto@chromium.org8609be262013-09-26 04:32:291188 GetOriginTaskRunner()->PostTask(FROM_HERE,
kylechar39c39282019-02-19 19:04:041189 base::BindOnce(callbacks[i], new_owner));
thestig@chromium.org049616e2013-06-10 22:52:341190 }
1191}
1192
1193// static
satorux@chromium.orga51076112011-08-17 20:58:121194dbus_bool_t Bus::OnAddWatchThunk(DBusWatch* raw_watch, void* data) {
1195 Bus* self = static_cast<Bus*>(data);
1196 return self->OnAddWatch(raw_watch);
1197}
1198
thestig@chromium.org049616e2013-06-10 22:52:341199// static
satorux@chromium.orga51076112011-08-17 20:58:121200void Bus::OnRemoveWatchThunk(DBusWatch* raw_watch, void* data) {
1201 Bus* self = static_cast<Bus*>(data);
jhawkins@chromium.org3ca1d592012-04-27 19:40:421202 self->OnRemoveWatch(raw_watch);
satorux@chromium.orga51076112011-08-17 20:58:121203}
1204
thestig@chromium.org049616e2013-06-10 22:52:341205// static
satorux@chromium.orga51076112011-08-17 20:58:121206void Bus::OnToggleWatchThunk(DBusWatch* raw_watch, void* data) {
1207 Bus* self = static_cast<Bus*>(data);
jhawkins@chromium.org3ca1d592012-04-27 19:40:421208 self->OnToggleWatch(raw_watch);
satorux@chromium.orga51076112011-08-17 20:58:121209}
1210
thestig@chromium.org049616e2013-06-10 22:52:341211// static
satorux@chromium.orga51076112011-08-17 20:58:121212dbus_bool_t Bus::OnAddTimeoutThunk(DBusTimeout* raw_timeout, void* data) {
1213 Bus* self = static_cast<Bus*>(data);
1214 return self->OnAddTimeout(raw_timeout);
1215}
1216
thestig@chromium.org049616e2013-06-10 22:52:341217// static
satorux@chromium.orga51076112011-08-17 20:58:121218void Bus::OnRemoveTimeoutThunk(DBusTimeout* raw_timeout, void* data) {
1219 Bus* self = static_cast<Bus*>(data);
jhawkins@chromium.org3ca1d592012-04-27 19:40:421220 self->OnRemoveTimeout(raw_timeout);
satorux@chromium.orga51076112011-08-17 20:58:121221}
1222
thestig@chromium.org049616e2013-06-10 22:52:341223// static
satorux@chromium.orga51076112011-08-17 20:58:121224void Bus::OnToggleTimeoutThunk(DBusTimeout* raw_timeout, void* data) {
1225 Bus* self = static_cast<Bus*>(data);
jhawkins@chromium.org3ca1d592012-04-27 19:40:421226 self->OnToggleTimeout(raw_timeout);
satorux@chromium.orga51076112011-08-17 20:58:121227}
1228
thestig@chromium.org049616e2013-06-10 22:52:341229// static
satorux@chromium.orga51076112011-08-17 20:58:121230void Bus::OnDispatchStatusChangedThunk(DBusConnection* connection,
1231 DBusDispatchStatus status,
1232 void* data) {
1233 Bus* self = static_cast<Bus*>(data);
jhawkins@chromium.org3ca1d592012-04-27 19:40:421234 self->OnDispatchStatusChanged(connection, status);
satorux@chromium.orga51076112011-08-17 20:58:121235}
1236
thestig@chromium.org049616e2013-06-10 22:52:341237// static
nona@chromium.org7c8f3ef2013-02-08 10:53:391238DBusHandlerResult Bus::OnConnectionDisconnectedFilter(
thestig@chromium.org200328a2013-02-20 01:36:531239 DBusConnection* connection,
1240 DBusMessage* message,
1241 void* data) {
nona@chromium.org7c8f3ef2013-02-08 10:53:391242 if (dbus_message_is_signal(message,
1243 DBUS_INTERFACE_LOCAL,
1244 kDisconnectedSignal)) {
hashimotoe8aa0b4e2014-12-09 04:50:231245 // Abort when the connection is lost.
1246 LOG(FATAL) << "D-Bus connection was disconnected. Aborting.";
nona@chromium.org7c8f3ef2013-02-08 10:53:391247 }
1248 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1249}
1250
thestig@chromium.org049616e2013-06-10 22:52:341251// static
1252DBusHandlerResult 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
satorux@chromium.orga51076112011-08-17 20:58:121267} // namespace dbus