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"
26 const char kErrorServiceUnknown
[] = "org.freedesktop.DBus.Error.ServiceUnknown";
28 // Used for success ratio histograms. 1 for success, 0 for failure.
29 const int kSuccessRatioHistogramMaxValue
= 2;
31 // The path of D-Bus Object sending NameOwnerChanged signal.
32 const char kDBusSystemObjectPath
[] = "/org/freedesktop/DBus";
34 // The D-Bus Object interface.
35 const char kDBusSystemObjectInterface
[] = "org.freedesktop.DBus";
37 // The D-Bus Object address.
38 const char kDBusSystemObjectAddress
[] = "org.freedesktop.DBus";
40 // The NameOwnerChanged member in |kDBusSystemObjectInterface|.
41 const char kNameOwnerChangedMember
[] = "NameOwnerChanged";
43 // Gets the absolute signal name by concatenating the interface name and
44 // the signal name. Used for building keys for method_table_ in
46 std::string
GetAbsoluteSignalName(
47 const std::string
& interface_name
,
48 const std::string
& signal_name
) {
49 return interface_name
+ "." + signal_name
;
52 // An empty function used for ObjectProxy::EmptyResponseCallback().
53 void EmptyResponseCallbackBody(Response
* /*response*/) {
58 ObjectProxy::ObjectProxy(Bus
* bus
,
59 const std::string
& service_name
,
60 const ObjectPath
& object_path
,
63 service_name_(service_name
),
64 object_path_(object_path
),
66 ignore_service_unknown_errors_(
67 options
& IGNORE_SERVICE_UNKNOWN_ERRORS
) {
70 ObjectProxy::~ObjectProxy() {
73 // Originally we tried to make |method_call| a const reference, but we
74 // gave up as dbus_connection_send_with_reply_and_block() takes a
75 // non-const pointer of DBusMessage as the second parameter.
76 scoped_ptr
<Response
> ObjectProxy::CallMethodAndBlock(MethodCall
* method_call
,
78 bus_
->AssertOnDBusThread();
80 if (!bus_
->Connect() ||
81 !method_call
->SetDestination(service_name_
) ||
82 !method_call
->SetPath(object_path_
))
83 return scoped_ptr
<Response
>();
85 DBusMessage
* request_message
= method_call
->raw_message();
87 ScopedDBusError error
;
89 // Send the message synchronously.
90 const base::TimeTicks start_time
= base::TimeTicks::Now();
91 DBusMessage
* response_message
=
92 bus_
->SendWithReplyAndBlock(request_message
, timeout_ms
, error
.get());
93 // Record if the method call is successful, or not. 1 if successful.
94 UMA_HISTOGRAM_ENUMERATION("DBus.SyncMethodCallSuccess",
95 response_message
? 1 : 0,
96 kSuccessRatioHistogramMaxValue
);
97 statistics::AddBlockingSentMethodCall(service_name_
,
98 method_call
->GetInterface(),
99 method_call
->GetMember());
101 if (!response_message
) {
102 LogMethodCallFailure(method_call
->GetInterface(),
103 method_call
->GetMember(),
104 error
.is_set() ? error
.name() : "unknown error type",
105 error
.is_set() ? error
.message() : "");
106 return scoped_ptr
<Response
>();
108 // Record time spent for the method call. Don't include failures.
109 UMA_HISTOGRAM_TIMES("DBus.SyncMethodCallTime",
110 base::TimeTicks::Now() - start_time
);
112 return Response::FromRawMessage(response_message
);
115 void ObjectProxy::CallMethod(MethodCall
* method_call
,
117 ResponseCallback callback
) {
118 CallMethodWithErrorCallback(method_call
, timeout_ms
, callback
,
119 base::Bind(&ObjectProxy::OnCallMethodError
,
121 method_call
->GetInterface(),
122 method_call
->GetMember(),
126 void ObjectProxy::CallMethodWithErrorCallback(MethodCall
* method_call
,
128 ResponseCallback callback
,
129 ErrorCallback error_callback
) {
130 bus_
->AssertOnOriginThread();
132 const base::TimeTicks start_time
= base::TimeTicks::Now();
134 if (!method_call
->SetDestination(service_name_
) ||
135 !method_call
->SetPath(object_path_
)) {
136 // In case of a failure, run the error callback with NULL.
137 DBusMessage
* response_message
= NULL
;
138 base::Closure task
= base::Bind(&ObjectProxy::RunResponseCallback
,
144 bus_
->GetOriginTaskRunner()->PostTask(FROM_HERE
, task
);
148 // Increment the reference count so we can safely reference the
149 // underlying request message until the method call is complete. This
150 // will be unref'ed in StartAsyncMethodCall().
151 DBusMessage
* request_message
= method_call
->raw_message();
152 dbus_message_ref(request_message
);
154 base::Closure task
= base::Bind(&ObjectProxy::StartAsyncMethodCall
,
161 statistics::AddSentMethodCall(service_name_
,
162 method_call
->GetInterface(),
163 method_call
->GetMember());
165 // Wait for the response in the D-Bus thread.
166 bus_
->GetDBusTaskRunner()->PostTask(FROM_HERE
, task
);
169 void ObjectProxy::ConnectToSignal(const std::string
& interface_name
,
170 const std::string
& signal_name
,
171 SignalCallback signal_callback
,
172 OnConnectedCallback on_connected_callback
) {
173 bus_
->AssertOnOriginThread();
175 base::PostTaskAndReplyWithResult(
176 bus_
->GetDBusTaskRunner(),
178 base::Bind(&ObjectProxy::ConnectToSignalInternal
,
183 base::Bind(on_connected_callback
,
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();
209 if (!bus_
->RemoveFilterFunction(&ObjectProxy::HandleMessageThunk
, this)) {
210 LOG(ERROR
) << "Failed to remove filter function";
214 for (std::set
<std::string
>::iterator iter
= match_rules_
.begin();
215 iter
!= match_rules_
.end(); ++iter
) {
216 ScopedDBusError error
;
217 bus_
->RemoveMatch(*iter
, error
.get());
218 if (error
.is_set()) {
219 // There is nothing we can do to recover, so just print the error.
220 LOG(ERROR
) << "Failed to remove match rule: " << *iter
;
223 match_rules_
.clear();
227 ObjectProxy::ResponseCallback
ObjectProxy::EmptyResponseCallback() {
228 return base::Bind(&EmptyResponseCallbackBody
);
231 ObjectProxy::OnPendingCallIsCompleteData::OnPendingCallIsCompleteData(
232 ObjectProxy
* in_object_proxy
,
233 ResponseCallback in_response_callback
,
234 ErrorCallback in_error_callback
,
235 base::TimeTicks in_start_time
)
236 : object_proxy(in_object_proxy
),
237 response_callback(in_response_callback
),
238 error_callback(in_error_callback
),
239 start_time(in_start_time
) {
242 ObjectProxy::OnPendingCallIsCompleteData::~OnPendingCallIsCompleteData() {
245 void ObjectProxy::StartAsyncMethodCall(int timeout_ms
,
246 DBusMessage
* request_message
,
247 ResponseCallback response_callback
,
248 ErrorCallback error_callback
,
249 base::TimeTicks start_time
) {
250 bus_
->AssertOnDBusThread();
252 if (!bus_
->Connect() || !bus_
->SetUpAsyncOperations()) {
253 // In case of a failure, run the error callback with NULL.
254 DBusMessage
* response_message
= NULL
;
255 base::Closure task
= base::Bind(&ObjectProxy::RunResponseCallback
,
261 bus_
->GetOriginTaskRunner()->PostTask(FROM_HERE
, task
);
263 dbus_message_unref(request_message
);
267 DBusPendingCall
* pending_call
= NULL
;
269 bus_
->SendWithReply(request_message
, &pending_call
, timeout_ms
);
271 // Prepare the data we'll be passing to OnPendingCallIsCompleteThunk().
272 // The data will be deleted in OnPendingCallIsCompleteThunk().
273 OnPendingCallIsCompleteData
* data
=
274 new OnPendingCallIsCompleteData(this, response_callback
, error_callback
,
277 // This returns false only when unable to allocate memory.
278 const bool success
= dbus_pending_call_set_notify(
280 &ObjectProxy::OnPendingCallIsCompleteThunk
,
283 CHECK(success
) << "Unable to allocate memory";
284 dbus_pending_call_unref(pending_call
);
286 // It's now safe to unref the request message.
287 dbus_message_unref(request_message
);
290 void ObjectProxy::OnPendingCallIsComplete(DBusPendingCall
* pending_call
,
291 ResponseCallback response_callback
,
292 ErrorCallback error_callback
,
293 base::TimeTicks start_time
) {
294 bus_
->AssertOnDBusThread();
296 DBusMessage
* response_message
= dbus_pending_call_steal_reply(pending_call
);
297 base::Closure task
= base::Bind(&ObjectProxy::RunResponseCallback
,
303 bus_
->GetOriginTaskRunner()->PostTask(FROM_HERE
, task
);
306 void ObjectProxy::RunResponseCallback(ResponseCallback response_callback
,
307 ErrorCallback error_callback
,
308 base::TimeTicks start_time
,
309 DBusMessage
* response_message
) {
310 bus_
->AssertOnOriginThread();
312 bool method_call_successful
= false;
313 if (!response_message
) {
314 // The response is not received.
315 error_callback
.Run(NULL
);
316 } else if (dbus_message_get_type(response_message
) ==
317 DBUS_MESSAGE_TYPE_ERROR
) {
318 // This will take |response_message| and release (unref) it.
319 scoped_ptr
<ErrorResponse
> error_response(
320 ErrorResponse::FromRawMessage(response_message
));
321 error_callback
.Run(error_response
.get());
322 // Delete the message on the D-Bus thread. See below for why.
323 bus_
->GetDBusTaskRunner()->PostTask(
325 base::Bind(&base::DeletePointer
<ErrorResponse
>,
326 error_response
.release()));
328 // This will take |response_message| and release (unref) it.
329 scoped_ptr
<Response
> response(Response::FromRawMessage(response_message
));
330 // The response is successfully received.
331 response_callback
.Run(response
.get());
332 // The message should be deleted on the D-Bus thread for a complicated
335 // libdbus keeps track of the number of bytes in the incoming message
336 // queue to ensure that the data size in the queue is manageable. The
337 // bookkeeping is partly done via dbus_message_unref(), and immediately
338 // asks the client code (Chrome) to stop monitoring the underlying
339 // socket, if the number of bytes exceeds a certian number, which is set
340 // to 63MB, per dbus-transport.cc:
342 // /* Try to default to something that won't totally hose the system,
343 // * but doesn't impose too much of a limitation.
345 // transport->max_live_messages_size = _DBUS_ONE_MEGABYTE * 63;
347 // The monitoring of the socket is done on the D-Bus thread (see Watch
348 // class in bus.cc), hence we should stop the monitoring from D-Bus
349 // thread, not from the current thread here, which is likely UI thread.
350 bus_
->GetDBusTaskRunner()->PostTask(
352 base::Bind(&base::DeletePointer
<Response
>, response
.release()));
354 method_call_successful
= true;
355 // Record time spent for the method call. Don't include failures.
356 UMA_HISTOGRAM_TIMES("DBus.AsyncMethodCallTime",
357 base::TimeTicks::Now() - start_time
);
359 // Record if the method call is successful, or not. 1 if successful.
360 UMA_HISTOGRAM_ENUMERATION("DBus.AsyncMethodCallSuccess",
361 method_call_successful
,
362 kSuccessRatioHistogramMaxValue
);
365 void ObjectProxy::OnPendingCallIsCompleteThunk(DBusPendingCall
* pending_call
,
367 OnPendingCallIsCompleteData
* data
=
368 reinterpret_cast<OnPendingCallIsCompleteData
*>(user_data
);
369 ObjectProxy
* self
= data
->object_proxy
;
370 self
->OnPendingCallIsComplete(pending_call
,
371 data
->response_callback
,
372 data
->error_callback
,
377 bool ObjectProxy::ConnectToNameOwnerChangedSignal() {
378 bus_
->AssertOnDBusThread();
380 if (!bus_
->Connect() || !bus_
->SetUpAsyncOperations())
383 // We should add the filter only once. Otherwise, HandleMessage() will
384 // be called more than once.
385 if (!filter_added_
) {
386 if (bus_
->AddFilterFunction(&ObjectProxy::HandleMessageThunk
, this)) {
387 filter_added_
= true;
389 LOG(ERROR
) << "Failed to add filter function";
392 // Add a match_rule listening NameOwnerChanged for the well-known name
394 const std::string name_owner_changed_match_rule
=
396 "type='signal',interface='org.freedesktop.DBus',"
397 "member='NameOwnerChanged',path='/org/freedesktop/DBus',"
398 "sender='org.freedesktop.DBus',arg0='%s'",
399 service_name_
.c_str());
402 AddMatchRuleWithoutCallback(name_owner_changed_match_rule
,
403 "org.freedesktop.DBus.NameOwnerChanged");
405 // Try getting the current name owner. It's not guaranteed that we can get
406 // the name owner at this moment, as the service may not yet be started. If
407 // that's the case, we'll get the name owner via NameOwnerChanged signal,
408 // as soon as the service is started.
409 UpdateNameOwnerAndBlock();
414 bool ObjectProxy::ConnectToSignalInternal(const std::string
& interface_name
,
415 const std::string
& signal_name
,
416 SignalCallback signal_callback
) {
417 bus_
->AssertOnDBusThread();
419 if (!ConnectToNameOwnerChangedSignal())
422 const std::string absolute_signal_name
=
423 GetAbsoluteSignalName(interface_name
, signal_name
);
425 // Add a match rule so the signal goes through HandleMessage().
426 const std::string match_rule
=
427 base::StringPrintf("type='signal', interface='%s', path='%s'",
428 interface_name
.c_str(),
429 object_path_
.value().c_str());
430 return AddMatchRuleWithCallback(match_rule
,
431 absolute_signal_name
,
435 void ObjectProxy::WaitForServiceToBeAvailableInternal() {
436 bus_
->AssertOnDBusThread();
438 if (!ConnectToNameOwnerChangedSignal()) { // Failed to connect to the signal.
439 const bool service_is_ready
= false;
440 bus_
->GetOriginTaskRunner()->PostTask(
442 base::Bind(&ObjectProxy::RunWaitForServiceToBeAvailableCallbacks
,
443 this, service_is_ready
));
447 const bool service_is_available
= !service_name_owner_
.empty();
448 if (service_is_available
) { // Service is already available.
449 bus_
->GetOriginTaskRunner()->PostTask(
451 base::Bind(&ObjectProxy::RunWaitForServiceToBeAvailableCallbacks
,
452 this, service_is_available
));
457 DBusHandlerResult
ObjectProxy::HandleMessage(
458 DBusConnection
* connection
,
459 DBusMessage
* raw_message
) {
460 bus_
->AssertOnDBusThread();
462 if (dbus_message_get_type(raw_message
) != DBUS_MESSAGE_TYPE_SIGNAL
)
463 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED
;
465 // raw_message will be unrefed on exit of the function. Increment the
466 // reference so we can use it in Signal.
467 dbus_message_ref(raw_message
);
468 scoped_ptr
<Signal
> signal(
469 Signal::FromRawMessage(raw_message
));
471 // Verify the signal comes from the object we're proxying for, this is
472 // our last chance to return DBUS_HANDLER_RESULT_NOT_YET_HANDLED and
473 // allow other object proxies to handle instead.
474 const ObjectPath path
= signal
->GetPath();
475 if (path
!= object_path_
) {
476 if (path
.value() == kDBusSystemObjectPath
&&
477 signal
->GetMember() == kNameOwnerChangedMember
) {
478 // Handle NameOwnerChanged separately
479 return HandleNameOwnerChanged(signal
.Pass());
481 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED
;
484 const std::string interface
= signal
->GetInterface();
485 const std::string member
= signal
->GetMember();
487 statistics::AddReceivedSignal(service_name_
, interface
, member
);
489 // Check if we know about the signal.
490 const std::string absolute_signal_name
= GetAbsoluteSignalName(
492 MethodTable::const_iterator iter
= method_table_
.find(absolute_signal_name
);
493 if (iter
== method_table_
.end()) {
494 // Don't know about the signal.
495 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED
;
497 VLOG(1) << "Signal received: " << signal
->ToString();
499 std::string sender
= signal
->GetSender();
500 if (service_name_owner_
!= sender
) {
501 LOG(ERROR
) << "Rejecting a message from a wrong sender.";
502 UMA_HISTOGRAM_COUNTS("DBus.RejectedSignalCount", 1);
503 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED
;
506 const base::TimeTicks start_time
= base::TimeTicks::Now();
507 if (bus_
->HasDBusThread()) {
508 // Post a task to run the method in the origin thread.
509 // Transfer the ownership of |signal| to RunMethod().
510 // |released_signal| will be deleted in RunMethod().
511 Signal
* released_signal
= signal
.release();
512 bus_
->GetOriginTaskRunner()->PostTask(FROM_HERE
,
513 base::Bind(&ObjectProxy::RunMethod
,
519 const base::TimeTicks start_time
= base::TimeTicks::Now();
520 // If the D-Bus thread is not used, just call the callback on the
521 // current thread. Transfer the ownership of |signal| to RunMethod().
522 Signal
* released_signal
= signal
.release();
523 RunMethod(start_time
, iter
->second
, released_signal
);
526 // We don't return DBUS_HANDLER_RESULT_HANDLED for signals because other
527 // objects may be interested in them. (e.g. Signals from org.freedesktop.DBus)
528 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED
;
531 void ObjectProxy::RunMethod(base::TimeTicks start_time
,
532 std::vector
<SignalCallback
> signal_callbacks
,
534 bus_
->AssertOnOriginThread();
536 for (std::vector
<SignalCallback
>::iterator iter
= signal_callbacks
.begin();
537 iter
!= signal_callbacks
.end(); ++iter
)
540 // Delete the message on the D-Bus thread. See comments in
541 // RunResponseCallback().
542 bus_
->GetDBusTaskRunner()->PostTask(
544 base::Bind(&base::DeletePointer
<Signal
>, signal
));
546 // Record time spent for handling the signal.
547 UMA_HISTOGRAM_TIMES("DBus.SignalHandleTime",
548 base::TimeTicks::Now() - start_time
);
551 DBusHandlerResult
ObjectProxy::HandleMessageThunk(
552 DBusConnection
* connection
,
553 DBusMessage
* raw_message
,
555 ObjectProxy
* self
= reinterpret_cast<ObjectProxy
*>(user_data
);
556 return self
->HandleMessage(connection
, raw_message
);
559 void ObjectProxy::LogMethodCallFailure(
560 const base::StringPiece
& interface_name
,
561 const base::StringPiece
& method_name
,
562 const base::StringPiece
& error_name
,
563 const base::StringPiece
& error_message
) const {
564 if (ignore_service_unknown_errors_
&& error_name
== kErrorServiceUnknown
)
566 LOG(ERROR
) << "Failed to call method: "
567 << interface_name
<< "." << method_name
568 << ": object_path= " << object_path_
.value()
569 << ": " << error_name
<< ": " << error_message
;
572 void ObjectProxy::OnCallMethodError(const std::string
& interface_name
,
573 const std::string
& method_name
,
574 ResponseCallback response_callback
,
575 ErrorResponse
* error_response
) {
576 if (error_response
) {
577 // Error message may contain the error message as string.
578 MessageReader
reader(error_response
);
579 std::string error_message
;
580 reader
.PopString(&error_message
);
581 LogMethodCallFailure(interface_name
,
583 error_response
->GetErrorName(),
586 response_callback
.Run(NULL
);
589 bool ObjectProxy::AddMatchRuleWithCallback(
590 const std::string
& match_rule
,
591 const std::string
& absolute_signal_name
,
592 SignalCallback signal_callback
) {
593 DCHECK(!match_rule
.empty());
594 DCHECK(!absolute_signal_name
.empty());
595 bus_
->AssertOnDBusThread();
597 if (match_rules_
.find(match_rule
) == match_rules_
.end()) {
598 ScopedDBusError error
;
599 bus_
->AddMatch(match_rule
, error
.get());
600 if (error
.is_set()) {
601 LOG(ERROR
) << "Failed to add match rule \"" << match_rule
<< "\". Got "
602 << error
.name() << ": " << error
.message();
605 // Store the match rule, so that we can remove this in Detach().
606 match_rules_
.insert(match_rule
);
607 // Add the signal callback to the method table.
608 method_table_
[absolute_signal_name
].push_back(signal_callback
);
612 // We already have the match rule.
613 method_table_
[absolute_signal_name
].push_back(signal_callback
);
618 bool ObjectProxy::AddMatchRuleWithoutCallback(
619 const std::string
& match_rule
,
620 const std::string
& absolute_signal_name
) {
621 DCHECK(!match_rule
.empty());
622 DCHECK(!absolute_signal_name
.empty());
623 bus_
->AssertOnDBusThread();
625 if (match_rules_
.find(match_rule
) != match_rules_
.end())
628 ScopedDBusError error
;
629 bus_
->AddMatch(match_rule
, error
.get());
630 if (error
.is_set()) {
631 LOG(ERROR
) << "Failed to add match rule \"" << match_rule
<< "\". Got "
632 << error
.name() << ": " << error
.message();
635 // Store the match rule, so that we can remove this in Detach().
636 match_rules_
.insert(match_rule
);
640 void ObjectProxy::UpdateNameOwnerAndBlock() {
641 bus_
->AssertOnDBusThread();
642 // Errors should be suppressed here, as the service may not be yet running
643 // when connecting to signals of the service, which is just fine.
644 // The ObjectProxy will be notified when the service is launched via
645 // NameOwnerChanged signal. See also comments in ConnectToSignalInternal().
646 service_name_owner_
=
647 bus_
->GetServiceOwnerAndBlock(service_name_
, Bus::SUPPRESS_ERRORS
);
650 DBusHandlerResult
ObjectProxy::HandleNameOwnerChanged(
651 scoped_ptr
<Signal
> signal
) {
653 bus_
->AssertOnDBusThread();
655 // Confirm the validity of the NameOwnerChanged signal.
656 if (signal
->GetMember() == kNameOwnerChangedMember
&&
657 signal
->GetInterface() == kDBusSystemObjectInterface
&&
658 signal
->GetSender() == kDBusSystemObjectAddress
) {
659 MessageReader
reader(signal
.get());
660 std::string name
, old_owner
, new_owner
;
661 if (reader
.PopString(&name
) &&
662 reader
.PopString(&old_owner
) &&
663 reader
.PopString(&new_owner
) &&
664 name
== service_name_
) {
665 service_name_owner_
= new_owner
;
666 bus_
->GetOriginTaskRunner()->PostTask(
668 base::Bind(&ObjectProxy::RunNameOwnerChangedCallback
,
669 this, old_owner
, new_owner
));
671 const bool service_is_available
= !service_name_owner_
.empty();
672 if (service_is_available
) {
673 bus_
->GetOriginTaskRunner()->PostTask(
675 base::Bind(&ObjectProxy::RunWaitForServiceToBeAvailableCallbacks
,
676 this, service_is_available
));
681 // Always return unhandled to let other object proxies handle the same
683 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED
;
686 void ObjectProxy::RunNameOwnerChangedCallback(const std::string
& old_owner
,
687 const std::string
& new_owner
) {
688 bus_
->AssertOnOriginThread();
689 if (!name_owner_changed_callback_
.is_null())
690 name_owner_changed_callback_
.Run(old_owner
, new_owner
);
693 void ObjectProxy::RunWaitForServiceToBeAvailableCallbacks(
694 bool service_is_available
) {
695 bus_
->AssertOnOriginThread();
697 std::vector
<WaitForServiceToBeAvailableCallback
> callbacks
;
698 callbacks
.swap(wait_for_service_to_be_available_callbacks_
);
699 for (size_t i
= 0; i
< callbacks
.size(); ++i
)
700 callbacks
[i
].Run(service_is_available
);