Supervised user interstitial: Remove image URL resolving hack.
[chromium-blink-merge.git] / dbus / object_proxy.cc
blobd0b660b600dbc368fc28e4804d905cc5b90e6198
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"
22 namespace dbus {
24 namespace {
26 const char kErrorServiceUnknown[] = "org.freedesktop.DBus.Error.ServiceUnknown";
27 const char kErrorObjectUnknown[] = "org.freedesktop.DBus.Error.UnknownObject";
29 // Used for success ratio histograms. 1 for success, 0 for failure.
30 const int kSuccessRatioHistogramMaxValue = 2;
32 // The path of D-Bus Object sending NameOwnerChanged signal.
33 const char kDBusSystemObjectPath[] = "/org/freedesktop/DBus";
35 // The D-Bus Object interface.
36 const char kDBusSystemObjectInterface[] = "org.freedesktop.DBus";
38 // The D-Bus Object address.
39 const char kDBusSystemObjectAddress[] = "org.freedesktop.DBus";
41 // The NameOwnerChanged member in |kDBusSystemObjectInterface|.
42 const char kNameOwnerChangedMember[] = "NameOwnerChanged";
44 // Gets the absolute signal name by concatenating the interface name and
45 // the signal name. Used for building keys for method_table_ in
46 // ObjectProxy.
47 std::string GetAbsoluteSignalName(
48 const std::string& interface_name,
49 const std::string& signal_name) {
50 return interface_name + "." + signal_name;
53 // An empty function used for ObjectProxy::EmptyResponseCallback().
54 void EmptyResponseCallbackBody(Response* /*response*/) {
57 } // namespace
59 ObjectProxy::ObjectProxy(Bus* bus,
60 const std::string& service_name,
61 const ObjectPath& object_path,
62 int options)
63 : bus_(bus),
64 service_name_(service_name),
65 object_path_(object_path),
66 filter_added_(false),
67 ignore_service_unknown_errors_(
68 options & IGNORE_SERVICE_UNKNOWN_ERRORS) {
71 ObjectProxy::~ObjectProxy() {
74 // Originally we tried to make |method_call| a const reference, but we
75 // gave up as dbus_connection_send_with_reply_and_block() takes a
76 // non-const pointer of DBusMessage as the second parameter.
77 scoped_ptr<Response> ObjectProxy::CallMethodAndBlock(MethodCall* method_call,
78 int timeout_ms) {
79 bus_->AssertOnDBusThread();
81 if (!bus_->Connect() ||
82 !method_call->SetDestination(service_name_) ||
83 !method_call->SetPath(object_path_))
84 return scoped_ptr<Response>();
86 DBusMessage* request_message = method_call->raw_message();
88 ScopedDBusError error;
90 // Send the message synchronously.
91 const base::TimeTicks start_time = base::TimeTicks::Now();
92 DBusMessage* response_message =
93 bus_->SendWithReplyAndBlock(request_message, timeout_ms, error.get());
94 // Record if the method call is successful, or not. 1 if successful.
95 UMA_HISTOGRAM_ENUMERATION("DBus.SyncMethodCallSuccess",
96 response_message ? 1 : 0,
97 kSuccessRatioHistogramMaxValue);
98 statistics::AddBlockingSentMethodCall(service_name_,
99 method_call->GetInterface(),
100 method_call->GetMember());
102 if (!response_message) {
103 LogMethodCallFailure(method_call->GetInterface(),
104 method_call->GetMember(),
105 error.is_set() ? error.name() : "unknown error type",
106 error.is_set() ? error.message() : "");
107 return scoped_ptr<Response>();
109 // Record time spent for the method call. Don't include failures.
110 UMA_HISTOGRAM_TIMES("DBus.SyncMethodCallTime",
111 base::TimeTicks::Now() - start_time);
113 return Response::FromRawMessage(response_message);
116 void ObjectProxy::CallMethod(MethodCall* method_call,
117 int timeout_ms,
118 ResponseCallback callback) {
119 CallMethodWithErrorCallback(method_call, timeout_ms, callback,
120 base::Bind(&ObjectProxy::OnCallMethodError,
121 this,
122 method_call->GetInterface(),
123 method_call->GetMember(),
124 callback));
127 void ObjectProxy::CallMethodWithErrorCallback(MethodCall* method_call,
128 int timeout_ms,
129 ResponseCallback callback,
130 ErrorCallback error_callback) {
131 bus_->AssertOnOriginThread();
133 const base::TimeTicks start_time = base::TimeTicks::Now();
135 if (!method_call->SetDestination(service_name_) ||
136 !method_call->SetPath(object_path_)) {
137 // In case of a failure, run the error callback with NULL.
138 DBusMessage* response_message = NULL;
139 base::Closure task = base::Bind(&ObjectProxy::RunResponseCallback,
140 this,
141 callback,
142 error_callback,
143 start_time,
144 response_message);
145 bus_->GetOriginTaskRunner()->PostTask(FROM_HERE, task);
146 return;
149 // Increment the reference count so we can safely reference the
150 // underlying request message until the method call is complete. This
151 // will be unref'ed in StartAsyncMethodCall().
152 DBusMessage* request_message = method_call->raw_message();
153 dbus_message_ref(request_message);
155 base::Closure task = base::Bind(&ObjectProxy::StartAsyncMethodCall,
156 this,
157 timeout_ms,
158 request_message,
159 callback,
160 error_callback,
161 start_time);
162 statistics::AddSentMethodCall(service_name_,
163 method_call->GetInterface(),
164 method_call->GetMember());
166 // Wait for the response in the D-Bus thread.
167 bus_->GetDBusTaskRunner()->PostTask(FROM_HERE, task);
170 void ObjectProxy::ConnectToSignal(const std::string& interface_name,
171 const std::string& signal_name,
172 SignalCallback signal_callback,
173 OnConnectedCallback on_connected_callback) {
174 bus_->AssertOnOriginThread();
176 base::PostTaskAndReplyWithResult(
177 bus_->GetDBusTaskRunner(),
178 FROM_HERE,
179 base::Bind(&ObjectProxy::ConnectToSignalInternal,
180 this,
181 interface_name,
182 signal_name,
183 signal_callback),
184 base::Bind(on_connected_callback,
185 interface_name,
186 signal_name));
189 void ObjectProxy::SetNameOwnerChangedCallback(
190 NameOwnerChangedCallback callback) {
191 bus_->AssertOnOriginThread();
193 name_owner_changed_callback_ = callback;
196 void ObjectProxy::WaitForServiceToBeAvailable(
197 WaitForServiceToBeAvailableCallback callback) {
198 bus_->AssertOnOriginThread();
200 wait_for_service_to_be_available_callbacks_.push_back(callback);
201 bus_->GetDBusTaskRunner()->PostTask(
202 FROM_HERE,
203 base::Bind(&ObjectProxy::WaitForServiceToBeAvailableInternal, this));
206 void ObjectProxy::Detach() {
207 bus_->AssertOnDBusThread();
209 if (filter_added_) {
210 if (!bus_->RemoveFilterFunction(&ObjectProxy::HandleMessageThunk, this)) {
211 LOG(ERROR) << "Failed to remove filter function";
215 for (std::set<std::string>::iterator iter = match_rules_.begin();
216 iter != match_rules_.end(); ++iter) {
217 ScopedDBusError error;
218 bus_->RemoveMatch(*iter, error.get());
219 if (error.is_set()) {
220 // There is nothing we can do to recover, so just print the error.
221 LOG(ERROR) << "Failed to remove match rule: " << *iter;
224 match_rules_.clear();
227 // static
228 ObjectProxy::ResponseCallback ObjectProxy::EmptyResponseCallback() {
229 return base::Bind(&EmptyResponseCallbackBody);
232 ObjectProxy::OnPendingCallIsCompleteData::OnPendingCallIsCompleteData(
233 ObjectProxy* in_object_proxy,
234 ResponseCallback in_response_callback,
235 ErrorCallback in_error_callback,
236 base::TimeTicks in_start_time)
237 : object_proxy(in_object_proxy),
238 response_callback(in_response_callback),
239 error_callback(in_error_callback),
240 start_time(in_start_time) {
243 ObjectProxy::OnPendingCallIsCompleteData::~OnPendingCallIsCompleteData() {
246 void ObjectProxy::StartAsyncMethodCall(int timeout_ms,
247 DBusMessage* request_message,
248 ResponseCallback response_callback,
249 ErrorCallback error_callback,
250 base::TimeTicks start_time) {
251 bus_->AssertOnDBusThread();
253 if (!bus_->Connect() || !bus_->SetUpAsyncOperations()) {
254 // In case of a failure, run the error callback with NULL.
255 DBusMessage* response_message = NULL;
256 base::Closure task = base::Bind(&ObjectProxy::RunResponseCallback,
257 this,
258 response_callback,
259 error_callback,
260 start_time,
261 response_message);
262 bus_->GetOriginTaskRunner()->PostTask(FROM_HERE, task);
264 dbus_message_unref(request_message);
265 return;
268 DBusPendingCall* pending_call = NULL;
270 bus_->SendWithReply(request_message, &pending_call, timeout_ms);
272 // Prepare the data we'll be passing to OnPendingCallIsCompleteThunk().
273 // The data will be deleted in OnPendingCallIsCompleteThunk().
274 OnPendingCallIsCompleteData* data =
275 new OnPendingCallIsCompleteData(this, response_callback, error_callback,
276 start_time);
278 // This returns false only when unable to allocate memory.
279 const bool success = dbus_pending_call_set_notify(
280 pending_call,
281 &ObjectProxy::OnPendingCallIsCompleteThunk,
282 data,
283 NULL);
284 CHECK(success) << "Unable to allocate memory";
285 dbus_pending_call_unref(pending_call);
287 // It's now safe to unref the request message.
288 dbus_message_unref(request_message);
291 void ObjectProxy::OnPendingCallIsComplete(DBusPendingCall* pending_call,
292 ResponseCallback response_callback,
293 ErrorCallback error_callback,
294 base::TimeTicks start_time) {
295 bus_->AssertOnDBusThread();
297 DBusMessage* response_message = dbus_pending_call_steal_reply(pending_call);
298 base::Closure task = base::Bind(&ObjectProxy::RunResponseCallback,
299 this,
300 response_callback,
301 error_callback,
302 start_time,
303 response_message);
304 bus_->GetOriginTaskRunner()->PostTask(FROM_HERE, task);
307 void ObjectProxy::RunResponseCallback(ResponseCallback response_callback,
308 ErrorCallback error_callback,
309 base::TimeTicks start_time,
310 DBusMessage* response_message) {
311 bus_->AssertOnOriginThread();
313 bool method_call_successful = false;
314 if (!response_message) {
315 // The response is not received.
316 error_callback.Run(NULL);
317 } else if (dbus_message_get_type(response_message) ==
318 DBUS_MESSAGE_TYPE_ERROR) {
319 // This will take |response_message| and release (unref) it.
320 scoped_ptr<ErrorResponse> error_response(
321 ErrorResponse::FromRawMessage(response_message));
322 error_callback.Run(error_response.get());
323 // Delete the message on the D-Bus thread. See below for why.
324 bus_->GetDBusTaskRunner()->PostTask(
325 FROM_HERE,
326 base::Bind(&base::DeletePointer<ErrorResponse>,
327 error_response.release()));
328 } else {
329 // This will take |response_message| and release (unref) it.
330 scoped_ptr<Response> response(Response::FromRawMessage(response_message));
331 // The response is successfully received.
332 response_callback.Run(response.get());
333 // The message should be deleted on the D-Bus thread for a complicated
334 // reason:
336 // libdbus keeps track of the number of bytes in the incoming message
337 // queue to ensure that the data size in the queue is manageable. The
338 // bookkeeping is partly done via dbus_message_unref(), and immediately
339 // asks the client code (Chrome) to stop monitoring the underlying
340 // socket, if the number of bytes exceeds a certian number, which is set
341 // to 63MB, per dbus-transport.cc:
343 // /* Try to default to something that won't totally hose the system,
344 // * but doesn't impose too much of a limitation.
345 // */
346 // transport->max_live_messages_size = _DBUS_ONE_MEGABYTE * 63;
348 // The monitoring of the socket is done on the D-Bus thread (see Watch
349 // class in bus.cc), hence we should stop the monitoring from D-Bus
350 // thread, not from the current thread here, which is likely UI thread.
351 bus_->GetDBusTaskRunner()->PostTask(
352 FROM_HERE,
353 base::Bind(&base::DeletePointer<Response>, response.release()));
355 method_call_successful = true;
356 // Record time spent for the method call. Don't include failures.
357 UMA_HISTOGRAM_TIMES("DBus.AsyncMethodCallTime",
358 base::TimeTicks::Now() - start_time);
360 // Record if the method call is successful, or not. 1 if successful.
361 UMA_HISTOGRAM_ENUMERATION("DBus.AsyncMethodCallSuccess",
362 method_call_successful,
363 kSuccessRatioHistogramMaxValue);
366 void ObjectProxy::OnPendingCallIsCompleteThunk(DBusPendingCall* pending_call,
367 void* user_data) {
368 OnPendingCallIsCompleteData* data =
369 reinterpret_cast<OnPendingCallIsCompleteData*>(user_data);
370 ObjectProxy* self = data->object_proxy;
371 self->OnPendingCallIsComplete(pending_call,
372 data->response_callback,
373 data->error_callback,
374 data->start_time);
375 delete data;
378 bool ObjectProxy::ConnectToNameOwnerChangedSignal() {
379 bus_->AssertOnDBusThread();
381 if (!bus_->Connect() || !bus_->SetUpAsyncOperations())
382 return false;
384 // We should add the filter only once. Otherwise, HandleMessage() will
385 // be called more than once.
386 if (!filter_added_) {
387 if (bus_->AddFilterFunction(&ObjectProxy::HandleMessageThunk, this)) {
388 filter_added_ = true;
389 } else {
390 LOG(ERROR) << "Failed to add filter function";
393 // Add a match_rule listening NameOwnerChanged for the well-known name
394 // |service_name_|.
395 const std::string name_owner_changed_match_rule =
396 base::StringPrintf(
397 "type='signal',interface='org.freedesktop.DBus',"
398 "member='NameOwnerChanged',path='/org/freedesktop/DBus',"
399 "sender='org.freedesktop.DBus',arg0='%s'",
400 service_name_.c_str());
402 const bool success =
403 AddMatchRuleWithoutCallback(name_owner_changed_match_rule,
404 "org.freedesktop.DBus.NameOwnerChanged");
406 // Try getting the current name owner. It's not guaranteed that we can get
407 // the name owner at this moment, as the service may not yet be started. If
408 // that's the case, we'll get the name owner via NameOwnerChanged signal,
409 // as soon as the service is started.
410 UpdateNameOwnerAndBlock();
412 return success;
415 bool ObjectProxy::ConnectToSignalInternal(const std::string& interface_name,
416 const std::string& signal_name,
417 SignalCallback signal_callback) {
418 bus_->AssertOnDBusThread();
420 if (!ConnectToNameOwnerChangedSignal())
421 return false;
423 const std::string absolute_signal_name =
424 GetAbsoluteSignalName(interface_name, signal_name);
426 // Add a match rule so the signal goes through HandleMessage().
427 const std::string match_rule =
428 base::StringPrintf("type='signal', interface='%s', path='%s'",
429 interface_name.c_str(),
430 object_path_.value().c_str());
431 return AddMatchRuleWithCallback(match_rule,
432 absolute_signal_name,
433 signal_callback);
436 void ObjectProxy::WaitForServiceToBeAvailableInternal() {
437 bus_->AssertOnDBusThread();
439 if (!ConnectToNameOwnerChangedSignal()) { // Failed to connect to the signal.
440 const bool service_is_ready = false;
441 bus_->GetOriginTaskRunner()->PostTask(
442 FROM_HERE,
443 base::Bind(&ObjectProxy::RunWaitForServiceToBeAvailableCallbacks,
444 this, service_is_ready));
445 return;
448 const bool service_is_available = !service_name_owner_.empty();
449 if (service_is_available) { // Service is already available.
450 bus_->GetOriginTaskRunner()->PostTask(
451 FROM_HERE,
452 base::Bind(&ObjectProxy::RunWaitForServiceToBeAvailableCallbacks,
453 this, service_is_available));
454 return;
458 DBusHandlerResult ObjectProxy::HandleMessage(
459 DBusConnection* connection,
460 DBusMessage* raw_message) {
461 bus_->AssertOnDBusThread();
463 if (dbus_message_get_type(raw_message) != DBUS_MESSAGE_TYPE_SIGNAL)
464 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
466 // raw_message will be unrefed on exit of the function. Increment the
467 // reference so we can use it in Signal.
468 dbus_message_ref(raw_message);
469 scoped_ptr<Signal> signal(
470 Signal::FromRawMessage(raw_message));
472 // Verify the signal comes from the object we're proxying for, this is
473 // our last chance to return DBUS_HANDLER_RESULT_NOT_YET_HANDLED and
474 // allow other object proxies to handle instead.
475 const ObjectPath path = signal->GetPath();
476 if (path != object_path_) {
477 if (path.value() == kDBusSystemObjectPath &&
478 signal->GetMember() == kNameOwnerChangedMember) {
479 // Handle NameOwnerChanged separately
480 return HandleNameOwnerChanged(signal.Pass());
482 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
485 const std::string interface = signal->GetInterface();
486 const std::string member = signal->GetMember();
488 statistics::AddReceivedSignal(service_name_, interface, member);
490 // Check if we know about the signal.
491 const std::string absolute_signal_name = GetAbsoluteSignalName(
492 interface, member);
493 MethodTable::const_iterator iter = method_table_.find(absolute_signal_name);
494 if (iter == method_table_.end()) {
495 // Don't know about the signal.
496 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
498 VLOG(1) << "Signal received: " << signal->ToString();
500 std::string sender = signal->GetSender();
501 if (service_name_owner_ != sender) {
502 LOG(ERROR) << "Rejecting a message from a wrong sender.";
503 UMA_HISTOGRAM_COUNTS("DBus.RejectedSignalCount", 1);
504 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
507 const base::TimeTicks start_time = base::TimeTicks::Now();
508 if (bus_->HasDBusThread()) {
509 // Post a task to run the method in the origin thread.
510 // Transfer the ownership of |signal| to RunMethod().
511 // |released_signal| will be deleted in RunMethod().
512 Signal* released_signal = signal.release();
513 bus_->GetOriginTaskRunner()->PostTask(FROM_HERE,
514 base::Bind(&ObjectProxy::RunMethod,
515 this,
516 start_time,
517 iter->second,
518 released_signal));
519 } else {
520 const base::TimeTicks start_time = base::TimeTicks::Now();
521 // If the D-Bus thread is not used, just call the callback on the
522 // current thread. Transfer the ownership of |signal| to RunMethod().
523 Signal* released_signal = signal.release();
524 RunMethod(start_time, iter->second, released_signal);
527 // We don't return DBUS_HANDLER_RESULT_HANDLED for signals because other
528 // objects may be interested in them. (e.g. Signals from org.freedesktop.DBus)
529 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
532 void ObjectProxy::RunMethod(base::TimeTicks start_time,
533 std::vector<SignalCallback> signal_callbacks,
534 Signal* signal) {
535 bus_->AssertOnOriginThread();
537 for (std::vector<SignalCallback>::iterator iter = signal_callbacks.begin();
538 iter != signal_callbacks.end(); ++iter)
539 iter->Run(signal);
541 // Delete the message on the D-Bus thread. See comments in
542 // RunResponseCallback().
543 bus_->GetDBusTaskRunner()->PostTask(
544 FROM_HERE,
545 base::Bind(&base::DeletePointer<Signal>, signal));
547 // Record time spent for handling the signal.
548 UMA_HISTOGRAM_TIMES("DBus.SignalHandleTime",
549 base::TimeTicks::Now() - start_time);
552 DBusHandlerResult ObjectProxy::HandleMessageThunk(
553 DBusConnection* connection,
554 DBusMessage* raw_message,
555 void* user_data) {
556 ObjectProxy* self = reinterpret_cast<ObjectProxy*>(user_data);
557 return self->HandleMessage(connection, raw_message);
560 void ObjectProxy::LogMethodCallFailure(
561 const base::StringPiece& interface_name,
562 const base::StringPiece& method_name,
563 const base::StringPiece& error_name,
564 const base::StringPiece& error_message) const {
565 if (ignore_service_unknown_errors_ &&
566 (error_name == kErrorServiceUnknown || error_name == kErrorObjectUnknown))
567 return;
568 logging::LogSeverity severity = logging::LOG_ERROR;
569 // "UnknownObject" indicates that an object or service is no longer available,
570 // e.g. a Shill network service has gone out of range. Treat these as warnings
571 // not errors.
572 if (error_name == kErrorObjectUnknown)
573 severity = logging::LOG_WARNING;
574 std::ostringstream msg;
575 msg << "Failed to call method: " << interface_name << "." << method_name
576 << ": object_path= " << object_path_.value()
577 << ": " << error_name << ": " << error_message;
578 logging::LogAtLevel(severity, msg.str());
581 void ObjectProxy::OnCallMethodError(const std::string& interface_name,
582 const std::string& method_name,
583 ResponseCallback response_callback,
584 ErrorResponse* error_response) {
585 if (error_response) {
586 // Error message may contain the error message as string.
587 MessageReader reader(error_response);
588 std::string error_message;
589 reader.PopString(&error_message);
590 LogMethodCallFailure(interface_name,
591 method_name,
592 error_response->GetErrorName(),
593 error_message);
595 response_callback.Run(NULL);
598 bool ObjectProxy::AddMatchRuleWithCallback(
599 const std::string& match_rule,
600 const std::string& absolute_signal_name,
601 SignalCallback signal_callback) {
602 DCHECK(!match_rule.empty());
603 DCHECK(!absolute_signal_name.empty());
604 bus_->AssertOnDBusThread();
606 if (match_rules_.find(match_rule) == match_rules_.end()) {
607 ScopedDBusError error;
608 bus_->AddMatch(match_rule, error.get());
609 if (error.is_set()) {
610 LOG(ERROR) << "Failed to add match rule \"" << match_rule << "\". Got "
611 << error.name() << ": " << error.message();
612 return false;
613 } else {
614 // Store the match rule, so that we can remove this in Detach().
615 match_rules_.insert(match_rule);
616 // Add the signal callback to the method table.
617 method_table_[absolute_signal_name].push_back(signal_callback);
618 return true;
620 } else {
621 // We already have the match rule.
622 method_table_[absolute_signal_name].push_back(signal_callback);
623 return true;
627 bool ObjectProxy::AddMatchRuleWithoutCallback(
628 const std::string& match_rule,
629 const std::string& absolute_signal_name) {
630 DCHECK(!match_rule.empty());
631 DCHECK(!absolute_signal_name.empty());
632 bus_->AssertOnDBusThread();
634 if (match_rules_.find(match_rule) != match_rules_.end())
635 return true;
637 ScopedDBusError error;
638 bus_->AddMatch(match_rule, error.get());
639 if (error.is_set()) {
640 LOG(ERROR) << "Failed to add match rule \"" << match_rule << "\". Got "
641 << error.name() << ": " << error.message();
642 return false;
644 // Store the match rule, so that we can remove this in Detach().
645 match_rules_.insert(match_rule);
646 return true;
649 void ObjectProxy::UpdateNameOwnerAndBlock() {
650 bus_->AssertOnDBusThread();
651 // Errors should be suppressed here, as the service may not be yet running
652 // when connecting to signals of the service, which is just fine.
653 // The ObjectProxy will be notified when the service is launched via
654 // NameOwnerChanged signal. See also comments in ConnectToSignalInternal().
655 service_name_owner_ =
656 bus_->GetServiceOwnerAndBlock(service_name_, Bus::SUPPRESS_ERRORS);
659 DBusHandlerResult ObjectProxy::HandleNameOwnerChanged(
660 scoped_ptr<Signal> signal) {
661 DCHECK(signal);
662 bus_->AssertOnDBusThread();
664 // Confirm the validity of the NameOwnerChanged signal.
665 if (signal->GetMember() == kNameOwnerChangedMember &&
666 signal->GetInterface() == kDBusSystemObjectInterface &&
667 signal->GetSender() == kDBusSystemObjectAddress) {
668 MessageReader reader(signal.get());
669 std::string name, old_owner, new_owner;
670 if (reader.PopString(&name) &&
671 reader.PopString(&old_owner) &&
672 reader.PopString(&new_owner) &&
673 name == service_name_) {
674 service_name_owner_ = new_owner;
675 bus_->GetOriginTaskRunner()->PostTask(
676 FROM_HERE,
677 base::Bind(&ObjectProxy::RunNameOwnerChangedCallback,
678 this, old_owner, new_owner));
680 const bool service_is_available = !service_name_owner_.empty();
681 if (service_is_available) {
682 bus_->GetOriginTaskRunner()->PostTask(
683 FROM_HERE,
684 base::Bind(&ObjectProxy::RunWaitForServiceToBeAvailableCallbacks,
685 this, service_is_available));
690 // Always return unhandled to let other object proxies handle the same
691 // signal.
692 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
695 void ObjectProxy::RunNameOwnerChangedCallback(const std::string& old_owner,
696 const std::string& new_owner) {
697 bus_->AssertOnOriginThread();
698 if (!name_owner_changed_callback_.is_null())
699 name_owner_changed_callback_.Run(old_owner, new_owner);
702 void ObjectProxy::RunWaitForServiceToBeAvailableCallbacks(
703 bool service_is_available) {
704 bus_->AssertOnOriginThread();
706 std::vector<WaitForServiceToBeAvailableCallback> callbacks;
707 callbacks.swap(wait_for_service_to_be_available_callbacks_);
708 for (size_t i = 0; i < callbacks.size(); ++i)
709 callbacks[i].Run(service_is_available);
712 } // namespace dbus