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.
5 #include "dbus/object_proxy.h"
10 #include "base/containers/contains.h"
11 #include "base/debug/alias.h"
12 #include "base/debug/leak_annotations.h"
13 #include "base/functional/bind.h"
14 #include "base/functional/callback_helpers.h"
15 #include "base/logging.h"
16 #include "base/strings/string_piece.h"
17 #include "base/strings/stringprintf.h"
18 #include "base/task/sequenced_task_runner.h"
19 #include "base/threading/scoped_blocking_call.h"
20 #include "base/threading/thread.h"
21 #include "base/threading/thread_restrictions.h"
23 #include "dbus/dbus_statistics.h"
24 #include "dbus/error.h"
25 #include "dbus/message.h"
26 #include "dbus/object_path.h"
27 #include "dbus/scoped_dbus_error.h"
28 #include "dbus/util.h"
34 constexpr char kErrorServiceUnknown[] =
35 "org.freedesktop.DBus.Error.ServiceUnknown";
36 constexpr char kErrorObjectUnknown[] =
37 "org.freedesktop.DBus.Error.UnknownObject";
39 // The path of D-Bus Object sending NameOwnerChanged signal.
40 constexpr char kDBusSystemObjectPath[] = "/org/freedesktop/DBus";
42 // The D-Bus Object interface.
43 constexpr char kDBusSystemObjectInterface[] = "org.freedesktop.DBus";
45 // The D-Bus Object address.
46 constexpr char kDBusSystemObjectAddress[] = "org.freedesktop.DBus";
48 // The NameOwnerChanged member in |kDBusSystemObjectInterface|.
49 constexpr char kNameOwnerChangedMember[] = "NameOwnerChanged";
53 ObjectProxy::ReplyCallbackHolder::ReplyCallbackHolder(
54 scoped_refptr<base::SequencedTaskRunner> origin_task_runner,
55 ResponseOrErrorCallback callback)
56 : origin_task_runner_(std::move(origin_task_runner)),
57 callback_(std::move(callback)) {
58 DCHECK(origin_task_runner_.get());
59 DCHECK(!callback_.is_null());
62 ObjectProxy::ReplyCallbackHolder::ReplyCallbackHolder(
63 ReplyCallbackHolder&& other) = default;
65 ObjectProxy::ReplyCallbackHolder::~ReplyCallbackHolder() {
66 if (callback_.is_null()) {
67 // This is the regular case.
68 // CallMethod and its family creates this object on the origin thread,
69 // PostTask()s to the D-Bus thread for actual D-Bus communication,
70 // then PostTask()s back to the origin thread to invoke the |callback_|.
71 // At that timing, the ownership of callback should be released via
73 // Otherwise, this instance was moved to another one. Do nothing in
78 // The only case where |origin_task_runner_| becomes nullptr is that
79 // this is moved. In such a case, |callback_| should be nullptr, too, so it
80 // should be handled above. Thus, here |origin_task_runner_| must not be
82 DCHECK(origin_task_runner_.get());
84 if (origin_task_runner_->RunsTasksInCurrentSequence()) {
85 // Destroyed on the origin thread. This happens when PostTask()ing to
86 // the D-Bus thread fails. The |callback_| can be destroyed on the
87 // current thread safely. Do nothing here, and let member destruction
88 // destroy the callback.
92 // Here is on D-Bus thread, so try to PostTask() to destroy the callback.
93 // to the origin thread.
94 // The |origin_task_runner_| may already have stopped. E.g., on Chrome's
95 // shutdown the message loop of the UI thread (= the origin thread) stops
96 // before D-Bus threaed's. In such a case, PostTask() fails. Because we
97 // cannot do much thing here, instead, simply leak the callback rather than
98 // destroying it on the D-Bus thread, which could be unexpected from the
99 // direct or indirect caller of CallMethod.
100 auto* callback_to_be_deleted =
101 new ResponseOrErrorCallback(std::move(callback_));
102 ANNOTATE_LEAKING_OBJECT_PTR(callback_to_be_deleted);
103 origin_task_runner_->PostTask(
104 FROM_HERE, base::BindOnce(&base::DeletePointer<ResponseOrErrorCallback>,
105 callback_to_be_deleted));
108 ObjectProxy::ResponseOrErrorCallback
109 ObjectProxy::ReplyCallbackHolder::ReleaseCallback() {
110 DCHECK(origin_task_runner_->RunsTasksInCurrentSequence());
111 return std::move(callback_);
114 ObjectProxy::ObjectProxy(Bus* bus,
115 const std::string& service_name,
116 const ObjectPath& object_path,
119 service_name_(service_name),
120 object_path_(object_path),
121 ignore_service_unknown_errors_(options & IGNORE_SERVICE_UNKNOWN_ERRORS) {
122 LOG_IF(FATAL, !object_path_.IsValid()) << object_path_.value();
125 ObjectProxy::~ObjectProxy() {
126 DCHECK(pending_calls_.empty());
129 // Originally we tried to make |method_call| a const reference, but we
130 // gave up as dbus_connection_send_with_reply_and_block() takes a
131 // non-const pointer of DBusMessage as the second parameter.
132 base::expected<std::unique_ptr<Response>, Error>
133 ObjectProxy::CallMethodAndBlock(MethodCall* method_call, int timeout_ms) {
134 bus_->AssertOnDBusThread();
136 if (!bus_->Connect() || !method_call->SetDestination(service_name_) ||
137 !method_call->SetPath(object_path_)) {
138 // Not an error from libdbus, so returns invalid error.
139 return base::unexpected(Error());
142 // Send the message synchronously.
144 bus_->SendWithReplyAndBlock(method_call->raw_message(), timeout_ms);
145 statistics::AddBlockingSentMethodCall(
146 service_name_, method_call->GetInterface(), method_call->GetMember());
147 if (!result.has_value()) {
148 LogMethodCallFailure(method_call->GetInterface(), method_call->GetMember(),
149 result.error().name(), result.error().message());
154 void ObjectProxy::CallMethod(MethodCall* method_call,
156 ResponseCallback callback) {
157 auto internal_callback = base::BindOnce(
158 &ObjectProxy::OnCallMethod, this, method_call->GetInterface(),
159 method_call->GetMember(), std::move(callback));
161 CallMethodWithErrorResponse(method_call, timeout_ms,
162 std::move(internal_callback));
165 void ObjectProxy::CallMethodWithErrorResponse(
166 MethodCall* method_call,
168 ResponseOrErrorCallback callback) {
169 bus_->AssertOnOriginThread();
171 ReplyCallbackHolder callback_holder(bus_->GetOriginTaskRunner(),
172 std::move(callback));
174 if (!method_call->SetDestination(service_name_) ||
175 !method_call->SetPath(object_path_)) {
176 // In case of a failure, run the error callback with nullptr.
177 base::OnceClosure task =
178 base::BindOnce(&ObjectProxy::RunResponseOrErrorCallback, this,
179 std::move(callback_holder), nullptr /* response */,
180 nullptr /* error_response */);
181 bus_->GetOriginTaskRunner()->PostTask(FROM_HERE, std::move(task));
185 // Increment the reference count so we can safely reference the
186 // underlying request message until the method call is complete. This
187 // will be unref'ed in StartAsyncMethodCall().
188 DBusMessage* request_message = method_call->raw_message();
189 dbus_message_ref(request_message);
191 statistics::AddSentMethodCall(service_name_, method_call->GetInterface(),
192 method_call->GetMember());
194 // Wait for the response in the D-Bus thread.
195 base::OnceClosure task =
196 base::BindOnce(&ObjectProxy::StartAsyncMethodCall, this, timeout_ms,
197 request_message, std::move(callback_holder));
198 bus_->GetDBusTaskRunner()->PostTask(FROM_HERE, std::move(task));
201 void ObjectProxy::CallMethodWithErrorCallback(MethodCall* method_call,
203 ResponseCallback callback,
204 ErrorCallback error_callback) {
205 auto internal_callback = base::BindOnce(
206 [](ResponseCallback callback, ErrorCallback error_callback,
207 Response* response, ErrorResponse* error_response) {
209 std::move(callback).Run(response);
211 std::move(error_callback).Run(error_response);
214 std::move(callback), std::move(error_callback));
216 CallMethodWithErrorResponse(method_call, timeout_ms,
217 std::move(internal_callback));
220 void ObjectProxy::ConnectToSignal(const std::string& interface_name,
221 const std::string& signal_name,
222 SignalCallback signal_callback,
223 OnConnectedCallback on_connected_callback) {
224 bus_->AssertOnOriginThread();
226 if (bus_->HasDBusThread()) {
227 bus_->GetDBusTaskRunner()->PostTaskAndReplyWithResult(
229 base::BindOnce(&ObjectProxy::ConnectToSignalAndBlock, this,
230 interface_name, signal_name, signal_callback),
231 base::BindOnce(std::move(on_connected_callback), interface_name,
234 // If the bus doesn't have a dedicated dbus thread we need to call
235 // ConnectToSignalAndBlock directly otherwise we might miss a signal
236 // that is currently queued if we do a PostTask.
238 ConnectToSignalAndBlock(interface_name, signal_name, signal_callback);
239 std::move(on_connected_callback).Run(interface_name, signal_name, success);
243 bool ObjectProxy::ConnectToSignalAndBlock(const std::string& interface_name,
244 const std::string& signal_name,
245 SignalCallback signal_callback) {
246 bus_->AssertOnDBusThread();
248 if (!ConnectToNameOwnerChangedSignal())
251 const std::string absolute_signal_name =
252 GetAbsoluteMemberName(interface_name, signal_name);
254 // Add a match rule so the signal goes through HandleMessage().
255 const std::string match_rule = base::StringPrintf(
256 "type='signal', sender='%s', interface='%s', path='%s'",
257 service_name_.c_str(), interface_name.c_str(),
258 object_path_.value().c_str());
259 return AddMatchRuleWithCallback(match_rule, absolute_signal_name,
263 void ObjectProxy::SetNameOwnerChangedCallback(
264 NameOwnerChangedCallback callback) {
265 bus_->AssertOnOriginThread();
267 name_owner_changed_callback_ = callback;
269 bus_->GetDBusTaskRunner()->PostTask(
271 base::BindOnce(&ObjectProxy::TryConnectToNameOwnerChangedSignal, this));
274 void ObjectProxy::WaitForServiceToBeAvailable(
275 WaitForServiceToBeAvailableCallback callback) {
276 bus_->AssertOnOriginThread();
278 wait_for_service_to_be_available_callbacks_.push_back(std::move(callback));
279 bus_->GetDBusTaskRunner()->PostTask(
281 base::BindOnce(&ObjectProxy::WaitForServiceToBeAvailableInternal, this));
284 void ObjectProxy::Detach() {
285 bus_->AssertOnDBusThread();
287 if (bus_->IsConnected())
288 bus_->RemoveFilterFunction(&ObjectProxy::HandleMessageThunk, this);
290 for (const auto& match_rule : match_rules_) {
292 bus_->RemoveMatch(match_rule, &error);
293 if (error.IsValid()) {
294 // There is nothing we can do to recover, so just print the error.
295 LOG(ERROR) << "Failed to remove match rule: " << match_rule;
298 match_rules_.clear();
300 for (auto* pending_call : pending_calls_) {
301 base::ScopedBlockingCall scoped_blocking_call(
302 FROM_HERE, base::BlockingType::MAY_BLOCK);
304 dbus_pending_call_cancel(pending_call);
305 dbus_pending_call_unref(pending_call);
307 pending_calls_.clear();
310 void ObjectProxy::StartAsyncMethodCall(int timeout_ms,
311 DBusMessage* request_message,
312 ReplyCallbackHolder callback_holder) {
313 bus_->AssertOnDBusThread();
314 base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
315 base::BlockingType::MAY_BLOCK);
317 if (!bus_->Connect() || !bus_->SetUpAsyncOperations()) {
318 // In case of a failure, run the error callback with nullptr.
319 base::OnceClosure task =
320 base::BindOnce(&ObjectProxy::RunResponseOrErrorCallback, this,
321 std::move(callback_holder), nullptr /* response */,
322 nullptr /* error_response */);
323 bus_->GetOriginTaskRunner()->PostTask(FROM_HERE, std::move(task));
325 dbus_message_unref(request_message);
329 DBusPendingCall* dbus_pending_call = nullptr;
330 bus_->SendWithReply(request_message, &dbus_pending_call, timeout_ms);
332 using PendingCallback =
333 base::OnceCallback<void(DBusPendingCall * pending_call)>;
334 // This returns false only when unable to allocate memory.
335 const bool success = dbus_pending_call_set_notify(
337 [](DBusPendingCall* pending_call, void* user_data) {
338 std::move(*static_cast<PendingCallback*>(user_data)).Run(pending_call);
340 // PendingCallback instance is owned by libdbus.
341 new PendingCallback(base::BindOnce(&ObjectProxy::OnPendingCallIsComplete,
342 this, std::move(callback_holder))),
343 [](void* user_data) { delete static_cast<PendingCallback*>(user_data); });
344 CHECK(success) << "Unable to allocate memory";
345 pending_calls_.insert(dbus_pending_call);
347 // It's now safe to unref the request message.
348 dbus_message_unref(request_message);
351 void ObjectProxy::OnPendingCallIsComplete(ReplyCallbackHolder callback_holder,
352 DBusPendingCall* pending_call) {
353 bus_->AssertOnDBusThread();
354 base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
355 base::BlockingType::MAY_BLOCK);
357 DBusMessage* response_message = dbus_pending_call_steal_reply(pending_call);
359 // Either |response| or |error_response| takes ownership of the
360 // |response_message|.
361 std::unique_ptr<Response> response;
362 std::unique_ptr<ErrorResponse> error_response;
363 if (dbus_message_get_type(response_message) == DBUS_MESSAGE_TYPE_ERROR) {
364 error_response = ErrorResponse::FromRawMessage(response_message);
366 response = Response::FromRawMessage(response_message);
369 base::OnceClosure task = base::BindOnce(
370 &ObjectProxy::RunResponseOrErrorCallback, this,
371 std::move(callback_holder), response.get(), error_response.get());
373 // The message should be deleted on the D-Bus thread for a complicated
376 // libdbus keeps track of the number of bytes in the incoming message
377 // queue to ensure that the data size in the queue is manageable. The
378 // bookkeeping is partly done via dbus_message_unref(), and immediately
379 // asks the client code (Chrome) to stop monitoring the underlying
380 // socket, if the number of bytes exceeds a certian number, which is set
381 // to 63MB, per dbus-transport.cc:
383 // /* Try to default to something that won't totally hose the system,
384 // * but doesn't impose too much of a limitation.
386 // transport->max_live_messages_size = _DBUS_ONE_MEGABYTE * 63;
388 // The monitoring of the socket is done on the D-Bus thread (see Watch
389 // class in bus.cc), hence we should stop the monitoring on D-Bus thread.
390 bus_->GetOriginTaskRunner()->PostTaskAndReply(
391 FROM_HERE, std::move(task),
393 [](Response* response, ErrorResponse* error_response) {
396 base::Owned(response.release()),
397 base::Owned(error_response.release())));
399 // Remove the pending call from the set.
400 pending_calls_.erase(pending_call);
401 dbus_pending_call_unref(pending_call);
404 void ObjectProxy::RunResponseOrErrorCallback(
405 ReplyCallbackHolder callback_holder,
407 ErrorResponse* error_response) {
408 bus_->AssertOnOriginThread();
409 callback_holder.ReleaseCallback().Run(response, error_response);
412 bool ObjectProxy::ConnectToNameOwnerChangedSignal() {
413 bus_->AssertOnDBusThread();
415 if (!bus_->Connect() || !bus_->SetUpAsyncOperations())
418 bus_->AddFilterFunction(&ObjectProxy::HandleMessageThunk, this);
420 // Add a match_rule listening NameOwnerChanged for the well-known name
422 const std::string name_owner_changed_match_rule = base::StringPrintf(
423 "type='signal',interface='org.freedesktop.DBus',"
424 "member='NameOwnerChanged',path='/org/freedesktop/DBus',"
425 "sender='org.freedesktop.DBus',arg0='%s'",
426 service_name_.c_str());
428 const bool success = AddMatchRuleWithoutCallback(
429 name_owner_changed_match_rule, "org.freedesktop.DBus.NameOwnerChanged");
431 // Try getting the current name owner. It's not guaranteed that we can get
432 // the name owner at this moment, as the service may not yet be started. If
433 // that's the case, we'll get the name owner via NameOwnerChanged signal,
434 // as soon as the service is started.
435 UpdateNameOwnerAndBlock();
440 void ObjectProxy::TryConnectToNameOwnerChangedSignal() {
441 bus_->AssertOnDBusThread();
443 bool success = ConnectToNameOwnerChangedSignal();
444 LOG_IF(WARNING, !success)
445 << "Failed to connect to NameOwnerChanged signal for object: "
446 << object_path_.value();
449 void ObjectProxy::WaitForServiceToBeAvailableInternal() {
450 bus_->AssertOnDBusThread();
452 if (!ConnectToNameOwnerChangedSignal()) { // Failed to connect to the signal.
453 const bool service_is_ready = false;
454 bus_->GetOriginTaskRunner()->PostTask(
456 base::BindOnce(&ObjectProxy::RunWaitForServiceToBeAvailableCallbacks,
457 this, service_is_ready));
461 const bool service_is_available = !service_name_owner_.empty();
462 if (service_is_available) { // Service is already available.
463 bus_->GetOriginTaskRunner()->PostTask(
465 base::BindOnce(&ObjectProxy::RunWaitForServiceToBeAvailableCallbacks,
466 this, service_is_available));
471 DBusHandlerResult ObjectProxy::HandleMessage(DBusConnection* connection,
472 DBusMessage* raw_message) {
473 bus_->AssertOnDBusThread();
475 if (dbus_message_get_type(raw_message) != DBUS_MESSAGE_TYPE_SIGNAL)
476 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
478 // raw_message will be unrefed on exit of the function. Increment the
479 // reference so we can use it in Signal.
480 dbus_message_ref(raw_message);
481 std::unique_ptr<Signal> signal(Signal::FromRawMessage(raw_message));
483 // Verify the signal comes from the object we're proxying for, this is
484 // our last chance to return DBUS_HANDLER_RESULT_NOT_YET_HANDLED and
485 // allow other object proxies to handle instead.
486 const ObjectPath path = signal->GetPath();
487 if (path != object_path_) {
488 if (path.value() == kDBusSystemObjectPath &&
489 signal->GetMember() == kNameOwnerChangedMember) {
490 // Handle NameOwnerChanged separately
491 return HandleNameOwnerChanged(std::move(signal));
493 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
496 std::string sender = signal->GetSender();
497 // Ignore message from sender we are not interested in.
498 if (service_name_owner_ != sender)
499 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
501 const std::string interface = signal->GetInterface();
502 const std::string member = signal->GetMember();
504 statistics::AddReceivedSignal(service_name_, interface, member);
506 // Check if we know about the signal.
507 const std::string absolute_signal_name =
508 GetAbsoluteMemberName(interface, member);
509 MethodTable::const_iterator iter = method_table_.find(absolute_signal_name);
510 if (iter == method_table_.end()) {
511 // Don't know about the signal.
512 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
514 VLOG(1) << "Signal received: " << signal->ToString();
516 if (bus_->HasDBusThread()) {
517 // Post a task to run the method in the origin thread.
518 // Transfer the ownership of |signal| to RunMethod().
519 // |released_signal| will be deleted in RunMethod().
520 Signal* released_signal = signal.release();
521 bus_->GetOriginTaskRunner()->PostTask(
522 FROM_HERE, base::BindOnce(&ObjectProxy::RunMethod, this, iter->second,
525 // If the D-Bus thread is not used, just call the callback on the
526 // current thread. Transfer the ownership of |signal| to RunMethod().
527 Signal* released_signal = signal.release();
528 RunMethod(iter->second, released_signal);
531 // We don't return DBUS_HANDLER_RESULT_HANDLED for signals because other
532 // objects may be interested in them. (e.g. Signals from org.freedesktop.DBus)
533 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
536 void ObjectProxy::RunMethod(std::vector<SignalCallback> signal_callbacks,
538 bus_->AssertOnOriginThread();
540 for (auto& signal_callback : signal_callbacks) {
541 signal_callback.Run(signal);
544 // Delete the message on the D-Bus thread. See comments in
545 // RunResponseOrErrorCallback().
546 bus_->GetDBusTaskRunner()->PostTask(
547 FROM_HERE, base::BindOnce(&base::DeletePointer<Signal>, signal));
550 DBusHandlerResult ObjectProxy::HandleMessageThunk(DBusConnection* connection,
551 DBusMessage* raw_message,
553 ObjectProxy* self = reinterpret_cast<ObjectProxy*>(user_data);
554 return self->HandleMessage(connection, raw_message);
557 void ObjectProxy::LogMethodCallFailure(
558 const base::StringPiece& interface_name,
559 const base::StringPiece& method_name,
560 const base::StringPiece& error_name,
561 const base::StringPiece& error_message) const {
562 if (ignore_service_unknown_errors_ &&
563 (error_name == kErrorServiceUnknown || error_name == kErrorObjectUnknown))
566 std::ostringstream msg;
567 msg << "Failed to call method: " << interface_name << "." << method_name
568 << ": object_path= " << object_path_.value() << ": " << error_name << ": "
571 // "UnknownObject" indicates that an object or service is no longer available,
572 // e.g. a Shill network service has gone out of range. Treat these as warnings
574 if (error_name == kErrorObjectUnknown)
575 LOG(WARNING) << msg.str();
577 LOG(ERROR) << msg.str();
580 void ObjectProxy::OnCallMethod(const std::string& interface_name,
581 const std::string& method_name,
582 ResponseCallback response_callback,
584 ErrorResponse* error_response) {
586 // Method call was successful.
587 std::move(response_callback).Run(response);
590 // Method call failed.
591 std::string error_name;
592 std::string error_message;
593 if (error_response) {
594 // Error message may contain the error message as string.
595 error_name = error_response->GetErrorName();
596 MessageReader reader(error_response);
597 reader.PopString(&error_message);
599 error_name = "unknown error type";
601 LogMethodCallFailure(interface_name, method_name, error_name, error_message);
603 std::move(response_callback).Run(nullptr);
606 bool ObjectProxy::AddMatchRuleWithCallback(
607 const std::string& match_rule,
608 const std::string& absolute_signal_name,
609 SignalCallback signal_callback) {
610 DCHECK(!match_rule.empty());
611 DCHECK(!absolute_signal_name.empty());
612 bus_->AssertOnDBusThread();
614 if (!base::Contains(match_rules_, match_rule)) {
616 bus_->AddMatch(match_rule, &error);
617 if (error.IsValid()) {
618 LOG(ERROR) << "Failed to add match rule \"" << match_rule << "\". Got "
619 << error.name() << ": " << error.message();
622 // Store the match rule, so that we can remove this in Detach().
623 match_rules_.insert(match_rule);
624 // Add the signal callback to the method table.
625 method_table_[absolute_signal_name].push_back(signal_callback);
630 // We already have the match rule.
631 method_table_[absolute_signal_name].push_back(signal_callback);
635 bool ObjectProxy::AddMatchRuleWithoutCallback(
636 const std::string& match_rule,
637 const std::string& absolute_signal_name) {
638 DCHECK(!match_rule.empty());
639 DCHECK(!absolute_signal_name.empty());
640 bus_->AssertOnDBusThread();
642 if (base::Contains(match_rules_, match_rule)) {
647 bus_->AddMatch(match_rule, &error);
648 if (error.IsValid()) {
649 LOG(ERROR) << "Failed to add match rule \"" << match_rule << "\". Got "
650 << error.name() << ": " << error.message();
653 // Store the match rule, so that we can remove this in Detach().
654 match_rules_.insert(match_rule);
658 void ObjectProxy::UpdateNameOwnerAndBlock() {
659 bus_->AssertOnDBusThread();
660 // Errors should be suppressed here, as the service may not be yet running
661 // when connecting to signals of the service, which is just fine.
662 // The ObjectProxy will be notified when the service is launched via
663 // NameOwnerChanged signal. See also comments in ConnectToSignalAndBlock().
664 service_name_owner_ =
665 bus_->GetServiceOwnerAndBlock(service_name_, Bus::SUPPRESS_ERRORS);
668 DBusHandlerResult ObjectProxy::HandleNameOwnerChanged(
669 std::unique_ptr<Signal> signal) {
671 bus_->AssertOnDBusThread();
673 // Confirm the validity of the NameOwnerChanged signal.
674 if (signal->GetMember() == kNameOwnerChangedMember &&
675 signal->GetInterface() == kDBusSystemObjectInterface &&
676 signal->GetSender() == kDBusSystemObjectAddress) {
677 MessageReader reader(signal.get());
678 std::string name, old_owner, new_owner;
679 if (reader.PopString(&name) && reader.PopString(&old_owner) &&
680 reader.PopString(&new_owner) && name == service_name_) {
681 service_name_owner_ = new_owner;
682 bus_->GetOriginTaskRunner()->PostTask(
683 FROM_HERE, base::BindOnce(&ObjectProxy::RunNameOwnerChangedCallback,
684 this, old_owner, new_owner));
686 const bool service_is_available = !service_name_owner_.empty();
687 if (service_is_available) {
688 bus_->GetOriginTaskRunner()->PostTask(
691 &ObjectProxy::RunWaitForServiceToBeAvailableCallbacks, this,
692 service_is_available));
697 // Always return unhandled to let other object proxies handle the same
699 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
702 void ObjectProxy::RunNameOwnerChangedCallback(const std::string& old_owner,
703 const std::string& new_owner) {
704 bus_->AssertOnOriginThread();
705 if (!name_owner_changed_callback_.is_null())
706 name_owner_changed_callback_.Run(old_owner, new_owner);
709 void ObjectProxy::RunWaitForServiceToBeAvailableCallbacks(
710 bool service_is_available) {
711 bus_->AssertOnOriginThread();
713 std::vector<WaitForServiceToBeAvailableCallback> callbacks;
714 callbacks.swap(wait_for_service_to_be_available_callbacks_);
715 for (auto& callback : callbacks) {
716 std::move(callback).Run(service_is_available);