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/object_proxy.h" 6 7 #include <stddef.h> 8 #include <utility> 9 10 #include "base/bind.h" 11 #include "base/logging.h" 12 #include "base/message_loop/message_loop.h" 13 #include "base/metrics/histogram.h" 14 #include "base/strings/string_piece.h" 15 #include "base/strings/stringprintf.h" 16 #include "base/task_runner_util.h" 17 #include "base/threading/thread.h" 18 #include "base/threading/thread_restrictions.h" 19 #include "dbus/bus.h" 20 #include "dbus/dbus_statistics.h" 21 #include "dbus/message.h" 22 #include "dbus/object_path.h" 23 #include "dbus/scoped_dbus_error.h" 24 #include "dbus/util.h" 25 26 namespace dbus { 27 28 namespace { 29 30 const char kErrorServiceUnknown[] = "org.freedesktop.DBus.Error.ServiceUnknown"; 31 const char kErrorObjectUnknown[] = "org.freedesktop.DBus.Error.UnknownObject"; 32 33 // Used for success ratio histograms. 1 for success, 0 for failure. 34 const int kSuccessRatioHistogramMaxValue = 2; 35 36 // The path of D-Bus Object sending NameOwnerChanged signal. 37 const char kDBusSystemObjectPath[] = "/org/freedesktop/DBus"; 38 39 // The D-Bus Object interface. 40 const char kDBusSystemObjectInterface[] = "org.freedesktop.DBus"; 41 42 // The D-Bus Object address. 43 const char kDBusSystemObjectAddress[] = "org.freedesktop.DBus"; 44 45 // The NameOwnerChanged member in |kDBusSystemObjectInterface|. 46 const char kNameOwnerChangedMember[] = "NameOwnerChanged"; 47 48 // An empty function used for ObjectProxy::EmptyResponseCallback(). 49 void EmptyResponseCallbackBody(Response* /*response*/) { 50 } 51 52 } // namespace 53 54 ObjectProxy::ObjectProxy(Bus* bus, 55 const std::string& service_name, 56 const ObjectPath& object_path, 57 int options) 58 : bus_(bus), 59 service_name_(service_name), 60 object_path_(object_path), 61 ignore_service_unknown_errors_( 62 options & IGNORE_SERVICE_UNKNOWN_ERRORS) { 63 } 64 65 ObjectProxy::~ObjectProxy() { 66 DCHECK(pending_calls_.empty()); 67 } 68 69 // Originally we tried to make |method_call| a const reference, but we 70 // gave up as dbus_connection_send_with_reply_and_block() takes a 71 // non-const pointer of DBusMessage as the second parameter. 72 scoped_ptr<Response> ObjectProxy::CallMethodAndBlockWithErrorDetails( 73 MethodCall* method_call, int timeout_ms, ScopedDBusError* error) { 74 bus_->AssertOnDBusThread(); 75 76 if (!bus_->Connect() || 77 !method_call->SetDestination(service_name_) || 78 !method_call->SetPath(object_path_)) 79 return scoped_ptr<Response>(); 80 81 DBusMessage* request_message = method_call->raw_message(); 82 83 // Send the message synchronously. 84 const base::TimeTicks start_time = base::TimeTicks::Now(); 85 DBusMessage* response_message = 86 bus_->SendWithReplyAndBlock(request_message, timeout_ms, error->get()); 87 // Record if the method call is successful, or not. 1 if successful. 88 UMA_HISTOGRAM_ENUMERATION("DBus.SyncMethodCallSuccess", 89 response_message ? 1 : 0, 90 kSuccessRatioHistogramMaxValue); 91 statistics::AddBlockingSentMethodCall(service_name_, 92 method_call->GetInterface(), 93 method_call->GetMember()); 94 95 if (!response_message) { 96 LogMethodCallFailure(method_call->GetInterface(), 97 method_call->GetMember(), 98 error->is_set() ? error->name() : "unknown error type", 99 error->is_set() ? error->message() : ""); 100 return scoped_ptr<Response>(); 101 } 102 // Record time spent for the method call. Don't include failures. 103 UMA_HISTOGRAM_TIMES("DBus.SyncMethodCallTime", 104 base::TimeTicks::Now() - start_time); 105 106 return Response::FromRawMessage(response_message); 107 } 108 109 scoped_ptr<Response> ObjectProxy::CallMethodAndBlock(MethodCall* method_call, 110 int timeout_ms) { 111 ScopedDBusError error; 112 return CallMethodAndBlockWithErrorDetails(method_call, timeout_ms, &error); 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 if (bus_->HasDBusThread()) { 176 base::PostTaskAndReplyWithResult( 177 bus_->GetDBusTaskRunner(), FROM_HERE, 178 base::Bind(&ObjectProxy::ConnectToSignalInternal, this, interface_name, 179 signal_name, signal_callback), 180 base::Bind(on_connected_callback, interface_name, signal_name)); 181 } else { 182 // If the bus doesn't have a dedicated dbus thread we need to call 183 // ConnectToSignalInternal directly otherwise we might miss a signal 184 // that is currently queued if we do a PostTask. 185 const bool success = 186 ConnectToSignalInternal(interface_name, signal_name, signal_callback); 187 on_connected_callback.Run(interface_name, signal_name, success); 188 } 189 } 190 191 void ObjectProxy::SetNameOwnerChangedCallback( 192 NameOwnerChangedCallback callback) { 193 bus_->AssertOnOriginThread(); 194 195 name_owner_changed_callback_ = callback; 196 } 197 198 void ObjectProxy::WaitForServiceToBeAvailable( 199 WaitForServiceToBeAvailableCallback callback) { 200 bus_->AssertOnOriginThread(); 201 202 wait_for_service_to_be_available_callbacks_.push_back(callback); 203 bus_->GetDBusTaskRunner()->PostTask( 204 FROM_HERE, 205 base::Bind(&ObjectProxy::WaitForServiceToBeAvailableInternal, this)); 206 } 207 208 void ObjectProxy::Detach() { 209 bus_->AssertOnDBusThread(); 210 211 if (bus_->is_connected()) 212 bus_->RemoveFilterFunction(&ObjectProxy::HandleMessageThunk, this); 213 214 for (const auto& match_rule : match_rules_) { 215 ScopedDBusError error; 216 bus_->RemoveMatch(match_rule, error.get()); 217 if (error.is_set()) { 218 // There is nothing we can do to recover, so just print the error. 219 LOG(ERROR) << "Failed to remove match rule: " << match_rule; 220 } 221 } 222 match_rules_.clear(); 223 224 for (auto* pending_call : pending_calls_) { 225 dbus_pending_call_cancel(pending_call); 226 dbus_pending_call_unref(pending_call); 227 } 228 pending_calls_.clear(); 229 } 230 231 // static 232 ObjectProxy::ResponseCallback ObjectProxy::EmptyResponseCallback() { 233 return base::Bind(&EmptyResponseCallbackBody); 234 } 235 236 ObjectProxy::OnPendingCallIsCompleteData::OnPendingCallIsCompleteData( 237 ObjectProxy* in_object_proxy, 238 ResponseCallback in_response_callback, 239 ErrorCallback in_error_callback, 240 base::TimeTicks in_start_time) 241 : object_proxy(in_object_proxy), 242 response_callback(in_response_callback), 243 error_callback(in_error_callback), 244 start_time(in_start_time) { 245 } 246 247 ObjectProxy::OnPendingCallIsCompleteData::~OnPendingCallIsCompleteData() { 248 } 249 250 void ObjectProxy::StartAsyncMethodCall(int timeout_ms, 251 DBusMessage* request_message, 252 ResponseCallback response_callback, 253 ErrorCallback error_callback, 254 base::TimeTicks start_time) { 255 bus_->AssertOnDBusThread(); 256 257 if (!bus_->Connect() || !bus_->SetUpAsyncOperations()) { 258 // In case of a failure, run the error callback with NULL. 259 DBusMessage* response_message = NULL; 260 base::Closure task = base::Bind(&ObjectProxy::RunResponseCallback, 261 this, 262 response_callback, 263 error_callback, 264 start_time, 265 response_message); 266 bus_->GetOriginTaskRunner()->PostTask(FROM_HERE, task); 267 268 dbus_message_unref(request_message); 269 return; 270 } 271 272 DBusPendingCall* pending_call = NULL; 273 274 bus_->SendWithReply(request_message, &pending_call, timeout_ms); 275 276 // Prepare the data we'll be passing to OnPendingCallIsCompleteThunk(). 277 // The data will be deleted in OnPendingCallIsCompleteThunk(). 278 OnPendingCallIsCompleteData* data = 279 new OnPendingCallIsCompleteData(this, response_callback, error_callback, 280 start_time); 281 282 // This returns false only when unable to allocate memory. 283 const bool success = dbus_pending_call_set_notify( 284 pending_call, 285 &ObjectProxy::OnPendingCallIsCompleteThunk, 286 data, 287 &DeleteVoidPointer<OnPendingCallIsCompleteData>); 288 CHECK(success) << "Unable to allocate memory"; 289 pending_calls_.insert(pending_call); 290 291 // It's now safe to unref the request message. 292 dbus_message_unref(request_message); 293 } 294 295 void ObjectProxy::OnPendingCallIsComplete(DBusPendingCall* pending_call, 296 ResponseCallback response_callback, 297 ErrorCallback error_callback, 298 base::TimeTicks start_time) { 299 bus_->AssertOnDBusThread(); 300 301 DBusMessage* response_message = dbus_pending_call_steal_reply(pending_call); 302 base::Closure task = base::Bind(&ObjectProxy::RunResponseCallback, 303 this, 304 response_callback, 305 error_callback, 306 start_time, 307 response_message); 308 bus_->GetOriginTaskRunner()->PostTask(FROM_HERE, task); 309 310 // Remove the pending call from the set. 311 pending_calls_.erase(pending_call); 312 dbus_pending_call_unref(pending_call); 313 } 314 315 void ObjectProxy::RunResponseCallback(ResponseCallback response_callback, 316 ErrorCallback error_callback, 317 base::TimeTicks start_time, 318 DBusMessage* response_message) { 319 bus_->AssertOnOriginThread(); 320 321 bool method_call_successful = false; 322 if (!response_message) { 323 // The response is not received. 324 error_callback.Run(NULL); 325 } else if (dbus_message_get_type(response_message) == 326 DBUS_MESSAGE_TYPE_ERROR) { 327 // This will take |response_message| and release (unref) it. 328 scoped_ptr<ErrorResponse> error_response( 329 ErrorResponse::FromRawMessage(response_message)); 330 error_callback.Run(error_response.get()); 331 // Delete the message on the D-Bus thread. See below for why. 332 bus_->GetDBusTaskRunner()->PostTask( 333 FROM_HERE, 334 base::Bind(&base::DeletePointer<ErrorResponse>, 335 error_response.release())); 336 } else { 337 // This will take |response_message| and release (unref) it. 338 scoped_ptr<Response> response(Response::FromRawMessage(response_message)); 339 // The response is successfully received. 340 response_callback.Run(response.get()); 341 // The message should be deleted on the D-Bus thread for a complicated 342 // reason: 343 // 344 // libdbus keeps track of the number of bytes in the incoming message 345 // queue to ensure that the data size in the queue is manageable. The 346 // bookkeeping is partly done via dbus_message_unref(), and immediately 347 // asks the client code (Chrome) to stop monitoring the underlying 348 // socket, if the number of bytes exceeds a certian number, which is set 349 // to 63MB, per dbus-transport.cc: 350 // 351 // /* Try to default to something that won't totally hose the system, 352 // * but doesn't impose too much of a limitation. 353 // */ 354 // transport->max_live_messages_size = _DBUS_ONE_MEGABYTE * 63; 355 // 356 // The monitoring of the socket is done on the D-Bus thread (see Watch 357 // class in bus.cc), hence we should stop the monitoring from D-Bus 358 // thread, not from the current thread here, which is likely UI thread. 359 bus_->GetDBusTaskRunner()->PostTask( 360 FROM_HERE, 361 base::Bind(&base::DeletePointer<Response>, response.release())); 362 363 method_call_successful = true; 364 // Record time spent for the method call. Don't include failures. 365 UMA_HISTOGRAM_TIMES("DBus.AsyncMethodCallTime", 366 base::TimeTicks::Now() - start_time); 367 } 368 // Record if the method call is successful, or not. 1 if successful. 369 UMA_HISTOGRAM_ENUMERATION("DBus.AsyncMethodCallSuccess", 370 method_call_successful, 371 kSuccessRatioHistogramMaxValue); 372 } 373 374 void ObjectProxy::OnPendingCallIsCompleteThunk(DBusPendingCall* pending_call, 375 void* user_data) { 376 OnPendingCallIsCompleteData* data = 377 reinterpret_cast<OnPendingCallIsCompleteData*>(user_data); 378 ObjectProxy* self = data->object_proxy; 379 self->OnPendingCallIsComplete(pending_call, 380 data->response_callback, 381 data->error_callback, 382 data->start_time); 383 } 384 385 bool ObjectProxy::ConnectToNameOwnerChangedSignal() { 386 bus_->AssertOnDBusThread(); 387 388 if (!bus_->Connect() || !bus_->SetUpAsyncOperations()) 389 return false; 390 391 bus_->AddFilterFunction(&ObjectProxy::HandleMessageThunk, this); 392 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()); 401 402 const bool success = 403 AddMatchRuleWithoutCallback(name_owner_changed_match_rule, 404 "org.freedesktop.DBus.NameOwnerChanged"); 405 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(); 411 412 return success; 413 } 414 415 bool ObjectProxy::ConnectToSignalInternal(const std::string& interface_name, 416 const std::string& signal_name, 417 SignalCallback signal_callback) { 418 bus_->AssertOnDBusThread(); 419 420 if (!ConnectToNameOwnerChangedSignal()) 421 return false; 422 423 const std::string absolute_signal_name = 424 GetAbsoluteMemberName(interface_name, signal_name); 425 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); 434 } 435 436 void ObjectProxy::WaitForServiceToBeAvailableInternal() { 437 bus_->AssertOnDBusThread(); 438 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; 446 } 447 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; 455 } 456 } 457 458 DBusHandlerResult ObjectProxy::HandleMessage( 459 DBusConnection* /* connection */, 460 DBusMessage* raw_message) { 461 bus_->AssertOnDBusThread(); 462 463 if (dbus_message_get_type(raw_message) != DBUS_MESSAGE_TYPE_SIGNAL) 464 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; 465 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)); 471 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(std::move(signal)); 481 } 482 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; 483 } 484 485 const std::string interface = signal->GetInterface(); 486 const std::string member = signal->GetMember(); 487 488 statistics::AddReceivedSignal(service_name_, interface, member); 489 490 // Check if we know about the signal. 491 const std::string absolute_signal_name = GetAbsoluteMemberName( 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; 497 } 498 VLOG(1) << "Signal received: " << signal->ToString(); 499 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; 505 } 506 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); 525 } 526 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; 530 } 531 532 void ObjectProxy::RunMethod(base::TimeTicks start_time, 533 std::vector<SignalCallback> signal_callbacks, 534 Signal* signal) { 535 bus_->AssertOnOriginThread(); 536 537 for (std::vector<SignalCallback>::iterator iter = signal_callbacks.begin(); 538 iter != signal_callbacks.end(); ++iter) 539 iter->Run(signal); 540 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)); 546 547 // Record time spent for handling the signal. 548 UMA_HISTOGRAM_TIMES("DBus.SignalHandleTime", 549 base::TimeTicks::Now() - start_time); 550 } 551 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); 558 } 559 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()); 579 } 580 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); 594 } 595 response_callback.Run(NULL); 596 } 597 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(); 605 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; 619 } 620 } else { 621 // We already have the match rule. 622 method_table_[absolute_signal_name].push_back(signal_callback); 623 return true; 624 } 625 } 626 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(); 633 634 if (match_rules_.find(match_rule) != match_rules_.end()) 635 return true; 636 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; 643 } 644 // Store the match rule, so that we can remove this in Detach(). 645 match_rules_.insert(match_rule); 646 return true; 647 } 648 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); 657 } 658 659 DBusHandlerResult ObjectProxy::HandleNameOwnerChanged( 660 scoped_ptr<Signal> signal) { 661 DCHECK(signal); 662 bus_->AssertOnDBusThread(); 663 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)); 679 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)); 686 } 687 } 688 } 689 690 // Always return unhandled to let other object proxies handle the same 691 // signal. 692 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; 693 } 694 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); 700 } 701 702 void ObjectProxy::RunWaitForServiceToBeAvailableCallbacks( 703 bool service_is_available) { 704 bus_->AssertOnOriginThread(); 705 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); 710 } 711 712 } // namespace dbus 713