1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127
  128
  129
  130
  131
  132
  133
  134
  135
  136
  137
  138
  139
  140
  141
  142
  143
  144
  145
  146
  147
  148
  149
  150
  151
  152
  153
  154
  155
  156
  157
  158
  159
  160
  161
  162
  163
  164
  165
  166
  167
  168
  169
  170
  171
  172
  173
  174
  175
  176
  177
  178
  179
  180
  181
  182
  183
  184
  185
  186
  187
  188
  189
  190
  191
  192
  193
  194
  195
  196
  197
  198
  199
  200
  201
  202
  203
  204
  205
  206
  207
  208
  209
  210
  211
  212
  213
  214

dbus / exported_object.h [blame]

// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef DBUS_EXPORTED_OBJECT_H_
#define DBUS_EXPORTED_OBJECT_H_

#include <dbus/dbus.h>

#include <map>
#include <memory>
#include <string>
#include <utility>

#include "base/functional/callback.h"
#include "base/memory/ref_counted.h"
#include "base/synchronization/waitable_event.h"
#include "base/threading/platform_thread.h"
#include "dbus/dbus_export.h"
#include "dbus/object_path.h"

namespace dbus {

class Bus;
class MethodCall;
class Response;
class Signal;

// ExportedObject is used to export objects and methods to other D-Bus
// clients.
//
// ExportedObject is a ref counted object, to ensure that |this| of the
// object is alive when callbacks referencing |this| are called.
class CHROME_DBUS_EXPORT ExportedObject
    : public base::RefCountedThreadSafe<ExportedObject> {
 public:
  // Client code should use Bus::GetExportedObject() instead of this
  // constructor.
  ExportedObject(Bus* bus, const ObjectPath& object_path);

  // Called to send a response from an exported method. |response| is the
  // response message. Callers should pass nullptr in the event of an error that
  // prevents the sending of a response.
  using ResponseSender =
      base::OnceCallback<void(std::unique_ptr<Response> response)>;

  // Called when an exported method is called. |method_call| is the request
  // message. |sender| is the callback that's used to send a response.
  //
  // |method_call| is owned by ExportedObject, hence client code should not
  // delete |method_call|.
  using MethodCallCallback =
      base::RepeatingCallback<void(MethodCall* method_call,
                                   ResponseSender sender)>;

  // Called when method exporting is done.
  // |success| indicates whether exporting was successful or not.
  using OnExportedCallback =
      base::OnceCallback<void(const std::string& interface_name,
                              const std::string& method_name,
                              bool success)>;

  // Called when method unexporting is done.
  // |success| indicates whether unexporting was successful or not.
  using OnUnexportedCallback =
      base::OnceCallback<void(const std::string& interface_name,
                              const std::string& method_name,
                              bool success)>;

  // Exports the method specified by |interface_name| and |method_name|,
  // and blocks until exporting is done. Returns true on success.
  //
  // |method_call_callback| will be called in the origin thread, when the
  // exported method is called. As it's called in the origin thread,
  // |method_callback| can safely reference objects in the origin thread
  // (i.e. UI thread in most cases).
  //
  // IMPORTANT NOTE: You should export all methods before requesting a
  // service name by Bus::RequestOwnership/AndBlock(). If you do it in the
  // wrong order (i.e. request a service name then export methods), there
  // will be a short time period where your service is unable to respond to
  // method calls because these methods aren't yet exposed. This race is a
  // real problem as clients may start calling methods of your service as
  // soon as you acquire a service name, by watching the name owner change.
  //
  // BLOCKING CALL.
  virtual bool ExportMethodAndBlock(
      const std::string& interface_name,
      const std::string& method_name,
      const MethodCallCallback& method_call_callback);

  // Unexports the method specified by |interface_name| and |method_name|,
  // and blocks until unexporting is done. Returns true on success.
  virtual bool UnexportMethodAndBlock(const std::string& interface_name,
                                      const std::string& method_name);

  // Requests to export the method specified by |interface_name| and
  // |method_name|. See Also ExportMethodAndBlock().
  //
  // |on_exported_callback| is called when the method is exported or
  // failed to be exported, in the origin thread.
  //
  // Must be called in the origin thread.
  virtual void ExportMethod(const std::string& interface_name,
                            const std::string& method_name,
                            const MethodCallCallback& method_call_callback,
                            OnExportedCallback on_exported_callback);

  // Requests to unexport the method specified by |interface_name| and
  // |method_name|. See also UnexportMethodAndBlock().
  //
  // |on_unexported_callback| is called when the method is unexported or
  // failed to be unexported, in the origin thread.
  //
  // Must be called in the origin thread.
  virtual void UnexportMethod(const std::string& interface_name,
                              const std::string& method_name,
                              OnUnexportedCallback on_unexported_callback);

  // Requests to send the signal from this object. The signal will be sent
  // synchronously if this method is called from the message loop in the D-Bus
  // thread and asynchronously otherwise.
  virtual void SendSignal(Signal* signal);

  // Unregisters the object from the bus. The Bus object will take care of
  // unregistering so you don't have to do this manually.
  //
  // BLOCKING CALL.
  virtual void Unregister();

 protected:
  // This is protected, so we can define sub classes.
  virtual ~ExportedObject();

 private:
  friend class base::RefCountedThreadSafe<ExportedObject>;

  // Helper function for ExportMethod().
  void ExportMethodInternal(const std::string& interface_name,
                            const std::string& method_name,
                            const MethodCallCallback& method_call_callback,
                            OnExportedCallback exported_callback);

  // Helper function for UnexportMethod().
  void UnexportMethodInternal(const std::string& interface_name,
                              const std::string& method_name,
                              OnUnexportedCallback unexported_callback);

  // Called when the object is exported.
  void OnExported(OnExportedCallback on_exported_callback,
                  const std::string& interface_name,
                  const std::string& method_name,
                  bool success);

  // Called when a method is unexported.
  void OnUnexported(OnExportedCallback on_unexported_callback,
                    const std::string& interface_name,
                    const std::string& method_name,
                    bool success);

  // Helper function for SendSignal().
  void SendSignalInternal(DBusMessage* signal_message);

  // Registers this object to the bus.
  // Returns true on success, or the object is already registered.
  //
  // BLOCKING CALL.
  bool Register();

  // Handles the incoming request messages and dispatches to the exported
  // methods.
  DBusHandlerResult HandleMessage(DBusConnection* connection,
                                  DBusMessage* raw_message);

  // Runs the method. Helper function for HandleMessage().
  void RunMethod(const MethodCallCallback& method_call_callback,
                 std::unique_ptr<MethodCall> method_call);

  // Callback invoked by service provider to send a response to a method call.
  // Can be called immediately from a MethodCallCallback to implement a
  // synchronous service or called later to implement an asynchronous service.
  void SendResponse(std::unique_ptr<MethodCall> method_call,
                    std::unique_ptr<Response> response);

  // Called on completion of the method run from SendResponse().
  // Takes ownership of |method_call| and |response|.
  void OnMethodCompleted(std::unique_ptr<MethodCall> method_call,
                         std::unique_ptr<Response> response);

  // Called when the object is unregistered.
  void OnUnregistered(DBusConnection* connection);

  // Redirects the function call to HandleMessage().
  static DBusHandlerResult HandleMessageThunk(DBusConnection* connection,
                                              DBusMessage* raw_message,
                                              void* user_data);

  // Redirects the function call to OnUnregistered().
  static void OnUnregisteredThunk(DBusConnection* connection,
                                  void* user_data);

  scoped_refptr<Bus> bus_;
  ObjectPath object_path_;
  bool object_is_registered_;

  // The method table where keys are absolute method names (i.e. interface
  // name + method name), and values are the corresponding callbacks.
  typedef std::map<std::string, MethodCallCallback> MethodTable;
  MethodTable method_table_;
};

}  // namespace dbus

#endif  // DBUS_EXPORTED_OBJECT_H_