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
|
// 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_
|