Add SetSupportsQuic method to explicitly specify server that supports QUIC.
[chromium-blink-merge.git] / dbus / object_proxy.cc
blob016425dd50b7c5bd702e0d539bbb6fe1379de1c3
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.
5 #include "dbus/bus.h"
7 #include "base/bind.h"
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"
23 namespace dbus {
25 namespace {
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*/) {
49 } // namespace
51 ObjectProxy::ObjectProxy(Bus* bus,
52 const std::string& service_name,
53 const ObjectPath& object_path,
54 int options)
55 : bus_(bus),
56 service_name_(service_name),
57 object_path_(object_path),
58 filter_added_(false),
59 ignore_service_unknown_errors_(
60 options & IGNORE_SERVICE_UNKNOWN_ERRORS) {
63 ObjectProxy::~ObjectProxy() {
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::CallMethodAndBlock(MethodCall* method_call,
70 int timeout_ms) {
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 ScopedDBusError error;
82 // Send the message synchronously.
83 const base::TimeTicks start_time = base::TimeTicks::Now();
84 DBusMessage* response_message =
85 bus_->SendWithReplyAndBlock(request_message, timeout_ms, error.get());
86 // Record if the method call is successful, or not. 1 if successful.
87 UMA_HISTOGRAM_ENUMERATION("DBus.SyncMethodCallSuccess",
88 response_message ? 1 : 0,
89 kSuccessRatioHistogramMaxValue);
90 statistics::AddBlockingSentMethodCall(service_name_,
91 method_call->GetInterface(),
92 method_call->GetMember());
94 if (!response_message) {
95 LogMethodCallFailure(method_call->GetInterface(),
96 method_call->GetMember(),
97 error.is_set() ? error.name() : "unknown error type",
98 error.is_set() ? error.message() : "");
99 return scoped_ptr<Response>();
101 // Record time spent for the method call. Don't include failures.
102 UMA_HISTOGRAM_TIMES("DBus.SyncMethodCallTime",
103 base::TimeTicks::Now() - start_time);
105 return Response::FromRawMessage(response_message);
108 void ObjectProxy::CallMethod(MethodCall* method_call,
109 int timeout_ms,
110 ResponseCallback callback) {
111 CallMethodWithErrorCallback(method_call, timeout_ms, callback,
112 base::Bind(&ObjectProxy::OnCallMethodError,
113 this,
114 method_call->GetInterface(),
115 method_call->GetMember(),
116 callback));
119 void ObjectProxy::CallMethodWithErrorCallback(MethodCall* method_call,
120 int timeout_ms,
121 ResponseCallback callback,
122 ErrorCallback error_callback) {
123 bus_->AssertOnOriginThread();
125 const base::TimeTicks start_time = base::TimeTicks::Now();
127 if (!method_call->SetDestination(service_name_) ||
128 !method_call->SetPath(object_path_)) {
129 // In case of a failure, run the error callback with NULL.
130 DBusMessage* response_message = NULL;
131 base::Closure task = base::Bind(&ObjectProxy::RunResponseCallback,
132 this,
133 callback,
134 error_callback,
135 start_time,
136 response_message);
137 bus_->GetOriginTaskRunner()->PostTask(FROM_HERE, task);
138 return;
141 // Increment the reference count so we can safely reference the
142 // underlying request message until the method call is complete. This
143 // will be unref'ed in StartAsyncMethodCall().
144 DBusMessage* request_message = method_call->raw_message();
145 dbus_message_ref(request_message);
147 base::Closure task = base::Bind(&ObjectProxy::StartAsyncMethodCall,
148 this,
149 timeout_ms,
150 request_message,
151 callback,
152 error_callback,
153 start_time);
154 statistics::AddSentMethodCall(service_name_,
155 method_call->GetInterface(),
156 method_call->GetMember());
158 // Wait for the response in the D-Bus thread.
159 bus_->GetDBusTaskRunner()->PostTask(FROM_HERE, task);
162 void ObjectProxy::ConnectToSignal(const std::string& interface_name,
163 const std::string& signal_name,
164 SignalCallback signal_callback,
165 OnConnectedCallback on_connected_callback) {
166 bus_->AssertOnOriginThread();
168 base::PostTaskAndReplyWithResult(
169 bus_->GetDBusTaskRunner(),
170 FROM_HERE,
171 base::Bind(&ObjectProxy::ConnectToSignalInternal,
172 this,
173 interface_name,
174 signal_name,
175 signal_callback),
176 base::Bind(on_connected_callback,
177 interface_name,
178 signal_name));
181 void ObjectProxy::SetNameOwnerChangedCallback(
182 NameOwnerChangedCallback callback) {
183 bus_->AssertOnOriginThread();
185 name_owner_changed_callback_ = callback;
188 void ObjectProxy::WaitForServiceToBeAvailable(
189 WaitForServiceToBeAvailableCallback callback) {
190 bus_->AssertOnOriginThread();
192 wait_for_service_to_be_available_callbacks_.push_back(callback);
193 bus_->GetDBusTaskRunner()->PostTask(
194 FROM_HERE,
195 base::Bind(&ObjectProxy::WaitForServiceToBeAvailableInternal, this));
198 void ObjectProxy::Detach() {
199 bus_->AssertOnDBusThread();
201 if (filter_added_) {
202 if (!bus_->RemoveFilterFunction(&ObjectProxy::HandleMessageThunk, this)) {
203 LOG(ERROR) << "Failed to remove filter function";
207 for (std::set<std::string>::iterator iter = match_rules_.begin();
208 iter != match_rules_.end(); ++iter) {
209 ScopedDBusError error;
210 bus_->RemoveMatch(*iter, error.get());
211 if (error.is_set()) {
212 // There is nothing we can do to recover, so just print the error.
213 LOG(ERROR) << "Failed to remove match rule: " << *iter;
216 match_rules_.clear();
219 // static
220 ObjectProxy::ResponseCallback ObjectProxy::EmptyResponseCallback() {
221 return base::Bind(&EmptyResponseCallbackBody);
224 ObjectProxy::OnPendingCallIsCompleteData::OnPendingCallIsCompleteData(
225 ObjectProxy* in_object_proxy,
226 ResponseCallback in_response_callback,
227 ErrorCallback in_error_callback,
228 base::TimeTicks in_start_time)
229 : object_proxy(in_object_proxy),
230 response_callback(in_response_callback),
231 error_callback(in_error_callback),
232 start_time(in_start_time) {
235 ObjectProxy::OnPendingCallIsCompleteData::~OnPendingCallIsCompleteData() {
238 void ObjectProxy::StartAsyncMethodCall(int timeout_ms,
239 DBusMessage* request_message,
240 ResponseCallback response_callback,
241 ErrorCallback error_callback,
242 base::TimeTicks start_time) {
243 bus_->AssertOnDBusThread();
245 if (!bus_->Connect() || !bus_->SetUpAsyncOperations()) {
246 // In case of a failure, run the error callback with NULL.
247 DBusMessage* response_message = NULL;
248 base::Closure task = base::Bind(&ObjectProxy::RunResponseCallback,
249 this,
250 response_callback,
251 error_callback,
252 start_time,
253 response_message);
254 bus_->GetOriginTaskRunner()->PostTask(FROM_HERE, task);
256 dbus_message_unref(request_message);
257 return;
260 DBusPendingCall* pending_call = NULL;
262 bus_->SendWithReply(request_message, &pending_call, timeout_ms);
264 // Prepare the data we'll be passing to OnPendingCallIsCompleteThunk().
265 // The data will be deleted in OnPendingCallIsCompleteThunk().
266 OnPendingCallIsCompleteData* data =
267 new OnPendingCallIsCompleteData(this, response_callback, error_callback,
268 start_time);
270 // This returns false only when unable to allocate memory.
271 const bool success = dbus_pending_call_set_notify(
272 pending_call,
273 &ObjectProxy::OnPendingCallIsCompleteThunk,
274 data,
275 NULL);
276 CHECK(success) << "Unable to allocate memory";
277 dbus_pending_call_unref(pending_call);
279 // It's now safe to unref the request message.
280 dbus_message_unref(request_message);
283 void ObjectProxy::OnPendingCallIsComplete(DBusPendingCall* pending_call,
284 ResponseCallback response_callback,
285 ErrorCallback error_callback,
286 base::TimeTicks start_time) {
287 bus_->AssertOnDBusThread();
289 DBusMessage* response_message = dbus_pending_call_steal_reply(pending_call);
290 base::Closure task = base::Bind(&ObjectProxy::RunResponseCallback,
291 this,
292 response_callback,
293 error_callback,
294 start_time,
295 response_message);
296 bus_->GetOriginTaskRunner()->PostTask(FROM_HERE, task);
299 void ObjectProxy::RunResponseCallback(ResponseCallback response_callback,
300 ErrorCallback error_callback,
301 base::TimeTicks start_time,
302 DBusMessage* response_message) {
303 bus_->AssertOnOriginThread();
305 bool method_call_successful = false;
306 if (!response_message) {
307 // The response is not received.
308 error_callback.Run(NULL);
309 } else if (dbus_message_get_type(response_message) ==
310 DBUS_MESSAGE_TYPE_ERROR) {
311 // This will take |response_message| and release (unref) it.
312 scoped_ptr<ErrorResponse> error_response(
313 ErrorResponse::FromRawMessage(response_message));
314 error_callback.Run(error_response.get());
315 // Delete the message on the D-Bus thread. See below for why.
316 bus_->GetDBusTaskRunner()->PostTask(
317 FROM_HERE,
318 base::Bind(&base::DeletePointer<ErrorResponse>,
319 error_response.release()));
320 } else {
321 // This will take |response_message| and release (unref) it.
322 scoped_ptr<Response> response(Response::FromRawMessage(response_message));
323 // The response is successfully received.
324 response_callback.Run(response.get());
325 // The message should be deleted on the D-Bus thread for a complicated
326 // reason:
328 // libdbus keeps track of the number of bytes in the incoming message
329 // queue to ensure that the data size in the queue is manageable. The
330 // bookkeeping is partly done via dbus_message_unref(), and immediately
331 // asks the client code (Chrome) to stop monitoring the underlying
332 // socket, if the number of bytes exceeds a certian number, which is set
333 // to 63MB, per dbus-transport.cc:
335 // /* Try to default to something that won't totally hose the system,
336 // * but doesn't impose too much of a limitation.
337 // */
338 // transport->max_live_messages_size = _DBUS_ONE_MEGABYTE * 63;
340 // The monitoring of the socket is done on the D-Bus thread (see Watch
341 // class in bus.cc), hence we should stop the monitoring from D-Bus
342 // thread, not from the current thread here, which is likely UI thread.
343 bus_->GetDBusTaskRunner()->PostTask(
344 FROM_HERE,
345 base::Bind(&base::DeletePointer<Response>, response.release()));
347 method_call_successful = true;
348 // Record time spent for the method call. Don't include failures.
349 UMA_HISTOGRAM_TIMES("DBus.AsyncMethodCallTime",
350 base::TimeTicks::Now() - start_time);
352 // Record if the method call is successful, or not. 1 if successful.
353 UMA_HISTOGRAM_ENUMERATION("DBus.AsyncMethodCallSuccess",
354 method_call_successful,
355 kSuccessRatioHistogramMaxValue);
358 void ObjectProxy::OnPendingCallIsCompleteThunk(DBusPendingCall* pending_call,
359 void* user_data) {
360 OnPendingCallIsCompleteData* data =
361 reinterpret_cast<OnPendingCallIsCompleteData*>(user_data);
362 ObjectProxy* self = data->object_proxy;
363 self->OnPendingCallIsComplete(pending_call,
364 data->response_callback,
365 data->error_callback,
366 data->start_time);
367 delete data;
370 bool ObjectProxy::ConnectToNameOwnerChangedSignal() {
371 bus_->AssertOnDBusThread();
373 if (!bus_->Connect() || !bus_->SetUpAsyncOperations())
374 return false;
376 // We should add the filter only once. Otherwise, HandleMessage() will
377 // be called more than once.
378 if (!filter_added_) {
379 if (bus_->AddFilterFunction(&ObjectProxy::HandleMessageThunk, this)) {
380 filter_added_ = true;
381 } else {
382 LOG(ERROR) << "Failed to add filter function";
385 // Add a match_rule listening NameOwnerChanged for the well-known name
386 // |service_name_|.
387 const std::string name_owner_changed_match_rule =
388 base::StringPrintf(
389 "type='signal',interface='org.freedesktop.DBus',"
390 "member='NameOwnerChanged',path='/org/freedesktop/DBus',"
391 "sender='org.freedesktop.DBus',arg0='%s'",
392 service_name_.c_str());
394 const bool success =
395 AddMatchRuleWithoutCallback(name_owner_changed_match_rule,
396 "org.freedesktop.DBus.NameOwnerChanged");
398 // Try getting the current name owner. It's not guaranteed that we can get
399 // the name owner at this moment, as the service may not yet be started. If
400 // that's the case, we'll get the name owner via NameOwnerChanged signal,
401 // as soon as the service is started.
402 UpdateNameOwnerAndBlock();
404 return success;
407 bool ObjectProxy::ConnectToSignalInternal(const std::string& interface_name,
408 const std::string& signal_name,
409 SignalCallback signal_callback) {
410 bus_->AssertOnDBusThread();
412 if (!ConnectToNameOwnerChangedSignal())
413 return false;
415 const std::string absolute_signal_name =
416 GetAbsoluteMemberName(interface_name, signal_name);
418 // Add a match rule so the signal goes through HandleMessage().
419 const std::string match_rule =
420 base::StringPrintf("type='signal', interface='%s', path='%s'",
421 interface_name.c_str(),
422 object_path_.value().c_str());
423 return AddMatchRuleWithCallback(match_rule,
424 absolute_signal_name,
425 signal_callback);
428 void ObjectProxy::WaitForServiceToBeAvailableInternal() {
429 bus_->AssertOnDBusThread();
431 if (!ConnectToNameOwnerChangedSignal()) { // Failed to connect to the signal.
432 const bool service_is_ready = false;
433 bus_->GetOriginTaskRunner()->PostTask(
434 FROM_HERE,
435 base::Bind(&ObjectProxy::RunWaitForServiceToBeAvailableCallbacks,
436 this, service_is_ready));
437 return;
440 const bool service_is_available = !service_name_owner_.empty();
441 if (service_is_available) { // Service is already available.
442 bus_->GetOriginTaskRunner()->PostTask(
443 FROM_HERE,
444 base::Bind(&ObjectProxy::RunWaitForServiceToBeAvailableCallbacks,
445 this, service_is_available));
446 return;
450 DBusHandlerResult ObjectProxy::HandleMessage(
451 DBusConnection* connection,
452 DBusMessage* raw_message) {
453 bus_->AssertOnDBusThread();
455 if (dbus_message_get_type(raw_message) != DBUS_MESSAGE_TYPE_SIGNAL)
456 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
458 // raw_message will be unrefed on exit of the function. Increment the
459 // reference so we can use it in Signal.
460 dbus_message_ref(raw_message);
461 scoped_ptr<Signal> signal(
462 Signal::FromRawMessage(raw_message));
464 // Verify the signal comes from the object we're proxying for, this is
465 // our last chance to return DBUS_HANDLER_RESULT_NOT_YET_HANDLED and
466 // allow other object proxies to handle instead.
467 const ObjectPath path = signal->GetPath();
468 if (path != object_path_) {
469 if (path.value() == kDBusSystemObjectPath &&
470 signal->GetMember() == kNameOwnerChangedMember) {
471 // Handle NameOwnerChanged separately
472 return HandleNameOwnerChanged(signal.Pass());
474 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
477 const std::string interface = signal->GetInterface();
478 const std::string member = signal->GetMember();
480 statistics::AddReceivedSignal(service_name_, interface, member);
482 // Check if we know about the signal.
483 const std::string absolute_signal_name = GetAbsoluteMemberName(
484 interface, member);
485 MethodTable::const_iterator iter = method_table_.find(absolute_signal_name);
486 if (iter == method_table_.end()) {
487 // Don't know about the signal.
488 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
490 VLOG(1) << "Signal received: " << signal->ToString();
492 std::string sender = signal->GetSender();
493 if (service_name_owner_ != sender) {
494 LOG(ERROR) << "Rejecting a message from a wrong sender.";
495 UMA_HISTOGRAM_COUNTS("DBus.RejectedSignalCount", 1);
496 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
499 const base::TimeTicks start_time = base::TimeTicks::Now();
500 if (bus_->HasDBusThread()) {
501 // Post a task to run the method in the origin thread.
502 // Transfer the ownership of |signal| to RunMethod().
503 // |released_signal| will be deleted in RunMethod().
504 Signal* released_signal = signal.release();
505 bus_->GetOriginTaskRunner()->PostTask(FROM_HERE,
506 base::Bind(&ObjectProxy::RunMethod,
507 this,
508 start_time,
509 iter->second,
510 released_signal));
511 } else {
512 const base::TimeTicks start_time = base::TimeTicks::Now();
513 // If the D-Bus thread is not used, just call the callback on the
514 // current thread. Transfer the ownership of |signal| to RunMethod().
515 Signal* released_signal = signal.release();
516 RunMethod(start_time, iter->second, released_signal);
519 // We don't return DBUS_HANDLER_RESULT_HANDLED for signals because other
520 // objects may be interested in them. (e.g. Signals from org.freedesktop.DBus)
521 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
524 void ObjectProxy::RunMethod(base::TimeTicks start_time,
525 std::vector<SignalCallback> signal_callbacks,
526 Signal* signal) {
527 bus_->AssertOnOriginThread();
529 for (std::vector<SignalCallback>::iterator iter = signal_callbacks.begin();
530 iter != signal_callbacks.end(); ++iter)
531 iter->Run(signal);
533 // Delete the message on the D-Bus thread. See comments in
534 // RunResponseCallback().
535 bus_->GetDBusTaskRunner()->PostTask(
536 FROM_HERE,
537 base::Bind(&base::DeletePointer<Signal>, signal));
539 // Record time spent for handling the signal.
540 UMA_HISTOGRAM_TIMES("DBus.SignalHandleTime",
541 base::TimeTicks::Now() - start_time);
544 DBusHandlerResult ObjectProxy::HandleMessageThunk(
545 DBusConnection* connection,
546 DBusMessage* raw_message,
547 void* user_data) {
548 ObjectProxy* self = reinterpret_cast<ObjectProxy*>(user_data);
549 return self->HandleMessage(connection, raw_message);
552 void ObjectProxy::LogMethodCallFailure(
553 const base::StringPiece& interface_name,
554 const base::StringPiece& method_name,
555 const base::StringPiece& error_name,
556 const base::StringPiece& error_message) const {
557 if (ignore_service_unknown_errors_ &&
558 (error_name == kErrorServiceUnknown || error_name == kErrorObjectUnknown))
559 return;
560 logging::LogSeverity severity = logging::LOG_ERROR;
561 // "UnknownObject" indicates that an object or service is no longer available,
562 // e.g. a Shill network service has gone out of range. Treat these as warnings
563 // not errors.
564 if (error_name == kErrorObjectUnknown)
565 severity = logging::LOG_WARNING;
566 std::ostringstream msg;
567 msg << "Failed to call method: " << interface_name << "." << method_name
568 << ": object_path= " << object_path_.value()
569 << ": " << error_name << ": " << error_message;
570 logging::LogAtLevel(severity, msg.str());
573 void ObjectProxy::OnCallMethodError(const std::string& interface_name,
574 const std::string& method_name,
575 ResponseCallback response_callback,
576 ErrorResponse* error_response) {
577 if (error_response) {
578 // Error message may contain the error message as string.
579 MessageReader reader(error_response);
580 std::string error_message;
581 reader.PopString(&error_message);
582 LogMethodCallFailure(interface_name,
583 method_name,
584 error_response->GetErrorName(),
585 error_message);
587 response_callback.Run(NULL);
590 bool ObjectProxy::AddMatchRuleWithCallback(
591 const std::string& match_rule,
592 const std::string& absolute_signal_name,
593 SignalCallback signal_callback) {
594 DCHECK(!match_rule.empty());
595 DCHECK(!absolute_signal_name.empty());
596 bus_->AssertOnDBusThread();
598 if (match_rules_.find(match_rule) == match_rules_.end()) {
599 ScopedDBusError error;
600 bus_->AddMatch(match_rule, error.get());
601 if (error.is_set()) {
602 LOG(ERROR) << "Failed to add match rule \"" << match_rule << "\". Got "
603 << error.name() << ": " << error.message();
604 return false;
605 } else {
606 // Store the match rule, so that we can remove this in Detach().
607 match_rules_.insert(match_rule);
608 // Add the signal callback to the method table.
609 method_table_[absolute_signal_name].push_back(signal_callback);
610 return true;
612 } else {
613 // We already have the match rule.
614 method_table_[absolute_signal_name].push_back(signal_callback);
615 return true;
619 bool ObjectProxy::AddMatchRuleWithoutCallback(
620 const std::string& match_rule,
621 const std::string& absolute_signal_name) {
622 DCHECK(!match_rule.empty());
623 DCHECK(!absolute_signal_name.empty());
624 bus_->AssertOnDBusThread();
626 if (match_rules_.find(match_rule) != match_rules_.end())
627 return true;
629 ScopedDBusError error;
630 bus_->AddMatch(match_rule, error.get());
631 if (error.is_set()) {
632 LOG(ERROR) << "Failed to add match rule \"" << match_rule << "\". Got "
633 << error.name() << ": " << error.message();
634 return false;
636 // Store the match rule, so that we can remove this in Detach().
637 match_rules_.insert(match_rule);
638 return true;
641 void ObjectProxy::UpdateNameOwnerAndBlock() {
642 bus_->AssertOnDBusThread();
643 // Errors should be suppressed here, as the service may not be yet running
644 // when connecting to signals of the service, which is just fine.
645 // The ObjectProxy will be notified when the service is launched via
646 // NameOwnerChanged signal. See also comments in ConnectToSignalInternal().
647 service_name_owner_ =
648 bus_->GetServiceOwnerAndBlock(service_name_, Bus::SUPPRESS_ERRORS);
651 DBusHandlerResult ObjectProxy::HandleNameOwnerChanged(
652 scoped_ptr<Signal> signal) {
653 DCHECK(signal);
654 bus_->AssertOnDBusThread();
656 // Confirm the validity of the NameOwnerChanged signal.
657 if (signal->GetMember() == kNameOwnerChangedMember &&
658 signal->GetInterface() == kDBusSystemObjectInterface &&
659 signal->GetSender() == kDBusSystemObjectAddress) {
660 MessageReader reader(signal.get());
661 std::string name, old_owner, new_owner;
662 if (reader.PopString(&name) &&
663 reader.PopString(&old_owner) &&
664 reader.PopString(&new_owner) &&
665 name == service_name_) {
666 service_name_owner_ = new_owner;
667 bus_->GetOriginTaskRunner()->PostTask(
668 FROM_HERE,
669 base::Bind(&ObjectProxy::RunNameOwnerChangedCallback,
670 this, old_owner, new_owner));
672 const bool service_is_available = !service_name_owner_.empty();
673 if (service_is_available) {
674 bus_->GetOriginTaskRunner()->PostTask(
675 FROM_HERE,
676 base::Bind(&ObjectProxy::RunWaitForServiceToBeAvailableCallbacks,
677 this, service_is_available));
682 // Always return unhandled to let other object proxies handle the same
683 // signal.
684 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
687 void ObjectProxy::RunNameOwnerChangedCallback(const std::string& old_owner,
688 const std::string& new_owner) {
689 bus_->AssertOnOriginThread();
690 if (!name_owner_changed_callback_.is_null())
691 name_owner_changed_callback_.Run(old_owner, new_owner);
694 void ObjectProxy::RunWaitForServiceToBeAvailableCallbacks(
695 bool service_is_available) {
696 bus_->AssertOnOriginThread();
698 std::vector<WaitForServiceToBeAvailableCallback> callbacks;
699 callbacks.swap(wait_for_service_to_be_available_callbacks_);
700 for (size_t i = 0; i < callbacks.size(); ++i)
701 callbacks[i].Run(service_is_available);
704 } // namespace dbus