OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "dbus/bus.h" | 5 #include "dbus/bus.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/logging.h" | 8 #include "base/logging.h" |
9 #include "base/message_loop.h" | 9 #include "base/message_loop.h" |
10 #include "base/metrics/histogram.h" | 10 #include "base/metrics/histogram.h" |
11 #include "base/stringprintf.h" | 11 #include "base/stringprintf.h" |
12 #include "base/strings/string_piece.h" | 12 #include "base/strings/string_piece.h" |
13 #include "base/threading/thread.h" | 13 #include "base/threading/thread.h" |
14 #include "base/threading/thread_restrictions.h" | 14 #include "base/threading/thread_restrictions.h" |
15 #include "dbus/dbus_statistics.h" | 15 #include "dbus/dbus_statistics.h" |
16 #include "dbus/message.h" | 16 #include "dbus/message.h" |
17 #include "dbus/object_path.h" | 17 #include "dbus/object_path.h" |
18 #include "dbus/object_proxy.h" | 18 #include "dbus/object_proxy.h" |
19 #include "dbus/scoped_dbus_error.h" | 19 #include "dbus/scoped_dbus_error.h" |
20 | 20 |
| 21 namespace dbus { |
| 22 |
21 namespace { | 23 namespace { |
22 | 24 |
23 const char kErrorServiceUnknown[] = "org.freedesktop.DBus.Error.ServiceUnknown"; | 25 const char kErrorServiceUnknown[] = "org.freedesktop.DBus.Error.ServiceUnknown"; |
24 | 26 |
25 // Used for success ratio histograms. 1 for success, 0 for failure. | 27 // Used for success ratio histograms. 1 for success, 0 for failure. |
26 const int kSuccessRatioHistogramMaxValue = 2; | 28 const int kSuccessRatioHistogramMaxValue = 2; |
27 | 29 |
28 // The path of D-Bus Object sending NameOwnerChanged signal. | 30 // The path of D-Bus Object sending NameOwnerChanged signal. |
29 const char kDBusSystemObjectPath[] = "/org/freedesktop/DBus"; | 31 const char kDBusSystemObjectPath[] = "/org/freedesktop/DBus"; |
30 | 32 |
| 33 // The D-Bus Object interface. |
| 34 const char kDBusSystemObjectInterface[] = "org.freedesktop.DBus"; |
| 35 |
| 36 // The D-Bus Object address. |
| 37 const char kDBusSystemObjectAddress[] = "org.freedesktop.DBus"; |
| 38 |
| 39 // The NameOwnerChanged member in |kDBusSystemObjectInterface|. |
| 40 const char kNameOwnerChangedMember[] = "NameOwnerChanged"; |
| 41 |
31 // Gets the absolute signal name by concatenating the interface name and | 42 // Gets the absolute signal name by concatenating the interface name and |
32 // the signal name. Used for building keys for method_table_ in | 43 // the signal name. Used for building keys for method_table_ in |
33 // ObjectProxy. | 44 // ObjectProxy. |
34 std::string GetAbsoluteSignalName( | 45 std::string GetAbsoluteSignalName( |
35 const std::string& interface_name, | 46 const std::string& interface_name, |
36 const std::string& signal_name) { | 47 const std::string& signal_name) { |
37 return interface_name + "." + signal_name; | 48 return interface_name + "." + signal_name; |
38 } | 49 } |
39 | 50 |
40 // An empty function used for ObjectProxy::EmptyResponseCallback(). | 51 // An empty function used for ObjectProxy::EmptyResponseCallback(). |
41 void EmptyResponseCallbackBody(dbus::Response* unused_response) { | 52 void EmptyResponseCallbackBody(Response* /*response*/) { |
42 } | 53 } |
43 | 54 |
44 } // namespace | 55 } // namespace |
45 | 56 |
46 namespace dbus { | |
47 | |
48 ObjectProxy::ObjectProxy(Bus* bus, | 57 ObjectProxy::ObjectProxy(Bus* bus, |
49 const std::string& service_name, | 58 const std::string& service_name, |
50 const ObjectPath& object_path, | 59 const ObjectPath& object_path, |
51 int options) | 60 int options) |
52 : bus_(bus), | 61 : bus_(bus), |
53 service_name_(service_name), | 62 service_name_(service_name), |
54 object_path_(object_path), | 63 object_path_(object_path), |
55 filter_added_(false), | 64 filter_added_(false), |
56 ignore_service_unknown_errors_( | 65 ignore_service_unknown_errors_( |
57 options & IGNORE_SERVICE_UNKNOWN_ERRORS) { | 66 options & IGNORE_SERVICE_UNKNOWN_ERRORS) { |
(...skipping 220 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
278 DBusMessage* response_message) { | 287 DBusMessage* response_message) { |
279 bus_->AssertOnOriginThread(); | 288 bus_->AssertOnOriginThread(); |
280 | 289 |
281 bool method_call_successful = false; | 290 bool method_call_successful = false; |
282 if (!response_message) { | 291 if (!response_message) { |
283 // The response is not received. | 292 // The response is not received. |
284 error_callback.Run(NULL); | 293 error_callback.Run(NULL); |
285 } else if (dbus_message_get_type(response_message) == | 294 } else if (dbus_message_get_type(response_message) == |
286 DBUS_MESSAGE_TYPE_ERROR) { | 295 DBUS_MESSAGE_TYPE_ERROR) { |
287 // This will take |response_message| and release (unref) it. | 296 // This will take |response_message| and release (unref) it. |
288 scoped_ptr<dbus::ErrorResponse> error_response( | 297 scoped_ptr<ErrorResponse> error_response( |
289 dbus::ErrorResponse::FromRawMessage(response_message)); | 298 ErrorResponse::FromRawMessage(response_message)); |
290 error_callback.Run(error_response.get()); | 299 error_callback.Run(error_response.get()); |
291 // Delete the message on the D-Bus thread. See below for why. | 300 // Delete the message on the D-Bus thread. See below for why. |
292 bus_->PostTaskToDBusThread( | 301 bus_->PostTaskToDBusThread( |
293 FROM_HERE, | 302 FROM_HERE, |
294 base::Bind(&base::DeletePointer<dbus::ErrorResponse>, | 303 base::Bind(&base::DeletePointer<ErrorResponse>, |
295 error_response.release())); | 304 error_response.release())); |
296 } else { | 305 } else { |
297 // This will take |response_message| and release (unref) it. | 306 // This will take |response_message| and release (unref) it. |
298 scoped_ptr<dbus::Response> response( | 307 scoped_ptr<Response> response(Response::FromRawMessage(response_message)); |
299 dbus::Response::FromRawMessage(response_message)); | |
300 // The response is successfully received. | 308 // The response is successfully received. |
301 response_callback.Run(response.get()); | 309 response_callback.Run(response.get()); |
302 // The message should be deleted on the D-Bus thread for a complicated | 310 // The message should be deleted on the D-Bus thread for a complicated |
303 // reason: | 311 // reason: |
304 // | 312 // |
305 // libdbus keeps track of the number of bytes in the incoming message | 313 // libdbus keeps track of the number of bytes in the incoming message |
306 // queue to ensure that the data size in the queue is manageable. The | 314 // queue to ensure that the data size in the queue is manageable. The |
307 // bookkeeping is partly done via dbus_message_unref(), and immediately | 315 // bookkeeping is partly done via dbus_message_unref(), and immediately |
308 // asks the client code (Chrome) to stop monitoring the underlying | 316 // asks the client code (Chrome) to stop monitoring the underlying |
309 // socket, if the number of bytes exceeds a certian number, which is set | 317 // socket, if the number of bytes exceeds a certian number, which is set |
310 // to 63MB, per dbus-transport.cc: | 318 // to 63MB, per dbus-transport.cc: |
311 // | 319 // |
312 // /* Try to default to something that won't totally hose the system, | 320 // /* Try to default to something that won't totally hose the system, |
313 // * but doesn't impose too much of a limitation. | 321 // * but doesn't impose too much of a limitation. |
314 // */ | 322 // */ |
315 // transport->max_live_messages_size = _DBUS_ONE_MEGABYTE * 63; | 323 // transport->max_live_messages_size = _DBUS_ONE_MEGABYTE * 63; |
316 // | 324 // |
317 // The monitoring of the socket is done on the D-Bus thread (see Watch | 325 // The monitoring of the socket is done on the D-Bus thread (see Watch |
318 // class in bus.cc), hence we should stop the monitoring from D-Bus | 326 // class in bus.cc), hence we should stop the monitoring from D-Bus |
319 // thread, not from the current thread here, which is likely UI thread. | 327 // thread, not from the current thread here, which is likely UI thread. |
320 bus_->PostTaskToDBusThread( | 328 bus_->PostTaskToDBusThread( |
321 FROM_HERE, | 329 FROM_HERE, |
322 base::Bind(&base::DeletePointer<dbus::Response>, | 330 base::Bind(&base::DeletePointer<Response>, response.release())); |
323 response.release())); | |
324 | 331 |
325 method_call_successful = true; | 332 method_call_successful = true; |
326 // Record time spent for the method call. Don't include failures. | 333 // Record time spent for the method call. Don't include failures. |
327 UMA_HISTOGRAM_TIMES("DBus.AsyncMethodCallTime", | 334 UMA_HISTOGRAM_TIMES("DBus.AsyncMethodCallTime", |
328 base::TimeTicks::Now() - start_time); | 335 base::TimeTicks::Now() - start_time); |
329 } | 336 } |
330 // Record if the method call is successful, or not. 1 if successful. | 337 // Record if the method call is successful, or not. 1 if successful. |
331 UMA_HISTOGRAM_ENUMERATION("DBus.AsyncMethodCallSuccess", | 338 UMA_HISTOGRAM_ENUMERATION("DBus.AsyncMethodCallSuccess", |
332 method_call_successful, | 339 method_call_successful, |
333 kSuccessRatioHistogramMaxValue); | 340 kSuccessRatioHistogramMaxValue); |
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
432 | 439 |
433 // raw_message will be unrefed on exit of the function. Increment the | 440 // raw_message will be unrefed on exit of the function. Increment the |
434 // reference so we can use it in Signal. | 441 // reference so we can use it in Signal. |
435 dbus_message_ref(raw_message); | 442 dbus_message_ref(raw_message); |
436 scoped_ptr<Signal> signal( | 443 scoped_ptr<Signal> signal( |
437 Signal::FromRawMessage(raw_message)); | 444 Signal::FromRawMessage(raw_message)); |
438 | 445 |
439 // Verify the signal comes from the object we're proxying for, this is | 446 // Verify the signal comes from the object we're proxying for, this is |
440 // our last chance to return DBUS_HANDLER_RESULT_NOT_YET_HANDLED and | 447 // our last chance to return DBUS_HANDLER_RESULT_NOT_YET_HANDLED and |
441 // allow other object proxies to handle instead. | 448 // allow other object proxies to handle instead. |
442 const dbus::ObjectPath path = signal->GetPath(); | 449 const ObjectPath path = signal->GetPath(); |
443 if (path != object_path_) { | 450 if (path != object_path_) { |
444 if (path.value() == kDBusSystemObjectPath && | 451 if (path.value() == kDBusSystemObjectPath && |
445 signal->GetMember() == "NameOwnerChanged") { | 452 signal->GetMember() == kNameOwnerChangedMember) { |
446 // Handle NameOwnerChanged separately | 453 // Handle NameOwnerChanged separately |
447 return HandleNameOwnerChanged(signal.Pass()); | 454 return HandleNameOwnerChanged(signal.Pass()); |
448 } | 455 } |
449 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; | 456 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; |
450 } | 457 } |
451 | 458 |
452 const std::string interface = signal->GetInterface(); | 459 const std::string interface = signal->GetInterface(); |
453 const std::string member = signal->GetMember(); | 460 const std::string member = signal->GetMember(); |
454 | 461 |
455 statistics::AddReceivedSignal(service_name_, interface, member); | 462 statistics::AddReceivedSignal(service_name_, interface, member); |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
500 bus_->AssertOnOriginThread(); | 507 bus_->AssertOnOriginThread(); |
501 | 508 |
502 for (std::vector<SignalCallback>::iterator iter = signal_callbacks.begin(); | 509 for (std::vector<SignalCallback>::iterator iter = signal_callbacks.begin(); |
503 iter != signal_callbacks.end(); ++iter) | 510 iter != signal_callbacks.end(); ++iter) |
504 iter->Run(signal); | 511 iter->Run(signal); |
505 | 512 |
506 // Delete the message on the D-Bus thread. See comments in | 513 // Delete the message on the D-Bus thread. See comments in |
507 // RunResponseCallback(). | 514 // RunResponseCallback(). |
508 bus_->PostTaskToDBusThread( | 515 bus_->PostTaskToDBusThread( |
509 FROM_HERE, | 516 FROM_HERE, |
510 base::Bind(&base::DeletePointer<dbus::Signal>, signal)); | 517 base::Bind(&base::DeletePointer<Signal>, signal)); |
511 | 518 |
512 // Record time spent for handling the signal. | 519 // Record time spent for handling the signal. |
513 UMA_HISTOGRAM_TIMES("DBus.SignalHandleTime", | 520 UMA_HISTOGRAM_TIMES("DBus.SignalHandleTime", |
514 base::TimeTicks::Now() - start_time); | 521 base::TimeTicks::Now() - start_time); |
515 } | 522 } |
516 | 523 |
517 DBusHandlerResult ObjectProxy::HandleMessageThunk( | 524 DBusHandlerResult ObjectProxy::HandleMessageThunk( |
518 DBusConnection* connection, | 525 DBusConnection* connection, |
519 DBusMessage* raw_message, | 526 DBusMessage* raw_message, |
520 void* user_data) { | 527 void* user_data) { |
(...skipping 13 matching lines...) Expand all Loading... |
534 << ": object_path= " << object_path_.value() | 541 << ": object_path= " << object_path_.value() |
535 << ": " << error_name << ": " << error_message; | 542 << ": " << error_name << ": " << error_message; |
536 } | 543 } |
537 | 544 |
538 void ObjectProxy::OnCallMethodError(const std::string& interface_name, | 545 void ObjectProxy::OnCallMethodError(const std::string& interface_name, |
539 const std::string& method_name, | 546 const std::string& method_name, |
540 ResponseCallback response_callback, | 547 ResponseCallback response_callback, |
541 ErrorResponse* error_response) { | 548 ErrorResponse* error_response) { |
542 if (error_response) { | 549 if (error_response) { |
543 // Error message may contain the error message as string. | 550 // Error message may contain the error message as string. |
544 dbus::MessageReader reader(error_response); | 551 MessageReader reader(error_response); |
545 std::string error_message; | 552 std::string error_message; |
546 reader.PopString(&error_message); | 553 reader.PopString(&error_message); |
547 LogMethodCallFailure(interface_name, | 554 LogMethodCallFailure(interface_name, |
548 method_name, | 555 method_name, |
549 error_response->GetErrorName(), | 556 error_response->GetErrorName(), |
550 error_message); | 557 error_message); |
551 } | 558 } |
552 response_callback.Run(NULL); | 559 response_callback.Run(NULL); |
553 } | 560 } |
554 | 561 |
555 bool ObjectProxy::AddMatchRuleWithCallback( | 562 bool ObjectProxy::AddMatchRuleWithCallback( |
556 const std::string& match_rule, | 563 const std::string& match_rule, |
557 const std::string& absolute_signal_name, | 564 const std::string& absolute_signal_name, |
558 SignalCallback signal_callback) { | 565 SignalCallback signal_callback) { |
559 DCHECK(!match_rule.empty()); | 566 DCHECK(!match_rule.empty()); |
560 DCHECK(!absolute_signal_name.empty()); | 567 DCHECK(!absolute_signal_name.empty()); |
561 bus_->AssertOnDBusThread(); | 568 bus_->AssertOnDBusThread(); |
562 | 569 |
563 if (match_rules_.find(match_rule) == match_rules_.end()) { | 570 if (match_rules_.find(match_rule) == match_rules_.end()) { |
564 ScopedDBusError error; | 571 ScopedDBusError error; |
565 bus_->AddMatch(match_rule, error.get()); | 572 bus_->AddMatch(match_rule, error.get()); |
566 if (error.is_set()) { | 573 if (error.is_set()) { |
567 LOG(ERROR) << "Failed to add match rule \"" << match_rule << "\". Got " << | 574 LOG(ERROR) << "Failed to add match rule \"" << match_rule << "\". Got " |
568 error.name() << ": " << error.message(); | 575 << error.name() << ": " << error.message(); |
569 return false; | 576 return false; |
570 } else { | 577 } else { |
571 // Store the match rule, so that we can remove this in Detach(). | 578 // Store the match rule, so that we can remove this in Detach(). |
572 match_rules_.insert(match_rule); | 579 match_rules_.insert(match_rule); |
573 // Add the signal callback to the method table. | 580 // Add the signal callback to the method table. |
574 method_table_[absolute_signal_name].push_back(signal_callback); | 581 method_table_[absolute_signal_name].push_back(signal_callback); |
575 return true; | 582 return true; |
576 } | 583 } |
577 } else { | 584 } else { |
578 // We already have the match rule. | 585 // We already have the match rule. |
579 method_table_[absolute_signal_name].push_back(signal_callback); | 586 method_table_[absolute_signal_name].push_back(signal_callback); |
580 return true; | 587 return true; |
581 } | 588 } |
582 } | 589 } |
583 | 590 |
584 bool ObjectProxy::AddMatchRuleWithoutCallback( | 591 bool ObjectProxy::AddMatchRuleWithoutCallback( |
585 const std::string& match_rule, | 592 const std::string& match_rule, |
586 const std::string& absolute_signal_name) { | 593 const std::string& absolute_signal_name) { |
587 DCHECK(!match_rule.empty()); | 594 DCHECK(!match_rule.empty()); |
588 DCHECK(!absolute_signal_name.empty()); | 595 DCHECK(!absolute_signal_name.empty()); |
589 bus_->AssertOnDBusThread(); | 596 bus_->AssertOnDBusThread(); |
590 | 597 |
591 if (match_rules_.find(match_rule) != match_rules_.end()) | 598 if (match_rules_.find(match_rule) != match_rules_.end()) |
592 return true; | 599 return true; |
593 | 600 |
594 ScopedDBusError error; | 601 ScopedDBusError error; |
595 bus_->AddMatch(match_rule, error.get()); | 602 bus_->AddMatch(match_rule, error.get()); |
596 if (error.is_set()) { | 603 if (error.is_set()) { |
597 LOG(ERROR) << "Failed to add match rule \"" << match_rule << "\". Got " << | 604 LOG(ERROR) << "Failed to add match rule \"" << match_rule << "\". Got " |
598 error.name() << ": " << error.message(); | 605 << error.name() << ": " << error.message(); |
599 return false; | 606 return false; |
600 } | 607 } |
601 // Store the match rule, so that we can remove this in Detach(). | 608 // Store the match rule, so that we can remove this in Detach(). |
602 match_rules_.insert(match_rule); | 609 match_rules_.insert(match_rule); |
603 return true; | 610 return true; |
604 } | 611 } |
605 | 612 |
606 void ObjectProxy::UpdateNameOwnerAndBlock() { | 613 void ObjectProxy::UpdateNameOwnerAndBlock() { |
607 bus_->AssertOnDBusThread(); | 614 bus_->AssertOnDBusThread(); |
608 | 615 service_name_owner_ = |
609 MethodCall get_name_owner_call("org.freedesktop.DBus", "GetNameOwner"); | 616 bus_->GetServiceOwnerAndBlock(service_name_, Bus::SUPPRESS_ERRORS); |
610 MessageWriter writer(&get_name_owner_call); | |
611 writer.AppendString(service_name_); | |
612 VLOG(1) << "Method call: " << get_name_owner_call.ToString(); | |
613 | |
614 const dbus::ObjectPath obj_path("/org/freedesktop/DBus"); | |
615 ScopedDBusError error; | |
616 if (!get_name_owner_call.SetDestination("org.freedesktop.DBus") || | |
617 !get_name_owner_call.SetPath(obj_path)) { | |
618 LOG(ERROR) << "Failed to get name owner."; | |
619 return; | |
620 } | |
621 | |
622 DBusMessage* response_message = bus_->SendWithReplyAndBlock( | |
623 get_name_owner_call.raw_message(), | |
624 TIMEOUT_USE_DEFAULT, | |
625 error.get()); | |
626 if (!response_message) { | |
627 LOG(ERROR) << "Failed to get name owner. Got " << error.name() << ": " << | |
628 error.message(); | |
629 return; | |
630 } | |
631 scoped_ptr<Response> response(Response::FromRawMessage(response_message)); | |
632 MessageReader reader(response.get()); | |
633 | |
634 std::string new_service_name_owner; | |
635 if (reader.PopString(&new_service_name_owner)) | |
636 service_name_owner_ = new_service_name_owner; | |
637 else | |
638 service_name_owner_.clear(); | |
639 } | 617 } |
640 | 618 |
641 DBusHandlerResult ObjectProxy::HandleNameOwnerChanged( | 619 DBusHandlerResult ObjectProxy::HandleNameOwnerChanged( |
642 scoped_ptr<Signal> signal) { | 620 scoped_ptr<Signal> signal) { |
643 DCHECK(signal); | 621 DCHECK(signal); |
644 bus_->AssertOnDBusThread(); | 622 bus_->AssertOnDBusThread(); |
645 | 623 |
646 // Confirm the validity of the NameOwnerChanged signal. | 624 // Confirm the validity of the NameOwnerChanged signal. |
647 if (signal->GetMember() == "NameOwnerChanged" && | 625 if (signal->GetMember() == kNameOwnerChangedMember && |
648 signal->GetInterface() == "org.freedesktop.DBus" && | 626 signal->GetInterface() == kDBusSystemObjectInterface && |
649 signal->GetSender() == "org.freedesktop.DBus") { | 627 signal->GetSender() == kDBusSystemObjectAddress) { |
650 MessageReader reader(signal.get()); | 628 MessageReader reader(signal.get()); |
651 std::string name, old_owner, new_owner; | 629 std::string name, old_owner, new_owner; |
652 if (reader.PopString(&name) && | 630 if (reader.PopString(&name) && |
653 reader.PopString(&old_owner) && | 631 reader.PopString(&old_owner) && |
654 reader.PopString(&new_owner) && | 632 reader.PopString(&new_owner) && |
655 name == service_name_) { | 633 name == service_name_) { |
656 service_name_owner_ = new_owner; | 634 service_name_owner_ = new_owner; |
657 if (!name_owner_changed_callback_.is_null()) { | 635 if (!name_owner_changed_callback_.is_null()) { |
658 const base::TimeTicks start_time = base::TimeTicks::Now(); | 636 const base::TimeTicks start_time = base::TimeTicks::Now(); |
659 Signal* released_signal = signal.release(); | 637 Signal* released_signal = signal.release(); |
660 std::vector<SignalCallback> callbacks; | 638 std::vector<SignalCallback> callbacks; |
661 callbacks.push_back(name_owner_changed_callback_); | 639 callbacks.push_back(name_owner_changed_callback_); |
662 bus_->PostTaskToOriginThread(FROM_HERE, | 640 bus_->PostTaskToOriginThread(FROM_HERE, |
663 base::Bind(&ObjectProxy::RunMethod, | 641 base::Bind(&ObjectProxy::RunMethod, |
664 this, | 642 this, |
665 start_time, | 643 start_time, |
666 callbacks, | 644 callbacks, |
667 released_signal)); | 645 released_signal)); |
668 } | 646 } |
669 } | 647 } |
670 } | 648 } |
671 | 649 |
672 // Always return unhandled to let other object proxies handle the same | 650 // Always return unhandled to let other object proxies handle the same |
673 // signal. | 651 // signal. |
674 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; | 652 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; |
675 } | 653 } |
676 | 654 |
677 } // namespace dbus | 655 } // namespace dbus |
OLD | NEW |