Chromium Code Reviews| 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(); | |
|
stevenjb
2011/08/10 19:40:07
nit: a struct shouldn't need a destructor, and I f
satorux1
2011/08/10 21:14:27
I agree with you that it'd be nicer to inline the
stevenjb
2011/08/10 21:31:18
Meh. I didn't realize clang would trigger on numbe
| |
| 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 | |
|
stevenjb
2011/08/10 19:40:07
nit: Shuts down
satorux1
2011/08/10 21:14:27
Done.
| |
| 191 // function does the followings: | |
|
stevenjb
2011/08/10 19:40:07
nit: following
satorux1
2011/08/10 21:14:27
Done.
| |
| 192 // | |
| 193 // - Unregisters the object paths | |
| 194 // - Releases the service names | |
| 195 // - Close the connection to dbus-daemon. | |
|
stevenjb
2011/08/10 19:40:07
nit: Closes
satorux1
2011/08/10 21:14:27
Done.
| |
| 196 // | |
| 197 // BLOCKING CALL. | |
| 198 virtual void ShutdownAndBlock(); | |
| 199 | |
| 200 // Shutdowns the bus in the D-Bus thread. |callback| will be called in | |
|
stevenjb
2011/08/10 19:40:07
nit: Shuts down
satorux1
2011/08/10 21:14:27
Done.
| |
| 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); | |
|
stevenjb
2011/08/10 19:40:07
Can these be declared in a local namespace inside
satorux1
2011/08/10 21:14:27
These need to be static member functions, as these
stevenjb
2011/08/10 21:31:18
That makes sense.
| |
| 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 |