OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2011 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 #ifndef DBUS_BUS_H_ |
| 6 #define DBUS_BUS_H_ |
| 7 #pragma once |
| 8 |
| 9 #include <set> |
| 10 #include <string> |
| 11 #include <dbus/dbus.h> |
| 12 |
| 13 #include "base/callback.h" |
| 14 #include "base/memory/ref_counted.h" |
| 15 #include "base/memory/scoped_ptr.h" |
| 16 #include "base/tracked_objects.h" |
| 17 |
| 18 class MessageLoop; |
| 19 |
| 20 namespace base { |
| 21 class Thread; |
| 22 } |
| 23 |
| 24 namespace dbus { |
| 25 |
| 26 class ExportedObject; |
| 27 class ObjectProxy; |
| 28 |
| 29 // Bus is used to establish a connection with D-Bus, create object |
| 30 // proxies, and export objects. |
| 31 // |
| 32 // For asynchronous operations such as an asynchronous method call, the |
| 33 // bus object will use a message loop to monitor the underlying file |
| 34 // descriptor used for D-Bus communication. By default, the bus will use |
| 35 // the current thread's MessageLoopForIO. If |dbus_thread| option is |
| 36 // specified, the bus will use the D-Bus thread's message loop. |
| 37 // |
| 38 // THREADING |
| 39 // |
| 40 // In the D-Bus library, we use the two threads: |
| 41 // |
| 42 // - The origin thread: the thread that created the Bus object. |
| 43 // - The D-Bus thread: the thread supplifed by |dbus_thread| option. |
| 44 // |
| 45 // The origin thread is usually Chrome's UI thread. The D-Bus thread is |
| 46 // usually a dedicated thread for the D-Bus library. |
| 47 // |
| 48 // BLOCKING CALLS |
| 49 // |
| 50 // Functions that issue blocking calls are marked "BLOCKING CALL" and |
| 51 // these functions should be called in the D-Bus thread (if |
| 52 // supplied). AssertOnDBusThread() is placed in these functions. |
| 53 // |
| 54 // Note that it's hard to tell if a libdbus function is actually blocking |
| 55 // or not (ex. dbus_bus_request_name() internally calls |
| 56 // dbus_connection_send_with_reply_and_block(), which is a blocking |
| 57 // call). To err on the side, we consider all libdbus functions that deal |
| 58 // with the connection to dbus-damoen to be blocking. |
| 59 // |
| 60 // EXAMPLE USAGE: |
| 61 // |
| 62 // Synchronous method call: |
| 63 // |
| 64 // dbus::Bus::Options options; |
| 65 // // Set up the bus options here. |
| 66 // ... |
| 67 // dbus::Bus bus(options); |
| 68 // |
| 69 // dbus::ObjectProxy* object_proxy = |
| 70 // bus.GetObjectProxy(service_name, object_path); |
| 71 // |
| 72 // dbus::MethodCall method_call(interface_name, method_name); |
| 73 // dbus::Response response; |
| 74 // bool success = |
| 75 // object_proxy.CallMethodAndBlock(&method_call, timeout_ms, &response); |
| 76 // |
| 77 // Asynchronous method call: |
| 78 // |
| 79 // void OnResponse(dbus::Response* response) { |
| 80 // // response is NULL if the method call failed. |
| 81 // if (!response) |
| 82 // return; |
| 83 // // Do something with response here, and delete it. |
| 84 // delete response; |
| 85 // } |
| 86 // |
| 87 // ... |
| 88 // object_proxy.CallMethod(&method_call, timeout_ms, |
| 89 // base::Bind(&OnResponse)); |
| 90 // |
| 91 // Exporting a method: |
| 92 // |
| 93 // Response* Echo(dbus::MethodCall* method_call) { |
| 94 // // Do something with method_call. |
| 95 // Response* response = Response::FromMethodCall(method_call); |
| 96 // // Build response here. |
| 97 // return response; |
| 98 // } |
| 99 // |
| 100 // void OnExported(const std::string& interface_name, |
| 101 // const std::string& object_path, |
| 102 // bool success) { |
| 103 // // success is true if the method was exported successfully. |
| 104 // } |
| 105 // |
| 106 // ... |
| 107 // dbus::ExportedObject* exported_object = |
| 108 // bus.GetExportedObject(service_name, object_path); |
| 109 // exported_object.ExportMethod(interface_name, method_name, |
| 110 // base::Bind(&Echo), |
| 111 // base::Bind(&OnExported)); |
| 112 // |
| 113 // WHY IS THIS A REF COUNTED OBJECT? |
| 114 // |
| 115 // Bus is a ref counted object, to ensure that |this| of the object is |
| 116 // alive when callbacks referencing |this| are called. However, after |
| 117 // Shutdown() is called, |connection_| can be NULL. Hence, calbacks should |
| 118 // not rely on that |connection_| is alive. |
| 119 class Bus : public base::RefCountedThreadSafe<Bus> { |
| 120 public: |
| 121 // Specifies the bus type. SESSION is used to communicate with per-user |
| 122 // services like GNOME applications. SYSTEM is used to communicate with |
| 123 // system-wide services like NetworkManager. |
| 124 enum BusType { |
| 125 SESSION = DBUS_BUS_SESSION, |
| 126 SYSTEM = DBUS_BUS_SYSTEM, |
| 127 }; |
| 128 |
| 129 // Specifies the connection type. PRIVATE should usually be used unless |
| 130 // you are sure that SHARED is safe for you, which is unlikely the case |
| 131 // in Chrome. |
| 132 // |
| 133 // PRIVATE gives you a private connection, that won't be shared with |
| 134 // other Bus objects. |
| 135 // |
| 136 // SHARED gives you a connection shared among other Bus objects, which |
| 137 // is unsafe if the connection is shared with multiple threads. |
| 138 enum ConnectionType { |
| 139 PRIVATE, |
| 140 SHARED, |
| 141 }; |
| 142 |
| 143 // Options used to create a Bus object. |
| 144 struct Options { |
| 145 Options(); |
| 146 ~Options(); |
| 147 |
| 148 BusType bus_type; // SESSION by default. |
| 149 ConnectionType connection_type; // PRIVATE by default. |
| 150 // If the thread is set, the bus object will use the message loop |
| 151 // attached to the thread to process asynchronous operations. |
| 152 // |
| 153 // The thread should meet the following requirements: |
| 154 // 1) Already running. |
| 155 // 2) Has a MessageLoopForIO. |
| 156 // 3) Outlives the bus. |
| 157 base::Thread* dbus_thread; // NULL by default. |
| 158 }; |
| 159 |
| 160 // Called when shutdown is done. Used for Shutdown(). |
| 161 typedef base::Callback<void ()> OnShutdownCallback; |
| 162 |
| 163 // Creates a Bus object. The actual connection will be established when |
| 164 // Connect() is called. |
| 165 explicit Bus(const Options& options); |
| 166 |
| 167 // Gets the object proxy for the given service name and the object path. |
| 168 // The caller must not delete the returned object. The bus will own the |
| 169 // object. Never returns NULL. |
| 170 // |
| 171 // The object proxy is used to call remote methods. |
| 172 // |
| 173 // |service_name| looks like "org.freedesktop.NetworkManager", and |
| 174 // |object_path| looks like "/org/freedesktop/NetworkManager/Devices/0". |
| 175 // |
| 176 // Must be called in the origin thread. |
| 177 virtual ObjectProxy* GetObjectProxy(const std::string& service_name, |
| 178 const std::string& object_path); |
| 179 |
| 180 // Gets the exported object for the given service name and the object |
| 181 // path. The caller must not delete the returned object. The bus will |
| 182 // own the object. Never returns NULL. |
| 183 // |
| 184 // The exported object is used to export objects to other D-Bus clients. |
| 185 // |
| 186 // Must be called in the origin thread. |
| 187 virtual ExportedObject* GetExportedObject(const std::string& service_name, |
| 188 const std::string& object_path); |
| 189 |
| 190 // Shutdowns the bus and blocks until it's done. More specifically, this |
| 191 // function does the followings: |
| 192 // |
| 193 // - Unregisters the object paths |
| 194 // - Releases the service names |
| 195 // - Close the connection to dbus-daemon. |
| 196 // |
| 197 // BLOCKING CALL. |
| 198 virtual void ShutdownAndBlock(); |
| 199 |
| 200 // Shutdowns the bus in the D-Bus thread. |callback| will be called in |
| 201 // the origin thread. |
| 202 // |
| 203 // Must be called in the origin thread. |
| 204 virtual void Shutdown(OnShutdownCallback callback); |
| 205 |
| 206 // |
| 207 // The public functions below are not intended to be used in client |
| 208 // code. These are used to implement ObjectProxy and ExportedObject. |
| 209 // |
| 210 |
| 211 // Connects the bus to the dbus-daemon. |
| 212 // Returns true on success, or the bus is already connected. |
| 213 // |
| 214 // BLOCKING CALL. |
| 215 virtual bool Connect(); |
| 216 |
| 217 // Requests the ownership of the given service name. |
| 218 // Returns true on success, or the the service name is already obtained. |
| 219 // |
| 220 // BLOCKING CALL. |
| 221 virtual bool RequestOwnership(const std::string& service_name); |
| 222 |
| 223 // Releases the ownership of the given service name. |
| 224 // Returns true on success. |
| 225 // |
| 226 // BLOCKING CALL. |
| 227 virtual bool ReleaseOwnership(const std::string& service_name); |
| 228 |
| 229 // Sets up async operations. |
| 230 // Returns true on success, or it's already set up. |
| 231 // This function needs to be called before starting async operations. |
| 232 // |
| 233 // BLOCKING CALL. |
| 234 virtual bool SetUpAsyncOperations(); |
| 235 |
| 236 // Sends a message to the bus and blocks until the response is |
| 237 // received. Used to implement synchronous method calls. |
| 238 // |
| 239 // BLOCKING CALL. |
| 240 virtual DBusMessage* SendWithReplyAndBlock(DBusMessage* request, |
| 241 int timeout_ms, |
| 242 DBusError* error); |
| 243 |
| 244 // Requests to send a message to the bus. |
| 245 // |
| 246 // BLOCKING CALL. |
| 247 virtual void SendWithReply(DBusMessage* request, |
| 248 DBusPendingCall** pending_call, |
| 249 int timeout_ms); |
| 250 |
| 251 // Tries to register the object path. |
| 252 // |
| 253 // BLOCKING CALL. |
| 254 virtual bool TryRegisterObjectPath(const std::string& object_path, |
| 255 const DBusObjectPathVTable* vtable, |
| 256 void* user_data, |
| 257 DBusError* error); |
| 258 |
| 259 // Unregister the object path. |
| 260 // |
| 261 // BLOCKING CALL. |
| 262 virtual bool UnregisterObjectPath(const std::string& object_path); |
| 263 |
| 264 // Posts the task to the message loop of the thread that created the bus. |
| 265 virtual void PostTaskToOriginThread( |
| 266 const tracked_objects::Location& from_here, |
| 267 const base::Closure& task); |
| 268 |
| 269 // Posts the task to the message loop of the D-Bus thread. If D-Bus |
| 270 // thread is not supplied, the message loop of the origin thread will be |
| 271 // used. |
| 272 virtual void PostTaskToDBusThread( |
| 273 const tracked_objects::Location& from_here, |
| 274 const base::Closure& task); |
| 275 |
| 276 // Posts the delayed task to the message loop of the D-Bus thread. If |
| 277 // D-Bus thread is not supplied, the message loop of the origin thread |
| 278 // will be used. |
| 279 virtual void PostDelayedTaskToDBusThread( |
| 280 const tracked_objects::Location& from_here, |
| 281 const base::Closure& task, |
| 282 int delay_ms); |
| 283 |
| 284 // Check whether the current thread is on the origin thread (the thread |
| 285 // that created the bus). If not, DCHECK will fail. |
| 286 virtual void AssertOnOriginThread(); |
| 287 |
| 288 // Check whether the current thread is on the D-Bus thread. If not, |
| 289 // DCHECK will fail. If the D-Bus thread is not supplied, it calls |
| 290 // AssertOnOriginThread(). |
| 291 virtual void AssertOnDBusThread(); |
| 292 |
| 293 // Returns true if the bus has the D-Bus thread. |
| 294 virtual bool has_dbus_thread() { return dbus_thread_ != NULL; } |
| 295 |
| 296 private: |
| 297 friend class base::RefCountedThreadSafe<Bus>; |
| 298 virtual ~Bus(); |
| 299 |
| 300 // Helper function used for Shutdown(). |
| 301 void ShutdownInternal(OnShutdownCallback callback); |
| 302 |
| 303 // Processes the all incoming data to the connection, if any. |
| 304 // |
| 305 // BLOCKING CALL. |
| 306 void ProcessAllIncomingDataIfAny(); |
| 307 |
| 308 // Called when a watch object is added. Used to start monitoring the |
| 309 // file descriptor used for D-Bus communication. |
| 310 dbus_bool_t OnAddWatch(DBusWatch* raw_watch); |
| 311 |
| 312 // Called when a watch object is removed. |
| 313 void OnRemoveWatch(DBusWatch* raw_watch); |
| 314 |
| 315 // Called when the "enabled" status of |raw_watch| is toggled. |
| 316 void OnToggleWatch(DBusWatch* raw_watch); |
| 317 |
| 318 // Called when a timeout object is added. Used to start monitoring |
| 319 // timeout for method calls. |
| 320 dbus_bool_t OnAddTimeout(DBusTimeout* raw_timeout); |
| 321 |
| 322 // Called when a timeout object is removed. |
| 323 void OnRemoveTimeout(DBusTimeout* raw_timeout); |
| 324 |
| 325 // Called when the "enabled" status of |raw_timeout| is toggled. |
| 326 void OnToggleTimeout(DBusTimeout* raw_timeout); |
| 327 |
| 328 // Called when the dispatch status (i.e. if any incoming data is |
| 329 // available) is changed. |
| 330 void OnDispatchStatusChanged(DBusConnection* connection, |
| 331 DBusDispatchStatus status); |
| 332 |
| 333 // Callback helper functions. Redirects to the corresponding member function. |
| 334 static dbus_bool_t OnAddWatchThunk(DBusWatch* raw_watch, void* data); |
| 335 static void OnRemoveWatchThunk(DBusWatch* raw_watch, void* data); |
| 336 static void OnToggleWatchThunk(DBusWatch* raw_watch, void* data); |
| 337 static dbus_bool_t OnAddTimeoutThunk(DBusTimeout* raw_timeout, void* data); |
| 338 static void OnRemoveTimeoutThunk(DBusTimeout* raw_timeout, void* data); |
| 339 static void OnToggleTimeoutThunk(DBusTimeout* raw_timeout, void* data); |
| 340 static void OnDispatchStatusChangedThunk(DBusConnection* connection, |
| 341 DBusDispatchStatus status, |
| 342 void* data); |
| 343 const BusType bus_type_; |
| 344 const ConnectionType connection_type_; |
| 345 base::Thread* dbus_thread_; |
| 346 DBusConnection* connection_; |
| 347 |
| 348 MessageLoop* origin_loop_; |
| 349 base::PlatformThreadId origin_thread_id_; |
| 350 base::PlatformThreadId dbus_thread_id_; |
| 351 |
| 352 std::set<std::string> owned_service_names_; |
| 353 std::vector<dbus::ObjectProxy*> object_proxies_; |
| 354 std::vector<dbus::ExportedObject*> exported_objects_; |
| 355 |
| 356 bool async_operations_are_set_up_; |
| 357 |
| 358 DISALLOW_COPY_AND_ASSIGN(Bus); |
| 359 }; |
| 360 |
| 361 } // namespace dbus |
| 362 |
| 363 #endif // DBUS_BUS_H_ |
OLD | NEW |