Mask the value of passwords in accessible value.
[chromium-blink-merge.git] / dbus / object_proxy.cc
blob7347db0ad726fd8e35d1d0624b5093caccd15648
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 ignore_service_unknown_errors_(
59 options & IGNORE_SERVICE_UNKNOWN_ERRORS) {
62 ObjectProxy::~ObjectProxy() {
65 // Originally we tried to make |method_call| a const reference, but we
66 // gave up as dbus_connection_send_with_reply_and_block() takes a
67 // non-const pointer of DBusMessage as the second parameter.
68 scoped_ptr<Response> ObjectProxy::CallMethodAndBlockWithErrorDetails(
69 MethodCall* method_call, int timeout_ms, ScopedDBusError* error) {
70 bus_->AssertOnDBusThread();
72 if (!bus_->Connect() ||
73 !method_call->SetDestination(service_name_) ||
74 !method_call->SetPath(object_path_))
75 return scoped_ptr<Response>();
77 DBusMessage* request_message = method_call->raw_message();
79 // Send the message synchronously.
80 const base::TimeTicks start_time = base::TimeTicks::Now();
81 DBusMessage* response_message =
82 bus_->SendWithReplyAndBlock(request_message, timeout_ms, error->get());
83 // Record if the method call is successful, or not. 1 if successful.
84 UMA_HISTOGRAM_ENUMERATION("DBus.SyncMethodCallSuccess",
85 response_message ? 1 : 0,
86 kSuccessRatioHistogramMaxValue);
87 statistics::AddBlockingSentMethodCall(service_name_,
88 method_call->GetInterface(),
89 method_call->GetMember());
91 if (!response_message) {
92 LogMethodCallFailure(method_call->GetInterface(),
93 method_call->GetMember(),
94 error->is_set() ? error->name() : "unknown error type",
95 error->is_set() ? error->message() : "");
96 return scoped_ptr<Response>();
98 // Record time spent for the method call. Don't include failures.
99 UMA_HISTOGRAM_TIMES("DBus.SyncMethodCallTime",
100 base::TimeTicks::Now() - start_time);
102 return Response::FromRawMessage(response_message);
105 scoped_ptr<Response> ObjectProxy::CallMethodAndBlock(MethodCall* method_call,
106 int timeout_ms) {
107 ScopedDBusError error;
108 return CallMethodAndBlockWithErrorDetails(method_call, timeout_ms, &error);
111 void ObjectProxy::CallMethod(MethodCall* method_call,
112 int timeout_ms,
113 ResponseCallback callback) {
114 CallMethodWithErrorCallback(method_call, timeout_ms, callback,
115 base::Bind(&ObjectProxy::OnCallMethodError,
116 this,
117 method_call->GetInterface(),
118 method_call->GetMember(),
119 callback));
122 void ObjectProxy::CallMethodWithErrorCallback(MethodCall* method_call,
123 int timeout_ms,
124 ResponseCallback callback,
125 ErrorCallback error_callback) {
126 bus_->AssertOnOriginThread();
128 const base::TimeTicks start_time = base::TimeTicks::Now();
130 if (!method_call->SetDestination(service_name_) ||
131 !method_call->SetPath(object_path_)) {
132 // In case of a failure, run the error callback with NULL.
133 DBusMessage* response_message = NULL;
134 base::Closure task = base::Bind(&ObjectProxy::RunResponseCallback,
135 this,
136 callback,
137 error_callback,
138 start_time,
139 response_message);
140 bus_->GetOriginTaskRunner()->PostTask(FROM_HERE, task);
141 return;
144 // Increment the reference count so we can safely reference the
145 // underlying request message until the method call is complete. This
146 // will be unref'ed in StartAsyncMethodCall().
147 DBusMessage* request_message = method_call->raw_message();
148 dbus_message_ref(request_message);
150 base::Closure task = base::Bind(&ObjectProxy::StartAsyncMethodCall,
151 this,
152 timeout_ms,
153 request_message,
154 callback,
155 error_callback,
156 start_time);
157 statistics::AddSentMethodCall(service_name_,
158 method_call->GetInterface(),
159 method_call->GetMember());
161 // Wait for the response in the D-Bus thread.
162 bus_->GetDBusTaskRunner()->PostTask(FROM_HERE, task);
165 void ObjectProxy::ConnectToSignal(const std::string& interface_name,
166 const std::string& signal_name,
167 SignalCallback signal_callback,
168 OnConnectedCallback on_connected_callback) {
169 bus_->AssertOnOriginThread();
171 if (bus_->HasDBusThread()) {
172 base::PostTaskAndReplyWithResult(
173 bus_->GetDBusTaskRunner(), FROM_HERE,
174 base::Bind(&ObjectProxy::ConnectToSignalInternal, this, interface_name,
175 signal_name, signal_callback),
176 base::Bind(on_connected_callback, interface_name, signal_name));
177 } else {
178 // If the bus doesn't have a dedicated dbus thread we need to call
179 // ConnectToSignalInternal directly otherwise we might miss a signal
180 // that is currently queued if we do a PostTask.
181 const bool success =
182 ConnectToSignalInternal(interface_name, signal_name, signal_callback);
183 on_connected_callback.Run(interface_name, signal_name, success);
187 void ObjectProxy::SetNameOwnerChangedCallback(
188 NameOwnerChangedCallback callback) {
189 bus_->AssertOnOriginThread();
191 name_owner_changed_callback_ = callback;
194 void ObjectProxy::WaitForServiceToBeAvailable(
195 WaitForServiceToBeAvailableCallback callback) {
196 bus_->AssertOnOriginThread();
198 wait_for_service_to_be_available_callbacks_.push_back(callback);
199 bus_->GetDBusTaskRunner()->PostTask(
200 FROM_HERE,
201 base::Bind(&ObjectProxy::WaitForServiceToBeAvailableInternal, this));
204 void ObjectProxy::Detach() {
205 bus_->AssertOnDBusThread();
207 if (bus_->is_connected())
208 bus_->RemoveFilterFunction(&ObjectProxy::HandleMessageThunk, this);
210 for (std::set<std::string>::iterator iter = match_rules_.begin();
211 iter != match_rules_.end(); ++iter) {
212 ScopedDBusError error;
213 bus_->RemoveMatch(*iter, 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: " << *iter;
219 match_rules_.clear();
222 // static
223 ObjectProxy::ResponseCallback ObjectProxy::EmptyResponseCallback() {
224 return base::Bind(&EmptyResponseCallbackBody);
227 ObjectProxy::OnPendingCallIsCompleteData::OnPendingCallIsCompleteData(
228 ObjectProxy* in_object_proxy,
229 ResponseCallback in_response_callback,
230 ErrorCallback in_error_callback,
231 base::TimeTicks in_start_time)
232 : object_proxy(in_object_proxy),
233 response_callback(in_response_callback),
234 error_callback(in_error_callback),
235 start_time(in_start_time) {
238 ObjectProxy::OnPendingCallIsCompleteData::~OnPendingCallIsCompleteData() {
241 void ObjectProxy::StartAsyncMethodCall(int timeout_ms,
242 DBusMessage* request_message,
243 ResponseCallback response_callback,
244 ErrorCallback error_callback,
245 base::TimeTicks start_time) {
246 bus_->AssertOnDBusThread();
248 if (!bus_->Connect() || !bus_->SetUpAsyncOperations()) {
249 // In case of a failure, run the error callback with NULL.
250 DBusMessage* response_message = NULL;
251 base::Closure task = base::Bind(&ObjectProxy::RunResponseCallback,
252 this,
253 response_callback,
254 error_callback,
255 start_time,
256 response_message);
257 bus_->GetOriginTaskRunner()->PostTask(FROM_HERE, task);
259 dbus_message_unref(request_message);
260 return;
263 DBusPendingCall* pending_call = NULL;
265 bus_->SendWithReply(request_message, &pending_call, timeout_ms);
267 // Prepare the data we'll be passing to OnPendingCallIsCompleteThunk().
268 // The data will be deleted in OnPendingCallIsCompleteThunk().
269 OnPendingCallIsCompleteData* data =
270 new OnPendingCallIsCompleteData(this, response_callback, error_callback,
271 start_time);
273 // This returns false only when unable to allocate memory.
274 const bool success = dbus_pending_call_set_notify(
275 pending_call,
276 &ObjectProxy::OnPendingCallIsCompleteThunk,
277 data,
278 NULL);
279 CHECK(success) << "Unable to allocate memory";
280 dbus_pending_call_unref(pending_call);
282 // It's now safe to unref the request message.
283 dbus_message_unref(request_message);
286 void ObjectProxy::OnPendingCallIsComplete(DBusPendingCall* pending_call,
287 ResponseCallback response_callback,
288 ErrorCallback error_callback,
289 base::TimeTicks start_time) {
290 bus_->AssertOnDBusThread();
292 DBusMessage* response_message = dbus_pending_call_steal_reply(pending_call);
293 base::Closure task = base::Bind(&ObjectProxy::RunResponseCallback,
294 this,
295 response_callback,
296 error_callback,
297 start_time,
298 response_message);
299 bus_->GetOriginTaskRunner()->PostTask(FROM_HERE, task);
302 void ObjectProxy::RunResponseCallback(ResponseCallback response_callback,
303 ErrorCallback error_callback,
304 base::TimeTicks start_time,
305 DBusMessage* response_message) {
306 bus_->AssertOnOriginThread();
308 bool method_call_successful = false;
309 if (!response_message) {
310 // The response is not received.
311 error_callback.Run(NULL);
312 } else if (dbus_message_get_type(response_message) ==
313 DBUS_MESSAGE_TYPE_ERROR) {
314 // This will take |response_message| and release (unref) it.
315 scoped_ptr<ErrorResponse> error_response(
316 ErrorResponse::FromRawMessage(response_message));
317 error_callback.Run(error_response.get());
318 // Delete the message on the D-Bus thread. See below for why.
319 bus_->GetDBusTaskRunner()->PostTask(
320 FROM_HERE,
321 base::Bind(&base::DeletePointer<ErrorResponse>,
322 error_response.release()));
323 } else {
324 // This will take |response_message| and release (unref) it.
325 scoped_ptr<Response> response(Response::FromRawMessage(response_message));
326 // The response is successfully received.
327 response_callback.Run(response.get());
328 // The message should be deleted on the D-Bus thread for a complicated
329 // reason:
331 // libdbus keeps track of the number of bytes in the incoming message
332 // queue to ensure that the data size in the queue is manageable. The
333 // bookkeeping is partly done via dbus_message_unref(), and immediately
334 // asks the client code (Chrome) to stop monitoring the underlying
335 // socket, if the number of bytes exceeds a certian number, which is set
336 // to 63MB, per dbus-transport.cc:
338 // /* Try to default to something that won't totally hose the system,
339 // * but doesn't impose too much of a limitation.
340 // */
341 // transport->max_live_messages_size = _DBUS_ONE_MEGABYTE * 63;
343 // The monitoring of the socket is done on the D-Bus thread (see Watch
344 // class in bus.cc), hence we should stop the monitoring from D-Bus
345 // thread, not from the current thread here, which is likely UI thread.
346 bus_->GetDBusTaskRunner()->PostTask(
347 FROM_HERE,
348 base::Bind(&base::DeletePointer<Response>, response.release()));
350 method_call_successful = true;
351 // Record time spent for the method call. Don't include failures.
352 UMA_HISTOGRAM_TIMES("DBus.AsyncMethodCallTime",
353 base::TimeTicks::Now() - start_time);
355 // Record if the method call is successful, or not. 1 if successful.
356 UMA_HISTOGRAM_ENUMERATION("DBus.AsyncMethodCallSuccess",
357 method_call_successful,
358 kSuccessRatioHistogramMaxValue);
361 void ObjectProxy::OnPendingCallIsCompleteThunk(DBusPendingCall* pending_call,
362 void* user_data) {
363 OnPendingCallIsCompleteData* data =
364 reinterpret_cast<OnPendingCallIsCompleteData*>(user_data);
365 ObjectProxy* self = data->object_proxy;
366 self->OnPendingCallIsComplete(pending_call,
367 data->response_callback,
368 data->error_callback,
369 data->start_time);
370 delete data;
373 bool ObjectProxy::ConnectToNameOwnerChangedSignal() {
374 bus_->AssertOnDBusThread();
376 if (!bus_->Connect() || !bus_->SetUpAsyncOperations())
377 return false;
379 bus_->AddFilterFunction(&ObjectProxy::HandleMessageThunk, this);
381 // Add a match_rule listening NameOwnerChanged for the well-known name
382 // |service_name_|.
383 const std::string name_owner_changed_match_rule =
384 base::StringPrintf(
385 "type='signal',interface='org.freedesktop.DBus',"
386 "member='NameOwnerChanged',path='/org/freedesktop/DBus',"
387 "sender='org.freedesktop.DBus',arg0='%s'",
388 service_name_.c_str());
390 const bool success =
391 AddMatchRuleWithoutCallback(name_owner_changed_match_rule,
392 "org.freedesktop.DBus.NameOwnerChanged");
394 // Try getting the current name owner. It's not guaranteed that we can get
395 // the name owner at this moment, as the service may not yet be started. If
396 // that's the case, we'll get the name owner via NameOwnerChanged signal,
397 // as soon as the service is started.
398 UpdateNameOwnerAndBlock();
400 return success;
403 bool ObjectProxy::ConnectToSignalInternal(const std::string& interface_name,
404 const std::string& signal_name,
405 SignalCallback signal_callback) {
406 bus_->AssertOnDBusThread();
408 if (!ConnectToNameOwnerChangedSignal())
409 return false;
411 const std::string absolute_signal_name =
412 GetAbsoluteMemberName(interface_name, signal_name);
414 // Add a match rule so the signal goes through HandleMessage().
415 const std::string match_rule =
416 base::StringPrintf("type='signal', interface='%s', path='%s'",
417 interface_name.c_str(),
418 object_path_.value().c_str());
419 return AddMatchRuleWithCallback(match_rule,
420 absolute_signal_name,
421 signal_callback);
424 void ObjectProxy::WaitForServiceToBeAvailableInternal() {
425 bus_->AssertOnDBusThread();
427 if (!ConnectToNameOwnerChangedSignal()) { // Failed to connect to the signal.
428 const bool service_is_ready = false;
429 bus_->GetOriginTaskRunner()->PostTask(
430 FROM_HERE,
431 base::Bind(&ObjectProxy::RunWaitForServiceToBeAvailableCallbacks,
432 this, service_is_ready));
433 return;
436 const bool service_is_available = !service_name_owner_.empty();
437 if (service_is_available) { // Service is already available.
438 bus_->GetOriginTaskRunner()->PostTask(
439 FROM_HERE,
440 base::Bind(&ObjectProxy::RunWaitForServiceToBeAvailableCallbacks,
441 this, service_is_available));
442 return;
446 DBusHandlerResult ObjectProxy::HandleMessage(
447 DBusConnection* connection,
448 DBusMessage* raw_message) {
449 bus_->AssertOnDBusThread();
451 if (dbus_message_get_type(raw_message) != DBUS_MESSAGE_TYPE_SIGNAL)
452 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
454 // raw_message will be unrefed on exit of the function. Increment the
455 // reference so we can use it in Signal.
456 dbus_message_ref(raw_message);
457 scoped_ptr<Signal> signal(
458 Signal::FromRawMessage(raw_message));
460 // Verify the signal comes from the object we're proxying for, this is
461 // our last chance to return DBUS_HANDLER_RESULT_NOT_YET_HANDLED and
462 // allow other object proxies to handle instead.
463 const ObjectPath path = signal->GetPath();
464 if (path != object_path_) {
465 if (path.value() == kDBusSystemObjectPath &&
466 signal->GetMember() == kNameOwnerChangedMember) {
467 // Handle NameOwnerChanged separately
468 return HandleNameOwnerChanged(signal.Pass());
470 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
473 const std::string interface = signal->GetInterface();
474 const std::string member = signal->GetMember();
476 statistics::AddReceivedSignal(service_name_, interface, member);
478 // Check if we know about the signal.
479 const std::string absolute_signal_name = GetAbsoluteMemberName(
480 interface, member);
481 MethodTable::const_iterator iter = method_table_.find(absolute_signal_name);
482 if (iter == method_table_.end()) {
483 // Don't know about the signal.
484 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
486 VLOG(1) << "Signal received: " << signal->ToString();
488 std::string sender = signal->GetSender();
489 if (service_name_owner_ != sender) {
490 LOG(ERROR) << "Rejecting a message from a wrong sender.";
491 UMA_HISTOGRAM_COUNTS("DBus.RejectedSignalCount", 1);
492 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
495 const base::TimeTicks start_time = base::TimeTicks::Now();
496 if (bus_->HasDBusThread()) {
497 // Post a task to run the method in the origin thread.
498 // Transfer the ownership of |signal| to RunMethod().
499 // |released_signal| will be deleted in RunMethod().
500 Signal* released_signal = signal.release();
501 bus_->GetOriginTaskRunner()->PostTask(FROM_HERE,
502 base::Bind(&ObjectProxy::RunMethod,
503 this,
504 start_time,
505 iter->second,
506 released_signal));
507 } else {
508 const base::TimeTicks start_time = base::TimeTicks::Now();
509 // If the D-Bus thread is not used, just call the callback on the
510 // current thread. Transfer the ownership of |signal| to RunMethod().
511 Signal* released_signal = signal.release();
512 RunMethod(start_time, iter->second, released_signal);
515 // We don't return DBUS_HANDLER_RESULT_HANDLED for signals because other
516 // objects may be interested in them. (e.g. Signals from org.freedesktop.DBus)
517 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
520 void ObjectProxy::RunMethod(base::TimeTicks start_time,
521 std::vector<SignalCallback> signal_callbacks,
522 Signal* signal) {
523 bus_->AssertOnOriginThread();
525 for (std::vector<SignalCallback>::iterator iter = signal_callbacks.begin();
526 iter != signal_callbacks.end(); ++iter)
527 iter->Run(signal);
529 // Delete the message on the D-Bus thread. See comments in
530 // RunResponseCallback().
531 bus_->GetDBusTaskRunner()->PostTask(
532 FROM_HERE,
533 base::Bind(&base::DeletePointer<Signal>, signal));
535 // Record time spent for handling the signal.
536 UMA_HISTOGRAM_TIMES("DBus.SignalHandleTime",
537 base::TimeTicks::Now() - start_time);
540 DBusHandlerResult ObjectProxy::HandleMessageThunk(
541 DBusConnection* connection,
542 DBusMessage* raw_message,
543 void* user_data) {
544 ObjectProxy* self = reinterpret_cast<ObjectProxy*>(user_data);
545 return self->HandleMessage(connection, raw_message);
548 void ObjectProxy::LogMethodCallFailure(
549 const base::StringPiece& interface_name,
550 const base::StringPiece& method_name,
551 const base::StringPiece& error_name,
552 const base::StringPiece& error_message) const {
553 if (ignore_service_unknown_errors_ &&
554 (error_name == kErrorServiceUnknown || error_name == kErrorObjectUnknown))
555 return;
556 logging::LogSeverity severity = logging::LOG_ERROR;
557 // "UnknownObject" indicates that an object or service is no longer available,
558 // e.g. a Shill network service has gone out of range. Treat these as warnings
559 // not errors.
560 if (error_name == kErrorObjectUnknown)
561 severity = logging::LOG_WARNING;
562 std::ostringstream msg;
563 msg << "Failed to call method: " << interface_name << "." << method_name
564 << ": object_path= " << object_path_.value()
565 << ": " << error_name << ": " << error_message;
566 logging::LogAtLevel(severity, msg.str());
569 void ObjectProxy::OnCallMethodError(const std::string& interface_name,
570 const std::string& method_name,
571 ResponseCallback response_callback,
572 ErrorResponse* error_response) {
573 if (error_response) {
574 // Error message may contain the error message as string.
575 MessageReader reader(error_response);
576 std::string error_message;
577 reader.PopString(&error_message);
578 LogMethodCallFailure(interface_name,
579 method_name,
580 error_response->GetErrorName(),
581 error_message);
583 response_callback.Run(NULL);
586 bool ObjectProxy::AddMatchRuleWithCallback(
587 const std::string& match_rule,
588 const std::string& absolute_signal_name,
589 SignalCallback signal_callback) {
590 DCHECK(!match_rule.empty());
591 DCHECK(!absolute_signal_name.empty());
592 bus_->AssertOnDBusThread();
594 if (match_rules_.find(match_rule) == match_rules_.end()) {
595 ScopedDBusError error;
596 bus_->AddMatch(match_rule, error.get());
597 if (error.is_set()) {
598 LOG(ERROR) << "Failed to add match rule \"" << match_rule << "\". Got "
599 << error.name() << ": " << error.message();
600 return false;
601 } else {
602 // Store the match rule, so that we can remove this in Detach().
603 match_rules_.insert(match_rule);
604 // Add the signal callback to the method table.
605 method_table_[absolute_signal_name].push_back(signal_callback);
606 return true;
608 } else {
609 // We already have the match rule.
610 method_table_[absolute_signal_name].push_back(signal_callback);
611 return true;
615 bool ObjectProxy::AddMatchRuleWithoutCallback(
616 const std::string& match_rule,
617 const std::string& absolute_signal_name) {
618 DCHECK(!match_rule.empty());
619 DCHECK(!absolute_signal_name.empty());
620 bus_->AssertOnDBusThread();
622 if (match_rules_.find(match_rule) != match_rules_.end())
623 return true;
625 ScopedDBusError error;
626 bus_->AddMatch(match_rule, error.get());
627 if (error.is_set()) {
628 LOG(ERROR) << "Failed to add match rule \"" << match_rule << "\". Got "
629 << error.name() << ": " << error.message();
630 return false;
632 // Store the match rule, so that we can remove this in Detach().
633 match_rules_.insert(match_rule);
634 return true;
637 void ObjectProxy::UpdateNameOwnerAndBlock() {
638 bus_->AssertOnDBusThread();
639 // Errors should be suppressed here, as the service may not be yet running
640 // when connecting to signals of the service, which is just fine.
641 // The ObjectProxy will be notified when the service is launched via
642 // NameOwnerChanged signal. See also comments in ConnectToSignalInternal().
643 service_name_owner_ =
644 bus_->GetServiceOwnerAndBlock(service_name_, Bus::SUPPRESS_ERRORS);
647 DBusHandlerResult ObjectProxy::HandleNameOwnerChanged(
648 scoped_ptr<Signal> signal) {
649 DCHECK(signal);
650 bus_->AssertOnDBusThread();
652 // Confirm the validity of the NameOwnerChanged signal.
653 if (signal->GetMember() == kNameOwnerChangedMember &&
654 signal->GetInterface() == kDBusSystemObjectInterface &&
655 signal->GetSender() == kDBusSystemObjectAddress) {
656 MessageReader reader(signal.get());
657 std::string name, old_owner, new_owner;
658 if (reader.PopString(&name) &&
659 reader.PopString(&old_owner) &&
660 reader.PopString(&new_owner) &&
661 name == service_name_) {
662 service_name_owner_ = new_owner;
663 bus_->GetOriginTaskRunner()->PostTask(
664 FROM_HERE,
665 base::Bind(&ObjectProxy::RunNameOwnerChangedCallback,
666 this, old_owner, new_owner));
668 const bool service_is_available = !service_name_owner_.empty();
669 if (service_is_available) {
670 bus_->GetOriginTaskRunner()->PostTask(
671 FROM_HERE,
672 base::Bind(&ObjectProxy::RunWaitForServiceToBeAvailableCallbacks,
673 this, service_is_available));
678 // Always return unhandled to let other object proxies handle the same
679 // signal.
680 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
683 void ObjectProxy::RunNameOwnerChangedCallback(const std::string& old_owner,
684 const std::string& new_owner) {
685 bus_->AssertOnOriginThread();
686 if (!name_owner_changed_callback_.is_null())
687 name_owner_changed_callback_.Run(old_owner, new_owner);
690 void ObjectProxy::RunWaitForServiceToBeAvailableCallbacks(
691 bool service_is_available) {
692 bus_->AssertOnOriginThread();
694 std::vector<WaitForServiceToBeAvailableCallback> callbacks;
695 callbacks.swap(wait_for_service_to_be_available_callbacks_);
696 for (size_t i = 0; i < callbacks.size(); ++i)
697 callbacks[i].Run(service_is_available);
700 } // namespace dbus