From a4d8dee3905d784f40d8f480eaacae2655e68b47 Mon Sep 17 00:00:00 2001
From: Sonny Sasaka <sonnysasaka@chromium.org>
Date: Wed, 11 Jul 2018 20:55:58 -0700
Subject: [PATCH] dbus: Add TryRegisterFallback

The TryRegisterFallback works just like TryRegisterObjectPath,
with addition that the registered callbacks also apply to the specified
object path and its sub paths. This is useful to implement a "catch-all"
handler.

Currently this is needed by Bluetooth dispatcher which needs to catch
all method calls to all objects and forward them to another D-Bus
service.

Bug:862849
---
 dbus/bus.cc     | 27 +++++++++++++++++++++------
 dbus/bus.h      | 32 ++++++++++++++++++++++++++++++++
 dbus/mock_bus.h |  5 +++++
 3 files changed, 58 insertions(+), 6 deletions(-)

diff --git a/dbus/bus.cc b/dbus/bus.cc
index e62058e0dc34..29043609e760 100644
--- a/dbus/bus.cc
+++ b/dbus/bus.cc
@@ -722,6 +722,25 @@ bool Bus::TryRegisterObjectPath(const ObjectPath& object_path,
                                 const DBusObjectPathVTable* vtable,
                                 void* user_data,
                                 DBusError* error) {
+  return TryRegisterObjectPathInternal(
+      object_path, vtable, user_data, error,
+      dbus_connection_try_register_object_path);
+}
+
+bool Bus::TryRegisterFallback(const ObjectPath& object_path,
+                              const DBusObjectPathVTable* vtable,
+                              void* user_data,
+                              DBusError* error) {
+  return TryRegisterObjectPathInternal(object_path, vtable, user_data, error,
+                                       dbus_connection_try_register_fallback);
+}
+
+bool Bus::TryRegisterObjectPathInternal(
+    const ObjectPath& object_path,
+    const DBusObjectPathVTable* vtable,
+    void* user_data,
+    DBusError* error,
+    TryRegisterObjectPathFunction* register_function) {
   DCHECK(connection_);
   AssertOnDBusThread();
 
@@ -731,12 +750,8 @@ bool Bus::TryRegisterObjectPath(const ObjectPath& object_path,
     return false;
   }
 
-  const bool success = dbus_connection_try_register_object_path(
-      connection_,
-      object_path.value().c_str(),
-      vtable,
-      user_data,
-      error);
+  const bool success = register_function(
+      connection_, object_path.value().c_str(), vtable, user_data, error);
   if (success)
     registered_object_paths_.insert(object_path);
   return success;
diff --git a/dbus/bus.h b/dbus/bus.h
index c2c2685afdc4..704a4c3a0b54 100644
--- a/dbus/bus.h
+++ b/dbus/bus.h
@@ -520,6 +520,24 @@ class CHROME_DBUS_EXPORT Bus : public base::RefCountedThreadSafe<Bus> {
                                      void* user_data,
                                      DBusError* error);
 
+  // Tries to register the object path and its sub paths.
+  // Returns true on success.
+  // Returns false if the object path is already registered.
+  //
+  // |message_function| in |vtable| will be called every time when a new
+  // message sent to the object path (or hierarchically below) arrives.
+  //
+  // The same object path must not be added more than once.
+  //
+  // See also documentation of |dbus_connection_try_register_fallback| at
+  // http://dbus.freedesktop.org/doc/api/html/group__DBusConnection.html
+  //
+  // BLOCKING CALL.
+  virtual bool TryRegisterFallback(const ObjectPath& object_path,
+                                   const DBusObjectPathVTable* vtable,
+                                   void* user_data,
+                                   DBusError* error);
+
   // Unregister the object path.
   //
   // BLOCKING CALL.
@@ -590,8 +608,22 @@ class CHROME_DBUS_EXPORT Bus : public base::RefCountedThreadSafe<Bus> {
   virtual ~Bus();
 
  private:
+  using TryRegisterObjectPathFunction =
+      dbus_bool_t(DBusConnection* connection,
+                  const char* object_path,
+                  const DBusObjectPathVTable* vtable,
+                  void* user_data,
+                  DBusError* error);
+
   friend class base::RefCountedThreadSafe<Bus>;
 
+  bool TryRegisterObjectPathInternal(
+      const ObjectPath& object_path,
+      const DBusObjectPathVTable* vtable,
+      void* user_data,
+      DBusError* error,
+      TryRegisterObjectPathFunction* register_function);
+
   // Helper function used for RemoveObjectProxy().
   void RemoveObjectProxyInternal(scoped_refptr<dbus::ObjectProxy> object_proxy,
                                  const base::Closure& callback);
diff --git a/dbus/mock_bus.h b/dbus/mock_bus.h
index 216bc64bd068..6b3495db6014 100644
--- a/dbus/mock_bus.h
+++ b/dbus/mock_bus.h
@@ -62,6 +62,11 @@ class MockBus : public Bus {
                                            const DBusObjectPathVTable* vtable,
                                            void* user_data,
                                            DBusError* error));
+  MOCK_METHOD4(TryRegisterFallback,
+               bool(const ObjectPath& object_path,
+                    const DBusObjectPathVTable* vtable,
+                    void* user_data,
+                    DBusError* error));
   MOCK_METHOD1(UnregisterObjectPath, void(const ObjectPath& object_path));
   MOCK_METHOD0(GetDBusTaskRunner, base::TaskRunner*());
   MOCK_METHOD0(GetOriginTaskRunner, base::TaskRunner*());
-- 
2.18.0.203.gfac676dfb9-goog

