| 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/message_loop_proxy.h" | 10 #include "base/message_loop_proxy.h" |
| 11 #include "base/stl_util.h" | 11 #include "base/stl_util.h" |
| 12 #include "base/threading/thread.h" | 12 #include "base/threading/thread.h" |
| 13 #include "base/threading/thread_restrictions.h" | 13 #include "base/threading/thread_restrictions.h" |
| 14 #include "base/time.h" | 14 #include "base/time.h" |
| 15 #include "dbus/exported_object.h" | 15 #include "dbus/exported_object.h" |
| 16 #include "dbus/object_path.h" | |
| 17 #include "dbus/object_proxy.h" | 16 #include "dbus/object_proxy.h" |
| 18 #include "dbus/scoped_dbus_error.h" | 17 #include "dbus/scoped_dbus_error.h" |
| 19 | 18 |
| 20 namespace dbus { | 19 namespace dbus { |
| 21 | 20 |
| 22 namespace { | 21 namespace { |
| 23 | 22 |
| 24 const char kDisconnectedSignal[] = "Disconnected"; | 23 const char kDisconnectedSignal[] = "Disconnected"; |
| 25 const char kDisconnectedMatchRule[] = | 24 const char kDisconnectedMatchRule[] = |
| 26 "type='signal', path='/org/freedesktop/DBus/Local'," | 25 "type='signal', path='/org/freedesktop/DBus/Local'," |
| 27 "interface='org.freedesktop.DBus.Local', member='Disconnected'"; | 26 "interface='org.freedesktop.DBus.Local', member='Disconnected'"; |
| 28 | 27 |
| 29 // The class is used for watching the file descriptor used for D-Bus | 28 // The class is used for watching the file descriptor used for D-Bus |
| 30 // communication. | 29 // communication. |
| 31 class Watch : public base::MessagePumpLibevent::Watcher { | 30 class Watch : public base::MessagePumpLibevent::Watcher { |
| 32 public: | 31 public: |
| 33 Watch(DBusWatch* watch) | 32 explicit Watch(DBusWatch* watch) |
| 34 : raw_watch_(watch) { | 33 : raw_watch_(watch) { |
| 35 dbus_watch_set_data(raw_watch_, this, NULL); | 34 dbus_watch_set_data(raw_watch_, this, NULL); |
| 36 } | 35 } |
| 37 | 36 |
| 38 virtual ~Watch() { | 37 virtual ~Watch() { |
| 39 dbus_watch_set_data(raw_watch_, NULL, NULL); | 38 dbus_watch_set_data(raw_watch_, NULL, NULL); |
| 40 } | 39 } |
| 41 | 40 |
| 42 // Returns true if the underlying file descriptor is ready to be watched. | 41 // Returns true if the underlying file descriptor is ready to be watched. |
| 43 bool IsReadyToBeWatched() { | 42 bool IsReadyToBeWatched() { |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 94 // The class is used for monitoring the timeout used for D-Bus method | 93 // The class is used for monitoring the timeout used for D-Bus method |
| 95 // calls. | 94 // calls. |
| 96 // | 95 // |
| 97 // Unlike Watch, Timeout is a ref counted object, to ensure that |this| of | 96 // Unlike Watch, Timeout is a ref counted object, to ensure that |this| of |
| 98 // the object is is alive when HandleTimeout() is called. It's unlikely | 97 // the object is is alive when HandleTimeout() is called. It's unlikely |
| 99 // but it may be possible that HandleTimeout() is called after | 98 // but it may be possible that HandleTimeout() is called after |
| 100 // Bus::OnRemoveTimeout(). That's why we don't simply delete the object in | 99 // Bus::OnRemoveTimeout(). That's why we don't simply delete the object in |
| 101 // Bus::OnRemoveTimeout(). | 100 // Bus::OnRemoveTimeout(). |
| 102 class Timeout : public base::RefCountedThreadSafe<Timeout> { | 101 class Timeout : public base::RefCountedThreadSafe<Timeout> { |
| 103 public: | 102 public: |
| 104 Timeout(DBusTimeout* timeout) | 103 explicit Timeout(DBusTimeout* timeout) |
| 105 : raw_timeout_(timeout), | 104 : raw_timeout_(timeout), |
| 106 monitoring_is_active_(false), | 105 monitoring_is_active_(false), |
| 107 is_completed(false) { | 106 is_completed(false) { |
| 108 dbus_timeout_set_data(raw_timeout_, this, NULL); | 107 dbus_timeout_set_data(raw_timeout_, this, NULL); |
| 109 AddRef(); // Balanced on Complete(). | 108 AddRef(); // Balanced on Complete(). |
| 110 } | 109 } |
| 111 | 110 |
| 112 // Returns true if the timeout is ready to be monitored. | 111 // Returns true if the timeout is ready to be monitored. |
| 113 bool IsReadyToBeMonitored() { | 112 bool IsReadyToBeMonitored() { |
| 114 return dbus_timeout_get_enabled(raw_timeout_); | 113 return dbus_timeout_get_enabled(raw_timeout_); |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 174 : bus_type(SESSION), | 173 : bus_type(SESSION), |
| 175 connection_type(PRIVATE) { | 174 connection_type(PRIVATE) { |
| 176 } | 175 } |
| 177 | 176 |
| 178 Bus::Options::~Options() { | 177 Bus::Options::~Options() { |
| 179 } | 178 } |
| 180 | 179 |
| 181 Bus::Bus(const Options& options) | 180 Bus::Bus(const Options& options) |
| 182 : bus_type_(options.bus_type), | 181 : bus_type_(options.bus_type), |
| 183 connection_type_(options.connection_type), | 182 connection_type_(options.connection_type), |
| 184 dbus_thread_message_loop_proxy_(options.dbus_thread_message_loop_proxy), | 183 dbus_task_runner_(options.dbus_task_runner), |
| 185 on_shutdown_(false /* manual_reset */, false /* initially_signaled */), | 184 on_shutdown_(false /* manual_reset */, false /* initially_signaled */), |
| 186 connection_(NULL), | 185 connection_(NULL), |
| 187 origin_thread_id_(base::PlatformThread::CurrentId()), | 186 origin_thread_id_(base::PlatformThread::CurrentId()), |
| 188 async_operations_set_up_(false), | 187 async_operations_set_up_(false), |
| 189 shutdown_completed_(false), | 188 shutdown_completed_(false), |
| 190 num_pending_watches_(0), | 189 num_pending_watches_(0), |
| 191 num_pending_timeouts_(0), | 190 num_pending_timeouts_(0), |
| 192 address_(options.address), | 191 address_(options.address), |
| 193 on_disconnected_closure_(options.disconnected_callback) { | 192 on_disconnected_closure_(options.disconnected_callback) { |
| 194 // This is safe to call multiple times. | 193 // This is safe to call multiple times. |
| 195 dbus_threads_init_default(); | 194 dbus_threads_init_default(); |
| 196 // The origin message loop is unnecessary if the client uses synchronous | 195 // The origin message loop is unnecessary if the client uses synchronous |
| 197 // functions only. | 196 // functions only. |
| 198 if (MessageLoop::current()) | 197 if (MessageLoop::current()) |
| 199 origin_message_loop_proxy_ = MessageLoop::current()->message_loop_proxy(); | 198 origin_task_runner_ = MessageLoop::current()->message_loop_proxy(); |
| 200 } | 199 } |
| 201 | 200 |
| 202 Bus::~Bus() { | 201 Bus::~Bus() { |
| 203 DCHECK(!connection_); | 202 DCHECK(!connection_); |
| 204 DCHECK(owned_service_names_.empty()); | 203 DCHECK(owned_service_names_.empty()); |
| 205 DCHECK(match_rules_added_.empty()); | 204 DCHECK(match_rules_added_.empty()); |
| 206 DCHECK(filter_functions_added_.empty()); | 205 DCHECK(filter_functions_added_.empty()); |
| 207 DCHECK(registered_object_paths_.empty()); | 206 DCHECK(registered_object_paths_.empty()); |
| 208 DCHECK_EQ(0, num_pending_watches_); | 207 DCHECK_EQ(0, num_pending_watches_); |
| 209 // TODO(satorux): This check fails occasionally in browser_tests for tests | 208 // TODO(satorux): This check fails occasionally in browser_tests for tests |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 301 // GetExportedObject() call to return a new object, rather than this one. | 300 // GetExportedObject() call to return a new object, rather than this one. |
| 302 ExportedObjectTable::iterator iter = exported_object_table_.find(object_path); | 301 ExportedObjectTable::iterator iter = exported_object_table_.find(object_path); |
| 303 if (iter == exported_object_table_.end()) | 302 if (iter == exported_object_table_.end()) |
| 304 return; | 303 return; |
| 305 | 304 |
| 306 scoped_refptr<ExportedObject> exported_object = iter->second; | 305 scoped_refptr<ExportedObject> exported_object = iter->second; |
| 307 exported_object_table_.erase(iter); | 306 exported_object_table_.erase(iter); |
| 308 | 307 |
| 309 // Post the task to perform the final unregistration to the D-Bus thread. | 308 // Post the task to perform the final unregistration to the D-Bus thread. |
| 310 // Since the registration also happens on the D-Bus thread in | 309 // Since the registration also happens on the D-Bus thread in |
| 311 // TryRegisterObjectPath(), and the message loop proxy we post to is a | 310 // TryRegisterObjectPath(), and the task runner we post to is a |
| 312 // MessageLoopProxy which inherits from SequencedTaskRunner, there is a | 311 // SequencedTaskRunner, there is a guarantee that this will happen before any |
| 313 // guarantee that this will happen before any future registration call. | 312 // future registration call. |
| 314 PostTaskToDBusThread(FROM_HERE, base::Bind( | 313 PostTaskToDBusThread(FROM_HERE, |
| 315 &Bus::UnregisterExportedObjectInternal, | 314 base::Bind(&Bus::UnregisterExportedObjectInternal, |
| 316 this, exported_object)); | 315 this, exported_object)); |
| 317 } | 316 } |
| 318 | 317 |
| 319 void Bus::UnregisterExportedObjectInternal( | 318 void Bus::UnregisterExportedObjectInternal( |
| 320 scoped_refptr<dbus::ExportedObject> exported_object) { | 319 scoped_refptr<dbus::ExportedObject> exported_object) { |
| 321 AssertOnDBusThread(); | 320 AssertOnDBusThread(); |
| 322 | 321 |
| 323 exported_object->Unregister(); | 322 exported_object->Unregister(); |
| 324 } | 323 } |
| 325 | 324 |
| 326 bool Bus::Connect() { | 325 bool Bus::Connect() { |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 431 // dbus_connection_close() won't unref. | 430 // dbus_connection_close() won't unref. |
| 432 dbus_connection_unref(connection_); | 431 dbus_connection_unref(connection_); |
| 433 } | 432 } |
| 434 | 433 |
| 435 connection_ = NULL; | 434 connection_ = NULL; |
| 436 shutdown_completed_ = true; | 435 shutdown_completed_ = true; |
| 437 } | 436 } |
| 438 | 437 |
| 439 void Bus::ShutdownOnDBusThreadAndBlock() { | 438 void Bus::ShutdownOnDBusThreadAndBlock() { |
| 440 AssertOnOriginThread(); | 439 AssertOnOriginThread(); |
| 441 DCHECK(dbus_thread_message_loop_proxy_.get()); | 440 DCHECK(dbus_task_runner_.get()); |
| 442 | 441 |
| 443 PostTaskToDBusThread(FROM_HERE, base::Bind( | 442 PostTaskToDBusThread(FROM_HERE, base::Bind( |
| 444 &Bus::ShutdownOnDBusThreadAndBlockInternal, | 443 &Bus::ShutdownOnDBusThreadAndBlockInternal, |
| 445 this)); | 444 this)); |
| 446 | 445 |
| 447 // http://crbug.com/125222 | 446 // http://crbug.com/125222 |
| 448 base::ThreadRestrictions::ScopedAllowWait allow_wait; | 447 base::ThreadRestrictions::ScopedAllowWait allow_wait; |
| 449 | 448 |
| 450 // Wait until the shutdown is complete on the D-Bus thread. | 449 // Wait until the shutdown is complete on the D-Bus thread. |
| 451 // The shutdown should not hang, but set timeout just in case. | 450 // The shutdown should not hang, but set timeout just in case. |
| (...skipping 283 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 735 // (crbug.com/174431) | 734 // (crbug.com/174431) |
| 736 if (dbus_connection_get_dispatch_status(connection_) == | 735 if (dbus_connection_get_dispatch_status(connection_) == |
| 737 DBUS_DISPATCH_DATA_REMAINS) { | 736 DBUS_DISPATCH_DATA_REMAINS) { |
| 738 while (dbus_connection_dispatch(connection_) == | 737 while (dbus_connection_dispatch(connection_) == |
| 739 DBUS_DISPATCH_DATA_REMAINS); | 738 DBUS_DISPATCH_DATA_REMAINS); |
| 740 } | 739 } |
| 741 } | 740 } |
| 742 | 741 |
| 743 void Bus::PostTaskToOriginThread(const tracked_objects::Location& from_here, | 742 void Bus::PostTaskToOriginThread(const tracked_objects::Location& from_here, |
| 744 const base::Closure& task) { | 743 const base::Closure& task) { |
| 745 DCHECK(origin_message_loop_proxy_.get()); | 744 DCHECK(origin_task_runner_.get()); |
| 746 if (!origin_message_loop_proxy_->PostTask(from_here, task)) { | 745 if (!origin_task_runner_->PostTask(from_here, task)) { |
| 747 LOG(WARNING) << "Failed to post a task to the origin message loop"; | 746 LOG(WARNING) << "Failed to post a task to the origin message loop"; |
| 748 } | 747 } |
| 749 } | 748 } |
| 750 | 749 |
| 751 void Bus::PostTaskToDBusThread(const tracked_objects::Location& from_here, | 750 void Bus::PostTaskToDBusThread(const tracked_objects::Location& from_here, |
| 752 const base::Closure& task) { | 751 const base::Closure& task) { |
| 753 if (dbus_thread_message_loop_proxy_.get()) { | 752 if (dbus_task_runner_.get()) { |
| 754 if (!dbus_thread_message_loop_proxy_->PostTask(from_here, task)) { | 753 if (!dbus_task_runner_->PostTask(from_here, task)) { |
| 755 LOG(WARNING) << "Failed to post a task to the D-Bus thread message loop"; | 754 LOG(WARNING) << "Failed to post a task to the D-Bus thread message loop"; |
| 756 } | 755 } |
| 757 } else { | 756 } else { |
| 758 DCHECK(origin_message_loop_proxy_.get()); | 757 DCHECK(origin_task_runner_.get()); |
| 759 if (!origin_message_loop_proxy_->PostTask(from_here, task)) { | 758 if (!origin_task_runner_->PostTask(from_here, task)) { |
| 760 LOG(WARNING) << "Failed to post a task to the origin message loop"; | 759 LOG(WARNING) << "Failed to post a task to the origin message loop"; |
| 761 } | 760 } |
| 762 } | 761 } |
| 763 } | 762 } |
| 764 | 763 |
| 765 void Bus::PostDelayedTaskToDBusThread( | 764 void Bus::PostDelayedTaskToDBusThread( |
| 766 const tracked_objects::Location& from_here, | 765 const tracked_objects::Location& from_here, |
| 767 const base::Closure& task, | 766 const base::Closure& task, |
| 768 base::TimeDelta delay) { | 767 base::TimeDelta delay) { |
| 769 if (dbus_thread_message_loop_proxy_.get()) { | 768 if (dbus_task_runner_.get()) { |
| 770 if (!dbus_thread_message_loop_proxy_->PostDelayedTask( | 769 if (!dbus_task_runner_->PostDelayedTask( |
| 771 from_here, task, delay)) { | 770 from_here, task, delay)) { |
| 772 LOG(WARNING) << "Failed to post a task to the D-Bus thread message loop"; | 771 LOG(WARNING) << "Failed to post a task to the D-Bus thread message loop"; |
| 773 } | 772 } |
| 774 } else { | 773 } else { |
| 775 DCHECK(origin_message_loop_proxy_.get()); | 774 DCHECK(origin_task_runner_.get()); |
| 776 if (!origin_message_loop_proxy_->PostDelayedTask( | 775 if (!origin_task_runner_->PostDelayedTask(from_here, task, delay)) { |
| 777 from_here, task, delay)) { | |
| 778 LOG(WARNING) << "Failed to post a task to the origin message loop"; | 776 LOG(WARNING) << "Failed to post a task to the origin message loop"; |
| 779 } | 777 } |
| 780 } | 778 } |
| 781 } | 779 } |
| 782 | 780 |
| 783 bool Bus::HasDBusThread() { | 781 bool Bus::HasDBusThread() { |
| 784 return dbus_thread_message_loop_proxy_.get() != NULL; | 782 return dbus_task_runner_.get() != NULL; |
| 785 } | 783 } |
| 786 | 784 |
| 787 void Bus::AssertOnOriginThread() { | 785 void Bus::AssertOnOriginThread() { |
| 788 DCHECK_EQ(origin_thread_id_, base::PlatformThread::CurrentId()); | 786 DCHECK_EQ(origin_thread_id_, base::PlatformThread::CurrentId()); |
| 789 } | 787 } |
| 790 | 788 |
| 791 void Bus::AssertOnDBusThread() { | 789 void Bus::AssertOnDBusThread() { |
| 792 base::ThreadRestrictions::AssertIOAllowed(); | 790 base::ThreadRestrictions::AssertIOAllowed(); |
| 793 | 791 |
| 794 if (dbus_thread_message_loop_proxy_.get()) { | 792 if (dbus_task_runner_.get()) { |
| 795 DCHECK(dbus_thread_message_loop_proxy_->BelongsToCurrentThread()); | 793 DCHECK(dbus_task_runner_->RunsTasksOnCurrentThread()); |
| 796 } else { | 794 } else { |
| 797 AssertOnOriginThread(); | 795 AssertOnOriginThread(); |
| 798 } | 796 } |
| 799 } | 797 } |
| 800 | 798 |
| 801 dbus_bool_t Bus::OnAddWatch(DBusWatch* raw_watch) { | 799 dbus_bool_t Bus::OnAddWatch(DBusWatch* raw_watch) { |
| 802 AssertOnDBusThread(); | 800 AssertOnDBusThread(); |
| 803 | 801 |
| 804 // watch will be deleted when raw_watch is removed in OnRemoveWatch(). | 802 // watch will be deleted when raw_watch is removed in OnRemoveWatch(). |
| 805 Watch* watch = new Watch(raw_watch); | 803 Watch* watch = new Watch(raw_watch); |
| (...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 921 } | 919 } |
| 922 | 920 |
| 923 void Bus::OnDispatchStatusChangedThunk(DBusConnection* connection, | 921 void Bus::OnDispatchStatusChangedThunk(DBusConnection* connection, |
| 924 DBusDispatchStatus status, | 922 DBusDispatchStatus status, |
| 925 void* data) { | 923 void* data) { |
| 926 Bus* self = static_cast<Bus*>(data); | 924 Bus* self = static_cast<Bus*>(data); |
| 927 self->OnDispatchStatusChanged(connection, status); | 925 self->OnDispatchStatusChanged(connection, status); |
| 928 } | 926 } |
| 929 | 927 |
| 930 DBusHandlerResult Bus::OnConnectionDisconnectedFilter( | 928 DBusHandlerResult Bus::OnConnectionDisconnectedFilter( |
| 931 DBusConnection *connection, | 929 DBusConnection* connection, |
| 932 DBusMessage *message, | 930 DBusMessage* message, |
| 933 void *data) { | 931 void* data) { |
| 934 if (dbus_message_is_signal(message, | 932 if (dbus_message_is_signal(message, |
| 935 DBUS_INTERFACE_LOCAL, | 933 DBUS_INTERFACE_LOCAL, |
| 936 kDisconnectedSignal)) { | 934 kDisconnectedSignal)) { |
| 937 Bus* self = static_cast<Bus*>(data); | 935 Bus* self = static_cast<Bus*>(data); |
| 938 self->AssertOnDBusThread(); | 936 self->AssertOnDBusThread(); |
| 939 self->OnConnectionDisconnected(connection); | 937 self->OnConnectionDisconnected(connection); |
| 940 return DBUS_HANDLER_RESULT_HANDLED; | 938 return DBUS_HANDLER_RESULT_HANDLED; |
| 941 } | 939 } |
| 942 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; | 940 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; |
| 943 } | 941 } |
| 944 | 942 |
| 945 } // namespace dbus | 943 } // namespace dbus |
| OLD | NEW |