xref: /aosp_15_r20/external/libbrillo/brillo/glib/dbus.h (revision 1a96fba65179ea7d3f56207137718607415c5953)
1 // Copyright (c) 2009 The Chromium OS 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 LIBBRILLO_BRILLO_GLIB_DBUS_H_
6 #define LIBBRILLO_BRILLO_GLIB_DBUS_H_
7 
8 // IMPORTANT: Do not use this in new code. Instead, use libchrome's D-Bus
9 // bindings. See https://goo.gl/EH3MmR for more details.
10 
11 #include <dbus/dbus-glib.h>
12 #include <glib-object.h>
13 
14 #include <algorithm>
15 #include <string>
16 #include <utility>
17 
18 #include "base/logging.h"
19 #include <brillo/brillo_export.h>
20 #include <brillo/glib/object.h>
21 
22 struct DBusMessage;
23 struct DBusConnection;
24 
25 namespace brillo {
26 
27 namespace dbus {
28 
29 // \brief   BusConnection manages the ref-count for a ::DBusGConnection*.
30 //
31 // A BusConnection has reference semantics bound to a particular communication
32 // bus.
33 //
34 // \models Copyable, Assignable
35 // \related GetSystemBusConnection()
36 
37 class BRILLO_EXPORT BusConnection {
38  public:
39   typedef ::DBusGConnection* value_type;
40 
BusConnection(const BusConnection & x)41   BusConnection(const BusConnection& x) : object_(x.object_) {
42     if (object_)
43       ::dbus_g_connection_ref(object_);
44   }
45 
~BusConnection()46   ~BusConnection() {
47     if (object_)
48       ::dbus_g_connection_unref(object_);
49   }
50 
51   BusConnection& operator=(BusConnection x) {
52     swap(*this, x);
53     return *this;
54   }
55 
g_connection()56   const value_type& g_connection() const {
57     DCHECK(object_) << "referencing an empty connection";
58     return object_;
59   }
60 
61   operator bool() const { return object_; }
62 
HasConnection()63   bool HasConnection() const { return object_; }
64 
65  private:
66   friend void swap(BusConnection& x, BusConnection& y);
67 
68   friend class Proxy;
69   friend BusConnection GetSystemBusConnection();
70   friend BusConnection GetPrivateBusConnection(const char* address);
71 
72   // Constructor takes ownership
BusConnection(::DBusGConnection * x)73   BRILLO_PRIVATE explicit BusConnection(::DBusGConnection* x) : object_(x) {}
74 
75   value_type object_;
76 };
77 
swap(BusConnection & x,BusConnection & y)78 inline void swap(BusConnection& x, BusConnection& y) {
79   std::swap(x.object_, y.object_);
80 }
81 
82 // \brief Proxy manages the ref-count for a ::DBusGProxy*.
83 //
84 // Proxy has reference semantics and represents a connection to on object on
85 // the bus. A proxy object is constructed with a connection to a bus, a name
86 // to an entity on the bus, a path to an object owned by the entity, and an
87 // interface protocol name used to communicate with the object.
88 
89 class BRILLO_EXPORT Proxy {
90  public:
91   typedef ::DBusGProxy* value_type;
92 
93   Proxy();
94 
95   // Set |connect_to_name_owner| true if you'd like to use
96   // dbus_g_proxy_new_for_name_owner() rather than dbus_g_proxy_new_for_name().
97   Proxy(const BusConnection& connection,
98         const char* name,
99         const char* path,
100         const char* interface,
101         bool connect_to_name_owner);
102 
103   // Equivalent to Proxy(connection, name, path, interface, false).
104   Proxy(const BusConnection& connection,
105         const char* name,
106         const char* path,
107         const char* interface);
108 
109   // Creates a peer proxy using dbus_g_proxy_new_for_peer.
110   Proxy(const BusConnection& connection,
111         const char* path,
112         const char* interface);
113 
114   Proxy(const Proxy& x);
115 
116   ~Proxy();
117 
118   Proxy& operator=(Proxy x) {
119     swap(*this, x);
120     return *this;
121   }
122 
path()123   const char* path() const {
124     DCHECK(object_) << "referencing an empty proxy";
125     return ::dbus_g_proxy_get_path(object_);
126   }
127 
128   // gproxy() returns a reference to the underlying ::DBusGProxy*. As this
129   // library evolves, the gproxy() will be moved to be private.
130 
gproxy()131   const value_type& gproxy() const {
132     DCHECK(object_) << "referencing an empty proxy";
133     return object_;
134   }
135 
136   operator bool() const { return object_; }
137 
138  private:
139   BRILLO_PRIVATE static value_type GetGProxy(const BusConnection& connection,
140                                              const char* name,
141                                              const char* path,
142                                              const char* interface,
143                                              bool connect_to_name_owner);
144 
145   BRILLO_PRIVATE static value_type GetGPeerProxy(
146       const BusConnection& connection,
147       const char* path,
148       const char* interface);
149 
150   BRILLO_PRIVATE operator int() const;  // for safe bool cast
151   friend void swap(Proxy& x, Proxy& y);
152 
153   value_type object_;
154 };
155 
swap(Proxy & x,Proxy & y)156 inline void swap(Proxy& x, Proxy& y) {
157   std::swap(x.object_, y.object_);
158 }
159 
160 // \brief RegisterExclusiveService configures a GObject to run as a service on
161 //  a supplied ::BusConnection.
162 //
163 //  RegisterExclusiveService encapsulates the process of configuring the
164 //  supplied \param object at \param service_path on the \param connection.
165 //  Exclusivity is ensured by replacing any existing services at that named
166 //  location and confirming that the connection is the primary owner.
167 //
168 //  Type information for the \param object must be installed with
169 //  dbus_g_object_type_install_info prior to use.
170 
171 BRILLO_EXPORT bool RegisterExclusiveService(const BusConnection& connection,
172                                             const char* interface_name,
173                                             const char* service_name,
174                                             const char* service_path,
175                                             GObject* object);
176 
177 template<typename F>  // F is a function signature
178 class MonitorConnection;
179 
180 template<typename A1>
181 class MonitorConnection<void(A1)> {
182  public:
MonitorConnection(const Proxy & proxy,const char * name,void (* monitor)(void *,A1),void * object)183   MonitorConnection(const Proxy& proxy,
184                     const char* name,
185                     void (*monitor)(void*, A1),
186                     void* object)
187       : proxy_(proxy), name_(name), monitor_(monitor), object_(object) {}
188 
Run(::DBusGProxy *,A1 x,MonitorConnection * self)189   static void Run(::DBusGProxy*, A1 x, MonitorConnection* self) {
190     self->monitor_(self->object_, x);
191   }
proxy()192   const Proxy& proxy() const { return proxy_; }
name()193   const std::string& name() const { return name_; }
194 
195  private:
196   Proxy proxy_;
197   std::string name_;
198   void (*monitor_)(void*, A1);
199   void* object_;
200 };
201 
202 template<typename A1, typename A2>
203 class MonitorConnection<void(A1, A2)> {
204  public:
MonitorConnection(const Proxy & proxy,const char * name,void (* monitor)(void *,A1,A2),void * object)205   MonitorConnection(const Proxy& proxy,
206                     const char* name,
207                     void (*monitor)(void*, A1, A2),
208                     void* object)
209       : proxy_(proxy), name_(name), monitor_(monitor), object_(object) {}
210 
Run(::DBusGProxy *,A1 x,A2 y,MonitorConnection * self)211   static void Run(::DBusGProxy*, A1 x, A2 y, MonitorConnection* self) {
212     self->monitor_(self->object_, x, y);
213   }
proxy()214   const Proxy& proxy() const { return proxy_; }
name()215   const std::string& name() const { return name_; }
216 
217  private:
218   Proxy proxy_;
219   std::string name_;
220   void (*monitor_)(void*, A1, A2);
221   void* object_;
222 };
223 
224 template<typename A1, typename A2, typename A3>
225 class MonitorConnection<void(A1, A2, A3)> {
226  public:
MonitorConnection(const Proxy & proxy,const char * name,void (* monitor)(void *,A1,A2,A3),void * object)227   MonitorConnection(const Proxy& proxy,
228                     const char* name,
229                     void (*monitor)(void*, A1, A2, A3),
230                     void* object)
231       : proxy_(proxy), name_(name), monitor_(monitor), object_(object) {}
232 
Run(::DBusGProxy *,A1 x,A2 y,A3 z,MonitorConnection * self)233   static void Run(::DBusGProxy*, A1 x, A2 y, A3 z, MonitorConnection* self) {
234     self->monitor_(self->object_, x, y, z);
235   }
proxy()236   const Proxy& proxy() const { return proxy_; }
name()237   const std::string& name() const { return name_; }
238 
239  private:
240   Proxy proxy_;
241   std::string name_;
242   void (*monitor_)(void*, A1, A2, A3);
243   void* object_;
244 };
245 
246 template<typename A1, typename A2, typename A3, typename A4>
247 class MonitorConnection<void(A1, A2, A3, A4)> {
248  public:
MonitorConnection(const Proxy & proxy,const char * name,void (* monitor)(void *,A1,A2,A3,A4),void * object)249   MonitorConnection(const Proxy& proxy,
250                     const char* name,
251                     void (*monitor)(void*, A1, A2, A3, A4),
252                     void* object)
253       : proxy_(proxy), name_(name), monitor_(monitor), object_(object) {}
254 
Run(::DBusGProxy *,A1 x,A2 y,A3 z,A4 w,MonitorConnection * self)255   static void Run(::DBusGProxy*,
256                   A1 x,
257                   A2 y,
258                   A3 z,
259                   A4 w,
260                   MonitorConnection* self) {
261     self->monitor_(self->object_, x, y, z, w);
262   }
proxy()263   const Proxy& proxy() const { return proxy_; }
name()264   const std::string& name() const { return name_; }
265 
266  private:
267   Proxy proxy_;
268   std::string name_;
269   void (*monitor_)(void*, A1, A2, A3, A4);
270   void* object_;
271 };
272 
273 template<typename A1>
Monitor(const Proxy & proxy,const char * name,void (* monitor)(void *,A1),void * object)274 MonitorConnection<void(A1)>* Monitor(const Proxy& proxy,
275                                      const char* name,
276                                      void (*monitor)(void*, A1),
277                                      void* object) {
278   typedef MonitorConnection<void(A1)> ConnectionType;
279 
280   ConnectionType* result = new ConnectionType(proxy, name, monitor, object);
281 
282   ::dbus_g_proxy_add_signal(
283       proxy.gproxy(), name, glib::type_to_gtypeid<A1>(), G_TYPE_INVALID);
284   ::dbus_g_proxy_connect_signal(
285       proxy.gproxy(), name, G_CALLBACK(&ConnectionType::Run), result, nullptr);
286   return result;
287 }
288 
289 template<typename A1, typename A2>
Monitor(const Proxy & proxy,const char * name,void (* monitor)(void *,A1,A2),void * object)290 MonitorConnection<void(A1, A2)>* Monitor(const Proxy& proxy,
291                                          const char* name,
292                                          void (*monitor)(void*, A1, A2),
293                                          void* object) {
294   typedef MonitorConnection<void(A1, A2)> ConnectionType;
295 
296   ConnectionType* result = new ConnectionType(proxy, name, monitor, object);
297 
298   ::dbus_g_proxy_add_signal(proxy.gproxy(),
299                             name,
300                             glib::type_to_gtypeid<A1>(),
301                             glib::type_to_gtypeid<A2>(),
302                             G_TYPE_INVALID);
303   ::dbus_g_proxy_connect_signal(
304       proxy.gproxy(), name, G_CALLBACK(&ConnectionType::Run), result, nullptr);
305   return result;
306 }
307 
308 template<typename A1, typename A2, typename A3>
Monitor(const Proxy & proxy,const char * name,void (* monitor)(void *,A1,A2,A3),void * object)309 MonitorConnection<void(A1, A2, A3)>* Monitor(const Proxy& proxy,
310                                              const char* name,
311                                              void (*monitor)(void*, A1, A2, A3),
312                                              void* object) {
313   typedef MonitorConnection<void(A1, A2, A3)> ConnectionType;
314 
315   ConnectionType* result = new ConnectionType(proxy, name, monitor, object);
316 
317   ::dbus_g_proxy_add_signal(proxy.gproxy(),
318                             name,
319                             glib::type_to_gtypeid<A1>(),
320                             glib::type_to_gtypeid<A2>(),
321                             glib::type_to_gtypeid<A3>(),
322                             G_TYPE_INVALID);
323   ::dbus_g_proxy_connect_signal(
324       proxy.gproxy(), name, G_CALLBACK(&ConnectionType::Run), result, nullptr);
325   return result;
326 }
327 
328 template<typename A1, typename A2, typename A3, typename A4>
Monitor(const Proxy & proxy,const char * name,void (* monitor)(void *,A1,A2,A3,A4),void * object)329 MonitorConnection<void(A1, A2, A3, A4)>* Monitor(
330     const Proxy& proxy,
331     const char* name,
332     void (*monitor)(void*, A1, A2, A3, A4),
333     void* object) {
334   typedef MonitorConnection<void(A1, A2, A3, A4)> ConnectionType;
335 
336   ConnectionType* result = new ConnectionType(proxy, name, monitor, object);
337 
338   ::dbus_g_proxy_add_signal(proxy.gproxy(),
339                             name,
340                             glib::type_to_gtypeid<A1>(),
341                             glib::type_to_gtypeid<A2>(),
342                             glib::type_to_gtypeid<A3>(),
343                             glib::type_to_gtypeid<A4>(),
344                             G_TYPE_INVALID);
345   ::dbus_g_proxy_connect_signal(
346       proxy.gproxy(), name, G_CALLBACK(&ConnectionType::Run), result, nullptr);
347   return result;
348 }
349 
350 template<typename F>
Disconnect(MonitorConnection<F> * connection)351 void Disconnect(MonitorConnection<F>* connection) {
352   typedef MonitorConnection<F> ConnectionType;
353 
354   ::dbus_g_proxy_disconnect_signal(connection->proxy().gproxy(),
355                                    connection->name().c_str(),
356                                    G_CALLBACK(&ConnectionType::Run),
357                                    connection);
358   delete connection;
359 }
360 
361 // \brief call_PtrArray() invokes a method on a proxy returning a
362 //  glib::PtrArray.
363 //
364 // CallPtrArray is the first instance of what is likely to be a general
365 // way to make method calls to a proxy. It will likely be replaced with
366 // something like Call(proxy, method, arg1, arg2, ..., ResultType*) in the
367 // future. However, I don't yet have enough cases to generalize from.
368 
369 BRILLO_EXPORT bool CallPtrArray(const Proxy& proxy,
370                                   const char* method,
371                                   glib::ScopedPtrArray<const char*>* result);
372 
373 // \brief RetrieveProperty() retrieves a property of an object associated with a
374 //  proxy.
375 //
376 // Given a proxy to an object supporting the org.freedesktop.DBus.Properties
377 // interface, the RetrieveProperty() call will retrieve a property of the
378 // specified interface on the object storing it in \param result and returning
379 // \true. If the dbus call fails or the object returned is not of type \param T,
380 // then \false is returned and \param result is unchanged.
381 //
382 // \example
383 // Proxy proxy(GetSystemBusConnection(),
384 //             "org.freedesktop.DeviceKit.Power", // A named entity on the bus
385 //             battery_name,  // Path to a battery on the bus
386 //             "org.freedesktop.DBus.Properties") // Properties interface
387 //
388 // double x;
389 // if (RetrieveProperty(proxy,
390 //                      "org.freedesktop.DeviceKit.Power.Device",
391 //                      "percentage")
392 //   std::cout << "Battery charge is " << x << "% of capacity.";
393 // \end_example
394 
395 template<typename T>
RetrieveProperty(const Proxy & proxy,const char * interface,const char * property,T * result)396 inline bool RetrieveProperty(const Proxy& proxy,
397                              const char* interface,
398                              const char* property,
399                              T* result) {
400   glib::ScopedError error;
401   glib::Value value;
402 
403   if (!::dbus_g_proxy_call(proxy.gproxy(), "Get", &Resetter(&error).lvalue(),
404                            G_TYPE_STRING, interface,
405                            G_TYPE_STRING, property,
406                            G_TYPE_INVALID,
407                            G_TYPE_VALUE, &value,
408                            G_TYPE_INVALID)) {
409     LOG(ERROR) << "Getting property failed: "
410                << (error->message ? error->message : "Unknown Error.");
411     return false;
412   }
413   return glib::Retrieve(value, result);
414 }
415 
416 // \brief RetrieveProperties returns a HashTable of all properties for the
417 // specified interface.
418 
419 BRILLO_EXPORT bool RetrieveProperties(const Proxy& proxy,
420                                       const char* interface,
421                                       glib::ScopedHashTable* result);
422 
423 // \brief Returns a connection to the system bus.
424 
425 BRILLO_EXPORT BusConnection GetSystemBusConnection();
426 
427 // \brief Returns a private connection to a bus at |address|.
428 
429 BRILLO_EXPORT BusConnection GetPrivateBusConnection(const char* address);
430 
431 // \brief Calls a method |method_name| with no arguments per the given |path|
432 // and |interface_name|.  Ignores return value.
433 
434 BRILLO_EXPORT void CallMethodWithNoArguments(const char* service_name,
435                                              const char* path,
436                                              const char* interface_name,
437                                              const char* method_name);
438 
439 // \brief Low-level signal monitor base class.
440 //
441 // Used when there is no definite named signal sender (that Proxy
442 // could be used for).
443 
444 class BRILLO_EXPORT SignalWatcher {
445  public:
SignalWatcher()446   SignalWatcher() {}
447   ~SignalWatcher();
448   void StartMonitoring(const std::string& interface, const std::string& signal);
449 
450  private:
451   // Callback invoked on the given signal arrival.
452   virtual void OnSignal(DBusMessage* message) = 0;
453 
454   // Returns a string matching the D-Bus messages that we want to listen for.
455   BRILLO_PRIVATE std::string GetDBusMatchString() const;
456 
457   // A D-Bus message filter to receive signals.
458   BRILLO_PRIVATE static DBusHandlerResult FilterDBusMessage(
459       DBusConnection* dbus_conn,
460       DBusMessage* message,
461       void* data);
462   std::string interface_;
463   std::string signal_;
464 };
465 
466 }  // namespace dbus
467 }  // namespace brillo
468 
469 #endif  // LIBBRILLO_BRILLO_GLIB_DBUS_H_
470