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 #include "dbus/util.h" 22 23 namespace dbus { 24 25 namespace { 26 27 const char kErrorServiceUnknown[] = "org.freedesktop.DBus.Error.ServiceUnknown"; 28 const char kErrorObjectUnknown[] = "org.freedesktop.DBus.Error.UnknownObject"; 29 30 // Used for success ratio histograms. 1 for success, 0 for failure. 31 const int kSuccessRatioHistogramMaxValue = 2; 32 33 // The path of D-Bus Object sending NameOwnerChanged signal. 34 const char kDBusSystemObjectPath[] = "/org/freedesktop/DBus"; 35 36 // The D-Bus Object interface. 37 const char kDBusSystemObjectInterface[] = "org.freedesktop.DBus"; 38 39 // The D-Bus Object address. 40 const char kDBusSystemObjectAddress[] = "org.freedesktop.DBus"; 41 42 // The NameOwnerChanged member in |kDBusSystemObjectInterface|. 43 const char kNameOwnerChangedMember[] = "NameOwnerChanged"; 44 45 // An empty function used for ObjectProxy::EmptyResponseCallback(). 46 void EmptyResponseCallbackBody(Response* /*response*/) { 47 } 48 49 } // namespace 50 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) { 61 } 62 63 ObjectProxy::~ObjectProxy() { 64 } 65 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(); 72 73 if (!bus_->Connect() || 74 !method_call->SetDestination(service_name_) || 75 !method_call->SetPath(object_path_)) 76 return scoped_ptr<Response>(); 77 78 DBusMessage* request_message = method_call->raw_message(); 79 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()); 91 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>(); 98 } 99 // Record time spent for the method call. Don't include failures. 100 UMA_HISTOGRAM_TIMES("DBus.SyncMethodCallTime", 101 base::TimeTicks::Now() - start_time); 102 103 return Response::FromRawMessage(response_message); 104 } 105 106 scoped_ptr<Response> ObjectProxy::CallMethodAndBlock(MethodCall* method_call, 107 int timeout_ms) { 108 ScopedDBusError error; 109 return CallMethodAndBlockWithErrorDetails(method_call, timeout_ms, &error); 110 } 111 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)); 121 } 122 123 void ObjectProxy::CallMethodWithErrorCallback(MethodCall* method_call, 124 int timeout_ms, 125 ResponseCallback callback, 126 ErrorCallback error_callback) { 127 bus_->AssertOnOriginThread(); 128 129 const base::TimeTicks start_time = base::TimeTicks::Now(); 130 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; 143 } 144 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); 150 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()); 161 162 // Wait for the response in the D-Bus thread. 163 bus_->GetDBusTaskRunner()->PostTask(FROM_HERE, task); 164 } 165 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(); 171 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)); 183 } 184 185 void ObjectProxy::SetNameOwnerChangedCallback( 186 NameOwnerChangedCallback callback) { 187 bus_->AssertOnOriginThread(); 188 189 name_owner_changed_callback_ = callback; 190 } 191 192 void ObjectProxy::WaitForServiceToBeAvailable( 193 WaitForServiceToBeAvailableCallback callback) { 194 bus_->AssertOnOriginThread(); 195 196 wait_for_service_to_be_available_callbacks_.push_back(callback); 197 bus_->GetDBusTaskRunner()->PostTask( 198 FROM_HERE, 199 base::Bind(&ObjectProxy::WaitForServiceToBeAvailableInternal, this)); 200 } 201 202 void ObjectProxy::Detach() { 203 bus_->AssertOnDBusThread(); 204 205 if (filter_added_) { 206 if (!bus_->RemoveFilterFunction(&ObjectProxy::HandleMessageThunk, this)) { 207 LOG(ERROR) << "Failed to remove filter function"; 208 } 209 } 210 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; 218 } 219 } 220 match_rules_.clear(); 221 } 222 223 // static 224 ObjectProxy::ResponseCallback ObjectProxy::EmptyResponseCallback() { 225 return base::Bind(&EmptyResponseCallbackBody); 226 } 227 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) { 237 } 238 239 ObjectProxy::OnPendingCallIsCompleteData::~OnPendingCallIsCompleteData() { 240 } 241 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(); 248 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); 259 260 dbus_message_unref(request_message); 261 return; 262 } 263 264 DBusPendingCall* pending_call = NULL; 265 266 bus_->SendWithReply(request_message, &pending_call, timeout_ms); 267 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); 273 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); 282 283 // It's now safe to unref the request message. 284 dbus_message_unref(request_message); 285 } 286 287 void ObjectProxy::OnPendingCallIsComplete(DBusPendingCall* pending_call, 288 ResponseCallback response_callback, 289 ErrorCallback error_callback, 290 base::TimeTicks start_time) { 291 bus_->AssertOnDBusThread(); 292 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); 301 } 302 303 void ObjectProxy::RunResponseCallback(ResponseCallback response_callback, 304 ErrorCallback error_callback, 305 base::TimeTicks start_time, 306 DBusMessage* response_message) { 307 bus_->AssertOnOriginThread(); 308 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: 331 // 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: 338 // 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; 343 // 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())); 350 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); 355 } 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); 360 } 361 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; 372 } 373 374 bool ObjectProxy::ConnectToNameOwnerChangedSignal() { 375 bus_->AssertOnDBusThread(); 376 377 if (!bus_->Connect() || !bus_->SetUpAsyncOperations()) 378 return false; 379 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"; 387 } 388 } 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()); 397 398 const bool success = 399 AddMatchRuleWithoutCallback(name_owner_changed_match_rule, 400 "org.freedesktop.DBus.NameOwnerChanged"); 401 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(); 407 408 return success; 409 } 410 411 bool ObjectProxy::ConnectToSignalInternal(const std::string& interface_name, 412 const std::string& signal_name, 413 SignalCallback signal_callback) { 414 bus_->AssertOnDBusThread(); 415 416 if (!ConnectToNameOwnerChangedSignal()) 417 return false; 418 419 const std::string absolute_signal_name = 420 GetAbsoluteMemberName(interface_name, signal_name); 421 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); 430 } 431 432 void ObjectProxy::WaitForServiceToBeAvailableInternal() { 433 bus_->AssertOnDBusThread(); 434 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; 442 } 443 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; 451 } 452 } 453 454 DBusHandlerResult ObjectProxy::HandleMessage( 455 DBusConnection* connection, 456 DBusMessage* raw_message) { 457 bus_->AssertOnDBusThread(); 458 459 if (dbus_message_get_type(raw_message) != DBUS_MESSAGE_TYPE_SIGNAL) 460 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; 461 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)); 467 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()); 477 } 478 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; 479 } 480 481 const std::string interface = signal->GetInterface(); 482 const std::string member = signal->GetMember(); 483 484 statistics::AddReceivedSignal(service_name_, interface, member); 485 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; 493 } 494 VLOG(1) << "Signal received: " << signal->ToString(); 495 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; 501 } 502 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); 521 } 522 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; 526 } 527 528 void ObjectProxy::RunMethod(base::TimeTicks start_time, 529 std::vector<SignalCallback> signal_callbacks, 530 Signal* signal) { 531 bus_->AssertOnOriginThread(); 532 533 for (std::vector<SignalCallback>::iterator iter = signal_callbacks.begin(); 534 iter != signal_callbacks.end(); ++iter) 535 iter->Run(signal); 536 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)); 542 543 // Record time spent for handling the signal. 544 UMA_HISTOGRAM_TIMES("DBus.SignalHandleTime", 545 base::TimeTicks::Now() - start_time); 546 } 547 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); 554 } 555 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()); 575 } 576 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); 590 } 591 response_callback.Run(NULL); 592 } 593 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(); 601 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; 615 } 616 } else { 617 // We already have the match rule. 618 method_table_[absolute_signal_name].push_back(signal_callback); 619 return true; 620 } 621 } 622 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(); 629 630 if (match_rules_.find(match_rule) != match_rules_.end()) 631 return true; 632 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; 639 } 640 // Store the match rule, so that we can remove this in Detach(). 641 match_rules_.insert(match_rule); 642 return true; 643 } 644 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); 653 } 654 655 DBusHandlerResult ObjectProxy::HandleNameOwnerChanged( 656 scoped_ptr<Signal> signal) { 657 DCHECK(signal); 658 bus_->AssertOnDBusThread(); 659 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)); 675 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)); 682 } 683 } 684 } 685 686 // Always return unhandled to let other object proxies handle the same 687 // signal. 688 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; 689 } 690 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); 696 } 697 698 void ObjectProxy::RunWaitForServiceToBeAvailableCallbacks( 699 bool service_is_available) { 700 bus_->AssertOnOriginThread(); 701 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); 706 } 707 708 } // namespace dbus 709