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