Add more logging to pin down Mac GPU bots random crashes at browser startup.
[chromium-blink-merge.git] / dbus / object_proxy.cc
blob59584f2ce34fa750783b378d2f84f48485ebfdfc
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::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,
107 int timeout_ms) {
108 ScopedDBusError error;
109 return CallMethodAndBlockWithErrorDetails(method_call, timeout_ms, &error);
112 void ObjectProxy::CallMethod(MethodCall* method_call,
113 int timeout_ms,
114 ResponseCallback callback) {
115 CallMethodWithErrorCallback(method_call, timeout_ms, callback,
116 base::Bind(&ObjectProxy::OnCallMethodError,
117 this,
118 method_call->GetInterface(),
119 method_call->GetMember(),
120 callback));
123 void ObjectProxy::CallMethodWithErrorCallback(MethodCall* method_call,
124 int timeout_ms,
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,
136 this,
137 callback,
138 error_callback,
139 start_time,
140 response_message);
141 bus_->GetOriginTaskRunner()->PostTask(FROM_HERE, task);
142 return;
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,
152 this,
153 timeout_ms,
154 request_message,
155 callback,
156 error_callback,
157 start_time);
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 base::PostTaskAndReplyWithResult(
173 bus_->GetDBusTaskRunner(),
174 FROM_HERE,
175 base::Bind(&ObjectProxy::ConnectToSignalInternal,
176 this,
177 interface_name,
178 signal_name,
179 signal_callback),
180 base::Bind(on_connected_callback,
181 interface_name,
182 signal_name));
185 void ObjectProxy::SetNameOwnerChangedCallback(
186 NameOwnerChangedCallback callback) {
187 bus_->AssertOnOriginThread();
189 name_owner_changed_callback_ = callback;
192 void ObjectProxy::WaitForServiceToBeAvailable(
193 WaitForServiceToBeAvailableCallback callback) {
194 bus_->AssertOnOriginThread();
196 wait_for_service_to_be_available_callbacks_.push_back(callback);
197 bus_->GetDBusTaskRunner()->PostTask(
198 FROM_HERE,
199 base::Bind(&ObjectProxy::WaitForServiceToBeAvailableInternal, this));
202 void ObjectProxy::Detach() {
203 bus_->AssertOnDBusThread();
205 if (filter_added_) {
206 if (!bus_->RemoveFilterFunction(&ObjectProxy::HandleMessageThunk, this)) {
207 LOG(ERROR) << "Failed to remove filter function";
211 for (std::set<std::string>::iterator iter = match_rules_.begin();
212 iter != match_rules_.end(); ++iter) {
213 ScopedDBusError error;
214 bus_->RemoveMatch(*iter, error.get());
215 if (error.is_set()) {
216 // There is nothing we can do to recover, so just print the error.
217 LOG(ERROR) << "Failed to remove match rule: " << *iter;
220 match_rules_.clear();
223 // static
224 ObjectProxy::ResponseCallback ObjectProxy::EmptyResponseCallback() {
225 return base::Bind(&EmptyResponseCallbackBody);
228 ObjectProxy::OnPendingCallIsCompleteData::OnPendingCallIsCompleteData(
229 ObjectProxy* in_object_proxy,
230 ResponseCallback in_response_callback,
231 ErrorCallback in_error_callback,
232 base::TimeTicks in_start_time)
233 : object_proxy(in_object_proxy),
234 response_callback(in_response_callback),
235 error_callback(in_error_callback),
236 start_time(in_start_time) {
239 ObjectProxy::OnPendingCallIsCompleteData::~OnPendingCallIsCompleteData() {
242 void ObjectProxy::StartAsyncMethodCall(int timeout_ms,
243 DBusMessage* request_message,
244 ResponseCallback response_callback,
245 ErrorCallback error_callback,
246 base::TimeTicks start_time) {
247 bus_->AssertOnDBusThread();
249 if (!bus_->Connect() || !bus_->SetUpAsyncOperations()) {
250 // In case of a failure, run the error callback with NULL.
251 DBusMessage* response_message = NULL;
252 base::Closure task = base::Bind(&ObjectProxy::RunResponseCallback,
253 this,
254 response_callback,
255 error_callback,
256 start_time,
257 response_message);
258 bus_->GetOriginTaskRunner()->PostTask(FROM_HERE, task);
260 dbus_message_unref(request_message);
261 return;
264 DBusPendingCall* pending_call = NULL;
266 bus_->SendWithReply(request_message, &pending_call, timeout_ms);
268 // Prepare the data we'll be passing to OnPendingCallIsCompleteThunk().
269 // The data will be deleted in OnPendingCallIsCompleteThunk().
270 OnPendingCallIsCompleteData* data =
271 new OnPendingCallIsCompleteData(this, response_callback, error_callback,
272 start_time);
274 // This returns false only when unable to allocate memory.
275 const bool success = dbus_pending_call_set_notify(
276 pending_call,
277 &ObjectProxy::OnPendingCallIsCompleteThunk,
278 data,
279 NULL);
280 CHECK(success) << "Unable to allocate memory";
281 dbus_pending_call_unref(pending_call);
283 // It's now safe to unref the request message.
284 dbus_message_unref(request_message);
287 void ObjectProxy::OnPendingCallIsComplete(DBusPendingCall* pending_call,
288 ResponseCallback response_callback,
289 ErrorCallback error_callback,
290 base::TimeTicks start_time) {
291 bus_->AssertOnDBusThread();
293 DBusMessage* response_message = dbus_pending_call_steal_reply(pending_call);
294 base::Closure task = base::Bind(&ObjectProxy::RunResponseCallback,
295 this,
296 response_callback,
297 error_callback,
298 start_time,
299 response_message);
300 bus_->GetOriginTaskRunner()->PostTask(FROM_HERE, task);
303 void ObjectProxy::RunResponseCallback(ResponseCallback response_callback,
304 ErrorCallback error_callback,
305 base::TimeTicks start_time,
306 DBusMessage* response_message) {
307 bus_->AssertOnOriginThread();
309 bool method_call_successful = false;
310 if (!response_message) {
311 // The response is not received.
312 error_callback.Run(NULL);
313 } else if (dbus_message_get_type(response_message) ==
314 DBUS_MESSAGE_TYPE_ERROR) {
315 // This will take |response_message| and release (unref) it.
316 scoped_ptr<ErrorResponse> error_response(
317 ErrorResponse::FromRawMessage(response_message));
318 error_callback.Run(error_response.get());
319 // Delete the message on the D-Bus thread. See below for why.
320 bus_->GetDBusTaskRunner()->PostTask(
321 FROM_HERE,
322 base::Bind(&base::DeletePointer<ErrorResponse>,
323 error_response.release()));
324 } else {
325 // This will take |response_message| and release (unref) it.
326 scoped_ptr<Response> response(Response::FromRawMessage(response_message));
327 // The response is successfully received.
328 response_callback.Run(response.get());
329 // The message should be deleted on the D-Bus thread for a complicated
330 // reason:
332 // libdbus keeps track of the number of bytes in the incoming message
333 // queue to ensure that the data size in the queue is manageable. The
334 // bookkeeping is partly done via dbus_message_unref(), and immediately
335 // asks the client code (Chrome) to stop monitoring the underlying
336 // socket, if the number of bytes exceeds a certian number, which is set
337 // to 63MB, per dbus-transport.cc:
339 // /* Try to default to something that won't totally hose the system,
340 // * but doesn't impose too much of a limitation.
341 // */
342 // transport->max_live_messages_size = _DBUS_ONE_MEGABYTE * 63;
344 // The monitoring of the socket is done on the D-Bus thread (see Watch
345 // class in bus.cc), hence we should stop the monitoring from D-Bus
346 // thread, not from the current thread here, which is likely UI thread.
347 bus_->GetDBusTaskRunner()->PostTask(
348 FROM_HERE,
349 base::Bind(&base::DeletePointer<Response>, response.release()));
351 method_call_successful = true;
352 // Record time spent for the method call. Don't include failures.
353 UMA_HISTOGRAM_TIMES("DBus.AsyncMethodCallTime",
354 base::TimeTicks::Now() - start_time);
356 // Record if the method call is successful, or not. 1 if successful.
357 UMA_HISTOGRAM_ENUMERATION("DBus.AsyncMethodCallSuccess",
358 method_call_successful,
359 kSuccessRatioHistogramMaxValue);
362 void ObjectProxy::OnPendingCallIsCompleteThunk(DBusPendingCall* pending_call,
363 void* user_data) {
364 OnPendingCallIsCompleteData* data =
365 reinterpret_cast<OnPendingCallIsCompleteData*>(user_data);
366 ObjectProxy* self = data->object_proxy;
367 self->OnPendingCallIsComplete(pending_call,
368 data->response_callback,
369 data->error_callback,
370 data->start_time);
371 delete data;
374 bool ObjectProxy::ConnectToNameOwnerChangedSignal() {
375 bus_->AssertOnDBusThread();
377 if (!bus_->Connect() || !bus_->SetUpAsyncOperations())
378 return false;
380 // We should add the filter only once. Otherwise, HandleMessage() will
381 // be called more than once.
382 if (!filter_added_) {
383 if (bus_->AddFilterFunction(&ObjectProxy::HandleMessageThunk, this)) {
384 filter_added_ = true;
385 } else {
386 LOG(ERROR) << "Failed to add filter function";
389 // Add a match_rule listening NameOwnerChanged for the well-known name
390 // |service_name_|.
391 const std::string name_owner_changed_match_rule =
392 base::StringPrintf(
393 "type='signal',interface='org.freedesktop.DBus',"
394 "member='NameOwnerChanged',path='/org/freedesktop/DBus',"
395 "sender='org.freedesktop.DBus',arg0='%s'",
396 service_name_.c_str());
398 const bool success =
399 AddMatchRuleWithoutCallback(name_owner_changed_match_rule,
400 "org.freedesktop.DBus.NameOwnerChanged");
402 // Try getting the current name owner. It's not guaranteed that we can get
403 // the name owner at this moment, as the service may not yet be started. If
404 // that's the case, we'll get the name owner via NameOwnerChanged signal,
405 // as soon as the service is started.
406 UpdateNameOwnerAndBlock();
408 return success;
411 bool ObjectProxy::ConnectToSignalInternal(const std::string& interface_name,
412 const std::string& signal_name,
413 SignalCallback signal_callback) {
414 bus_->AssertOnDBusThread();
416 if (!ConnectToNameOwnerChangedSignal())
417 return false;
419 const std::string absolute_signal_name =
420 GetAbsoluteMemberName(interface_name, signal_name);
422 // Add a match rule so the signal goes through HandleMessage().
423 const std::string match_rule =
424 base::StringPrintf("type='signal', interface='%s', path='%s'",
425 interface_name.c_str(),
426 object_path_.value().c_str());
427 return AddMatchRuleWithCallback(match_rule,
428 absolute_signal_name,
429 signal_callback);
432 void ObjectProxy::WaitForServiceToBeAvailableInternal() {
433 bus_->AssertOnDBusThread();
435 if (!ConnectToNameOwnerChangedSignal()) { // Failed to connect to the signal.
436 const bool service_is_ready = false;
437 bus_->GetOriginTaskRunner()->PostTask(
438 FROM_HERE,
439 base::Bind(&ObjectProxy::RunWaitForServiceToBeAvailableCallbacks,
440 this, service_is_ready));
441 return;
444 const bool service_is_available = !service_name_owner_.empty();
445 if (service_is_available) { // Service is already available.
446 bus_->GetOriginTaskRunner()->PostTask(
447 FROM_HERE,
448 base::Bind(&ObjectProxy::RunWaitForServiceToBeAvailableCallbacks,
449 this, service_is_available));
450 return;
454 DBusHandlerResult ObjectProxy::HandleMessage(
455 DBusConnection* connection,
456 DBusMessage* raw_message) {
457 bus_->AssertOnDBusThread();
459 if (dbus_message_get_type(raw_message) != DBUS_MESSAGE_TYPE_SIGNAL)
460 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
462 // raw_message will be unrefed on exit of the function. Increment the
463 // reference so we can use it in Signal.
464 dbus_message_ref(raw_message);
465 scoped_ptr<Signal> signal(
466 Signal::FromRawMessage(raw_message));
468 // Verify the signal comes from the object we're proxying for, this is
469 // our last chance to return DBUS_HANDLER_RESULT_NOT_YET_HANDLED and
470 // allow other object proxies to handle instead.
471 const ObjectPath path = signal->GetPath();
472 if (path != object_path_) {
473 if (path.value() == kDBusSystemObjectPath &&
474 signal->GetMember() == kNameOwnerChangedMember) {
475 // Handle NameOwnerChanged separately
476 return HandleNameOwnerChanged(signal.Pass());
478 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
481 const std::string interface = signal->GetInterface();
482 const std::string member = signal->GetMember();
484 statistics::AddReceivedSignal(service_name_, interface, member);
486 // Check if we know about the signal.
487 const std::string absolute_signal_name = GetAbsoluteMemberName(
488 interface, member);
489 MethodTable::const_iterator iter = method_table_.find(absolute_signal_name);
490 if (iter == method_table_.end()) {
491 // Don't know about the signal.
492 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
494 VLOG(1) << "Signal received: " << signal->ToString();
496 std::string sender = signal->GetSender();
497 if (service_name_owner_ != sender) {
498 LOG(ERROR) << "Rejecting a message from a wrong sender.";
499 UMA_HISTOGRAM_COUNTS("DBus.RejectedSignalCount", 1);
500 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
503 const base::TimeTicks start_time = base::TimeTicks::Now();
504 if (bus_->HasDBusThread()) {
505 // Post a task to run the method in the origin thread.
506 // Transfer the ownership of |signal| to RunMethod().
507 // |released_signal| will be deleted in RunMethod().
508 Signal* released_signal = signal.release();
509 bus_->GetOriginTaskRunner()->PostTask(FROM_HERE,
510 base::Bind(&ObjectProxy::RunMethod,
511 this,
512 start_time,
513 iter->second,
514 released_signal));
515 } else {
516 const base::TimeTicks start_time = base::TimeTicks::Now();
517 // If the D-Bus thread is not used, just call the callback on the
518 // current thread. Transfer the ownership of |signal| to RunMethod().
519 Signal* released_signal = signal.release();
520 RunMethod(start_time, iter->second, released_signal);
523 // We don't return DBUS_HANDLER_RESULT_HANDLED for signals because other
524 // objects may be interested in them. (e.g. Signals from org.freedesktop.DBus)
525 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
528 void ObjectProxy::RunMethod(base::TimeTicks start_time,
529 std::vector<SignalCallback> signal_callbacks,
530 Signal* signal) {
531 bus_->AssertOnOriginThread();
533 for (std::vector<SignalCallback>::iterator iter = signal_callbacks.begin();
534 iter != signal_callbacks.end(); ++iter)
535 iter->Run(signal);
537 // Delete the message on the D-Bus thread. See comments in
538 // RunResponseCallback().
539 bus_->GetDBusTaskRunner()->PostTask(
540 FROM_HERE,
541 base::Bind(&base::DeletePointer<Signal>, signal));
543 // Record time spent for handling the signal.
544 UMA_HISTOGRAM_TIMES("DBus.SignalHandleTime",
545 base::TimeTicks::Now() - start_time);
548 DBusHandlerResult ObjectProxy::HandleMessageThunk(
549 DBusConnection* connection,
550 DBusMessage* raw_message,
551 void* user_data) {
552 ObjectProxy* self = reinterpret_cast<ObjectProxy*>(user_data);
553 return self->HandleMessage(connection, raw_message);
556 void ObjectProxy::LogMethodCallFailure(
557 const base::StringPiece& interface_name,
558 const base::StringPiece& method_name,
559 const base::StringPiece& error_name,
560 const base::StringPiece& error_message) const {
561 if (ignore_service_unknown_errors_ &&
562 (error_name == kErrorServiceUnknown || error_name == kErrorObjectUnknown))
563 return;
564 logging::LogSeverity severity = logging::LOG_ERROR;
565 // "UnknownObject" indicates that an object or service is no longer available,
566 // e.g. a Shill network service has gone out of range. Treat these as warnings
567 // not errors.
568 if (error_name == kErrorObjectUnknown)
569 severity = logging::LOG_WARNING;
570 std::ostringstream msg;
571 msg << "Failed to call method: " << interface_name << "." << method_name
572 << ": object_path= " << object_path_.value()
573 << ": " << error_name << ": " << error_message;
574 logging::LogAtLevel(severity, msg.str());
577 void ObjectProxy::OnCallMethodError(const std::string& interface_name,
578 const std::string& method_name,
579 ResponseCallback response_callback,
580 ErrorResponse* error_response) {
581 if (error_response) {
582 // Error message may contain the error message as string.
583 MessageReader reader(error_response);
584 std::string error_message;
585 reader.PopString(&error_message);
586 LogMethodCallFailure(interface_name,
587 method_name,
588 error_response->GetErrorName(),
589 error_message);
591 response_callback.Run(NULL);
594 bool ObjectProxy::AddMatchRuleWithCallback(
595 const std::string& match_rule,
596 const std::string& absolute_signal_name,
597 SignalCallback signal_callback) {
598 DCHECK(!match_rule.empty());
599 DCHECK(!absolute_signal_name.empty());
600 bus_->AssertOnDBusThread();
602 if (match_rules_.find(match_rule) == match_rules_.end()) {
603 ScopedDBusError error;
604 bus_->AddMatch(match_rule, error.get());
605 if (error.is_set()) {
606 LOG(ERROR) << "Failed to add match rule \"" << match_rule << "\". Got "
607 << error.name() << ": " << error.message();
608 return false;
609 } else {
610 // Store the match rule, so that we can remove this in Detach().
611 match_rules_.insert(match_rule);
612 // Add the signal callback to the method table.
613 method_table_[absolute_signal_name].push_back(signal_callback);
614 return true;
616 } else {
617 // We already have the match rule.
618 method_table_[absolute_signal_name].push_back(signal_callback);
619 return true;
623 bool ObjectProxy::AddMatchRuleWithoutCallback(
624 const std::string& match_rule,
625 const std::string& absolute_signal_name) {
626 DCHECK(!match_rule.empty());
627 DCHECK(!absolute_signal_name.empty());
628 bus_->AssertOnDBusThread();
630 if (match_rules_.find(match_rule) != match_rules_.end())
631 return true;
633 ScopedDBusError error;
634 bus_->AddMatch(match_rule, error.get());
635 if (error.is_set()) {
636 LOG(ERROR) << "Failed to add match rule \"" << match_rule << "\". Got "
637 << error.name() << ": " << error.message();
638 return false;
640 // Store the match rule, so that we can remove this in Detach().
641 match_rules_.insert(match_rule);
642 return true;
645 void ObjectProxy::UpdateNameOwnerAndBlock() {
646 bus_->AssertOnDBusThread();
647 // Errors should be suppressed here, as the service may not be yet running
648 // when connecting to signals of the service, which is just fine.
649 // The ObjectProxy will be notified when the service is launched via
650 // NameOwnerChanged signal. See also comments in ConnectToSignalInternal().
651 service_name_owner_ =
652 bus_->GetServiceOwnerAndBlock(service_name_, Bus::SUPPRESS_ERRORS);
655 DBusHandlerResult ObjectProxy::HandleNameOwnerChanged(
656 scoped_ptr<Signal> signal) {
657 DCHECK(signal);
658 bus_->AssertOnDBusThread();
660 // Confirm the validity of the NameOwnerChanged signal.
661 if (signal->GetMember() == kNameOwnerChangedMember &&
662 signal->GetInterface() == kDBusSystemObjectInterface &&
663 signal->GetSender() == kDBusSystemObjectAddress) {
664 MessageReader reader(signal.get());
665 std::string name, old_owner, new_owner;
666 if (reader.PopString(&name) &&
667 reader.PopString(&old_owner) &&
668 reader.PopString(&new_owner) &&
669 name == service_name_) {
670 service_name_owner_ = new_owner;
671 bus_->GetOriginTaskRunner()->PostTask(
672 FROM_HERE,
673 base::Bind(&ObjectProxy::RunNameOwnerChangedCallback,
674 this, old_owner, new_owner));
676 const bool service_is_available = !service_name_owner_.empty();
677 if (service_is_available) {
678 bus_->GetOriginTaskRunner()->PostTask(
679 FROM_HERE,
680 base::Bind(&ObjectProxy::RunWaitForServiceToBeAvailableCallbacks,
681 this, service_is_available));
686 // Always return unhandled to let other object proxies handle the same
687 // signal.
688 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
691 void ObjectProxy::RunNameOwnerChangedCallback(const std::string& old_owner,
692 const std::string& new_owner) {
693 bus_->AssertOnOriginThread();
694 if (!name_owner_changed_callback_.is_null())
695 name_owner_changed_callback_.Run(old_owner, new_owner);
698 void ObjectProxy::RunWaitForServiceToBeAvailableCallbacks(
699 bool service_is_available) {
700 bus_->AssertOnOriginThread();
702 std::vector<WaitForServiceToBeAvailableCallback> callbacks;
703 callbacks.swap(wait_for_service_to_be_available_callbacks_);
704 for (size_t i = 0; i < callbacks.size(); ++i)
705 callbacks[i].Run(service_is_available);
708 } // namespace dbus