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