1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
8 #include "base/logging.h"
9 #include "base/message_loop/message_loop.h"
10 #include "base/metrics/histogram.h"
11 #include "base/strings/string_piece.h"
12 #include "base/strings/stringprintf.h"
13 #include "base/task_runner_util.h"
14 #include "base/threading/thread.h"
15 #include "base/threading/thread_restrictions.h"
16 #include "dbus/dbus_statistics.h"
17 #include "dbus/message.h"
18 #include "dbus/object_path.h"
19 #include "dbus/object_proxy.h"
20 #include "dbus/scoped_dbus_error.h"
21 #include "dbus/util.h"
27 const char kErrorServiceUnknown
[] = "org.freedesktop.DBus.Error.ServiceUnknown";
28 const char kErrorObjectUnknown
[] = "org.freedesktop.DBus.Error.UnknownObject";
30 // Used for success ratio histograms. 1 for success, 0 for failure.
31 const int kSuccessRatioHistogramMaxValue
= 2;
33 // The path of D-Bus Object sending NameOwnerChanged signal.
34 const char kDBusSystemObjectPath
[] = "/org/freedesktop/DBus";
36 // The D-Bus Object interface.
37 const char kDBusSystemObjectInterface
[] = "org.freedesktop.DBus";
39 // The D-Bus Object address.
40 const char kDBusSystemObjectAddress
[] = "org.freedesktop.DBus";
42 // The NameOwnerChanged member in |kDBusSystemObjectInterface|.
43 const char kNameOwnerChangedMember
[] = "NameOwnerChanged";
45 // An empty function used for ObjectProxy::EmptyResponseCallback().
46 void EmptyResponseCallbackBody(Response
* /*response*/) {
51 ObjectProxy::ObjectProxy(Bus
* bus
,
52 const std::string
& service_name
,
53 const ObjectPath
& object_path
,
56 service_name_(service_name
),
57 object_path_(object_path
),
58 ignore_service_unknown_errors_(
59 options
& IGNORE_SERVICE_UNKNOWN_ERRORS
) {
62 ObjectProxy::~ObjectProxy() {
63 DCHECK(pending_calls_
.empty());
66 // Originally we tried to make |method_call| a const reference, but we
67 // gave up as dbus_connection_send_with_reply_and_block() takes a
68 // non-const pointer of DBusMessage as the second parameter.
69 scoped_ptr
<Response
> ObjectProxy::CallMethodAndBlockWithErrorDetails(
70 MethodCall
* method_call
, int timeout_ms
, ScopedDBusError
* error
) {
71 bus_
->AssertOnDBusThread();
73 if (!bus_
->Connect() ||
74 !method_call
->SetDestination(service_name_
) ||
75 !method_call
->SetPath(object_path_
))
76 return scoped_ptr
<Response
>();
78 DBusMessage
* request_message
= method_call
->raw_message();
80 // Send the message synchronously.
81 const base::TimeTicks start_time
= base::TimeTicks::Now();
82 DBusMessage
* response_message
=
83 bus_
->SendWithReplyAndBlock(request_message
, timeout_ms
, error
->get());
84 // Record if the method call is successful, or not. 1 if successful.
85 UMA_HISTOGRAM_ENUMERATION("DBus.SyncMethodCallSuccess",
86 response_message
? 1 : 0,
87 kSuccessRatioHistogramMaxValue
);
88 statistics::AddBlockingSentMethodCall(service_name_
,
89 method_call
->GetInterface(),
90 method_call
->GetMember());
92 if (!response_message
) {
93 LogMethodCallFailure(method_call
->GetInterface(),
94 method_call
->GetMember(),
95 error
->is_set() ? error
->name() : "unknown error type",
96 error
->is_set() ? error
->message() : "");
97 return scoped_ptr
<Response
>();
99 // Record time spent for the method call. Don't include failures.
100 UMA_HISTOGRAM_TIMES("DBus.SyncMethodCallTime",
101 base::TimeTicks::Now() - start_time
);
103 return Response::FromRawMessage(response_message
);
106 scoped_ptr
<Response
> ObjectProxy::CallMethodAndBlock(MethodCall
* method_call
,
108 ScopedDBusError error
;
109 return CallMethodAndBlockWithErrorDetails(method_call
, timeout_ms
, &error
);
112 void ObjectProxy::CallMethod(MethodCall
* method_call
,
114 ResponseCallback callback
) {
115 CallMethodWithErrorCallback(method_call
, timeout_ms
, callback
,
116 base::Bind(&ObjectProxy::OnCallMethodError
,
118 method_call
->GetInterface(),
119 method_call
->GetMember(),
123 void ObjectProxy::CallMethodWithErrorCallback(MethodCall
* method_call
,
125 ResponseCallback callback
,
126 ErrorCallback error_callback
) {
127 bus_
->AssertOnOriginThread();
129 const base::TimeTicks start_time
= base::TimeTicks::Now();
131 if (!method_call
->SetDestination(service_name_
) ||
132 !method_call
->SetPath(object_path_
)) {
133 // In case of a failure, run the error callback with NULL.
134 DBusMessage
* response_message
= NULL
;
135 base::Closure task
= base::Bind(&ObjectProxy::RunResponseCallback
,
141 bus_
->GetOriginTaskRunner()->PostTask(FROM_HERE
, task
);
145 // Increment the reference count so we can safely reference the
146 // underlying request message until the method call is complete. This
147 // will be unref'ed in StartAsyncMethodCall().
148 DBusMessage
* request_message
= method_call
->raw_message();
149 dbus_message_ref(request_message
);
151 base::Closure task
= base::Bind(&ObjectProxy::StartAsyncMethodCall
,
158 statistics::AddSentMethodCall(service_name_
,
159 method_call
->GetInterface(),
160 method_call
->GetMember());
162 // Wait for the response in the D-Bus thread.
163 bus_
->GetDBusTaskRunner()->PostTask(FROM_HERE
, task
);
166 void ObjectProxy::ConnectToSignal(const std::string
& interface_name
,
167 const std::string
& signal_name
,
168 SignalCallback signal_callback
,
169 OnConnectedCallback on_connected_callback
) {
170 bus_
->AssertOnOriginThread();
172 if (bus_
->HasDBusThread()) {
173 base::PostTaskAndReplyWithResult(
174 bus_
->GetDBusTaskRunner(), FROM_HERE
,
175 base::Bind(&ObjectProxy::ConnectToSignalInternal
, this, interface_name
,
176 signal_name
, signal_callback
),
177 base::Bind(on_connected_callback
, interface_name
, signal_name
));
179 // If the bus doesn't have a dedicated dbus thread we need to call
180 // ConnectToSignalInternal directly otherwise we might miss a signal
181 // that is currently queued if we do a PostTask.
183 ConnectToSignalInternal(interface_name
, signal_name
, signal_callback
);
184 on_connected_callback
.Run(interface_name
, signal_name
, success
);
188 void ObjectProxy::SetNameOwnerChangedCallback(
189 NameOwnerChangedCallback callback
) {
190 bus_
->AssertOnOriginThread();
192 name_owner_changed_callback_
= callback
;
195 void ObjectProxy::WaitForServiceToBeAvailable(
196 WaitForServiceToBeAvailableCallback callback
) {
197 bus_
->AssertOnOriginThread();
199 wait_for_service_to_be_available_callbacks_
.push_back(callback
);
200 bus_
->GetDBusTaskRunner()->PostTask(
202 base::Bind(&ObjectProxy::WaitForServiceToBeAvailableInternal
, this));
205 void ObjectProxy::Detach() {
206 bus_
->AssertOnDBusThread();
208 if (bus_
->is_connected())
209 bus_
->RemoveFilterFunction(&ObjectProxy::HandleMessageThunk
, this);
211 for (const auto& match_rule
: match_rules_
) {
212 ScopedDBusError error
;
213 bus_
->RemoveMatch(match_rule
, error
.get());
214 if (error
.is_set()) {
215 // There is nothing we can do to recover, so just print the error.
216 LOG(ERROR
) << "Failed to remove match rule: " << match_rule
;
219 match_rules_
.clear();
221 for (auto* pending_call
: pending_calls_
) {
222 dbus_pending_call_cancel(pending_call
);
223 dbus_pending_call_unref(pending_call
);
225 pending_calls_
.clear();
229 ObjectProxy::ResponseCallback
ObjectProxy::EmptyResponseCallback() {
230 return base::Bind(&EmptyResponseCallbackBody
);
233 ObjectProxy::OnPendingCallIsCompleteData::OnPendingCallIsCompleteData(
234 ObjectProxy
* in_object_proxy
,
235 ResponseCallback in_response_callback
,
236 ErrorCallback in_error_callback
,
237 base::TimeTicks in_start_time
)
238 : object_proxy(in_object_proxy
),
239 response_callback(in_response_callback
),
240 error_callback(in_error_callback
),
241 start_time(in_start_time
) {
244 ObjectProxy::OnPendingCallIsCompleteData::~OnPendingCallIsCompleteData() {
247 void ObjectProxy::StartAsyncMethodCall(int timeout_ms
,
248 DBusMessage
* request_message
,
249 ResponseCallback response_callback
,
250 ErrorCallback error_callback
,
251 base::TimeTicks start_time
) {
252 bus_
->AssertOnDBusThread();
254 if (!bus_
->Connect() || !bus_
->SetUpAsyncOperations()) {
255 // In case of a failure, run the error callback with NULL.
256 DBusMessage
* response_message
= NULL
;
257 base::Closure task
= base::Bind(&ObjectProxy::RunResponseCallback
,
263 bus_
->GetOriginTaskRunner()->PostTask(FROM_HERE
, task
);
265 dbus_message_unref(request_message
);
269 DBusPendingCall
* pending_call
= NULL
;
271 bus_
->SendWithReply(request_message
, &pending_call
, timeout_ms
);
273 // Prepare the data we'll be passing to OnPendingCallIsCompleteThunk().
274 // The data will be deleted in OnPendingCallIsCompleteThunk().
275 OnPendingCallIsCompleteData
* data
=
276 new OnPendingCallIsCompleteData(this, response_callback
, error_callback
,
279 // This returns false only when unable to allocate memory.
280 const bool success
= dbus_pending_call_set_notify(
282 &ObjectProxy::OnPendingCallIsCompleteThunk
,
284 &DeleteVoidPointer
<OnPendingCallIsCompleteData
>);
285 CHECK(success
) << "Unable to allocate memory";
286 pending_calls_
.insert(pending_call
);
288 // It's now safe to unref the request message.
289 dbus_message_unref(request_message
);
292 void ObjectProxy::OnPendingCallIsComplete(DBusPendingCall
* pending_call
,
293 ResponseCallback response_callback
,
294 ErrorCallback error_callback
,
295 base::TimeTicks start_time
) {
296 bus_
->AssertOnDBusThread();
298 DBusMessage
* response_message
= dbus_pending_call_steal_reply(pending_call
);
299 base::Closure task
= base::Bind(&ObjectProxy::RunResponseCallback
,
305 bus_
->GetOriginTaskRunner()->PostTask(FROM_HERE
, task
);
307 // Remove the pending call from the set.
308 pending_calls_
.erase(pending_call
);
309 dbus_pending_call_unref(pending_call
);
312 void ObjectProxy::RunResponseCallback(ResponseCallback response_callback
,
313 ErrorCallback error_callback
,
314 base::TimeTicks start_time
,
315 DBusMessage
* response_message
) {
316 bus_
->AssertOnOriginThread();
318 bool method_call_successful
= false;
319 if (!response_message
) {
320 // The response is not received.
321 error_callback
.Run(NULL
);
322 } else if (dbus_message_get_type(response_message
) ==
323 DBUS_MESSAGE_TYPE_ERROR
) {
324 // This will take |response_message| and release (unref) it.
325 scoped_ptr
<ErrorResponse
> error_response(
326 ErrorResponse::FromRawMessage(response_message
));
327 error_callback
.Run(error_response
.get());
328 // Delete the message on the D-Bus thread. See below for why.
329 bus_
->GetDBusTaskRunner()->PostTask(
331 base::Bind(&base::DeletePointer
<ErrorResponse
>,
332 error_response
.release()));
334 // This will take |response_message| and release (unref) it.
335 scoped_ptr
<Response
> response(Response::FromRawMessage(response_message
));
336 // The response is successfully received.
337 response_callback
.Run(response
.get());
338 // The message should be deleted on the D-Bus thread for a complicated
341 // libdbus keeps track of the number of bytes in the incoming message
342 // queue to ensure that the data size in the queue is manageable. The
343 // bookkeeping is partly done via dbus_message_unref(), and immediately
344 // asks the client code (Chrome) to stop monitoring the underlying
345 // socket, if the number of bytes exceeds a certian number, which is set
346 // to 63MB, per dbus-transport.cc:
348 // /* Try to default to something that won't totally hose the system,
349 // * but doesn't impose too much of a limitation.
351 // transport->max_live_messages_size = _DBUS_ONE_MEGABYTE * 63;
353 // The monitoring of the socket is done on the D-Bus thread (see Watch
354 // class in bus.cc), hence we should stop the monitoring from D-Bus
355 // thread, not from the current thread here, which is likely UI thread.
356 bus_
->GetDBusTaskRunner()->PostTask(
358 base::Bind(&base::DeletePointer
<Response
>, response
.release()));
360 method_call_successful
= true;
361 // Record time spent for the method call. Don't include failures.
362 UMA_HISTOGRAM_TIMES("DBus.AsyncMethodCallTime",
363 base::TimeTicks::Now() - start_time
);
365 // Record if the method call is successful, or not. 1 if successful.
366 UMA_HISTOGRAM_ENUMERATION("DBus.AsyncMethodCallSuccess",
367 method_call_successful
,
368 kSuccessRatioHistogramMaxValue
);
371 void ObjectProxy::OnPendingCallIsCompleteThunk(DBusPendingCall
* pending_call
,
373 OnPendingCallIsCompleteData
* data
=
374 reinterpret_cast<OnPendingCallIsCompleteData
*>(user_data
);
375 ObjectProxy
* self
= data
->object_proxy
;
376 self
->OnPendingCallIsComplete(pending_call
,
377 data
->response_callback
,
378 data
->error_callback
,
382 bool ObjectProxy::ConnectToNameOwnerChangedSignal() {
383 bus_
->AssertOnDBusThread();
385 if (!bus_
->Connect() || !bus_
->SetUpAsyncOperations())
388 bus_
->AddFilterFunction(&ObjectProxy::HandleMessageThunk
, this);
390 // Add a match_rule listening NameOwnerChanged for the well-known name
392 const std::string name_owner_changed_match_rule
=
394 "type='signal',interface='org.freedesktop.DBus',"
395 "member='NameOwnerChanged',path='/org/freedesktop/DBus',"
396 "sender='org.freedesktop.DBus',arg0='%s'",
397 service_name_
.c_str());
400 AddMatchRuleWithoutCallback(name_owner_changed_match_rule
,
401 "org.freedesktop.DBus.NameOwnerChanged");
403 // Try getting the current name owner. It's not guaranteed that we can get
404 // the name owner at this moment, as the service may not yet be started. If
405 // that's the case, we'll get the name owner via NameOwnerChanged signal,
406 // as soon as the service is started.
407 UpdateNameOwnerAndBlock();
412 bool ObjectProxy::ConnectToSignalInternal(const std::string
& interface_name
,
413 const std::string
& signal_name
,
414 SignalCallback signal_callback
) {
415 bus_
->AssertOnDBusThread();
417 if (!ConnectToNameOwnerChangedSignal())
420 const std::string absolute_signal_name
=
421 GetAbsoluteMemberName(interface_name
, signal_name
);
423 // Add a match rule so the signal goes through HandleMessage().
424 const std::string match_rule
=
425 base::StringPrintf("type='signal', interface='%s', path='%s'",
426 interface_name
.c_str(),
427 object_path_
.value().c_str());
428 return AddMatchRuleWithCallback(match_rule
,
429 absolute_signal_name
,
433 void ObjectProxy::WaitForServiceToBeAvailableInternal() {
434 bus_
->AssertOnDBusThread();
436 if (!ConnectToNameOwnerChangedSignal()) { // Failed to connect to the signal.
437 const bool service_is_ready
= false;
438 bus_
->GetOriginTaskRunner()->PostTask(
440 base::Bind(&ObjectProxy::RunWaitForServiceToBeAvailableCallbacks
,
441 this, service_is_ready
));
445 const bool service_is_available
= !service_name_owner_
.empty();
446 if (service_is_available
) { // Service is already available.
447 bus_
->GetOriginTaskRunner()->PostTask(
449 base::Bind(&ObjectProxy::RunWaitForServiceToBeAvailableCallbacks
,
450 this, service_is_available
));
455 DBusHandlerResult
ObjectProxy::HandleMessage(
456 DBusConnection
* connection
,
457 DBusMessage
* raw_message
) {
458 bus_
->AssertOnDBusThread();
460 if (dbus_message_get_type(raw_message
) != DBUS_MESSAGE_TYPE_SIGNAL
)
461 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED
;
463 // raw_message will be unrefed on exit of the function. Increment the
464 // reference so we can use it in Signal.
465 dbus_message_ref(raw_message
);
466 scoped_ptr
<Signal
> signal(
467 Signal::FromRawMessage(raw_message
));
469 // Verify the signal comes from the object we're proxying for, this is
470 // our last chance to return DBUS_HANDLER_RESULT_NOT_YET_HANDLED and
471 // allow other object proxies to handle instead.
472 const ObjectPath path
= signal
->GetPath();
473 if (path
!= object_path_
) {
474 if (path
.value() == kDBusSystemObjectPath
&&
475 signal
->GetMember() == kNameOwnerChangedMember
) {
476 // Handle NameOwnerChanged separately
477 return HandleNameOwnerChanged(signal
.Pass());
479 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED
;
482 const std::string interface
= signal
->GetInterface();
483 const std::string member
= signal
->GetMember();
485 statistics::AddReceivedSignal(service_name_
, interface
, member
);
487 // Check if we know about the signal.
488 const std::string absolute_signal_name
= GetAbsoluteMemberName(
490 MethodTable::const_iterator iter
= method_table_
.find(absolute_signal_name
);
491 if (iter
== method_table_
.end()) {
492 // Don't know about the signal.
493 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED
;
495 VLOG(1) << "Signal received: " << signal
->ToString();
497 std::string sender
= signal
->GetSender();
498 if (service_name_owner_
!= sender
) {
499 LOG(ERROR
) << "Rejecting a message from a wrong sender.";
500 UMA_HISTOGRAM_COUNTS("DBus.RejectedSignalCount", 1);
501 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED
;
504 const base::TimeTicks start_time
= base::TimeTicks::Now();
505 if (bus_
->HasDBusThread()) {
506 // Post a task to run the method in the origin thread.
507 // Transfer the ownership of |signal| to RunMethod().
508 // |released_signal| will be deleted in RunMethod().
509 Signal
* released_signal
= signal
.release();
510 bus_
->GetOriginTaskRunner()->PostTask(FROM_HERE
,
511 base::Bind(&ObjectProxy::RunMethod
,
517 const base::TimeTicks start_time
= base::TimeTicks::Now();
518 // If the D-Bus thread is not used, just call the callback on the
519 // current thread. Transfer the ownership of |signal| to RunMethod().
520 Signal
* released_signal
= signal
.release();
521 RunMethod(start_time
, iter
->second
, released_signal
);
524 // We don't return DBUS_HANDLER_RESULT_HANDLED for signals because other
525 // objects may be interested in them. (e.g. Signals from org.freedesktop.DBus)
526 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED
;
529 void ObjectProxy::RunMethod(base::TimeTicks start_time
,
530 std::vector
<SignalCallback
> signal_callbacks
,
532 bus_
->AssertOnOriginThread();
534 for (std::vector
<SignalCallback
>::iterator iter
= signal_callbacks
.begin();
535 iter
!= signal_callbacks
.end(); ++iter
)
538 // Delete the message on the D-Bus thread. See comments in
539 // RunResponseCallback().
540 bus_
->GetDBusTaskRunner()->PostTask(
542 base::Bind(&base::DeletePointer
<Signal
>, signal
));
544 // Record time spent for handling the signal.
545 UMA_HISTOGRAM_TIMES("DBus.SignalHandleTime",
546 base::TimeTicks::Now() - start_time
);
549 DBusHandlerResult
ObjectProxy::HandleMessageThunk(
550 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
))
565 logging::LogSeverity severity
= logging::LOG_ERROR
;
566 // "UnknownObject" indicates that an object or service is no longer available,
567 // e.g. a Shill network service has gone out of range. Treat these as warnings
569 if (error_name
== kErrorObjectUnknown
)
570 severity
= logging::LOG_WARNING
;
571 std::ostringstream msg
;
572 msg
<< "Failed to call method: " << interface_name
<< "." << method_name
573 << ": object_path= " << object_path_
.value()
574 << ": " << error_name
<< ": " << error_message
;
575 logging::LogAtLevel(severity
, msg
.str());
578 void ObjectProxy::OnCallMethodError(const std::string
& interface_name
,
579 const std::string
& method_name
,
580 ResponseCallback response_callback
,
581 ErrorResponse
* error_response
) {
582 if (error_response
) {
583 // Error message may contain the error message as string.
584 MessageReader
reader(error_response
);
585 std::string error_message
;
586 reader
.PopString(&error_message
);
587 LogMethodCallFailure(interface_name
,
589 error_response
->GetErrorName(),
592 response_callback
.Run(NULL
);
595 bool ObjectProxy::AddMatchRuleWithCallback(
596 const std::string
& match_rule
,
597 const std::string
& absolute_signal_name
,
598 SignalCallback signal_callback
) {
599 DCHECK(!match_rule
.empty());
600 DCHECK(!absolute_signal_name
.empty());
601 bus_
->AssertOnDBusThread();
603 if (match_rules_
.find(match_rule
) == match_rules_
.end()) {
604 ScopedDBusError error
;
605 bus_
->AddMatch(match_rule
, error
.get());
606 if (error
.is_set()) {
607 LOG(ERROR
) << "Failed to add match rule \"" << match_rule
<< "\". Got "
608 << error
.name() << ": " << error
.message();
611 // Store the match rule, so that we can remove this in Detach().
612 match_rules_
.insert(match_rule
);
613 // Add the signal callback to the method table.
614 method_table_
[absolute_signal_name
].push_back(signal_callback
);
618 // We already have the match rule.
619 method_table_
[absolute_signal_name
].push_back(signal_callback
);
624 bool ObjectProxy::AddMatchRuleWithoutCallback(
625 const std::string
& match_rule
,
626 const std::string
& absolute_signal_name
) {
627 DCHECK(!match_rule
.empty());
628 DCHECK(!absolute_signal_name
.empty());
629 bus_
->AssertOnDBusThread();
631 if (match_rules_
.find(match_rule
) != match_rules_
.end())
634 ScopedDBusError error
;
635 bus_
->AddMatch(match_rule
, error
.get());
636 if (error
.is_set()) {
637 LOG(ERROR
) << "Failed to add match rule \"" << match_rule
<< "\". Got "
638 << error
.name() << ": " << error
.message();
641 // Store the match rule, so that we can remove this in Detach().
642 match_rules_
.insert(match_rule
);
646 void ObjectProxy::UpdateNameOwnerAndBlock() {
647 bus_
->AssertOnDBusThread();
648 // Errors should be suppressed here, as the service may not be yet running
649 // when connecting to signals of the service, which is just fine.
650 // The ObjectProxy will be notified when the service is launched via
651 // NameOwnerChanged signal. See also comments in ConnectToSignalInternal().
652 service_name_owner_
=
653 bus_
->GetServiceOwnerAndBlock(service_name_
, Bus::SUPPRESS_ERRORS
);
656 DBusHandlerResult
ObjectProxy::HandleNameOwnerChanged(
657 scoped_ptr
<Signal
> signal
) {
659 bus_
->AssertOnDBusThread();
661 // Confirm the validity of the NameOwnerChanged signal.
662 if (signal
->GetMember() == kNameOwnerChangedMember
&&
663 signal
->GetInterface() == kDBusSystemObjectInterface
&&
664 signal
->GetSender() == kDBusSystemObjectAddress
) {
665 MessageReader
reader(signal
.get());
666 std::string name
, old_owner
, new_owner
;
667 if (reader
.PopString(&name
) &&
668 reader
.PopString(&old_owner
) &&
669 reader
.PopString(&new_owner
) &&
670 name
== service_name_
) {
671 service_name_owner_
= new_owner
;
672 bus_
->GetOriginTaskRunner()->PostTask(
674 base::Bind(&ObjectProxy::RunNameOwnerChangedCallback
,
675 this, old_owner
, new_owner
));
677 const bool service_is_available
= !service_name_owner_
.empty();
678 if (service_is_available
) {
679 bus_
->GetOriginTaskRunner()->PostTask(
681 base::Bind(&ObjectProxy::RunWaitForServiceToBeAvailableCallbacks
,
682 this, service_is_available
));
687 // Always return unhandled to let other object proxies handle the same
689 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED
;
692 void ObjectProxy::RunNameOwnerChangedCallback(const std::string
& old_owner
,
693 const std::string
& new_owner
) {
694 bus_
->AssertOnOriginThread();
695 if (!name_owner_changed_callback_
.is_null())
696 name_owner_changed_callback_
.Run(old_owner
, new_owner
);
699 void ObjectProxy::RunWaitForServiceToBeAvailableCallbacks(
700 bool service_is_available
) {
701 bus_
->AssertOnOriginThread();
703 std::vector
<WaitForServiceToBeAvailableCallback
> callbacks
;
704 callbacks
.swap(wait_for_service_to_be_available_callbacks_
);
705 for (size_t i
= 0; i
< callbacks
.size(); ++i
)
706 callbacks
[i
].Run(service_is_available
);