chromeos-dbus-bindings: Use object path and service name in generated code

To eliminate unnecessary dependencies on string constants from D-Bus
service providers, allow generated proxies extract fixed object paths
from the 'name' attribute of <node> in the XML file (if available) and
be able to pass in additional the D-Bus service configuration parameters
(such as D-Bus service name) as input to the generator, so that the proxy
code knows these values too and the caller doesn't have to provide this
information.

With these changes the object path and/or service names become embedded
into the generated proxies and are no longer required to be provided as
parameters to the constructors. If there are multiple instances of D-Bus
objects with the same interface are available (or the object could
appear at different bus paths), the path cannot be embedded into
the proxy and must still be provided in the constructor of the generated
class.

The service config can now be provided in --service-config=... argument
to the generator which is expected to be a JSON file.
If the service name it is not specified, the generated proxy code will
require this parameter in the constructor call, as before.

Also updated other targets that use the proxy generator to follow the
new constructor syntax (buffet, peerd, privetd).

BUG=chromium:431737
TEST=FEATURES=test emerge-link chromeos-dbus-bindings peerd buffet privetd

Change-Id: I4bb8387a9b21b75e3508fa13d14b79fbe653c929
Reviewed-on: https://chromium-review.googlesource.com/231920
Reviewed-by: Christopher Wiley <wiley@chromium.org>
Reviewed-by: Vitaly Buka <vitalybuka@chromium.org>
Commit-Queue: Alex Vakulenko <avakulenko@chromium.org>
Tested-by: Alex Vakulenko <avakulenko@chromium.org>
diff --git a/chromeos-dbus-bindings/proxy_generator_unittest.cc b/chromeos-dbus-bindings/proxy_generator_unittest.cc
index 0b35fc8..e4f596e 100644
--- a/chromeos-dbus-bindings/proxy_generator_unittest.cc
+++ b/chromeos-dbus-bindings/proxy_generator_unittest.cc
@@ -79,21 +79,18 @@
 
   TestInterfaceProxy(
       const scoped_refptr<dbus::Bus>& bus,
-      const std::string& service_name,
-      const std::string& object_path)
-      : bus_(bus),
-        service_name_(service_name),
-        object_path_(object_path),
-        dbus_object_proxy_(
-            bus_->GetObjectProxy(service_name_, object_path_)) {
+      const std::string& service_name) :
+          bus_(bus),
+          service_name_(service_name),
+          dbus_object_proxy_(
+              bus_->GetObjectProxy(service_name_, object_path_)) {
   }
 
   TestInterfaceProxy(
       const scoped_refptr<dbus::Bus>& bus,
       const std::string& service_name,
-      const std::string& object_path,
-      SignalReceiver* signal_receiver)
-      : TestInterfaceProxy(bus, service_name, object_path) {
+      SignalReceiver* signal_receiver) :
+          TestInterfaceProxy(bus, service_name) {
     chromeos::dbus_utils::ConnectToSignal(
         dbus_object_proxy_,
         "org.chromium.TestInterface",
@@ -192,7 +189,7 @@
  private:
   scoped_refptr<dbus::Bus> bus_;
   std::string service_name_;
-  dbus::ObjectPath object_path_;
+  const dbus::ObjectPath object_path_{"/org/chromium/Test"};
   dbus::ObjectProxy* dbus_object_proxy_;
 
   DISALLOW_COPY_AND_ASSIGN(TestInterfaceProxy);
@@ -210,12 +207,12 @@
   TestInterface2Proxy(
       const scoped_refptr<dbus::Bus>& bus,
       const std::string& service_name,
-      const std::string& object_path)
-      : bus_(bus),
-        service_name_(service_name),
-        object_path_(object_path),
-        dbus_object_proxy_(
-            bus_->GetObjectProxy(service_name_, object_path_)) {
+      const std::string& object_path) :
+          bus_(bus),
+          service_name_(service_name),
+          object_path_(object_path),
+          dbus_object_proxy_(
+              bus_->GetObjectProxy(service_name_, object_path_)) {
   }
 
   ~TestInterface2Proxy() {
@@ -252,6 +249,125 @@
 
 )literal_string";
 
+const char kExpectedContentWithService[] = R"literal_string(
+#include <string>
+#include <vector>
+
+#include <base/bind.h>
+#include <base/callback.h>
+#include <base/logging.h>
+#include <base/macros.h>
+#include <base/memory/ref_counted.h>
+#include <chromeos/any.h>
+#include <chromeos/dbus/dbus_method_invoker.h>
+#include <chromeos/dbus/dbus_signal_handler.h>
+#include <chromeos/errors/error.h>
+#include <chromeos/variant_dictionary.h>
+#include <dbus/bus.h>
+#include <dbus/message.h>
+#include <dbus/object_path.h>
+#include <dbus/object_proxy.h>
+
+namespace org {
+namespace chromium {
+
+// Interface proxy for org::chromium::TestInterface.
+class TestInterfaceProxy final {
+ public:
+  class SignalReceiver {
+   public:
+    virtual void OnCloserSignal() {}
+  };
+
+  TestInterfaceProxy(const scoped_refptr<dbus::Bus>& bus) :
+      bus_(bus),
+      dbus_object_proxy_(
+          bus_->GetObjectProxy(service_name_, object_path_)) {
+  }
+
+  TestInterfaceProxy(
+      const scoped_refptr<dbus::Bus>& bus,
+      SignalReceiver* signal_receiver) :
+          TestInterfaceProxy(bus) {
+    chromeos::dbus_utils::ConnectToSignal(
+        dbus_object_proxy_,
+        "org.chromium.TestInterface",
+        "Closer",
+        base::Bind(
+            &SignalReceiver::OnCloserSignal,
+            base::Unretained(signal_receiver)),
+        base::Bind(
+            &TestInterfaceProxy::OnDBusSignalConnected,
+            base::Unretained(this)));
+  }
+
+  ~TestInterfaceProxy() {
+  }
+
+  void ReleaseObjectProxy(const base::Closure& callback) {
+    bus_->RemoveObjectProxy(service_name_, object_path_, callback);
+  }
+
+  void OnDBusSignalConnected(
+      const std::string& interface,
+      const std::string& signal,
+      bool success) {
+    if (!success) {
+      LOG(ERROR)
+          << "Failed to connect to " << interface << "." << signal
+          << " for " << service_name_ << " at "
+          << object_path_.value();
+    }
+  }
+
+ private:
+  scoped_refptr<dbus::Bus> bus_;
+  const std::string service_name_{"org.chromium.Test"};
+  const dbus::ObjectPath object_path_{"/org/chromium/Test"};
+  dbus::ObjectProxy* dbus_object_proxy_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestInterfaceProxy);
+};
+
+}  // namespace chromium
+}  // namespace org
+
+namespace org {
+namespace chromium {
+
+// Interface proxy for org::chromium::TestInterface2.
+class TestInterface2Proxy final {
+ public:
+  TestInterface2Proxy(
+      const scoped_refptr<dbus::Bus>& bus,
+      const std::string& object_path) :
+          bus_(bus),
+          object_path_(object_path),
+          dbus_object_proxy_(
+              bus_->GetObjectProxy(service_name_, object_path_)) {
+  }
+
+  ~TestInterface2Proxy() {
+  }
+
+  void ReleaseObjectProxy(const base::Closure& callback) {
+    bus_->RemoveObjectProxy(service_name_, object_path_, callback);
+  }
+
+ private:
+  scoped_refptr<dbus::Bus> bus_;
+  const std::string service_name_{"org.chromium.Test"};
+  dbus::ObjectPath object_path_;
+  dbus::ObjectProxy* dbus_object_proxy_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestInterface2Proxy);
+};
+
+}  // namespace chromium
+}  // namespace org
+
+)literal_string";
+
 }  // namespace
 
 class ProxyGeneratorTest : public Test {
@@ -275,6 +391,7 @@
 TEST_F(ProxyGeneratorTest, GenerateAdaptors) {
   Interface interface;
   interface.name = kInterfaceName;
+  interface.path = "/org/chromium/Test";
   interface.methods.emplace_back(
       kMethod1Name,
       vector<Interface::Argument>{
@@ -296,7 +413,7 @@
       vector<Interface::Argument>{
           {"", kSignal2Argument1},
           {"", kSignal2Argument2}});
-  interface.methods.back().doc_string_ = "Comment line1\nline2";
+  interface.methods.back().doc_string = "Comment line1\nline2";
   Interface interface2;
   interface2.name = kInterfaceName2;
   interface2.methods.emplace_back(
@@ -307,7 +424,8 @@
           {kMethod5ArgumentName2, kMethod5Argument2}});
   vector<Interface> interfaces{interface, interface2};
   base::FilePath output_path = temp_dir_.path().Append("output.h");
-  EXPECT_TRUE(ProxyGenerator::GenerateProxies(interfaces, output_path));
+  ServiceConfig config;
+  EXPECT_TRUE(ProxyGenerator::GenerateProxies(config, interfaces, output_path));
   string contents;
   EXPECT_TRUE(base::ReadFileToString(output_path, &contents));
   // The header guards contain the (temporary) filename, so we search for
@@ -317,4 +435,25 @@
       << kExpectedContent << "...within content...\n" << contents;
 }
 
+TEST_F(ProxyGeneratorTest, GenerateAdaptorsWithServiceName) {
+  Interface interface;
+  interface.name = kInterfaceName;
+  interface.path = "/org/chromium/Test";
+  interface.signals.emplace_back(kSignal1Name);
+  Interface interface2;
+  interface2.name = kInterfaceName2;
+  vector<Interface> interfaces{interface, interface2};
+  base::FilePath output_path = temp_dir_.path().Append("output2.h");
+  ServiceConfig config;
+  config.service_name = "org.chromium.Test";
+  EXPECT_TRUE(ProxyGenerator::GenerateProxies(config, interfaces, output_path));
+  string contents;
+  EXPECT_TRUE(base::ReadFileToString(output_path, &contents));
+  // The header guards contain the (temporary) filename, so we search for
+  // the content we need within the string.
+  EXPECT_NE(string::npos, contents.find(kExpectedContentWithService))
+      << "Expected to find the following content...\n"
+      << kExpectedContentWithService << "...within content...\n" << contents;
+}
+
 }  // namespace chromeos_dbus_bindings