bus.h revision 5821806d5e7f356e8fa4b058a389a808ea183019
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#ifndef DBUS_BUS_H_ 6#define DBUS_BUS_H_ 7 8#include <map> 9#include <set> 10#include <string> 11#include <utility> 12#include <dbus/dbus.h> 13 14#include "base/callback.h" 15#include "base/memory/ref_counted.h" 16#include "base/synchronization/waitable_event.h" 17#include "base/threading/platform_thread.h" 18#include "base/tracked_objects.h" 19#include "dbus/dbus_export.h" 20#include "dbus/object_path.h" 21 22class MessageLoop; 23 24namespace base { 25class Thread; 26class MessageLoopProxy; 27} 28 29namespace dbus { 30 31class ExportedObject; 32class ObjectProxy; 33 34// Bus is used to establish a connection with D-Bus, create object 35// proxies, and export objects. 36// 37// For asynchronous operations such as an asynchronous method call, the 38// bus object will use a message loop to monitor the underlying file 39// descriptor used for D-Bus communication. By default, the bus will use 40// the current thread's MessageLoopForIO. If |dbus_thread_message_loop_proxy| 41// option is specified, the bus will use that message loop instead. 42// 43// THREADING 44// 45// In the D-Bus library, we use the two threads: 46// 47// - The origin thread: the thread that created the Bus object. 48// - The D-Bus thread: the thread servicing |dbus_thread_message_loop_proxy|. 49// 50// The origin thread is usually Chrome's UI thread. The D-Bus thread is 51// usually a dedicated thread for the D-Bus library. 52// 53// BLOCKING CALLS 54// 55// Functions that issue blocking calls are marked "BLOCKING CALL" and 56// these functions should be called in the D-Bus thread (if 57// supplied). AssertOnDBusThread() is placed in these functions. 58// 59// Note that it's hard to tell if a libdbus function is actually blocking 60// or not (ex. dbus_bus_request_name() internally calls 61// dbus_connection_send_with_reply_and_block(), which is a blocking 62// call). To err on the safe side, we consider all libdbus functions that 63// deal with the connection to dbus-daemon to be blocking. 64// 65// SHUTDOWN 66// 67// The Bus object must be shut down manually by ShutdownAndBlock() and 68// friends. We require the manual shutdown to make the operation explicit 69// rather than doing it silently in the destructor. 70// 71// EXAMPLE USAGE: 72// 73// Synchronous method call: 74// 75// dbus::Bus::Options options; 76// // Set up the bus options here. 77// ... 78// dbus::Bus bus(options); 79// 80// dbus::ObjectProxy* object_proxy = 81// bus.GetObjectProxy(service_name, object_path); 82// 83// dbus::MethodCall method_call(interface_name, method_name); 84// scoped_ptr<dbus::Response> response( 85// object_proxy.CallMethodAndBlock(&method_call, timeout_ms)); 86// if (response.get() != NULL) { // Success. 87// ... 88// } 89// 90// Asynchronous method call: 91// 92// void OnResponse(dbus::Response* response) { 93// // response is NULL if the method call failed. 94// if (!response) 95// return; 96// } 97// 98// ... 99// object_proxy.CallMethod(&method_call, timeout_ms, 100// base::Bind(&OnResponse)); 101// 102// Exporting a method: 103// 104// void Echo(dbus::MethodCall* method_call, 105// dbus::ExportedObject::ResponseSender response_sender) { 106// // Do something with method_call. 107// Response* response = Response::FromMethodCall(method_call); 108// // Build response here. 109// // Can send an immediate response here to implement a synchronous service 110// // or store the response_sender and send a response later to implement an 111// // asynchronous service. 112// response_sender.Run(response); 113// } 114// 115// void OnExported(const std::string& interface_name, 116// const ObjectPath& object_path, 117// bool success) { 118// // success is true if the method was exported successfully. 119// } 120// 121// ... 122// dbus::ExportedObject* exported_object = 123// bus.GetExportedObject(service_name, object_path); 124// exported_object.ExportMethod(interface_name, method_name, 125// base::Bind(&Echo), 126// base::Bind(&OnExported)); 127// 128// WHY IS THIS A REF COUNTED OBJECT? 129// 130// Bus is a ref counted object, to ensure that |this| of the object is 131// alive when callbacks referencing |this| are called. However, after the 132// bus is shut down, |connection_| can be NULL. Hence, callbacks should 133// not rely on that |connection_| is alive. 134class CHROME_DBUS_EXPORT Bus : public base::RefCountedThreadSafe<Bus> { 135 public: 136 // Specifies the bus type. SESSION is used to communicate with per-user 137 // services like GNOME applications. SYSTEM is used to communicate with 138 // system-wide services like NetworkManager. CUSTOM_ADDRESS is used to 139 // communicate with an user specified address. 140 enum BusType { 141 SESSION = DBUS_BUS_SESSION, 142 SYSTEM = DBUS_BUS_SYSTEM, 143 CUSTOM_ADDRESS, 144 }; 145 146 // Specifies the connection type. PRIVATE should usually be used unless 147 // you are sure that SHARED is safe for you, which is unlikely the case 148 // in Chrome. 149 // 150 // PRIVATE gives you a private connection, that won't be shared with 151 // other Bus objects. 152 // 153 // SHARED gives you a connection shared among other Bus objects, which 154 // is unsafe if the connection is shared with multiple threads. 155 enum ConnectionType { 156 PRIVATE, 157 SHARED, 158 }; 159 160 // Options used to create a Bus object. 161 struct CHROME_DBUS_EXPORT Options { 162 Options(); 163 ~Options(); 164 165 BusType bus_type; // SESSION by default. 166 ConnectionType connection_type; // PRIVATE by default. 167 // If dbus_thread_message_loop_proxy is set, the bus object will use that 168 // message loop to process asynchronous operations. 169 // 170 // The thread servicing the message loop proxy should meet the following 171 // requirements: 172 // 1) Already running. 173 // 2) Has a MessageLoopForIO. 174 scoped_refptr<base::MessageLoopProxy> dbus_thread_message_loop_proxy; 175 176 // Specifies the server addresses to be connected. If you want to 177 // communicate with non dbus-daemon such as ibus-daemon, set |bus_type| to 178 // CUSTOM_ADDRESS, and |address| to the D-Bus server address you want to 179 // connect to. The format of this address value is the dbus address style 180 // which is described in 181 // http://dbus.freedesktop.org/doc/dbus-specification.html#addresses 182 // 183 // EXAMPLE USAGE: 184 // dbus::Bus::Options options; 185 // options.bus_type = CUSTOM_ADDRESS; 186 // options.address.assign("unix:path=/tmp/dbus-XXXXXXX"); 187 // // Set up other options 188 // dbus::Bus bus(options); 189 // 190 // // Do something. 191 // 192 std::string address; 193 }; 194 195 // Creates a Bus object. The actual connection will be established when 196 // Connect() is called. 197 explicit Bus(const Options& options); 198 199 // Called when an ownership request is complete. 200 // Parameters: 201 // - the requested service name. 202 // - whether ownership has been obtained or not. 203 typedef base::Callback<void (const std::string&, bool)> OnOwnershipCallback; 204 205 // Gets the object proxy for the given service name and the object path. 206 // The caller must not delete the returned object. 207 // 208 // Returns an existing object proxy if the bus object already owns the 209 // object proxy for the given service name and the object path. 210 // Never returns NULL. 211 // 212 // The bus will own all object proxies created by the bus, to ensure 213 // that the object proxies are detached from remote objects at the 214 // shutdown time of the bus. 215 // 216 // The object proxy is used to call methods of remote objects, and 217 // receive signals from them. 218 // 219 // |service_name| looks like "org.freedesktop.NetworkManager", and 220 // |object_path| looks like "/org/freedesktop/NetworkManager/Devices/0". 221 // 222 // Must be called in the origin thread. 223 virtual ObjectProxy* GetObjectProxy(const std::string& service_name, 224 const ObjectPath& object_path); 225 226 // Same as above, but also takes a bitfield of ObjectProxy::Options. 227 // See object_proxy.h for available options. 228 virtual ObjectProxy* GetObjectProxyWithOptions( 229 const std::string& service_name, 230 const ObjectPath& object_path, 231 int options); 232 233 // Gets the exported object for the given object path. 234 // The caller must not delete the returned object. 235 // 236 // Returns an existing exported object if the bus object already owns 237 // the exported object for the given object path. Never returns NULL. 238 // 239 // The bus will own all exported objects created by the bus, to ensure 240 // that the exported objects are unregistered at the shutdown time of 241 // the bus. 242 // 243 // The exported object is used to export methods of local objects, and 244 // send signal from them. 245 // 246 // Must be called in the origin thread. 247 virtual ExportedObject* GetExportedObject(const ObjectPath& object_path); 248 249 // Unregisters the exported object for the given object path |object_path|. 250 // 251 // Getting an exported object for the same object path after this call 252 // will return a new object, method calls on any remaining copies of the 253 // previous object will not be called. 254 // 255 // Must be called in the origin thread. 256 virtual void UnregisterExportedObject(const ObjectPath& object_path); 257 258 // Shuts down the bus and blocks until it's done. More specifically, this 259 // function does the following: 260 // 261 // - Unregisters the object paths 262 // - Releases the service names 263 // - Closes the connection to dbus-daemon. 264 // 265 // BLOCKING CALL. 266 virtual void ShutdownAndBlock(); 267 268 // Similar to ShutdownAndBlock(), but this function is used to 269 // synchronously shut down the bus that uses the D-Bus thread. This 270 // function is intended to be used at the very end of the browser 271 // shutdown, where it makes more sense to shut down the bus 272 // synchronously, than trying to make it asynchronous. 273 // 274 // BLOCKING CALL, but must be called in the origin thread. 275 virtual void ShutdownOnDBusThreadAndBlock(); 276 277 // Returns true if the shutdown has been completed. 278 bool shutdown_completed() { return shutdown_completed_; } 279 280 // 281 // The public functions below are not intended to be used in client 282 // code. These are used to implement ObjectProxy and ExportedObject. 283 // 284 285 // Connects the bus to the dbus-daemon. 286 // Returns true on success, or the bus is already connected. 287 // 288 // BLOCKING CALL. 289 virtual bool Connect(); 290 291 // Requests the ownership of the service name given by |service_name|. 292 // See also RequestOwnershipAndBlock(). 293 // 294 // |on_ownership_callback| is called when the service name is obtained 295 // or failed to be obtained, in the origin thread. 296 // 297 // Must be called in the origin thread. 298 virtual void RequestOwnership(const std::string& service_name, 299 OnOwnershipCallback on_ownership_callback); 300 301 // Requests the ownership of the given service name. 302 // Returns true on success, or the the service name is already obtained. 303 // 304 // BLOCKING CALL. 305 virtual bool RequestOwnershipAndBlock(const std::string& service_name); 306 307 // Releases the ownership of the given service name. 308 // Returns true on success. 309 // 310 // BLOCKING CALL. 311 virtual bool ReleaseOwnership(const std::string& service_name); 312 313 // Sets up async operations. 314 // Returns true on success, or it's already set up. 315 // This function needs to be called before starting async operations. 316 // 317 // BLOCKING CALL. 318 virtual bool SetUpAsyncOperations(); 319 320 // Sends a message to the bus and blocks until the response is 321 // received. Used to implement synchronous method calls. 322 // 323 // BLOCKING CALL. 324 virtual DBusMessage* SendWithReplyAndBlock(DBusMessage* request, 325 int timeout_ms, 326 DBusError* error); 327 328 // Requests to send a message to the bus. The reply is handled with 329 // |pending_call| at a later time. 330 // 331 // BLOCKING CALL. 332 virtual void SendWithReply(DBusMessage* request, 333 DBusPendingCall** pending_call, 334 int timeout_ms); 335 336 // Requests to send a message to the bus. The message serial number will 337 // be stored in |serial|. 338 // 339 // BLOCKING CALL. 340 virtual void Send(DBusMessage* request, uint32* serial); 341 342 // Adds the message filter function. |filter_function| will be called 343 // when incoming messages are received. Returns true on success. 344 // 345 // When a new incoming message arrives, filter functions are called in 346 // the order that they were added until the the incoming message is 347 // handled by a filter function. 348 // 349 // The same filter function associated with the same user data cannot be 350 // added more than once. Returns false for this case. 351 // 352 // BLOCKING CALL. 353 virtual bool AddFilterFunction(DBusHandleMessageFunction filter_function, 354 void* user_data); 355 356 // Removes the message filter previously added by AddFilterFunction(). 357 // Returns true on success. 358 // 359 // BLOCKING CALL. 360 virtual bool RemoveFilterFunction(DBusHandleMessageFunction filter_function, 361 void* user_data); 362 363 // Adds the match rule. Messages that match the rule will be processed 364 // by the filter functions added by AddFilterFunction(). 365 // 366 // You cannot specify which filter function to use for a match rule. 367 // Instead, you should check if an incoming message is what you are 368 // interested in, in the filter functions. 369 // 370 // The same match rule can be added more than once, but ignored from the 371 // second time. 372 // 373 // The match rule looks like: 374 // "type='signal', interface='org.chromium.SomeInterface'". 375 // 376 // See "Message Bus Message Routing" section in the D-Bus specification 377 // for details about match rules: 378 // http://dbus.freedesktop.org/doc/dbus-specification.html#message-bus-routing 379 // 380 // BLOCKING CALL. 381 virtual void AddMatch(const std::string& match_rule, DBusError* error); 382 383 // Removes the match rule previously added by AddMatch(). 384 // 385 // BLOCKING CALL. 386 virtual void RemoveMatch(const std::string& match_rule, DBusError* error); 387 388 // Tries to register the object path. Returns true on success. 389 // Returns false if the object path is already registered. 390 // 391 // |message_function| in |vtable| will be called every time when a new 392 // |message sent to the object path arrives. 393 // 394 // The same object path must not be added more than once. 395 // 396 // See also documentation of |dbus_connection_try_register_object_path| at 397 // http://dbus.freedesktop.org/doc/api/html/group__DBusConnection.html 398 // 399 // BLOCKING CALL. 400 virtual bool TryRegisterObjectPath(const ObjectPath& object_path, 401 const DBusObjectPathVTable* vtable, 402 void* user_data, 403 DBusError* error); 404 405 // Unregister the object path. 406 // 407 // BLOCKING CALL. 408 virtual void UnregisterObjectPath(const ObjectPath& object_path); 409 410 // Posts the task to the message loop of the thread that created the bus. 411 virtual void PostTaskToOriginThread( 412 const tracked_objects::Location& from_here, 413 const base::Closure& task); 414 415 // Posts the task to the message loop of the D-Bus thread. If D-Bus 416 // thread is not supplied, the message loop of the origin thread will be 417 // used. 418 virtual void PostTaskToDBusThread( 419 const tracked_objects::Location& from_here, 420 const base::Closure& task); 421 422 // Posts the delayed task to the message loop of the D-Bus thread. If 423 // D-Bus thread is not supplied, the message loop of the origin thread 424 // will be used. 425 virtual void PostDelayedTaskToDBusThread( 426 const tracked_objects::Location& from_here, 427 const base::Closure& task, 428 base::TimeDelta delay); 429 430 // Returns true if the bus has the D-Bus thread. 431 virtual bool HasDBusThread(); 432 433 // Check whether the current thread is on the origin thread (the thread 434 // that created the bus). If not, DCHECK will fail. 435 virtual void AssertOnOriginThread(); 436 437 // Check whether the current thread is on the D-Bus thread. If not, 438 // DCHECK will fail. If the D-Bus thread is not supplied, it calls 439 // AssertOnOriginThread(). 440 virtual void AssertOnDBusThread(); 441 442 // Returns true if the bus is connected to D-Bus. 443 bool is_connected() { return connection_ != NULL; } 444 445 protected: 446 // This is protected, so we can define sub classes. 447 virtual ~Bus(); 448 449 private: 450 friend class base::RefCountedThreadSafe<Bus>; 451 452 // Helper function used for UnregisterExportedObject(). 453 void UnregisterExportedObjectInternal( 454 scoped_refptr<dbus::ExportedObject> exported_object); 455 456 // Helper function used for ShutdownOnDBusThreadAndBlock(). 457 void ShutdownOnDBusThreadAndBlockInternal(); 458 459 // Helper function used for RequestOwnership(). 460 void RequestOwnershipInternal(const std::string& service_name, 461 OnOwnershipCallback on_ownership_callback); 462 463 // Called when the ownership request is completed. 464 void OnOwnership(OnOwnershipCallback on_ownership_callback, 465 const std::string& service_name, 466 bool success); 467 468 // Processes the all incoming data to the connection, if any. 469 // 470 // BLOCKING CALL. 471 void ProcessAllIncomingDataIfAny(); 472 473 // Called when a watch object is added. Used to start monitoring the 474 // file descriptor used for D-Bus communication. 475 dbus_bool_t OnAddWatch(DBusWatch* raw_watch); 476 477 // Called when a watch object is removed. 478 void OnRemoveWatch(DBusWatch* raw_watch); 479 480 // Called when the "enabled" status of |raw_watch| is toggled. 481 void OnToggleWatch(DBusWatch* raw_watch); 482 483 // Called when a timeout object is added. Used to start monitoring 484 // timeout for method calls. 485 dbus_bool_t OnAddTimeout(DBusTimeout* raw_timeout); 486 487 // Called when a timeout object is removed. 488 void OnRemoveTimeout(DBusTimeout* raw_timeout); 489 490 // Called when the "enabled" status of |raw_timeout| is toggled. 491 void OnToggleTimeout(DBusTimeout* raw_timeout); 492 493 // Called when the dispatch status (i.e. if any incoming data is 494 // available) is changed. 495 void OnDispatchStatusChanged(DBusConnection* connection, 496 DBusDispatchStatus status); 497 498 // Callback helper functions. Redirects to the corresponding member function. 499 static dbus_bool_t OnAddWatchThunk(DBusWatch* raw_watch, void* data); 500 static void OnRemoveWatchThunk(DBusWatch* raw_watch, void* data); 501 static void OnToggleWatchThunk(DBusWatch* raw_watch, void* data); 502 static dbus_bool_t OnAddTimeoutThunk(DBusTimeout* raw_timeout, void* data); 503 static void OnRemoveTimeoutThunk(DBusTimeout* raw_timeout, void* data); 504 static void OnToggleTimeoutThunk(DBusTimeout* raw_timeout, void* data); 505 static void OnDispatchStatusChangedThunk(DBusConnection* connection, 506 DBusDispatchStatus status, 507 void* data); 508 const BusType bus_type_; 509 const ConnectionType connection_type_; 510 scoped_refptr<base::MessageLoopProxy> dbus_thread_message_loop_proxy_; 511 base::WaitableEvent on_shutdown_; 512 DBusConnection* connection_; 513 514 scoped_refptr<base::MessageLoopProxy> origin_message_loop_proxy_; 515 base::PlatformThreadId origin_thread_id_; 516 517 std::set<std::string> owned_service_names_; 518 // The following sets are used to check if rules/object_paths/filters 519 // are properly cleaned up before destruction of the bus object. 520 std::set<std::string> match_rules_added_; 521 std::set<ObjectPath> registered_object_paths_; 522 std::set<std::pair<DBusHandleMessageFunction, void*> > 523 filter_functions_added_; 524 525 // ObjectProxyTable is used to hold the object proxies created by the 526 // bus object. Key is a pair; the first part is a concatenated string of 527 // service name + object path, like 528 // "org.chromium.TestService/org/chromium/TestObject". 529 // The second part is the ObjectProxy::Options for the proxy. 530 typedef std::map<std::pair<std::string, int>, 531 scoped_refptr<dbus::ObjectProxy> > ObjectProxyTable; 532 ObjectProxyTable object_proxy_table_; 533 534 // ExportedObjectTable is used to hold the exported objects created by 535 // the bus object. Key is a concatenated string of service name + 536 // object path, like "org.chromium.TestService/org/chromium/TestObject". 537 typedef std::map<const dbus::ObjectPath, 538 scoped_refptr<dbus::ExportedObject> > ExportedObjectTable; 539 ExportedObjectTable exported_object_table_; 540 541 bool async_operations_set_up_; 542 bool shutdown_completed_; 543 544 // Counters to make sure that OnAddWatch()/OnRemoveWatch() and 545 // OnAddTimeout()/OnRemoveTimeou() are balanced. 546 int num_pending_watches_; 547 int num_pending_timeouts_; 548 549 std::string address_; 550 551 DISALLOW_COPY_AND_ASSIGN(Bus); 552}; 553 554} // namespace dbus 555 556#endif // DBUS_BUS_H_ 557