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