Project import
diff --git a/dbus-binding-generator/Android.mk b/dbus-binding-generator/Android.mk
new file mode 100644
index 0000000..544d8da
--- /dev/null
+++ b/dbus-binding-generator/Android.mk
@@ -0,0 +1,73 @@
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH := $(call my-dir)
+
+libdbusBindingGenCFlags := -Wall -Werror
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := libdbus-binding-gen-host
+LOCAL_CFLAGS := $(libdbusBindingGenCFlags)
+LOCAL_CPP_EXTENSION := .cc
+# Hack these includes, because we're not actually linking the libraries.
+LOCAL_C_INCLUDES := \
+    $(LOCAL_PATH) \
+    $(TOP)/external/dbus \
+    $(TOP)/external/gtest/include
+LOCAL_SHARED_LIBRARIES := libbrillo libchrome
+LOCAL_STATIC_LIBRARIES := libexpat
+LOCAL_SRC_FILES := \
+    chromeos-dbus-bindings/adaptor_generator.cc \
+    chromeos-dbus-bindings/dbus_signature.cc \
+    chromeos-dbus-bindings/header_generator.cc \
+    chromeos-dbus-bindings/indented_text.cc \
+    chromeos-dbus-bindings/method_name_generator.cc \
+    chromeos-dbus-bindings/name_parser.cc \
+    chromeos-dbus-bindings/proxy_generator.cc \
+    chromeos-dbus-bindings/xml_interface_parser.cc
+include $(BUILD_HOST_STATIC_LIBRARY)
+
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := dbus-binding-generator
+LOCAL_CFLAGS := $(libdbusBindingGenCFlags)
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_C_INCLUDES := $(LOCAL_PATH) $(TOP)/external/gtest/include
+LOCAL_SHARED_LIBRARIES := libbrillo libchrome
+LOCAL_SRC_FILES := chromeos-dbus-bindings/generate_chromeos_dbus_bindings.cc
+LOCAL_STATIC_LIBRARIES := libdbus-binding-gen-host libexpat
+include $(BUILD_HOST_EXECUTABLE)
+
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := dbus-binding-generator-tests
+LOCAL_CFLAGS := $(libdbusBindingGenCFlags)
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_C_INCLUDES := \
+    $(LOCAL_PATH) \
+    $(TOP)/external/dbus
+LOCAL_SHARED_LIBRARIES := libbrillo libchrome
+LOCAL_STATIC_LIBRARIES := libdbus-binding-gen-host libgmock_host libexpat
+LOCAL_SRC_FILES := \
+    chromeos-dbus-bindings/adaptor_generator_unittest.cc \
+    chromeos-dbus-bindings/dbus_signature_unittest.cc \
+    chromeos-dbus-bindings/indented_text_unittest.cc \
+    chromeos-dbus-bindings/method_name_generator_unittest.cc \
+    chromeos-dbus-bindings/name_parser_unittest.cc \
+    chromeos-dbus-bindings/proxy_generator_mock_unittest.cc \
+    chromeos-dbus-bindings/proxy_generator_unittest.cc \
+    chromeos-dbus-bindings/test_utils.cc \
+    chromeos-dbus-bindings/testrunner.cc \
+    chromeos-dbus-bindings/xml_interface_parser_unittest.cc
+include $(BUILD_HOST_NATIVE_TEST)
diff --git a/dbus-binding-generator/MODULE_LICENSE_BSD b/dbus-binding-generator/MODULE_LICENSE_BSD
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/dbus-binding-generator/MODULE_LICENSE_BSD
diff --git a/dbus-binding-generator/NOTICE b/dbus-binding-generator/NOTICE
new file mode 100644
index 0000000..b9e779f
--- /dev/null
+++ b/dbus-binding-generator/NOTICE
@@ -0,0 +1,27 @@
+// Copyright 2014 The Chromium OS Authors. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//    * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//    * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//    * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/dbus-binding-generator/chromeos-dbus-bindings/adaptor_generator.cc b/dbus-binding-generator/chromeos-dbus-bindings/adaptor_generator.cc
new file mode 100644
index 0000000..1916534
--- /dev/null
+++ b/dbus-binding-generator/chromeos-dbus-bindings/adaptor_generator.cc
@@ -0,0 +1,509 @@
+// Copyright 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chromeos-dbus-bindings/adaptor_generator.h"
+
+#include <string>
+
+#include <base/logging.h>
+#include <base/strings/string_util.h>
+#include <base/strings/stringprintf.h>
+#include <brillo/strings/string_utils.h>
+
+#include "chromeos-dbus-bindings/dbus_signature.h"
+#include "chromeos-dbus-bindings/indented_text.h"
+#include "chromeos-dbus-bindings/interface.h"
+#include "chromeos-dbus-bindings/name_parser.h"
+
+using base::StringPrintf;
+using std::string;
+using std::vector;
+
+namespace chromeos_dbus_bindings {
+
+// static
+bool AdaptorGenerator::GenerateAdaptors(
+    const std::vector<Interface>& interfaces,
+    const base::FilePath& output_file) {
+  IndentedText text;
+  CHECK(!interfaces.empty()) << "At least one interface must be provided";
+
+  text.AddLine("// Automatic generation of D-Bus interfaces:");
+  for (const auto& interface : interfaces) {
+    text.AddLine(StringPrintf("//  - %s", interface.name.c_str()));
+  }
+  string header_guard = GenerateHeaderGuard(output_file);
+  text.AddLine(StringPrintf("#ifndef %s", header_guard.c_str()));
+  text.AddLine(StringPrintf("#define %s", header_guard.c_str()));
+  text.AddLine("#include <memory>");
+  text.AddLine("#include <string>");
+  text.AddLine("#include <tuple>");
+  text.AddLine("#include <vector>");
+  text.AddBlankLine();
+  text.AddLine("#include <base/macros.h>");
+  text.AddLine("#include <dbus/object_path.h>");
+  text.AddLine("#include <brillo/any.h>");
+  text.AddLine("#include <brillo/dbus/dbus_object.h>");
+  text.AddLine("#include <brillo/dbus/exported_object_manager.h>");
+  text.AddLine("#include <brillo/variant_dictionary.h>");
+
+  for (const auto& interface : interfaces)
+    GenerateInterfaceAdaptor(interface, &text);
+
+  text.AddLine(StringPrintf("#endif  // %s", header_guard.c_str()));
+
+  return WriteTextToFile(output_file, text);
+}
+
+// static
+void AdaptorGenerator::GenerateInterfaceAdaptor(
+    const Interface& interface,
+    IndentedText *text) {
+  NameParser parser{interface.name};
+  string itf_name = parser.MakeInterfaceName(false);
+  string class_name = parser.MakeAdaptorName(false);
+  string full_itf_name = parser.MakeFullCppName();
+
+  text->AddBlankLine();
+  parser.AddOpenNamespaces(text, false);
+
+  text->AddBlankLine();
+  text->AddLine(StringPrintf("// Interface definition for %s.",
+                             full_itf_name.c_str()));
+  text->AddComments(interface.doc_string);
+  text->AddLine(StringPrintf("class %s {", itf_name.c_str()));
+  text->AddLineWithOffset("public:", kScopeOffset);
+  text->PushOffset(kBlockOffset);
+  text->AddLine(StringPrintf("virtual ~%s() = default;", itf_name.c_str()));
+  AddInterfaceMethods(interface, text);
+  text->PopOffset();
+  text->AddLine("};");
+
+  text->AddBlankLine();
+  text->AddLine(StringPrintf("// Interface adaptor for %s.",
+                             full_itf_name.c_str()));
+  text->AddLine(StringPrintf("class %s {", class_name.c_str()));
+  text->AddLineWithOffset("public:", kScopeOffset);
+  text->PushOffset(kBlockOffset);
+  AddConstructor(interface, class_name, itf_name, text);
+  AddRegisterWithDBusObject(itf_name, interface, text);
+  AddSendSignalMethods(interface, text);
+  AddPropertyMethodImplementation(interface, text);
+  if (!interface.path.empty()) {
+    text->AddBlankLine();
+    text->AddLine("static dbus::ObjectPath GetObjectPath() {");
+    text->PushOffset(kBlockOffset);
+    text->AddLine(StringPrintf("return dbus::ObjectPath{\"%s\"};",
+                               interface.path.c_str()));
+    text->PopOffset();
+    text->AddLine("}");
+  }
+  text->PopOffset();
+
+  text->AddBlankLine();
+  text->AddLineWithOffset("private:", kScopeOffset);
+  text->PushOffset(kBlockOffset);
+  AddSignalDataMembers(interface, text);
+  AddPropertyDataMembers(interface, text);
+
+  if (!interface.methods.empty()) {
+    text->AddLine(StringPrintf(
+        "%s* interface_;  // Owned by container of this adapter.",
+        itf_name.c_str()));
+  }
+
+  text->AddBlankLine();
+  text->AddLine(StringPrintf("DISALLOW_COPY_AND_ASSIGN(%s);",
+                             class_name.c_str()));
+  text->PopOffset();
+  text->AddLine("};");
+
+  text->AddBlankLine();
+  parser.AddCloseNamespaces(text, false);
+}
+
+// static
+void AdaptorGenerator::AddConstructor(const Interface& interface,
+                                      const string& class_name,
+                                      const string& itf_name,
+                                      IndentedText *text) {
+  if (interface.methods.empty()) {
+    text->AddLine(StringPrintf("%s(%s* /* interface */) {}",
+                               class_name.c_str(), itf_name.c_str()));
+
+  } else {
+    text->AddLine(StringPrintf("%s(%s* interface) : interface_(interface) {}",
+                               class_name.c_str(), itf_name.c_str()));
+  }
+}
+
+// static
+void AdaptorGenerator::AddRegisterWithDBusObject(
+    const std::string& itf_name,
+    const Interface& interface,
+    IndentedText *text) {
+  text->AddBlankLine();
+  text->AddLine(
+    "void RegisterWithDBusObject(brillo::dbus_utils::DBusObject* object) {");
+  text->PushOffset(kBlockOffset);
+  text->AddLine("brillo::dbus_utils::DBusInterface* itf =");
+  text->AddLineWithOffset(
+      StringPrintf("object->AddOrGetInterface(\"%s\");",
+                   interface.name.c_str()), kLineContinuationOffset);
+  RegisterInterface(itf_name, interface, text);
+  text->PopOffset();
+  text->AddLine("}");
+}
+
+// static
+void AdaptorGenerator::RegisterInterface(const string& itf_name,
+                                         const Interface& interface,
+                                         IndentedText *text) {
+  if (!interface.methods.empty())
+    text->AddBlankLine();
+  for (const auto& method : interface.methods) {
+    string add_handler_name;
+    switch (method.kind) {
+      case Interface::Method::Kind::kSimple:
+        add_handler_name = "AddSimpleMethodHandler";
+        break;
+      case Interface::Method::Kind::kNormal:
+        if (method.include_dbus_message)
+          add_handler_name = "AddSimpleMethodHandlerWithErrorAndMessage";
+        else
+          add_handler_name = "AddSimpleMethodHandlerWithError";
+        break;
+      case Interface::Method::Kind::kAsync:
+        if (method.include_dbus_message)
+          add_handler_name = "AddMethodHandlerWithMessage";
+        else
+          add_handler_name = "AddMethodHandler";
+        break;
+      case Interface::Method::Kind::kRaw:
+        add_handler_name = "AddRawMethodHandler";
+        break;
+    }
+
+    text->AddLine(StringPrintf("itf->%s(", add_handler_name.c_str()));
+    text->PushOffset(kLineContinuationOffset);
+    text->AddLine(StringPrintf("\"%s\",", method.name.c_str()));
+    text->AddLine("base::Unretained(interface_),");
+    text->AddLine(StringPrintf("&%s::%s);", itf_name.c_str(),
+                               method.name.c_str()));
+    text->PopOffset();
+  }
+
+  // Register signals.
+  if (!interface.signals.empty())
+    text->AddBlankLine();
+  for (const auto& signal : interface.signals) {
+    string signal_var_name = StringPrintf("signal_%s_", signal.name.c_str());
+    string signal_type_name = StringPrintf("Signal%sType", signal.name.c_str());
+    text->AddLine(StringPrintf("%s = itf->RegisterSignalOfType<%s>(\"%s\");",
+                               signal_var_name.c_str(),
+                               signal_type_name.c_str(),
+                               signal.name.c_str()));
+  }
+
+  // Register exported properties.
+  if (!interface.properties.empty())
+    text->AddBlankLine();
+  for (const auto& property : interface.properties) {
+    string variable_name = NameParser{property.name}.MakeVariableName();
+    string write_access;
+    if (property.access == "write") {
+      write_access = "kWriteOnly";
+    } else if (property.access == "readwrite") {
+      write_access = "kReadWrite";
+    }
+    if (!write_access.empty()) {
+      text->AddLine(StringPrintf("%s_.SetAccessMode(", variable_name.c_str()));
+      text->PushOffset(kLineContinuationOffset);
+      text->AddLine(
+          StringPrintf(
+              "brillo::dbus_utils::ExportedPropertyBase::Access::%s);",
+              write_access.c_str()));
+      text->PopOffset();
+      text->AddLine(StringPrintf("%s_.SetValidator(", variable_name.c_str()));
+      text->PushOffset(kLineContinuationOffset);
+      text->AddLineAndPushOffsetTo(
+          StringPrintf(
+              "base::Bind(&%s::Validate%s,",
+              NameParser{interface.name}.MakeAdaptorName(false).c_str(),
+              property.name.c_str()),
+          1, '(');
+      text->AddLine("base::Unretained(this)));");
+      text->PopOffset();
+      text->PopOffset();
+    }
+    text->AddLine(StringPrintf("itf->AddProperty(%sName(), &%s_);",
+                               property.name.c_str(), variable_name.c_str()));
+  }
+}
+
+// static
+void AdaptorGenerator::AddInterfaceMethods(const Interface& interface,
+                                           IndentedText *text) {
+  IndentedText block;
+  DbusSignature signature;
+  if (!interface.methods.empty())
+    block.AddBlankLine();
+
+  for (const auto& method : interface.methods) {
+    string const_method;
+    if (method.is_const)
+      const_method = " const";
+
+    string return_type = "void";
+    vector<string> method_params;
+    auto input_arguments_copy = method.input_arguments;
+    auto output_arguments_copy = method.output_arguments;
+    switch (method.kind) {
+      case Interface::Method::Kind::kSimple:
+        if (output_arguments_copy.size() == 1) {
+          CHECK(signature.Parse(output_arguments_copy[0].type, &return_type));
+          output_arguments_copy.clear();
+        }
+        break;
+      case Interface::Method::Kind::kNormal:
+        method_params.push_back("brillo::ErrorPtr* error");
+        if (method.include_dbus_message)
+          method_params.push_back("dbus::Message* message");
+        return_type = "bool";
+        break;
+      case Interface::Method::Kind::kAsync: {
+        std::vector<std::string> out_types;
+        for (const auto& argument : output_arguments_copy) {
+          string param_type;
+          CHECK(signature.Parse(argument.type, &param_type));
+          out_types.push_back(param_type);
+        }
+        method_params.push_back(base::StringPrintf(
+            "std::unique_ptr<brillo::dbus_utils::DBusMethodResponse<%s>> "
+            "response",
+             brillo::string_utils::Join(", ", out_types).c_str()));
+        if (method.include_dbus_message)
+          method_params.push_back("dbus::Message* message");
+        output_arguments_copy.clear();
+        break;
+      }
+      case Interface::Method::Kind::kRaw:
+        method_params.push_back("dbus::MethodCall* method_call");
+        method_params.push_back("brillo::dbus_utils::ResponseSender sender");
+        // Raw methods don't take static parameters or return values directly.
+        input_arguments_copy.clear();
+        output_arguments_copy.clear();
+        break;
+    }
+    block.AddComments(method.doc_string);
+    string method_start = StringPrintf("virtual %s %s(",
+                                       return_type.c_str(),
+                                       method.name.c_str());
+    string method_end = StringPrintf(")%s = 0;", const_method.c_str());
+    int index = 0;
+    for (const auto& argument : input_arguments_copy) {
+      string param_type;
+      CHECK(signature.Parse(argument.type, &param_type));
+      MakeConstReferenceIfNeeded(&param_type);
+      string param_name = GetArgName("in", argument.name, ++index);
+      method_params.push_back(param_type + ' ' + param_name);
+    }
+
+    for (const auto& argument : output_arguments_copy) {
+      string param_type;
+      CHECK(signature.Parse(argument.type, &param_type));
+      string param_name = GetArgName("out", argument.name, ++index);
+      method_params.push_back(param_type + "* " + param_name);
+    }
+
+    if (method_params.empty()) {
+      block.AddLine(method_start + method_end);
+    } else {
+      block.AddLine(method_start);
+      block.PushOffset(kLineContinuationOffset);
+      for (size_t i = 0; i < method_params.size() - 1; i++)
+        block.AddLine(method_params[i] + ',');
+      block.AddLine(method_params.back() + method_end);
+      block.PopOffset();
+    }
+  }
+  text->AddBlock(block);
+}
+
+// static
+void AdaptorGenerator::AddSendSignalMethods(
+    const Interface& interface,
+    IndentedText *text) {
+  IndentedText block;
+  DbusSignature signature;
+
+  if (!interface.signals.empty())
+    block.AddBlankLine();
+
+  for (const auto& signal : interface.signals) {
+    block.AddComments(signal.doc_string);
+    string method_start = StringPrintf("void Send%sSignal(",
+                                       signal.name.c_str());
+    string method_end = ") {";
+
+    int index = 0;
+    vector<string> method_params;
+    vector<string> param_names;
+    for (const auto& argument : signal.arguments) {
+      string param_type;
+      CHECK(signature.Parse(argument.type, &param_type));
+      MakeConstReferenceIfNeeded(&param_type);
+      string param_name = GetArgName("in", argument.name, ++index);
+      param_names.push_back(param_name);
+      method_params.push_back(param_type + ' ' + param_name);
+    }
+
+    if (method_params.empty()) {
+      block.AddLine(method_start + method_end);
+    } else {
+      block.AddLine(method_start);
+      block.PushOffset(kLineContinuationOffset);
+      for (size_t i = 0; i < method_params.size() - 1; i++)
+        block.AddLine(method_params[i] + ',');
+      block.AddLine(method_params.back() + method_end);
+      block.PopOffset();
+    }
+
+    string args = brillo::string_utils::Join(", ", param_names);
+    block.PushOffset(kBlockOffset);
+    block.AddLine(StringPrintf("auto signal = signal_%s_.lock();",
+                                signal.name.c_str()));
+    block.AddLine("if (signal)");
+    block.AddLineWithOffset(StringPrintf("signal->Send(%s);", args.c_str()),
+                            kBlockOffset);
+    block.PopOffset();
+    block.AddLine("}");
+  }
+  text->AddBlock(block);
+}
+
+// static
+void AdaptorGenerator::AddSignalDataMembers(const Interface& interface,
+                                            IndentedText *text) {
+  IndentedText block;
+  DbusSignature signature;
+
+  for (const auto& signal : interface.signals) {
+    string signal_type_name = StringPrintf("Signal%sType", signal.name.c_str());
+    string signal_type_alias_begin =
+        StringPrintf("using %s = brillo::dbus_utils::DBusSignal<",
+                     signal_type_name.c_str());
+    string signal_type_alias_end = ">;";
+    vector<string> params;
+    for (const auto& argument : signal.arguments) {
+      string param;
+      CHECK(signature.Parse(argument.type, &param));
+      if (!argument.name.empty())
+        base::StringAppendF(&param, " /*%s*/", argument.name.c_str());
+      params.push_back(param);
+    }
+    if (params.empty()) {
+      block.AddLine(signal_type_alias_begin + signal_type_alias_end);
+    } else {
+      block.AddLine(signal_type_alias_begin);
+      block.PushOffset(kLineContinuationOffset);
+      for (size_t i = 0; i < params.size() - 1; i++)
+        block.AddLine(params[i] + ',');
+      block.AddLine(params.back() + signal_type_alias_end);
+      block.PopOffset();
+    }
+    block.AddLine(
+        StringPrintf("std::weak_ptr<%s> signal_%s_;",
+                      signal_type_name.c_str(), signal.name.c_str()));
+    block.AddBlankLine();
+  }
+  text->AddBlock(block);
+}
+
+// static
+void AdaptorGenerator::AddPropertyMethodImplementation(
+    const Interface& interface,
+    IndentedText *text) {
+  IndentedText block;
+  DbusSignature signature;
+
+  for (const auto& property : interface.properties) {
+    block.AddBlankLine();
+    string type;
+    CHECK(signature.Parse(property.type, &type));
+    string variable_name = NameParser{property.name}.MakeVariableName();
+
+    // Property name accessor.
+    block.AddComments(property.doc_string);
+    block.AddLine(StringPrintf("static const char* %sName() { return \"%s\"; }",
+                               property.name.c_str(), property.name.c_str()));
+
+    // Getter method.
+    block.AddLine(StringPrintf("%s Get%s() const {",
+                               type.c_str(),
+                               property.name.c_str()));
+    block.PushOffset(kBlockOffset);
+    block.AddLine(StringPrintf("return %s_.GetValue().Get<%s>();",
+                               variable_name.c_str(),
+                               type.c_str()));
+    block.PopOffset();
+    block.AddLine("}");
+
+    // Setter method.
+    MakeConstReferenceIfNeeded(&type);
+    block.AddLine(StringPrintf("void Set%s(%s %s) {",
+                               property.name.c_str(),
+                               type.c_str(),
+                               variable_name.c_str()));
+    block.PushOffset(kBlockOffset);
+    block.AddLine(StringPrintf("%s_.SetValue(%s);",
+                               variable_name.c_str(),
+                               variable_name.c_str()));
+    block.PopOffset();
+    block.AddLine("}");
+
+    // Validation method for property with write access.
+    if (property.access != "read") {
+      CHECK(signature.Parse(property.type, &type));
+      block.AddLine(StringPrintf("virtual bool Validate%s(",
+                                 property.name.c_str()));
+      block.PushOffset(kLineContinuationOffset);
+      // Explicitly specify the "value" parameter as const & to match the
+      // validator callback function signature.
+      block.AddLine(
+          StringPrintf(
+              "brillo::ErrorPtr* /*error*/, const %s& /*value*/) {",
+              type.c_str()));
+      block.PopOffset();
+      block.PushOffset(kBlockOffset);
+      block.AddLine("return true;");
+      block.PopOffset();
+      block.AddLine("}");
+    }
+  }
+  text->AddBlock(block);
+}
+
+// static
+void AdaptorGenerator::AddPropertyDataMembers(const Interface& interface,
+                                              IndentedText *text) {
+  IndentedText block;
+  DbusSignature signature;
+
+  for (const auto& property : interface.properties) {
+    string type;
+    CHECK(signature.Parse(property.type, &type));
+    string variable_name = NameParser{property.name}.MakeVariableName();
+
+    block.AddLine(
+        StringPrintf("brillo::dbus_utils::ExportedProperty<%s> %s_;",
+                     type.c_str(), variable_name.c_str()));
+  }
+  if (!interface.properties.empty())
+    block.AddBlankLine();
+
+  text->AddBlock(block);
+}
+
+}  // namespace chromeos_dbus_bindings
diff --git a/dbus-binding-generator/chromeos-dbus-bindings/adaptor_generator.h b/dbus-binding-generator/chromeos-dbus-bindings/adaptor_generator.h
new file mode 100644
index 0000000..5cd68a3
--- /dev/null
+++ b/dbus-binding-generator/chromeos-dbus-bindings/adaptor_generator.h
@@ -0,0 +1,80 @@
+// Copyright 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMEOS_DBUS_BINDINGS_ADAPTOR_GENERATOR_H_
+#define CHROMEOS_DBUS_BINDINGS_ADAPTOR_GENERATOR_H_
+
+#include <string>
+#include <vector>
+
+#include <base/macros.h>
+
+#include "chromeos-dbus-bindings/header_generator.h"
+#include "chromeos-dbus-bindings/indented_text.h"
+
+namespace base {
+
+class FilePath;
+
+}  // namespace base
+
+namespace chromeos_dbus_bindings {
+
+class IndentedText;
+struct Interface;
+
+class AdaptorGenerator : public HeaderGenerator {
+ public:
+  static bool GenerateAdaptors(const std::vector<Interface>& interfaces,
+                               const base::FilePath& output_file);
+
+ private:
+  friend class AdaptorGeneratorTest;
+
+  // Generates one interface adaptor.
+  static void GenerateInterfaceAdaptor(const Interface& interface,
+                                       IndentedText *text);
+
+  // Generates the method prototypes for an interface declaration.
+  static void AddInterfaceMethods(const Interface& interface,
+                                  IndentedText *text);
+
+  // Generates the constructor for the adaptor.
+  static void AddConstructor(const Interface& interface,
+                             const std::string& class_name,
+                             const std::string& itf_name,
+                             IndentedText *text);
+
+  // Generates RegisterWithDBusObject() method.
+  static void AddRegisterWithDBusObject(const std::string& itf_name,
+                                        const Interface& interface,
+                                        IndentedText *text);
+
+  // Generates the code to register the interface with a D-Bus object.
+  static void RegisterInterface(const std::string& itf_name,
+                                const Interface& interface,
+                                IndentedText *text);
+
+  // Generates adaptor methods to send the signals.
+  static void AddSendSignalMethods(const Interface& interface,
+                                   IndentedText *text);
+
+  // Generates DBusSignal data members for the signals.
+  static void AddSignalDataMembers(const Interface& interface,
+                                   IndentedText *text);
+
+  // Generates adaptor accessor methods for the properties.
+  static void AddPropertyMethodImplementation(const Interface& interface,
+                                              IndentedText *text);
+
+  // Generate ExportProperty data members for the properties.
+  static void AddPropertyDataMembers(const Interface& interface,
+                                     IndentedText *text);
+
+  DISALLOW_COPY_AND_ASSIGN(AdaptorGenerator);
+};
+
+}  // namespace chromeos_dbus_bindings
+
+#endif  // CHROMEOS_DBUS_BINDINGS_ADAPTOR_GENERATOR_H_
diff --git a/dbus-binding-generator/chromeos-dbus-bindings/adaptor_generator_unittest.cc b/dbus-binding-generator/chromeos-dbus-bindings/adaptor_generator_unittest.cc
new file mode 100644
index 0000000..4baf847
--- /dev/null
+++ b/dbus-binding-generator/chromeos-dbus-bindings/adaptor_generator_unittest.cc
@@ -0,0 +1,313 @@
+// Copyright 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chromeos-dbus-bindings/adaptor_generator.h"
+
+#include <string>
+#include <vector>
+
+#include <base/files/file_path.h>
+#include <base/files/file_util.h>
+#include <base/files/scoped_temp_dir.h>
+#include <gtest/gtest.h>
+
+#include "chromeos-dbus-bindings/interface.h"
+#include "chromeos-dbus-bindings/test_utils.h"
+
+using std::string;
+using std::vector;
+using testing::Test;
+
+namespace chromeos_dbus_bindings {
+
+namespace {
+
+const char kDBusTypeArryOfObjects[] = "ao";
+const char kDBusTypeBool[] = "b";
+const char kDBusTypeInt32[] = "i";
+const char kDBusTypeInt64[] = "x";
+const char kDBusTypeString[] = "s";
+
+const char kPropertyAccessReadOnly[] = "read";
+const char kPropertyAccessReadWrite[] = "readwrite";
+
+const char kInterfaceName[] = "org.chromium.Test";
+const char kInterfaceName2[] = "org.chromium.Test2";
+
+const char kExpectedContent[] = R"literal_string(
+#include <memory>
+#include <string>
+#include <tuple>
+#include <vector>
+
+#include <base/macros.h>
+#include <dbus/object_path.h>
+#include <brillo/any.h>
+#include <brillo/dbus/dbus_object.h>
+#include <brillo/dbus/exported_object_manager.h>
+#include <brillo/variant_dictionary.h>
+
+namespace org {
+namespace chromium {
+
+// Interface definition for org::chromium::Test.
+class TestInterface {
+ public:
+  virtual ~TestInterface() = default;
+
+  virtual bool Kaneda(
+      brillo::ErrorPtr* error,
+      dbus::Message* message,
+      const std::string& in_iwata,
+      const std::vector<dbus::ObjectPath>& in_clarke,
+      std::string* out_3) = 0;
+  virtual bool Tetsuo(
+      brillo::ErrorPtr* error,
+      int32_t in_1,
+      int64_t* out_2) = 0;
+  virtual bool Kei(
+      brillo::ErrorPtr* error) = 0;
+  virtual bool Kiyoko(
+      brillo::ErrorPtr* error,
+      int64_t* out_akira,
+      std::string* out_2) = 0;
+};
+
+// Interface adaptor for org::chromium::Test.
+class TestAdaptor {
+ public:
+  TestAdaptor(TestInterface* interface) : interface_(interface) {}
+
+  void RegisterWithDBusObject(brillo::dbus_utils::DBusObject* object) {
+    brillo::dbus_utils::DBusInterface* itf =
+        object->AddOrGetInterface("org.chromium.Test");
+
+    itf->AddSimpleMethodHandlerWithErrorAndMessage(
+        "Kaneda",
+        base::Unretained(interface_),
+        &TestInterface::Kaneda);
+    itf->AddSimpleMethodHandlerWithError(
+        "Tetsuo",
+        base::Unretained(interface_),
+        &TestInterface::Tetsuo);
+    itf->AddSimpleMethodHandlerWithError(
+        "Kei",
+        base::Unretained(interface_),
+        &TestInterface::Kei);
+    itf->AddSimpleMethodHandlerWithError(
+        "Kiyoko",
+        base::Unretained(interface_),
+        &TestInterface::Kiyoko);
+
+    signal_Update_ = itf->RegisterSignalOfType<SignalUpdateType>("Update");
+    signal_Mapping_ = itf->RegisterSignalOfType<SignalMappingType>("Mapping");
+
+    itf->AddProperty(CharacterNameName(), &character_name_);
+    write_property_.SetAccessMode(
+        brillo::dbus_utils::ExportedPropertyBase::Access::kReadWrite);
+    write_property_.SetValidator(
+        base::Bind(&TestAdaptor::ValidateWriteProperty,
+                   base::Unretained(this)));
+    itf->AddProperty(WritePropertyName(), &write_property_);
+  }
+
+  void SendUpdateSignal() {
+    auto signal = signal_Update_.lock();
+    if (signal)
+      signal->Send();
+  }
+  void SendMappingSignal(
+      const std::string& in_key,
+      const std::vector<dbus::ObjectPath>& in_2) {
+    auto signal = signal_Mapping_.lock();
+    if (signal)
+      signal->Send(in_key, in_2);
+  }
+
+  static const char* CharacterNameName() { return "CharacterName"; }
+  std::string GetCharacterName() const {
+    return character_name_.GetValue().Get<std::string>();
+  }
+  void SetCharacterName(const std::string& character_name) {
+    character_name_.SetValue(character_name);
+  }
+
+  static const char* WritePropertyName() { return "WriteProperty"; }
+  std::string GetWriteProperty() const {
+    return write_property_.GetValue().Get<std::string>();
+  }
+  void SetWriteProperty(const std::string& write_property) {
+    write_property_.SetValue(write_property);
+  }
+  virtual bool ValidateWriteProperty(
+      brillo::ErrorPtr* /*error*/, const std::string& /*value*/) {
+    return true;
+  }
+
+  static dbus::ObjectPath GetObjectPath() {
+    return dbus::ObjectPath{"/org/chromium/Test"};
+  }
+
+ private:
+  using SignalUpdateType = brillo::dbus_utils::DBusSignal<>;
+  std::weak_ptr<SignalUpdateType> signal_Update_;
+
+  using SignalMappingType = brillo::dbus_utils::DBusSignal<
+      std::string /*key*/,
+      std::vector<dbus::ObjectPath>>;
+  std::weak_ptr<SignalMappingType> signal_Mapping_;
+
+  brillo::dbus_utils::ExportedProperty<std::string> character_name_;
+  brillo::dbus_utils::ExportedProperty<std::string> write_property_;
+
+  TestInterface* interface_;  // Owned by container of this adapter.
+
+  DISALLOW_COPY_AND_ASSIGN(TestAdaptor);
+};
+
+}  // namespace chromium
+}  // namespace org
+
+namespace org {
+namespace chromium {
+
+// Interface definition for org::chromium::Test2.
+class Test2Interface {
+ public:
+  virtual ~Test2Interface() = default;
+
+  virtual std::string Kaneda2(
+      const std::string& in_iwata) const = 0;
+  virtual void Tetsuo2(
+      std::unique_ptr<brillo::dbus_utils::DBusMethodResponse<int64_t>> response,
+      int32_t in_1) = 0;
+  virtual void Kei2(
+      std::unique_ptr<brillo::dbus_utils::DBusMethodResponse<bool>> response,
+      dbus::Message* message) = 0;
+};
+
+// Interface adaptor for org::chromium::Test2.
+class Test2Adaptor {
+ public:
+  Test2Adaptor(Test2Interface* interface) : interface_(interface) {}
+
+  void RegisterWithDBusObject(brillo::dbus_utils::DBusObject* object) {
+    brillo::dbus_utils::DBusInterface* itf =
+        object->AddOrGetInterface("org.chromium.Test2");
+
+    itf->AddSimpleMethodHandler(
+        "Kaneda2",
+        base::Unretained(interface_),
+        &Test2Interface::Kaneda2);
+    itf->AddMethodHandler(
+        "Tetsuo2",
+        base::Unretained(interface_),
+        &Test2Interface::Tetsuo2);
+    itf->AddMethodHandlerWithMessage(
+        "Kei2",
+        base::Unretained(interface_),
+        &Test2Interface::Kei2);
+  }
+
+ private:
+  Test2Interface* interface_;  // Owned by container of this adapter.
+
+  DISALLOW_COPY_AND_ASSIGN(Test2Adaptor);
+};
+
+}  // namespace chromium
+}  // namespace org
+)literal_string";
+
+}  // namespace
+class AdaptorGeneratorTest : public Test {
+ public:
+  void SetUp() override {
+    ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+  }
+
+ protected:
+  base::FilePath CreateInputFile(const string& contents) {
+    base::FilePath path;
+    EXPECT_TRUE(base::CreateTemporaryFileInDir(temp_dir_.path(), &path));
+    int written = base::WriteFile(path, contents.c_str(), contents.size());
+    EXPECT_EQ(contents.size(), static_cast<size_t>(written));
+    return path;
+  }
+
+  base::ScopedTempDir temp_dir_;
+};
+
+TEST_F(AdaptorGeneratorTest, GenerateAdaptors) {
+  Interface interface;
+  interface.name = kInterfaceName;
+  interface.path = "/org/chromium/Test";
+  interface.methods.emplace_back(
+      "Kaneda",
+      vector<Interface::Argument>{
+          {"iwata", kDBusTypeString},
+          {"clarke", kDBusTypeArryOfObjects}},
+      vector<Interface::Argument>{{"", kDBusTypeString}});
+  interface.methods.back().include_dbus_message = true;
+  interface.methods.emplace_back(
+      "Tetsuo",
+      vector<Interface::Argument>{{"", kDBusTypeInt32}},
+      vector<Interface::Argument>{{"", kDBusTypeInt64}});
+  interface.methods.emplace_back("Kei");
+  // Interface methods with more than one return argument should be ignored.
+  interface.methods.emplace_back(
+      "Kiyoko",
+      vector<Interface::Argument>{},
+      vector<Interface::Argument>{
+          {"akira", kDBusTypeInt64},
+          {"", kDBusTypeString}});
+  // Signals generate helper methods to send them.
+  interface.signals.emplace_back(
+      "Update",
+      vector<Interface::Argument>{});
+  interface.signals.emplace_back(
+      "Mapping",
+      vector<Interface::Argument>{
+          {"key", kDBusTypeString},
+          {"", kDBusTypeArryOfObjects}});
+  interface.properties.emplace_back(
+      "CharacterName",
+      kDBusTypeString,
+      kPropertyAccessReadOnly);
+  interface.properties.emplace_back(
+      "WriteProperty",
+      kDBusTypeString,
+      kPropertyAccessReadWrite);
+
+  Interface interface2;
+  interface2.name = kInterfaceName2;
+  interface2.methods.emplace_back(
+      "Kaneda2",
+      vector<Interface::Argument>{{"iwata", kDBusTypeString}},
+      vector<Interface::Argument>{{"", kDBusTypeString}});
+  interface2.methods.back().is_const = true;
+  interface2.methods.back().kind = Interface::Method::Kind::kSimple;
+  interface2.methods.emplace_back(
+      "Tetsuo2",
+      vector<Interface::Argument>{{"", kDBusTypeInt32}},
+      vector<Interface::Argument>{{"", kDBusTypeInt64}});
+  interface2.methods.back().kind = Interface::Method::Kind::kAsync;
+  interface2.methods.emplace_back(
+      "Kei2",
+      vector<Interface::Argument>{},
+      vector<Interface::Argument>{{"", kDBusTypeBool}});
+  interface2.methods.back().kind = Interface::Method::Kind::kAsync;
+  interface2.methods.back().include_dbus_message = true;
+
+  base::FilePath output_path = temp_dir_.path().Append("output.h");
+  EXPECT_TRUE(AdaptorGenerator::GenerateAdaptors({interface, interface2},
+                                                 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.
+  test_utils::EXPECT_TEXT_CONTAINED(kExpectedContent, contents);
+}
+
+}  // namespace chromeos_dbus_bindings
diff --git a/dbus-binding-generator/chromeos-dbus-bindings/chromeos-dbus-bindings.gyp b/dbus-binding-generator/chromeos-dbus-bindings/chromeos-dbus-bindings.gyp
new file mode 100644
index 0000000..6dbe423
--- /dev/null
+++ b/dbus-binding-generator/chromeos-dbus-bindings/chromeos-dbus-bindings.gyp
@@ -0,0 +1,90 @@
+{
+  'target_defaults': {
+    'variables': {
+      'deps': [
+        'libbrillo-<(libbase_ver)',
+        'libchrome-<(libbase_ver)',
+      ],
+    },
+    'cflags': [
+      '-Wextra',
+      '-Wno-unused-parameter',  # for scoped_ptr.h, included indirectly
+    ],
+    'cflags_cc': [
+      '-fno-strict-aliasing',
+      '-Woverloaded-virtual',
+    ],
+    'include_dirs': ['..'],
+  },
+  'targets': [
+    {
+      'target_name': 'libchromeos-dbus-bindings',
+      'type': 'static_library',
+      'sources': [
+        'adaptor_generator.cc',
+        'dbus_signature.cc',
+        'header_generator.cc',
+        'indented_text.cc',
+        'method_name_generator.cc',
+        'name_parser.cc',
+        'proxy_generator.cc',
+        'xml_interface_parser.cc',
+      ],
+      'variables': {
+        'exported_deps': [
+          'expat',
+        ],
+        'deps': [
+          'dbus-1',
+          '<@(exported_deps)',
+        ],
+      },
+      'all_dependent_settings': {
+        'variables': {
+          'deps': [
+            '<@(exported_deps)',
+          ],
+        },
+      },
+      'link_settings': {
+        'variables': {
+          'deps': [
+            'expat',
+          ],
+        },
+      },
+    },
+    {
+      'target_name': 'generate-chromeos-dbus-bindings',
+      'type': 'executable',
+      'dependencies': ['libchromeos-dbus-bindings'],
+      'sources': [
+        'generate_chromeos_dbus_bindings.cc',
+      ]
+    },
+  ],
+  'conditions': [
+    ['USE_test == 1', {
+      'targets': [
+        {
+          'target_name': 'chromeos_dbus_bindings_unittest',
+          'type': 'executable',
+          'dependencies': ['libchromeos-dbus-bindings'],
+          'includes': ['../../common-mk/common_test.gypi'],
+          'sources': [
+            'testrunner.cc',
+            'adaptor_generator_unittest.cc',
+            'dbus_signature_unittest.cc',
+            'indented_text_unittest.cc',
+            'method_name_generator_unittest.cc',
+            'name_parser_unittest.cc',
+            'proxy_generator_mock_unittest.cc',
+            'proxy_generator_unittest.cc',
+            'test_utils.cc',
+            'xml_interface_parser_unittest.cc',
+          ],
+        },
+      ],
+    }],
+  ],
+}
diff --git a/dbus-binding-generator/chromeos-dbus-bindings/dbus_signature.cc b/dbus-binding-generator/chromeos-dbus-bindings/dbus_signature.cc
new file mode 100644
index 0000000..81b969f
--- /dev/null
+++ b/dbus-binding-generator/chromeos-dbus-bindings/dbus_signature.cc
@@ -0,0 +1,243 @@
+// Copyright 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chromeos-dbus-bindings/dbus_signature.h"
+
+#include <base/logging.h>
+#include <base/strings/stringprintf.h>
+#include <brillo/strings/string_utils.h>
+#include <dbus/dbus-protocol.h>
+
+using base::StringPrintf;
+using std::string;
+using std::vector;
+
+namespace chromeos_dbus_bindings {
+
+// static
+const char DbusSignature::kArrayTypename[] = "std::vector";
+const char DbusSignature::kBooleanTypename[] = "bool";
+const char DbusSignature::kByteTypename[] = "uint8_t";
+const char DbusSignature::kDefaultObjectPathTypename[] = "dbus::ObjectPath";
+const char DbusSignature::kDictTypename[] = "std::map";
+const char DbusSignature::kDoubleTypename[] = "double";
+const char DbusSignature::kSigned16Typename[] = "int16_t";
+const char DbusSignature::kSigned32Typename[] = "int32_t";
+const char DbusSignature::kSigned64Typename[] = "int64_t";
+const char DbusSignature::kStringTypename[] = "std::string";
+const char DbusSignature::kUnixFdTypename[] = "dbus::FileDescriptor";
+const char DbusSignature::kUnsigned16Typename[] = "uint16_t";
+const char DbusSignature::kUnsigned32Typename[] = "uint32_t";
+const char DbusSignature::kUnsigned64Typename[] = "uint64_t";
+const char DbusSignature::kVariantTypename[] = "brillo::Any";
+const char DbusSignature::kVariantDictTypename[] = "brillo::VariantDictionary";
+const char DbusSignature::kTupleTypename[] = "std::tuple";
+
+DbusSignature::DbusSignature()
+    : object_path_typename_(kDefaultObjectPathTypename) {}
+
+bool DbusSignature::Parse(const string& signature, string* output) {
+  string::const_iterator end;
+  if (!GetTypenameForSignature(
+          signature.begin(), signature.end(), &end, output)) {
+    LOG(ERROR) << "Parse failed for signature " << signature;
+    return false;
+  }
+  if (end != signature.end()) {
+    LOG(WARNING) << "A portion of signature " << signature
+                 << " is left unparsed: " << string(end, signature.end());
+  }
+  return true;
+}
+
+bool DbusSignature::GetTypenameForSignature(
+    string::const_iterator signature,
+    string::const_iterator end,
+    string::const_iterator* next,
+    string* output) {
+  if (signature == end) {
+    LOG(ERROR) << "Signature is empty";
+    return false;
+  }
+
+  string::const_iterator cur = signature;
+  int signature_value = *cur++;
+  switch (signature_value) {
+    case DBUS_STRUCT_BEGIN_CHAR:
+      if (!GetStructTypenameForSignature(cur, end, &cur, output)) {
+        return false;
+      }
+      break;
+
+    case DBUS_TYPE_ARRAY:
+      if (!GetArrayTypenameForSignature(cur, end, &cur, output)) {
+        return false;
+      }
+      break;
+
+    case DBUS_TYPE_BOOLEAN:
+      *output = kBooleanTypename;
+      break;
+
+    case DBUS_TYPE_BYTE:
+      *output = kByteTypename;
+      break;
+
+    case DBUS_TYPE_DOUBLE:
+      *output = kDoubleTypename;
+      break;
+
+    case DBUS_TYPE_OBJECT_PATH:
+      *output = object_path_typename_;
+      break;
+
+    case DBUS_TYPE_INT16:
+      *output = kSigned16Typename;
+      break;
+
+    case DBUS_TYPE_INT32:
+      *output = kSigned32Typename;
+      break;
+
+    case DBUS_TYPE_INT64:
+      *output = kSigned64Typename;
+      break;
+
+    case DBUS_TYPE_STRING:
+      *output = kStringTypename;
+      break;
+
+    case DBUS_TYPE_UNIX_FD:
+      *output = kUnixFdTypename;
+      break;
+
+    case DBUS_TYPE_UINT16:
+      *output = kUnsigned16Typename;
+      break;
+
+    case DBUS_TYPE_UINT32:
+      *output = kUnsigned32Typename;
+      break;
+
+    case DBUS_TYPE_UINT64:
+      *output = kUnsigned64Typename;
+      break;
+
+    case DBUS_TYPE_VARIANT:
+      *output = kVariantTypename;
+      break;
+
+    default:
+      LOG(ERROR) << "Unexpected token " << *signature;
+      return false;
+  }
+
+  if (next) {
+    *next = cur;
+  }
+
+  return true;
+}
+
+bool DbusSignature::GetArrayTypenameForSignature(
+    string::const_iterator signature,
+    string::const_iterator end,
+    string::const_iterator* next,
+    string* output) {
+  string::const_iterator cur = signature;
+  if (cur == end) {
+    LOG(ERROR) << "At end of string while reading array parameter";
+    return false;
+  }
+
+  if (*cur == DBUS_DICT_ENTRY_BEGIN_CHAR) {
+    vector<string> children;
+    ++cur;
+    while (cur != end && *cur != DBUS_DICT_ENTRY_END_CHAR) {
+      children.emplace_back();
+      if (!GetTypenameForSignature(cur, end, &cur, &children.back())) {
+        LOG(ERROR) << "Unable to decode child elements starting at "
+                   << string(cur, end);
+        return false;
+      }
+    }
+    if (cur == end) {
+      LOG(ERROR) << "At end of string while processing dict "
+                 << "starting at " << string(signature, end);
+      return false;
+    }
+
+    DCHECK_EQ(DBUS_DICT_ENTRY_END_CHAR, *cur);
+    ++cur;
+
+    if (children.size() != 2) {
+      LOG(ERROR) << "Dict entry contains " << children.size()
+                 << " members starting at " << string(signature, end)
+                 << " where only 2 children is valid.";
+      return false;
+    }
+    string dict_signature{signature, cur};
+    if (dict_signature == "{sv}") {
+      *output = kVariantDictTypename;
+    } else {
+      *output = StringPrintf("%s<%s, %s>", kDictTypename,
+                             children[0].c_str(), children[1].c_str());
+    }
+  } else {
+    string child;
+    if (!GetTypenameForSignature(cur, end, &cur, &child)) {
+      LOG(ERROR) << "Unable to decode child element starting at "
+                 << string(cur, end);
+      return false;
+    }
+    *output = StringPrintf("%s<%s>", kArrayTypename, child.c_str());
+  }
+
+  if (next) {
+    *next = cur;
+  }
+
+  return true;
+}
+
+bool DbusSignature::GetStructTypenameForSignature(
+    string::const_iterator signature,
+    string::const_iterator end,
+    string::const_iterator* next,
+    string* output) {
+  string::const_iterator cur = signature;
+  if (cur == end) {
+    LOG(ERROR) << "At end of string while reading struct parameter";
+    return false;
+  }
+
+  vector<string> children;
+  while (cur != end && *cur != DBUS_STRUCT_END_CHAR) {
+    children.emplace_back();
+    if (!GetTypenameForSignature(cur, end, &cur, &children.back())) {
+      LOG(ERROR) << "Unable to decode child elements starting at "
+                 << string(cur, end);
+      return false;
+    }
+  }
+  if (cur == end) {
+    LOG(ERROR) << "At end of string while processing struct "
+               << "starting at " << string(signature, end);
+    return false;
+  }
+
+  DCHECK_EQ(DBUS_STRUCT_END_CHAR, *cur);
+  ++cur;
+
+  *output = StringPrintf("%s<%s>", kTupleTypename,
+                         brillo::string_utils::Join(", ", children).c_str());
+
+  if (next) {
+    *next = cur;
+  }
+
+  return true;
+}
+
+}  // namespace chromeos_dbus_bindings
diff --git a/dbus-binding-generator/chromeos-dbus-bindings/dbus_signature.h b/dbus-binding-generator/chromeos-dbus-bindings/dbus_signature.h
new file mode 100644
index 0000000..6a5a10b
--- /dev/null
+++ b/dbus-binding-generator/chromeos-dbus-bindings/dbus_signature.h
@@ -0,0 +1,90 @@
+// Copyright 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMEOS_DBUS_BINDINGS_DBUS_SIGNATURE_H_
+#define CHROMEOS_DBUS_BINDINGS_DBUS_SIGNATURE_H_
+
+#include <string>
+#include <vector>
+
+#include <base/macros.h>
+#include <gtest/gtest_prod.h>  // for FRIEND_TEST
+
+namespace chromeos_dbus_bindings {
+
+class DbusSignature {
+ public:
+  DbusSignature();
+  virtual ~DbusSignature() = default;
+
+  // Returns a C++ typename in |output| for a D-Bus signature in |signature|
+  // and returns true on success.  Returns false otherwise.
+  bool Parse(const std::string& signature, std::string* output);
+
+  void set_object_path_typename(const std::string& object_path_typename) {
+    object_path_typename_ = object_path_typename;
+  }
+
+ private:
+  friend class DbusSignatureTest;
+  FRIEND_TEST(DbusSignatureTest, DefaultObjectPathTypename);
+  FRIEND_TEST(DbusSignatureTest, ParseSuccesses);
+
+  // Typenames are C++ syntax types.
+  static const char kArrayTypename[];
+  static const char kBooleanTypename[];
+  static const char kByteTypename[];
+  static const char kDefaultObjectPathTypename[];
+  static const char kDictTypename[];
+  static const char kDoubleTypename[];
+  static const char kSigned16Typename[];
+  static const char kSigned32Typename[];
+  static const char kSigned64Typename[];
+  static const char kStringTypename[];
+  static const char kUnixFdTypename[];
+  static const char kUnsigned16Typename[];
+  static const char kUnsigned32Typename[];
+  static const char kUnsigned64Typename[];
+  static const char kVariantTypename[];
+  static const char kVariantDictTypename[];
+  static const char kPairTypename[];
+  static const char kTupleTypename[];
+
+  // Returns the C++ type name for the next D-Bus signature in the string at
+  // |signature| in |output|, as well as the next position within the string
+  // that parsing should continue |next|.  It is not an error to pass a
+  // pointer to |signature| or nullptr as |next|.  Returns true on success.
+  bool GetTypenameForSignature(std::string::const_iterator signature,
+                               std::string::const_iterator end,
+                               std::string::const_iterator* next,
+                               std::string* output);
+
+  // Utility task for GetTypenameForSignature() which handles array objects
+  // and decodes them into a map or vector depending on the encoded sub-elements
+  // in the array.  The arguments and return values are the same
+  // as GetTypenameForSignature().
+  bool GetArrayTypenameForSignature(std::string::const_iterator signature,
+                                    std::string::const_iterator end,
+                                    std::string::const_iterator* next,
+                                    std::string* output);
+
+  // Utility task for GetTypenameForSignature() which handles STRUCT objects
+  // and decodes them into a pair or tuple depending on the number of structure
+  // elements.  The arguments and return values are the same
+  // as GetTypenameForSignature().
+  bool GetStructTypenameForSignature(std::string::const_iterator signature,
+                                     std::string::const_iterator end,
+                                     std::string::const_iterator* next,
+                                     std::string* output);
+
+
+  // The C++ typename to be used for D-Bus object pathnames.
+  std::string object_path_typename_;
+
+  DISALLOW_COPY_AND_ASSIGN(DbusSignature);
+};
+
+}  // namespace chromeos_dbus_bindings
+
+#endif  // CHROMEOS_DBUS_BINDINGS_DBUS_SIGNATURE_H_
diff --git a/dbus-binding-generator/chromeos-dbus-bindings/dbus_signature_unittest.cc b/dbus-binding-generator/chromeos-dbus-bindings/dbus_signature_unittest.cc
new file mode 100644
index 0000000..a74772a
--- /dev/null
+++ b/dbus-binding-generator/chromeos-dbus-bindings/dbus_signature_unittest.cc
@@ -0,0 +1,120 @@
+// Copyright 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chromeos-dbus-bindings/dbus_signature.h"
+
+#include <map>
+#include <string>
+
+#include <dbus/dbus-protocol.h>
+#include <gtest/gtest.h>
+
+using std::map;
+using std::string;
+using testing::Test;
+
+namespace chromeos_dbus_bindings {
+
+namespace {
+
+// Failing signatures.
+const char kEmptySignature[] = "";
+const char kEmptyDictSignature[] = "a{}";
+const char kMissingArraryParameterSignature[] = "a";
+const char kMissingArraryParameterInnerSignature[] = "a{sa}i";
+const char kOrphanDictSignature[] = "a{s{i}}";
+const char kTooFewDictMembersSignature[] = "a{s}";
+const char kTooManyDictMembersSignature[] = "a{sa{i}u}";
+const char kUnclosedDictOuterSignature[] = "a{s";
+const char kUnclosedDictInnerSignature[] = "a{a{u}";
+const char kUnexpectedCloseSignature[] = "a}i{";
+const char kUnknownSignature[] = "al";
+
+// Define an object type name to disambiguate the typenames above.
+const char kObjectPathTypename[] = "ObjectPathType";
+
+}  // namespace
+
+class DbusSignatureTest : public Test {
+ protected:
+  DbusSignature signature_;
+};
+
+TEST_F(DbusSignatureTest, ParseFailures) {
+  for (const auto& failing_string : { kEmptySignature,
+                                      kEmptyDictSignature,
+                                      kMissingArraryParameterSignature,
+                                      kMissingArraryParameterInnerSignature,
+                                      kOrphanDictSignature,
+                                      kTooFewDictMembersSignature,
+                                      kTooManyDictMembersSignature,
+                                      kUnclosedDictOuterSignature,
+                                      kUnclosedDictInnerSignature,
+                                      kUnexpectedCloseSignature,
+                                      kUnknownSignature }) {
+    string unused_output;
+    EXPECT_FALSE(signature_.Parse(failing_string, &unused_output))
+        << "Expected signature " << failing_string
+        << " to fail but it succeeded";
+  }
+}
+
+TEST_F(DbusSignatureTest, DefaultObjectPathTypename) {
+  // The ParseSuccesses test below overrides the default object typename, so
+  // test the default behavior separately.
+  string output;
+  EXPECT_TRUE(signature_.Parse(DBUS_TYPE_OBJECT_PATH_AS_STRING, &output));
+  EXPECT_EQ(DbusSignature::kDefaultObjectPathTypename, output);
+}
+
+TEST_F(DbusSignatureTest, ParseSuccesses) {
+  const map<string, string> parse_values {
+    // Simple types.
+    { DBUS_TYPE_BOOLEAN_AS_STRING, DbusSignature::kBooleanTypename },
+    { DBUS_TYPE_BYTE_AS_STRING, DbusSignature::kByteTypename },
+    { DBUS_TYPE_DOUBLE_AS_STRING, DbusSignature::kDoubleTypename },
+    { DBUS_TYPE_OBJECT_PATH_AS_STRING, kObjectPathTypename },
+    { DBUS_TYPE_INT16_AS_STRING, DbusSignature::kSigned16Typename },
+    { DBUS_TYPE_INT32_AS_STRING, DbusSignature::kSigned32Typename },
+    { DBUS_TYPE_INT64_AS_STRING, DbusSignature::kSigned64Typename },
+    { DBUS_TYPE_STRING_AS_STRING, DbusSignature::kStringTypename },
+    { DBUS_TYPE_UNIX_FD_AS_STRING, DbusSignature::kUnixFdTypename },
+    { DBUS_TYPE_UINT16_AS_STRING, DbusSignature::kUnsigned16Typename },
+    { DBUS_TYPE_UINT32_AS_STRING, DbusSignature::kUnsigned32Typename },
+    { DBUS_TYPE_UINT64_AS_STRING, DbusSignature::kUnsigned64Typename },
+    { DBUS_TYPE_VARIANT_AS_STRING, DbusSignature::kVariantTypename },
+
+    // Complex types.
+    { "ab",             "std::vector<bool>" },
+    { "ay",             "std::vector<uint8_t>" },
+    { "aay",            "std::vector<std::vector<uint8_t>>" },
+    { "ao",             "std::vector<ObjectPathType>" },
+    { "a{oa{sa{sv}}}",  "std::map<ObjectPathType, std::map<std::string, "
+                          "brillo::VariantDictionary>>" },
+    { "a{os}",          "std::map<ObjectPathType, std::string>" },
+    { "as",             "std::vector<std::string>" },
+    { "a{ss}",          "std::map<std::string, std::string>" },
+    { "a{sa{ss}}",      "std::map<std::string, std::map<std::string, "
+                          "std::string>>"},
+    { "a{sa{sv}}",      "std::map<std::string, brillo::VariantDictionary>" },
+    { "a{sv}",          "brillo::VariantDictionary" },
+    { "a{sv}Garbage",   "brillo::VariantDictionary" },
+    { "at",             "std::vector<uint64_t>" },
+    { "a{iv}",          "std::map<int32_t, brillo::Any>" },
+    { "(ib)",           "std::tuple<int32_t, bool>" },
+    { "(ibs)",          "std::tuple<int32_t, bool, std::string>" },
+  };
+  signature_.set_object_path_typename(kObjectPathTypename);
+  for (const auto& parse_test : parse_values) {
+    string output;
+    EXPECT_TRUE(signature_.Parse(parse_test.first, &output))
+        << "Expected signature " << parse_test.first
+        << " to succeed but it failed.";
+    EXPECT_EQ(parse_test.second, output)
+        << "Expected typename for " << parse_test.first
+        << " to be " << parse_test.second << " but instead it was " << output;
+  }
+}
+
+}  // namespace chromeos_dbus_bindings
diff --git a/dbus-binding-generator/chromeos-dbus-bindings/generate_chromeos_dbus_bindings.cc b/dbus-binding-generator/chromeos-dbus-bindings/generate_chromeos_dbus_bindings.cc
new file mode 100644
index 0000000..c82326d
--- /dev/null
+++ b/dbus-binding-generator/chromeos-dbus-bindings/generate_chromeos_dbus_bindings.cc
@@ -0,0 +1,226 @@
+// Copyright 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <memory>
+#include <string>
+
+#include <base/command_line.h>
+#include <base/files/file_path.h>
+#include <base/files/file_util.h>
+#include <base/json/json_reader.h>
+#include <base/logging.h>
+#include <base/strings/string_util.h>
+#include <base/values.h>
+#include <brillo/syslog_logging.h>
+
+#include "chromeos-dbus-bindings/adaptor_generator.h"
+#include "chromeos-dbus-bindings/method_name_generator.h"
+#include "chromeos-dbus-bindings/proxy_generator.h"
+#include "chromeos-dbus-bindings/xml_interface_parser.h"
+
+using chromeos_dbus_bindings::AdaptorGenerator;
+using chromeos_dbus_bindings::MethodNameGenerator;
+using chromeos_dbus_bindings::ProxyGenerator;
+using chromeos_dbus_bindings::ServiceConfig;
+
+namespace switches {
+
+static const char kHelp[] = "help";
+static const char kMethodNames[] = "method-names";
+static const char kAdaptor[] = "adaptor";
+static const char kProxy[] = "proxy";
+static const char kMock[] = "mock";
+static const char kProxyPathForMocks[] = "proxy-path-in-mocks";
+static const char kServiceConfig[] = "service-config";
+static const char kHelpMessage[] = "\n"
+    "generate-chromeos-dbus-bindings itf1.xml [itf2.xml...] [switches]\n"
+    "    itf1.xml, ... = the input interface file(s) [mandatory].\n"
+    "Available Switches: \n"
+    "  --method-names=<method name header filename>\n"
+    "    The output header file with string constants for each method name.\n"
+    "  --adaptor=<adaptor header filename>\n"
+    "    The output header file name containing the DBus adaptor class.\n"
+    "  --proxy=<proxy header filename>\n"
+    "    The output header file name containing the DBus proxy class.\n"
+    "  --mock=<mock header filename>\n"
+    "    The output header file name containing the DBus proxy mock class.\n"
+    "  --service-config=<config.json>\n"
+    "    The DBus service configuration file for the generator.\n";
+
+}  // namespace switches
+
+namespace {
+// GYP sometimes enclosed the target file name in extra set of quotes like:
+//    generate-chromeos-dbus-bindings in.xml "--adaptor=\"out.h\""
+// So, this function helps us to remove them.
+base::FilePath RemoveQuotes(const std::string& path) {
+  std::string unquoted;
+  base::TrimString(path, "\"'", &unquoted);
+  return base::FilePath{unquoted};
+}
+
+// Makes a canonical path by making the path absolute and by removing any
+// '..' which makes base::ReadFileToString() to fail.
+base::FilePath SanitizeFilePath(const std::string& path) {
+  base::FilePath path_in = RemoveQuotes(path);
+  base::FilePath path_out = base::MakeAbsoluteFilePath(path_in);
+  if (path_out.value().empty()) {
+    LOG(WARNING) << "Failed to canonicalize '" << path << "'";
+    path_out = path_in;
+  }
+  return path_out;
+}
+
+
+// Load the service configuration from the provided JSON file.
+bool LoadConfig(const base::FilePath& path, ServiceConfig *config) {
+  std::string contents;
+  if (!base::ReadFileToString(path, &contents))
+    return false;
+
+  std::unique_ptr<base::Value> json{base::JSONReader::Read(contents).release()};
+  if (!json)
+    return false;
+
+  base::DictionaryValue* dict = nullptr;  // Aliased with |json|.
+  if (!json->GetAsDictionary(&dict))
+    return false;
+
+  dict->GetStringWithoutPathExpansion("service_name", &config->service_name);
+
+  base::DictionaryValue* om_dict = nullptr;  // Owned by |dict|.
+  if (dict->GetDictionaryWithoutPathExpansion("object_manager", &om_dict)) {
+    if (!om_dict->GetStringWithoutPathExpansion("name",
+                                                &config->object_manager.name) &&
+        !config->service_name.empty()) {
+      config->object_manager.name = config->service_name + ".ObjectManager";
+    }
+    om_dict->GetStringWithoutPathExpansion("object_path",
+                                           &config->object_manager.object_path);
+    if (config->object_manager.name.empty()) {
+      LOG(ERROR) << "Object manager name is missing.";
+      return false;
+    }
+  }
+
+  base::ListValue* list = nullptr;  // Owned by |dict|.
+  if (dict->GetListWithoutPathExpansion("ignore_interfaces", &list)) {
+    config->ignore_interfaces.reserve(list->GetSize());
+    for (const auto& item : *list) {
+      std::string interface_name;
+      if (!item->GetAsString(&interface_name)) {
+        LOG(ERROR) << "Invalid interface name in [ignore_interfaces] section";
+        return false;
+      }
+      config->ignore_interfaces.push_back(interface_name);
+    }
+  }
+
+  return true;
+}
+
+}   // anonymous namespace
+
+int main(int argc, char** argv) {
+  base::CommandLine::Init(argc, argv);
+  base::CommandLine* cl = base::CommandLine::ForCurrentProcess();
+
+  // Setup logging to stderr. This also parses some implicit flags using the
+  // CommandLine singleton.
+  brillo::InitLog(brillo::kLogToStderr | brillo::kLogHeader);
+
+  if (cl->HasSwitch(switches::kHelp)) {
+    LOG(INFO) << switches::kHelpMessage;
+    return 0;
+  }
+
+  auto input_files = cl->GetArgs();
+  if (input_files.empty()) {
+    LOG(ERROR) << "At least one file must be specified.";
+    LOG(ERROR) << switches::kHelpMessage;
+    return 1;
+  }
+
+  ServiceConfig config;
+  if (cl->HasSwitch(switches::kServiceConfig)) {
+    std::string config_file = cl->GetSwitchValueASCII(switches::kServiceConfig);
+    if (!config_file.empty() &&
+        !LoadConfig(SanitizeFilePath(config_file), &config)) {
+      LOG(ERROR) << "Failed to load DBus service config file " << config_file;
+      return 1;
+    }
+  }
+
+  chromeos_dbus_bindings::XmlInterfaceParser parser;
+  for (const auto& input : input_files) {
+    std::string contents;
+    if (!base::ReadFileToString(SanitizeFilePath(input), &contents)) {
+      LOG(ERROR) << "Failed to read file " << input;
+      return 1;
+    }
+    if (!parser.ParseXmlInterfaceFile(contents, config.ignore_interfaces)) {
+      LOG(ERROR) << "Failed to parse interface file " << input;
+      return 1;
+    }
+  }
+
+  if (cl->HasSwitch(switches::kMethodNames)) {
+    std::string method_name_file =
+        cl->GetSwitchValueASCII(switches::kMethodNames);
+    VLOG(1) << "Outputting method names to " << method_name_file;
+    if (!MethodNameGenerator::GenerateMethodNames(
+            parser.interfaces(),
+            RemoveQuotes(method_name_file))) {
+      LOG(ERROR) << "Failed to output method names.";
+      return 1;
+    }
+  }
+
+  if (cl->HasSwitch(switches::kAdaptor)) {
+    std::string adaptor_file = cl->GetSwitchValueASCII(switches::kAdaptor);
+    VLOG(1) << "Outputting adaptor to " << adaptor_file;
+    if (!AdaptorGenerator::GenerateAdaptors(parser.interfaces(),
+                                            RemoveQuotes(adaptor_file))) {
+      LOG(ERROR) << "Failed to output adaptor.";
+      return 1;
+     }
+  }
+
+  base::FilePath proxy_path;  // Used by both Proxy and Mock generation.
+  if (cl->HasSwitch(switches::kProxy)) {
+    std::string proxy_file = cl->GetSwitchValueASCII(switches::kProxy);
+    proxy_path = RemoveQuotes(proxy_file);
+    base::NormalizeFilePath(proxy_path, &proxy_path);
+    VLOG(1) << "Outputting proxy to " << proxy_path.value();
+    if (!ProxyGenerator::GenerateProxies(config, parser.interfaces(),
+                                         proxy_path)) {
+      LOG(ERROR) << "Failed to output proxy.";
+      return 1;
+     }
+  }
+
+  base::FilePath proxy_include_path = proxy_path;
+  bool use_literal_include_path = false;
+  if (cl->HasSwitch(switches::kProxyPathForMocks)) {
+    std::string proxy_file_in_mocks =
+        cl->GetSwitchValueASCII(switches::kProxyPathForMocks);
+    proxy_include_path = RemoveQuotes(proxy_file_in_mocks);
+    use_literal_include_path = true;
+  }
+
+  if (cl->HasSwitch(switches::kMock)) {
+    std::string mock_file = cl->GetSwitchValueASCII(switches::kMock);
+    base::FilePath mock_path = RemoveQuotes(mock_file);
+    base::NormalizeFilePath(mock_path, &mock_path);
+    VLOG(1) << "Outputting mock to " << mock_path.value();
+    if (!ProxyGenerator::GenerateMocks(config, parser.interfaces(), mock_path,
+                                       proxy_include_path,
+                                       use_literal_include_path)) {
+      LOG(ERROR) << "Failed to output mock.";
+      return 1;
+     }
+  }
+
+  return 0;
+}
diff --git a/dbus-binding-generator/chromeos-dbus-bindings/header_generator.cc b/dbus-binding-generator/chromeos-dbus-bindings/header_generator.cc
new file mode 100644
index 0000000..6989ffa
--- /dev/null
+++ b/dbus-binding-generator/chromeos-dbus-bindings/header_generator.cc
@@ -0,0 +1,70 @@
+// Copyright 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chromeos-dbus-bindings/header_generator.h"
+
+#include <string>
+
+#include <base/files/file_path.h>
+#include <base/files/file_util.h>
+#include <base/strings/string_util.h>
+#include <base/strings/stringprintf.h>
+#include <brillo/strings/string_utils.h>
+
+#include "chromeos-dbus-bindings/indented_text.h"
+
+using std::string;
+using std::vector;
+
+namespace chromeos_dbus_bindings {
+
+// static
+string HeaderGenerator::GenerateHeaderGuard(
+    const base::FilePath& output_file) {
+  string guard = base::StringPrintf("____chromeos_dbus_binding__%s",
+                                    output_file.value().c_str());
+  for (auto& c : guard) {
+    if (base::IsAsciiAlpha(c)) {
+      c = base::ToUpperASCII(c);
+    } else if (!base::IsAsciiDigit(c)) {
+      c = '_';
+    }
+  }
+  return guard;
+}
+
+// static
+bool HeaderGenerator::IsIntegralType(const string& type) {
+  return type.find("::") == std::string::npos;
+}
+
+// static
+void HeaderGenerator::MakeConstReferenceIfNeeded(std::string* type) {
+  if (!IsIntegralType(*type)) {
+    *type = base::StringPrintf("const %s&", type->c_str());
+  }
+}
+
+// static
+bool HeaderGenerator::WriteTextToFile(
+    const base::FilePath& output_file, const IndentedText &text) {
+  string contents = text.GetContents();
+  int expected_write_return = contents.size();
+  if (base::WriteFile(output_file, contents.c_str(), contents.size()) !=
+      expected_write_return) {
+    LOG(ERROR) << "Failed to write file " << output_file.value();
+    return false;
+  }
+  return true;
+}
+
+// static
+string HeaderGenerator::GetArgName(const char* prefix,
+                                   const string& arg_name,
+                                   int arg_index) {
+  string name = arg_name.empty() ? std::to_string(arg_index) : arg_name;
+  return base::StringPrintf("%s_%s", prefix, name.c_str());
+}
+
+}  // namespace chromeos_dbus_bindings
diff --git a/dbus-binding-generator/chromeos-dbus-bindings/header_generator.h b/dbus-binding-generator/chromeos-dbus-bindings/header_generator.h
new file mode 100644
index 0000000..0c28bd7
--- /dev/null
+++ b/dbus-binding-generator/chromeos-dbus-bindings/header_generator.h
@@ -0,0 +1,81 @@
+// Copyright 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMEOS_DBUS_BINDINGS_HEADER_GENERATOR_H_
+#define CHROMEOS_DBUS_BINDINGS_HEADER_GENERATOR_H_
+
+#include <string>
+#include <vector>
+
+#include <base/macros.h>
+
+namespace base {
+
+class FilePath;
+
+};
+
+namespace chromeos_dbus_bindings {
+
+struct Interface;
+class  IndentedText;
+
+// General D-Bus service configuration settings used by Adaptor/Proxy code
+// generators.
+struct ServiceConfig {
+  // D-Bus service name to be used when constructing proxy objects.
+  // If omitted (empty), the service name parameter will be added to the
+  // constructor of generated proxy class(es).
+  std::string service_name;
+  // Object Manager settings.
+  struct {
+    // The name of the Object Manager class to use. If empty, no object manager
+    // is generated in the proxy code (this also disables property support on
+    // proxy objects).
+    // This is a "fake" name used to generate namespaces and the actual class
+    // name for the object manager proxy. This name has no relationship to the
+    // actual D-Bus properties of the actual object manager.
+    std::string name;
+    // The D-Bus path to Object Manager instance.
+    std::string object_path;
+  } object_manager;
+
+  // A list of interfaces we should ignore and not generate any adaptors and
+  // proxies for.
+  std::vector<std::string> ignore_interfaces;
+};
+
+class HeaderGenerator {
+ protected:
+  // Create a unique header guard string to protect multiple includes of header.
+  static std::string GenerateHeaderGuard(const base::FilePath& output_file);
+
+  // Used to decide whether the argument should be a const reference.
+  static bool IsIntegralType(const std::string& type);
+
+  // If |type| is a non-integral type, converts it into a const reference.
+  static void MakeConstReferenceIfNeeded(std::string* type);
+
+  // Writes indented text to a file.
+  static bool WriteTextToFile(const base::FilePath& output_file,
+                              const IndentedText& text);
+
+  // Generate a name of a method/signal argument based on the name provided in
+  // the XML file. If |arg_name| is empty, it generates a name using
+  // the |arg_index| counter.
+  static std::string GetArgName(const char* prefix,
+                                const std::string& arg_name,
+                                int arg_index);
+
+  static const int kScopeOffset = 1;
+  static const int kBlockOffset = 2;
+  static const int kLineContinuationOffset = 4;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(HeaderGenerator);
+};
+
+}  // namespace chromeos_dbus_bindings
+
+#endif  // CHROMEOS_DBUS_BINDINGS_HEADER_GENERATOR_H_
diff --git a/dbus-binding-generator/chromeos-dbus-bindings/indented_text.cc b/dbus-binding-generator/chromeos-dbus-bindings/indented_text.cc
new file mode 100644
index 0000000..8831bf9
--- /dev/null
+++ b/dbus-binding-generator/chromeos-dbus-bindings/indented_text.cc
@@ -0,0 +1,141 @@
+// Copyright 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chromeos-dbus-bindings/indented_text.h"
+
+#include <string>
+#include <utility>
+#include <vector>
+
+#include <base/logging.h>
+#include <base/strings/string_util.h>
+#include <brillo/strings/string_utils.h>
+
+using std::string;
+using std::vector;
+
+namespace chromeos_dbus_bindings {
+
+IndentedText::IndentedText() : offset_(0) {}
+
+void IndentedText::AddBlankLine() {
+  AddLine("");
+}
+
+void IndentedText::AddBlock(const IndentedText& block) {
+  AddBlockWithOffset(block, 0);
+}
+
+void IndentedText::AddBlockWithOffset(const IndentedText& block, size_t shift) {
+  for (const auto& member : block.contents_) {
+    AddLineWithOffset(member.first, member.second + shift);
+  }
+}
+
+void IndentedText::AddLine(const std::string& line) {
+  AddLineWithOffset(line, 0);
+}
+
+void IndentedText::AddLineWithOffset(const std::string& line, size_t shift) {
+  contents_.emplace_back(line, shift + offset_);
+}
+
+void IndentedText::AddLineAndPushOffsetTo(const std::string& line,
+                                          size_t occurrence,
+                                          char c) {
+  AddLine(line);
+  size_t pos = 0;
+  while (occurrence > 0) {
+    pos = line.find(c, pos);
+    CHECK(pos != string::npos);
+    pos++;
+    occurrence--;
+  }
+  PushOffset(pos);
+}
+
+void IndentedText::AddComments(const std::string& doc_string) {
+  // Try to retain indentation in the comments. Find the first non-empty line
+  // of the comment and find its whitespace indentation prefix.
+  // For all subsequent lines, remove the same whitespace prefix as found
+  // at the first line of the comment but keep any additional spaces to
+  // maintain the comment layout.
+  auto lines = brillo::string_utils::Split(doc_string, "\n", false, false);
+  vector<string> lines_out;
+  lines_out.reserve(lines.size());
+  bool first_nonempty_found = false;
+  std::string trim_prefix;
+  for (string line : lines) {
+    base::TrimWhitespaceASCII(line, base::TRIM_TRAILING, &line);
+    if (!first_nonempty_found) {
+      size_t pos = line.find_first_not_of(" \t");
+      if (pos != std::string::npos) {
+        first_nonempty_found = true;
+        trim_prefix = line.substr(0, pos);
+        lines_out.push_back(line.substr(pos));
+      }
+    } else {
+      if (base::StartsWith(line, trim_prefix,
+                           base::CompareCase::INSENSITIVE_ASCII)) {
+        line = line.substr(trim_prefix.length());
+      } else {
+        base::TrimWhitespaceASCII(line, base::TRIM_LEADING, &line);
+      }
+      lines_out.push_back(line);
+    }
+  }
+
+  // We already eliminated all empty lines at the beginning of the comment
+  // block. Now remove the trailing empty lines.
+  while (!lines_out.empty() && lines_out.back().empty())
+    lines_out.pop_back();
+
+  for (const string& line : lines_out) {
+    const bool all_whitespace = (line.find_first_not_of(" \t") == string::npos);
+    if (all_whitespace) {
+      AddLine("//");
+    } else {
+      AddLine("// " + line);
+    }
+  }
+}
+
+string IndentedText::GetContents() const {
+  string output;
+  for (const string& line : GetLines()) {
+    output.append(line);
+    output.append("\n");
+  }
+  return output;
+}
+
+std::vector<std::string> IndentedText::GetLines() const {
+  vector<string> result;
+  for (const auto& member : contents_) {
+    const string& line = member.first;
+    size_t shift = line.empty() ? 0 : member.second;
+    string indent(shift, ' ');
+    result.push_back(indent + line);
+  }
+  return result;
+}
+
+void IndentedText::PushOffset(size_t shift) {
+  offset_ += shift;
+  offset_history_.push_back(shift);
+}
+
+void IndentedText::PopOffset() {
+  CHECK(!offset_history_.empty());
+  offset_ -= offset_history_.back();
+  offset_history_.pop_back();
+}
+
+void IndentedText::Reset() {
+  offset_ = 0;
+  offset_history_.clear();
+  contents_.clear();
+}
+
+}  // namespace chromeos_dbus_bindings
diff --git a/dbus-binding-generator/chromeos-dbus-bindings/indented_text.h b/dbus-binding-generator/chromeos-dbus-bindings/indented_text.h
new file mode 100644
index 0000000..6651a58
--- /dev/null
+++ b/dbus-binding-generator/chromeos-dbus-bindings/indented_text.h
@@ -0,0 +1,70 @@
+// Copyright 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMEOS_DBUS_BINDINGS_INDENTED_TEXT_H_
+#define CHROMEOS_DBUS_BINDINGS_INDENTED_TEXT_H_
+
+#include <string>
+#include <utility>
+#include <vector>
+
+#include <base/macros.h>
+
+namespace chromeos_dbus_bindings {
+
+class IndentedText {
+ public:
+  IndentedText();
+  virtual ~IndentedText() = default;
+
+  // Insert a blank line.
+  void AddBlankLine();
+
+  // Insert a block of indented text.
+  void AddBlock(const IndentedText& block);
+  void AddBlockWithOffset(const IndentedText& block, size_t shift);
+
+  // Add a line at the current indentation.
+  void AddLine(const std::string& line);
+  void AddLineWithOffset(const std::string& line, size_t shift);
+  // Adds a line and pushes an offset past the |nth_occurrence| of character |c|
+  // in that line, effectively allowing to align following line to the position
+  // following that character.
+  void AddLineAndPushOffsetTo(const std::string& line,
+                              size_t nth_occurrence,
+                              char c);
+
+  // Adds a block of comments.
+  void AddComments(const std::string& doc_string);
+
+  // Return a string representing the indented text.
+  std::string GetContents() const;
+
+  // Return a list of lines representing the intended indented text, not
+  // including the \n.
+  std::vector<std::string> GetLines() const;
+
+  // Add or remove an offset to the current stack of indentation offsets.
+  void PushOffset(size_t shift);
+  void PopOffset();
+
+  // Reset to initial state.
+  void Reset();
+
+
+ private:
+  using IndentedLine = std::pair<std::string, size_t>;
+
+  friend class IndentedTextTest;
+
+  size_t offset_;
+  std::vector<size_t> offset_history_;
+  std::vector<IndentedLine> contents_;
+
+  DISALLOW_COPY_AND_ASSIGN(IndentedText);
+};
+
+}  // namespace chromeos_dbus_bindings
+
+#endif  // CHROMEOS_DBUS_BINDINGS_INDENTED_TEXT_H_
diff --git a/dbus-binding-generator/chromeos-dbus-bindings/indented_text_unittest.cc b/dbus-binding-generator/chromeos-dbus-bindings/indented_text_unittest.cc
new file mode 100644
index 0000000..a75c396
--- /dev/null
+++ b/dbus-binding-generator/chromeos-dbus-bindings/indented_text_unittest.cc
@@ -0,0 +1,183 @@
+// Copyright 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chromeos-dbus-bindings/indented_text.h"
+
+#include <string>
+#include <vector>
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+using std::string;
+using std::vector;
+using testing::ElementsAre;
+using testing::Test;
+
+namespace chromeos_dbus_bindings {
+
+class IndentedTextTest : public Test {
+ protected:
+  size_t GetOffset() const { return text_.offset_; }
+  const vector<size_t>& GetHistory() const { return text_.offset_history_; }
+  IndentedText text_;
+};
+
+TEST_F(IndentedTextTest, Constructor) {
+  EXPECT_EQ("", text_.GetContents());
+  EXPECT_EQ(0u, GetOffset());
+  EXPECT_TRUE(GetHistory().empty());
+}
+
+TEST_F(IndentedTextTest, AddLine) {
+  const char kTestString0[] = "test";
+  text_.AddLine(kTestString0);
+  EXPECT_EQ(string(kTestString0) + "\n", text_.GetContents());
+  EXPECT_EQ(0u, GetOffset());
+  EXPECT_TRUE(GetHistory().empty());
+
+  const char kTestString1[] = "me";
+  text_.AddLine(kTestString1);
+  EXPECT_EQ(string(kTestString0) + "\n" + kTestString1 + "\n",
+            text_.GetContents());
+  EXPECT_EQ(0u, GetOffset());
+  EXPECT_TRUE(GetHistory().empty());
+}
+
+TEST_F(IndentedTextTest, AddLineWithOffset) {
+  const char kTestString[] = "test";
+  const int kShift = 4;
+  text_.AddLineWithOffset(kTestString, kShift);
+  EXPECT_EQ(string(kShift, ' ') + kTestString + "\n", text_.GetContents());
+}
+
+TEST_F(IndentedTextTest, AddLineAndPushOffsetTo) {
+  text_.AddLineAndPushOffsetTo("foo(bar(baz", 2, '(');
+  EXPECT_THAT(GetHistory(), ElementsAre(8));
+}
+
+TEST_F(IndentedTextTest, AddBlock) {
+  IndentedText block0;
+  const char kTestString[] = "test";
+  block0.AddLineWithOffset(kTestString, 10);
+  block0.AddLineWithOffset(kTestString, 20);
+  IndentedText block1;
+  block1.AddLineWithOffset(kTestString, 5);
+  block1.AddLineWithOffset(kTestString, 15);
+  text_.AddBlock(block0);
+  text_.AddBlock(block1);
+  EXPECT_EQ(block0.GetContents() + block1.GetContents(), text_.GetContents());
+}
+
+TEST_F(IndentedTextTest, AddBlockWithOffset) {
+  const char kTestString[] = "test";
+  IndentedText block;
+  const size_t kOffset0 = 0;
+  block.AddLineWithOffset(kTestString, kOffset0);
+  const size_t kOffset1 = 4;
+  block.AddLineWithOffset(kTestString, kOffset1);
+  const size_t kOffset2 = 20;
+  text_.AddBlockWithOffset(block, kOffset2);
+  EXPECT_EQ(string(kOffset2 + kOffset0, ' ') + kTestString + "\n" +
+            string(kOffset2 + kOffset1, ' ') + kTestString + "\n",
+            text_.GetContents());
+}
+
+TEST_F(IndentedTextTest, PushPop) {
+  const char kTestString[] = "test";
+  text_.AddLine(kTestString);
+
+  const size_t kShift0 = 2;
+  text_.PushOffset(kShift0);
+  EXPECT_EQ(2u, GetOffset());
+  EXPECT_THAT(GetHistory(), ElementsAre(kShift0));
+  text_.AddLine(kTestString);
+
+  const size_t kShift1 = 4;
+  text_.PushOffset(kShift1);
+  EXPECT_EQ(kShift0 + kShift1, GetOffset());
+  EXPECT_THAT(GetHistory(), ElementsAre(kShift0, kShift1));
+  text_.AddLine(kTestString);
+
+  text_.PopOffset();
+  text_.AddLine(kTestString);
+  EXPECT_EQ(2u, GetOffset());
+  EXPECT_THAT(GetHistory(), ElementsAre(kShift0));
+
+  text_.PopOffset();
+  text_.AddLine(kTestString);
+  EXPECT_EQ(0u, GetOffset());
+  EXPECT_TRUE(GetHistory().empty());
+
+  EXPECT_EQ(string(kTestString) + "\n" +
+            string(kShift0, ' ') + kTestString + "\n" +
+            string(kShift0 + kShift1, ' ') + kTestString + "\n" +
+            string(kShift0, ' ') + kTestString + "\n" +
+            string(kTestString) + "\n",
+            text_.GetContents());
+}
+
+TEST_F(IndentedTextTest, Reset) {
+  text_.PushOffset(10);
+  text_.AddLine("test");
+  EXPECT_NE("", text_.GetContents());
+  EXPECT_NE(0u, GetOffset());
+  EXPECT_FALSE(GetHistory().empty());
+  text_.Reset();
+  EXPECT_EQ("", text_.GetContents());
+  EXPECT_EQ(0u, GetOffset());
+  EXPECT_TRUE(GetHistory().empty());
+}
+
+TEST_F(IndentedTextTest, AddComments_Empty) {
+  text_.AddComments("");
+  EXPECT_EQ("", text_.GetContents());
+}
+
+TEST_F(IndentedTextTest, AddComments_WhitespaceOnly) {
+  text_.AddComments("  \n \t  \n");
+  EXPECT_EQ("", text_.GetContents());
+}
+
+TEST_F(IndentedTextTest, AddComments_EmptyLines) {
+  string comment_block = R"(
+
+    line1
+
+    line2
+
+
+  )";
+  text_.AddComments(comment_block);
+  EXPECT_EQ("// line1\n"
+            "//\n"
+            "// line2\n", text_.GetContents());
+}
+
+TEST_F(IndentedTextTest, AddComments_Indentation) {
+  string comment_block = R"(
+    line1
+      - bullet1
+        line2
+      - bullet2
+  line3
+  )";
+  text_.AddComments(comment_block);
+  EXPECT_EQ("// line1\n"
+            "//   - bullet1\n"
+            "//     line2\n"
+            "//   - bullet2\n"
+            "// line3\n", text_.GetContents());
+}
+
+TEST_F(IndentedTextTest, GetLines) {
+  text_.AddLine("no indent");
+  text_.PushOffset(2);
+  text_.AddLine("2 spaces");
+  text_.AddLine("");
+
+  EXPECT_EQ((vector<string>{"no indent", "  2 spaces", ""}), text_.GetLines());
+}
+
+}  // namespace chromeos_dbus_bindings
diff --git a/dbus-binding-generator/chromeos-dbus-bindings/interface.h b/dbus-binding-generator/chromeos-dbus-bindings/interface.h
new file mode 100644
index 0000000..73b1481
--- /dev/null
+++ b/dbus-binding-generator/chromeos-dbus-bindings/interface.h
@@ -0,0 +1,83 @@
+// Copyright 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMEOS_DBUS_BINDINGS_INTERFACE_H_
+#define CHROMEOS_DBUS_BINDINGS_INTERFACE_H_
+
+#include <string>
+#include <vector>
+
+namespace chromeos_dbus_bindings {
+
+struct Interface {
+  struct Argument {
+    Argument(const std::string& name_in,
+             const std::string& type_in) : name(name_in), type(type_in) {}
+    std::string name;
+    std::string type;
+  };
+  struct Method {
+    enum class Kind {
+      kSimple,
+      kNormal,
+      kAsync,
+      kRaw
+    };
+    Method(const std::string& name_in,
+           const std::vector<Argument>& input_arguments_in,
+           const std::vector<Argument>& output_arguments_in)
+        : name(name_in),
+          input_arguments(input_arguments_in),
+          output_arguments(output_arguments_in) {}
+    Method(const std::string& name_in,
+           const std::vector<Argument>& input_arguments_in)
+        : name(name_in),
+          input_arguments(input_arguments_in) {}
+    explicit Method(const std::string& name_in) : name(name_in) {}
+    std::string name;
+    std::vector<Argument> input_arguments;
+    std::vector<Argument> output_arguments;
+    std::string doc_string;
+    Kind kind{Kind::kNormal};
+    bool is_const{false};
+    bool include_dbus_message{false};
+  };
+  struct Signal {
+    Signal(const std::string& name_in,
+           const std::vector<Argument>& arguments_in)
+        : name(name_in), arguments(arguments_in) {}
+    explicit Signal(const std::string& name_in) : name(name_in) {}
+    std::string name;
+    std::vector<Argument> arguments;
+    std::string doc_string;
+  };
+  struct Property {
+    Property(const std::string& name_in,
+             const std::string& type_in,
+             const std::string& access_in)
+        : name(name_in), type(type_in), access(access_in) {}
+    std::string name;
+    std::string type;
+    std::string access;
+    std::string doc_string;
+  };
+
+  Interface() = default;
+  Interface(const std::string& name_in,
+            const std::vector<Method>& methods_in,
+            const std::vector<Signal>& signals_in,
+            const std::vector<Property>& properties_in)
+      : name(name_in), methods(methods_in), signals(signals_in),
+        properties(properties_in) {}
+  std::string name;
+  std::string path;
+  std::vector<Method> methods;
+  std::vector<Signal> signals;
+  std::vector<Property> properties;
+  std::string doc_string;
+};
+
+}  // namespace chromeos_dbus_bindings
+
+#endif  // CHROMEOS_DBUS_BINDINGS_INTERFACE_H_
diff --git a/dbus-binding-generator/chromeos-dbus-bindings/method_name_generator.cc b/dbus-binding-generator/chromeos-dbus-bindings/method_name_generator.cc
new file mode 100644
index 0000000..5332660
--- /dev/null
+++ b/dbus-binding-generator/chromeos-dbus-bindings/method_name_generator.cc
@@ -0,0 +1,46 @@
+// Copyright 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chromeos-dbus-bindings/method_name_generator.h"
+
+#include <base/files/file_path.h>
+#include <base/strings/stringprintf.h>
+
+#include "chromeos-dbus-bindings/indented_text.h"
+#include "chromeos-dbus-bindings/interface.h"
+#include "chromeos-dbus-bindings/name_parser.h"
+
+using std::string;
+using std::vector;
+
+namespace chromeos_dbus_bindings {
+
+// static
+string MethodNameGenerator::GenerateMethodNameConstant(
+    const string& method_name) {
+  return "k" + method_name + "Method";
+}
+
+// static
+bool MethodNameGenerator::GenerateMethodNames(
+    const vector<Interface>& interfaces,
+    const base::FilePath& output_file) {
+  string contents;
+  IndentedText text;
+  for (const auto& interface : interfaces) {
+    text.AddBlankLine();
+    NameParser parser{interface.name};
+    parser.AddOpenNamespaces(&text, true);
+    for (const auto& method : interface.methods) {
+      text.AddLine(
+        base::StringPrintf("const char %s[] = \"%s\";",
+                            GenerateMethodNameConstant(method.name).c_str(),
+                            method.name.c_str()));
+    }
+    parser.AddCloseNamespaces(&text, true);
+  }
+  return HeaderGenerator::WriteTextToFile(output_file, text);
+}
+
+}  // namespace chromeos_dbus_bindings
diff --git a/dbus-binding-generator/chromeos-dbus-bindings/method_name_generator.h b/dbus-binding-generator/chromeos-dbus-bindings/method_name_generator.h
new file mode 100644
index 0000000..24a3dc1
--- /dev/null
+++ b/dbus-binding-generator/chromeos-dbus-bindings/method_name_generator.h
@@ -0,0 +1,39 @@
+// Copyright 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMEOS_DBUS_BINDINGS_METHOD_NAME_GENERATOR_H_
+#define CHROMEOS_DBUS_BINDINGS_METHOD_NAME_GENERATOR_H_
+
+#include <string>
+#include <vector>
+
+#include <base/macros.h>
+
+#include "chromeos-dbus-bindings/header_generator.h"
+
+namespace base {
+
+class FilePath;
+
+}  // namespace base
+
+namespace chromeos_dbus_bindings {
+
+struct Interface;
+
+class MethodNameGenerator : public HeaderGenerator {
+ public:
+  static bool GenerateMethodNames(const std::vector<Interface>& interfaces,
+                                  const base::FilePath& output_file);
+  static std::string GenerateMethodNameConstant(const std::string& method_name);
+
+ private:
+  friend class MethodNameGeneratorTest;
+
+  DISALLOW_COPY_AND_ASSIGN(MethodNameGenerator);
+};
+
+}  // namespace chromeos_dbus_bindings
+
+#endif  // CHROMEOS_DBUS_BINDINGS_METHOD_NAME_GENERATOR_H_
diff --git a/dbus-binding-generator/chromeos-dbus-bindings/method_name_generator_unittest.cc b/dbus-binding-generator/chromeos-dbus-bindings/method_name_generator_unittest.cc
new file mode 100644
index 0000000..040c188
--- /dev/null
+++ b/dbus-binding-generator/chromeos-dbus-bindings/method_name_generator_unittest.cc
@@ -0,0 +1,69 @@
+// Copyright 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chromeos-dbus-bindings/method_name_generator.h"
+
+#include <string>
+#include <vector>
+
+#include <base/files/file_path.h>
+#include <base/files/file_util.h>
+#include <base/files/scoped_temp_dir.h>
+#include <gtest/gtest.h>
+
+#include "chromeos-dbus-bindings/interface.h"
+
+using std::string;
+using testing::Test;
+
+namespace chromeos_dbus_bindings {
+
+namespace {
+
+const char kMethodName0[] = "Zircon";
+const char kMethodName1[] = "Encrusted";
+const char kMethodName2[] = "Tweezers";
+const char kExpectedOutput[] = R"(
+namespace MyInterface {
+const char kZirconMethod[] = "Zircon";
+const char kEncrustedMethod[] = "Encrusted";
+const char kTweezersMethod[] = "Tweezers";
+}  // namespace MyInterface
+)";
+
+}  // namespace
+
+class MethodNameGeneratorTest : public Test {
+ public:
+  void SetUp() override {
+    ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+  }
+
+ protected:
+  base::FilePath CreateInputFile(const string& contents) {
+    base::FilePath path;
+    EXPECT_TRUE(base::CreateTemporaryFileInDir(temp_dir_.path(), &path));
+    int written = base::WriteFile(path, contents.c_str(), contents.size());
+    EXPECT_EQ(contents.size(), static_cast<size_t>(written));
+    return path;
+  }
+
+  base::ScopedTempDir temp_dir_;
+};
+
+TEST_F(MethodNameGeneratorTest, GnerateMethodNames) {
+  Interface interface;
+  interface.name = "MyInterface";
+  interface.methods.emplace_back(kMethodName0);
+  interface.methods.emplace_back(kMethodName1);
+  interface.methods.emplace_back(kMethodName2);
+  base::FilePath output_path = temp_dir_.path().Append("output.h");
+  EXPECT_TRUE(MethodNameGenerator::GenerateMethodNames({interface},
+                                                       output_path));
+  string contents;
+  EXPECT_TRUE(base::ReadFileToString(output_path, &contents));
+  EXPECT_STREQ(kExpectedOutput, contents.c_str());
+}
+
+}  // namespace chromeos_dbus_bindings
diff --git a/dbus-binding-generator/chromeos-dbus-bindings/name_parser.cc b/dbus-binding-generator/chromeos-dbus-bindings/name_parser.cc
new file mode 100644
index 0000000..7f71e49
--- /dev/null
+++ b/dbus-binding-generator/chromeos-dbus-bindings/name_parser.cc
@@ -0,0 +1,98 @@
+// Copyright 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chromeos-dbus-bindings/name_parser.h"
+
+#include <string>
+
+#include <base/strings/string_util.h>
+#include <base/strings/stringprintf.h>
+#include <brillo/strings/string_utils.h>
+
+#include "chromeos-dbus-bindings/indented_text.h"
+
+namespace chromeos_dbus_bindings {
+
+namespace {
+
+void AddOpenNamespace(IndentedText *text, const std::string& name) {
+  text->AddLine(base::StringPrintf("namespace %s {", name.c_str()));
+}
+
+void AddCloseNamespace(IndentedText *text, const std::string& name) {
+  text->AddLine(base::StringPrintf("}  // namespace %s", name.c_str()));
+}
+
+}  // anonymous namespace
+
+NameParser::NameParser(const std::string& name)
+    : namespaces{brillo::string_utils::Split(name, ".")} {
+  CHECK(!namespaces.empty()) << "Empty name specified";
+  type_name = namespaces.back();
+  namespaces.pop_back();
+}
+
+std::string NameParser::MakeFullyQualified(const std::string& name) const {
+  std::vector<std::string> parts = namespaces;
+  parts.push_back(name);
+  return brillo::string_utils::Join("::", parts);
+}
+
+std::string NameParser::MakeFullCppName() const {
+  return MakeFullyQualified(type_name);
+}
+
+std::string NameParser::MakeVariableName() const {
+  // Convert CamelCase name to google_style variable name.
+  std::string result;
+  bool last_upper = true;
+  for (char c : type_name) {
+    bool is_upper = isupper(c);
+    if (is_upper) {
+      if (!last_upper)
+        result += '_';
+      c = base::ToLowerASCII(c);
+    }
+    last_upper = is_upper;
+    result.push_back(c);
+  }
+  return result;
+}
+
+std::string NameParser::MakeInterfaceName(bool fully_qualified) const {
+  std::string interface_name = type_name + "Interface";
+  return fully_qualified ? MakeFullyQualified(interface_name) : interface_name;
+}
+
+std::string NameParser::MakeProxyName(bool fully_qualified) const {
+  std::string proxy_name = type_name + "Proxy";
+  return fully_qualified ? MakeFullyQualified(proxy_name) : proxy_name;
+}
+
+std::string NameParser::MakeAdaptorName(bool fully_qualified) const {
+  std::string adaptor_name = type_name + "Adaptor";
+  return fully_qualified ? MakeFullyQualified(adaptor_name) : adaptor_name;
+}
+
+void NameParser::AddOpenNamespaces(IndentedText *text,
+                                   bool add_main_type) const {
+  for (const auto& ns : namespaces) {
+    AddOpenNamespace(text, ns);
+  }
+
+  if (add_main_type)
+    AddOpenNamespace(text, type_name);
+}
+
+void NameParser::AddCloseNamespaces(IndentedText *text,
+                                    bool add_main_type) const {
+  if (add_main_type)
+    AddCloseNamespace(text, type_name);
+
+  for (auto it = namespaces.rbegin(); it != namespaces.rend(); ++it) {
+    AddCloseNamespace(text, *it);
+  }
+}
+
+}  // namespace chromeos_dbus_bindings
diff --git a/dbus-binding-generator/chromeos-dbus-bindings/name_parser.h b/dbus-binding-generator/chromeos-dbus-bindings/name_parser.h
new file mode 100644
index 0000000..0282819
--- /dev/null
+++ b/dbus-binding-generator/chromeos-dbus-bindings/name_parser.h
@@ -0,0 +1,63 @@
+// Copyright 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMEOS_DBUS_BINDINGS_NAME_PARSER_H_
+#define CHROMEOS_DBUS_BINDINGS_NAME_PARSER_H_
+
+#include <string>
+#include <vector>
+
+#include <base/macros.h>
+
+namespace chromeos_dbus_bindings {
+
+struct Interface;
+class  IndentedText;
+
+// A helper class that allows to decompose D-Bus name strings such as
+// "org.chromium.TestInterface" into components and be able to construct the
+// corresponding C++ identifiers, namespaces, variable names, etc.
+class NameParser {
+ public:
+  explicit NameParser(const std::string& name);
+
+  // Returns fully-qualified C++ type name for the current D-Bus name
+  // for example "org::chromium::TestInterface".
+  std::string MakeFullCppName() const;
+
+  // Returns a variable name suitable for object of this type.
+  // For example "test_interface".
+  std::string MakeVariableName() const;
+
+  // Returns a name of an interface for the given type, optionally qualifying
+  // it with the C++ namespaces.
+  std::string MakeInterfaceName(bool fully_qualified) const;
+
+  // Returns a name of a proxy class for the given type, optionally qualifying
+  // it with the C++ namespaces.
+  std::string MakeProxyName(bool fully_qualified) const;
+
+  // Returns a name of an adaptor class for the given type, optionally
+  // qualifying it with the C++ namespaces.
+  std::string MakeAdaptorName(bool fully_qualified) const;
+
+  // Adds opening "namespace ... {" statements to |text|.
+  // If |add_main_type| is true, adds the main type name as a namespace as well.
+  void AddOpenNamespaces(IndentedText *text, bool add_main_type) const;
+
+  // Adds closing "}  // namespace ..." statements to |text|.
+  // If |add_main_type| is true, adds the main type name as a namespace as well.
+  void AddCloseNamespaces(IndentedText *text, bool add_main_type) const;
+
+  std::string type_name;  // e.g. "TestInterface".
+  std::vector<std::string> namespaces;  // e.g. {"org", "chromium"}.
+
+ private:
+  // Helper function to prepend the C++ namespaces to the |name|.
+  std::string MakeFullyQualified(const std::string& name) const;
+};
+
+}  // namespace chromeos_dbus_bindings
+
+#endif  // CHROMEOS_DBUS_BINDINGS_NAME_PARSER_H_
diff --git a/dbus-binding-generator/chromeos-dbus-bindings/name_parser_unittest.cc b/dbus-binding-generator/chromeos-dbus-bindings/name_parser_unittest.cc
new file mode 100644
index 0000000..25c6c92
--- /dev/null
+++ b/dbus-binding-generator/chromeos-dbus-bindings/name_parser_unittest.cc
@@ -0,0 +1,123 @@
+// Copyright 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chromeos-dbus-bindings/name_parser.h"
+
+#include <map>
+#include <string>
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include "chromeos-dbus-bindings/indented_text.h"
+
+namespace chromeos_dbus_bindings {
+
+TEST(NameParser, Parsing_Empty) {
+  EXPECT_DEATH(NameParser{""}, "Empty name specified");
+}
+
+TEST(NameParser, Parsing_NoNamespaces) {
+  NameParser parser{"foo"};
+  EXPECT_EQ("foo", parser.type_name);
+  EXPECT_TRUE(parser.namespaces.empty());
+}
+
+TEST(NameParser, Parsing_FullyQualified) {
+  NameParser parser{"foo.bar.FooBar"};
+  EXPECT_EQ("FooBar", parser.type_name);
+  EXPECT_THAT(parser.namespaces, testing::ElementsAre("foo", "bar"));
+}
+
+TEST(NameParser, MakeFullCppName) {
+  NameParser parser{"foo.bar.FooBar"};
+  EXPECT_EQ("foo::bar::FooBar", parser.MakeFullCppName());
+}
+
+TEST(NameParser, MakeVariableName) {
+  NameParser parser{"foo.bar.FooBar"};
+  EXPECT_EQ("foo_bar", parser.MakeVariableName());
+}
+
+TEST(NameParser, MakeVariableName_NoCapitals) {
+  NameParser parser{"foo"};
+  EXPECT_EQ("foo", parser.MakeVariableName());
+}
+
+TEST(NameParser, MakeVariableName_NoInitialCapital) {
+  NameParser parser{"fooBarBaz"};
+  EXPECT_EQ("foo_bar_baz", parser.MakeVariableName());
+}
+
+TEST(NameParser, MakeVariableName_AllCapitals) {
+  NameParser parser{"UUID"};
+  EXPECT_EQ("uuid", parser.MakeVariableName());
+}
+
+TEST(NameParser, MakeVariableName_MixedCapital) {
+  NameParser parser{"FOObarBaz"};
+  EXPECT_EQ("foobar_baz", parser.MakeVariableName());
+}
+
+TEST(NameParser, MakeInterfaceName) {
+  NameParser parser{"foo.bar.FooBar"};
+  EXPECT_EQ("FooBarInterface", parser.MakeInterfaceName(false));
+  EXPECT_EQ("foo::bar::FooBarInterface", parser.MakeInterfaceName(true));
+}
+
+TEST(NameParser, MakeProxyName) {
+  NameParser parser{"foo.bar.FooBar"};
+  EXPECT_EQ("FooBarProxy", parser.MakeProxyName(false));
+  EXPECT_EQ("foo::bar::FooBarProxy", parser.MakeProxyName(true));
+}
+
+TEST(NameParser, MakeAdaptorName) {
+  NameParser parser{"foo.bar.FooBar"};
+  EXPECT_EQ("FooBarAdaptor", parser.MakeAdaptorName(false));
+  EXPECT_EQ("foo::bar::FooBarAdaptor", parser.MakeAdaptorName(true));
+}
+
+TEST(NameParser, AddOpenNamespaces) {
+  std::string expected =
+    "namespace foo {\n"
+    "namespace bar {\n";
+  NameParser parser{"foo.bar.FooBar"};
+  IndentedText text;
+  parser.AddOpenNamespaces(&text, false);
+  EXPECT_EQ(expected, text.GetContents());
+}
+
+TEST(NameParser, AddOpenNamespaces_WithMainType) {
+  std::string expected =
+    "namespace foo {\n"
+    "namespace bar {\n"
+    "namespace FooBar {\n";
+  NameParser parser{"foo.bar.FooBar"};
+  IndentedText text;
+  parser.AddOpenNamespaces(&text, true);
+  EXPECT_EQ(expected, text.GetContents());
+}
+
+TEST(NameParser, AddCloseNamespaces) {
+  std::string expected =
+    "}  // namespace bar\n"
+    "}  // namespace foo\n";
+  NameParser parser{"foo.bar.FooBar"};
+  IndentedText text;
+  parser.AddCloseNamespaces(&text, false);
+  EXPECT_EQ(expected, text.GetContents());
+}
+
+TEST(NameParser, AddCloseNamespaces_WithMainType) {
+  std::string expected =
+    "}  // namespace FooBar\n"
+    "}  // namespace bar\n"
+    "}  // namespace foo\n";
+  NameParser parser{"foo.bar.FooBar"};
+  IndentedText text;
+  parser.AddCloseNamespaces(&text, true);
+  EXPECT_EQ(expected, text.GetContents());
+}
+
+}  // namespace chromeos_dbus_bindings
diff --git a/dbus-binding-generator/chromeos-dbus-bindings/proxy_generator.cc b/dbus-binding-generator/chromeos-dbus-bindings/proxy_generator.cc
new file mode 100644
index 0000000..ea0d1dc
--- /dev/null
+++ b/dbus-binding-generator/chromeos-dbus-bindings/proxy_generator.cc
@@ -0,0 +1,1370 @@
+// Copyright 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chromeos-dbus-bindings/proxy_generator.h"
+
+#include <algorithm>
+#include <utility>
+
+#include <base/files/file_path.h>
+#include <base/format_macros.h>
+#include <base/logging.h>
+#include <base/strings/stringprintf.h>
+#include <brillo/strings/string_utils.h>
+
+#include "chromeos-dbus-bindings/dbus_signature.h"
+#include "chromeos-dbus-bindings/indented_text.h"
+#include "chromeos-dbus-bindings/name_parser.h"
+
+using base::StringPrintf;
+using std::pair;
+using std::string;
+using std::vector;
+
+namespace chromeos_dbus_bindings {
+
+namespace {
+// Helper struct to encapsulate information about method call parameter during
+// code generation.
+struct ParamDef {
+  ParamDef(const string& param_type, const string& param_name, bool param_ref)
+      : type(param_type), name(param_name), is_const_ref(param_ref) {}
+
+  string type;
+  string name;
+  bool is_const_ref;
+};
+
+string GetParamString(const ParamDef& param_def) {
+  return StringPrintf(param_def.is_const_ref ? "const %s& %s" : "%s* %s",
+                      param_def.type.c_str(), param_def.name.c_str());
+}
+}  // anonymous namespace
+
+// static
+bool ProxyGenerator::GenerateProxies(
+    const ServiceConfig& config,
+    const std::vector<Interface>& interfaces,
+    const base::FilePath& output_file) {
+  IndentedText text;
+
+  text.AddLine("// Automatic generation of D-Bus interfaces:");
+  for (const auto& interface : interfaces) {
+    text.AddLine(StringPrintf("//  - %s", interface.name.c_str()));
+  }
+  string header_guard = GenerateHeaderGuard(output_file);
+  text.AddLine(StringPrintf("#ifndef %s", header_guard.c_str()));
+  text.AddLine(StringPrintf("#define %s", header_guard.c_str()));
+  text.AddLine("#include <memory>");
+  text.AddLine("#include <string>");
+  text.AddLine("#include <vector>");
+  text.AddBlankLine();
+  text.AddLine("#include <base/bind.h>");
+  text.AddLine("#include <base/callback.h>");
+  text.AddLine("#include <base/logging.h>");
+  text.AddLine("#include <base/macros.h>");
+  text.AddLine("#include <base/memory/ref_counted.h>");
+  text.AddLine("#include <brillo/any.h>");
+  text.AddLine("#include <brillo/dbus/dbus_method_invoker.h>");
+  text.AddLine("#include <brillo/dbus/dbus_property.h>");
+  text.AddLine("#include <brillo/dbus/dbus_signal_handler.h>");
+  text.AddLine("#include <brillo/errors/error.h>");
+  text.AddLine("#include <brillo/variant_dictionary.h>");
+  text.AddLine("#include <dbus/bus.h>");
+  text.AddLine("#include <dbus/message.h>");
+  text.AddLine("#include <dbus/object_manager.h>");
+  text.AddLine("#include <dbus/object_path.h>");
+  text.AddLine("#include <dbus/object_proxy.h>");
+  text.AddBlankLine();
+
+  if (!config.object_manager.name.empty()) {
+    // Add forward-declaration for Object Manager proxy class.
+    NameParser parser{config.object_manager.name};
+    parser.AddOpenNamespaces(&text, false);
+    text.AddLine(StringPrintf("class %s;",
+                              parser.MakeProxyName(false).c_str()));
+    parser.AddCloseNamespaces(&text, false);
+    text.AddBlankLine();
+  }
+
+  for (const auto& interface : interfaces) {
+    GenerateInterfaceProxyInterface(config, interface, &text);
+    GenerateInterfaceProxy(config, interface, &text);
+  }
+
+  ObjectManager::GenerateProxy(config, interfaces, &text);
+
+  text.AddLine(StringPrintf("#endif  // %s", header_guard.c_str()));
+  return WriteTextToFile(output_file, text);
+}
+
+// static
+bool ProxyGenerator::GenerateMocks(const ServiceConfig& config,
+                                   const std::vector<Interface>& interfaces,
+                                   const base::FilePath& mock_file,
+                                   const base::FilePath& proxy_file,
+                                   bool use_literal_proxy_file) {
+  IndentedText text;
+
+  text.AddLine("// Automatic generation of D-Bus interface mock proxies for:");
+  for (const auto& interface : interfaces) {
+    text.AddLine(StringPrintf("//  - %s", interface.name.c_str()));
+  }
+  string header_guard = GenerateHeaderGuard(mock_file);
+  text.AddLine(StringPrintf("#ifndef %s", header_guard.c_str()));
+  text.AddLine(StringPrintf("#define %s", header_guard.c_str()));
+  text.AddLine("#include <string>");
+  text.AddLine("#include <vector>");
+  text.AddBlankLine();
+  text.AddLine("#include <base/callback_forward.h>");
+  text.AddLine("#include <base/logging.h>");
+  text.AddLine("#include <base/macros.h>");
+  text.AddLine("#include <brillo/any.h>");
+  text.AddLine("#include <brillo/errors/error.h>");
+  text.AddLine("#include <brillo/variant_dictionary.h>");
+  text.AddLine("#include <gmock/gmock.h>");
+  text.AddBlankLine();
+
+  if (!proxy_file.empty()) {
+    // If we have a proxy header file, it would have the proxy interfaces we
+    // need to base our mocks on, so we need to include that header file.
+    base::FilePath relative_path;
+    if (use_literal_proxy_file) {
+      relative_path = proxy_file;
+    } else {
+      // Generate a relative path from |mock_file| to |proxy_file|.
+
+      // First, get the path components for both source and destination paths.
+      std::vector<base::FilePath::StringType> src_components;
+      mock_file.DirName().GetComponents(&src_components);
+      std::vector<base::FilePath::StringType> dest_components;
+      proxy_file.DirName().GetComponents(&dest_components);
+
+      // Find the common root.
+
+      // I wish we had C++14 and its 4-parameter version of std::mismatch()...
+      auto src_end = src_components.end();
+      if (src_components.size() > dest_components.size())
+        src_end = src_components.begin() + dest_components.size();
+
+      auto mismatch_pair = std::mismatch(src_components.begin(), src_end,
+                                         dest_components.begin());
+
+      // For each remaining components in the |src_components|, generate the
+      // parent directory references ("..").
+      size_t src_count = std::distance(mismatch_pair.first,
+                                       src_components.end());
+      std::vector<base::FilePath::StringType> components{
+          src_count, base::FilePath::kParentDirectory};
+      // Append the remaining components from |dest_components|.
+      components.insert(components.end(),
+                        mismatch_pair.second, dest_components.end());
+      // Finally, add the base name of the target file name.
+      components.push_back(proxy_file.BaseName().value());
+      // Now reconstruct the relative path.
+      relative_path = base::FilePath{base::FilePath::kCurrentDirectory};
+      for (const auto& component : components)
+        relative_path = relative_path.Append(component);
+    }
+    text.AddLine(StringPrintf("#include \"%s\"",
+                              relative_path.value().c_str()));
+    text.AddBlankLine();
+  }
+
+  for (const auto& interface : interfaces) {
+    // If we have no proxy file, we need the abstract interfaces generated here.
+    if (proxy_file.empty())
+      GenerateInterfaceProxyInterface(config, interface, &text);
+    GenerateInterfaceMock(config, interface, &text);
+  }
+
+  text.AddLine(StringPrintf("#endif  // %s", header_guard.c_str()));
+  return WriteTextToFile(mock_file, text);
+}
+
+// static
+void ProxyGenerator::GenerateInterfaceProxyInterface(
+    const ServiceConfig& config,
+    const Interface& interface,
+    IndentedText* text) {
+  NameParser parser{interface.name};
+  string proxy_name = parser.MakeProxyName(false);
+  string base_interface_name = proxy_name + "Interface";
+
+  parser.AddOpenNamespaces(text, false);
+  text->AddBlankLine();
+
+  text->AddLine(StringPrintf("// Abstract interface proxy for %s.",
+                             parser.MakeFullCppName().c_str()));
+  text->AddComments(interface.doc_string);
+  text->AddLine(StringPrintf("class %s {", base_interface_name.c_str()));
+  text->AddLineWithOffset("public:", kScopeOffset);
+  text->PushOffset(kBlockOffset);
+  text->AddLine(
+      StringPrintf("virtual ~%s() = default;", base_interface_name.c_str()));
+
+  for (const auto& method : interface.methods) {
+    AddMethodProxy(method, interface.name, true, text);
+    AddAsyncMethodProxy(method, interface.name, true, text);
+  }
+  for (const auto& signal : interface.signals) {
+    AddSignalHandlerRegistration(signal, interface.name, true, text);
+  }
+  AddProperties(config, interface, true, text);
+  text->AddBlankLine();
+  text->AddLine("virtual const dbus::ObjectPath& GetObjectPath() const = 0;");
+  if (!config.object_manager.name.empty() && !interface.properties.empty())
+    AddPropertyPublicMethods(proxy_name, true, text);
+
+  text->PopOffset();
+  text->AddLine("};");
+  text->AddBlankLine();
+
+  parser.AddCloseNamespaces(text, false);
+  text->AddBlankLine();
+}
+
+// static
+void ProxyGenerator::GenerateInterfaceProxy(const ServiceConfig& config,
+                                            const Interface& interface,
+                                            IndentedText* text) {
+  NameParser parser{interface.name};
+  string proxy_name = parser.MakeProxyName(false);
+  string base_interface_name = proxy_name + "Interface";
+
+  parser.AddOpenNamespaces(text, false);
+  text->AddBlankLine();
+
+  text->AddLine(StringPrintf("// Interface proxy for %s.",
+                             parser.MakeFullCppName().c_str()));
+  text->AddComments(interface.doc_string);
+  text->AddLine(StringPrintf("class %s final : public %s {",
+                             proxy_name.c_str(), base_interface_name.c_str()));
+  text->AddLineWithOffset("public:", kScopeOffset);
+  text->PushOffset(kBlockOffset);
+  AddPropertySet(config, interface, text);
+  AddConstructor(config, interface, proxy_name, text);
+  AddDestructor(proxy_name, text);
+  for (const auto& signal : interface.signals) {
+    AddSignalHandlerRegistration(signal, interface.name, false, text);
+  }
+  AddReleaseObjectProxy(text);
+  AddGetObjectPath(text);
+  AddGetObjectProxy(text);
+  if (!config.object_manager.name.empty() && !interface.properties.empty())
+    AddPropertyPublicMethods(proxy_name, false, text);
+  for (const auto& method : interface.methods) {
+    AddMethodProxy(method, interface.name, false, text);
+    AddAsyncMethodProxy(method, interface.name, false, text);
+  }
+  AddProperties(config, interface, false, text);
+
+  text->PopOffset();
+  text->AddBlankLine();
+  text->AddLineWithOffset("private:", kScopeOffset);
+
+  text->PushOffset(kBlockOffset);
+  if (!config.object_manager.name.empty() && !interface.properties.empty())
+    AddOnPropertyChanged(text);
+  text->AddLine("scoped_refptr<dbus::Bus> bus_;");
+  if (config.service_name.empty()) {
+    text->AddLine("std::string service_name_;");
+  } else {
+    text->AddLine(StringPrintf("const std::string service_name_{\"%s\"};",
+                               config.service_name.c_str()));
+  }
+  if (interface.path.empty()) {
+    text->AddLine("dbus::ObjectPath object_path_;");
+  } else {
+    text->AddLine(StringPrintf("const dbus::ObjectPath object_path_{\"%s\"};",
+                               interface.path.c_str()));
+  }
+  if (!config.object_manager.name.empty() && !interface.properties.empty()) {
+    text->AddLine("PropertySet* property_set_;");
+    text->AddLine(
+        StringPrintf("base::Callback<void(%sInterface*, const std::string&)> "
+                     "on_property_changed_;",
+                     proxy_name.c_str()));
+  }
+  text->AddLine("dbus::ObjectProxy* dbus_object_proxy_;");
+  text->AddBlankLine();
+
+  if (!config.object_manager.name.empty() && !interface.properties.empty()) {
+    text->AddLine(StringPrintf(
+        "friend class %s;",
+        NameParser{config.object_manager.name}.MakeProxyName(true).c_str()));
+  }
+  text->AddLine(StringPrintf("DISALLOW_COPY_AND_ASSIGN(%s);",
+                             proxy_name.c_str()));
+  text->PopOffset();
+  text->AddLine("};");
+
+  text->AddBlankLine();
+
+  parser.AddCloseNamespaces(text, false);
+
+  text->AddBlankLine();
+}
+
+// static
+void ProxyGenerator::GenerateInterfaceMock(const ServiceConfig& config,
+                                           const Interface& interface,
+                                           IndentedText* text) {
+  NameParser parser{interface.name};
+  string proxy_name = parser.MakeProxyName(false);
+  string base_interface_name = proxy_name + "Interface";
+  string mock_name = proxy_name + "Mock";
+
+  parser.AddOpenNamespaces(text, false);
+  text->AddBlankLine();
+
+  text->AddLine(StringPrintf("// Mock object for %s.",
+                             base_interface_name.c_str()));
+  text->AddLine(StringPrintf("class %s : public %s {",
+                             mock_name.c_str(), base_interface_name.c_str()));
+  text->AddLineWithOffset("public:", kScopeOffset);
+  text->PushOffset(kBlockOffset);
+  text->AddLine(StringPrintf("%s() = default;", mock_name.c_str()));
+  text->AddBlankLine();
+
+  for (const auto& method : interface.methods) {
+    AddMethodMock(method, interface.name, text);
+    AddAsyncMethodMock(method, interface.name, text);
+  }
+  for (const auto& signal : interface.signals) {
+    AddSignalHandlerRegistrationMock(signal, text);
+  }
+
+  DbusSignature signature;
+  for (const auto& prop : interface.properties) {
+    string type;
+    CHECK(signature.Parse(prop.type, &type));
+    MakeConstReferenceIfNeeded(&type);
+    string name = NameParser{prop.name}.MakeVariableName();
+    text->AddLine(StringPrintf("MOCK_CONST_METHOD0(%s, %s());",
+                               name.c_str(), type.c_str()));
+    if (prop.access == "readwrite") {
+      text->AddLine(StringPrintf("MOCK_METHOD2(set_%s, void(%s, "
+                                 "const base::Callback<bool>&));",
+                                 name.c_str(), type.c_str()));
+    }
+  }
+  text->AddLine(
+      "MOCK_CONST_METHOD0(GetObjectPath, const dbus::ObjectPath&());");
+  if (!config.object_manager.name.empty() && !interface.properties.empty()) {
+    text->AddLineAndPushOffsetTo(
+        "MOCK_METHOD1(SetPropertyChangedCallback,", 1, '(');
+    text->AddLine(StringPrintf(
+        "void(const base::Callback<void(%sInterface*, const std::string&)>&));",
+        proxy_name.c_str()));
+    text->PopOffset();
+  }
+
+  text->PopOffset();
+  text->AddBlankLine();
+  text->AddLineWithOffset("private:", kScopeOffset);
+  text->AddLineWithOffset(StringPrintf("DISALLOW_COPY_AND_ASSIGN(%s);",
+                                       mock_name.c_str()),
+                          kBlockOffset);
+  text->AddLine("};");
+
+  parser.AddCloseNamespaces(text, false);
+  text->AddBlankLine();
+}
+
+// static
+void ProxyGenerator::AddConstructor(const ServiceConfig& config,
+                                    const Interface& interface,
+                                    const string& class_name,
+                                    IndentedText* text) {
+  IndentedText block;
+  vector<ParamDef> args{{"scoped_refptr<dbus::Bus>", "bus", true}};
+  if (config.service_name.empty())
+    args.emplace_back("std::string", "service_name", true);
+  if (interface.path.empty())
+    args.emplace_back("dbus::ObjectPath", "object_path", true);
+  if (!config.object_manager.name.empty() && !interface.properties.empty())
+    args.emplace_back("PropertySet", "property_set", false);
+
+  if (args.size() == 1) {
+    block.AddLine(StringPrintf("%s(%s) :", class_name.c_str(),
+                               GetParamString(args.front()).c_str()));
+  } else {
+    block.AddLine(StringPrintf("%s(", class_name.c_str()));
+    block.PushOffset(kLineContinuationOffset);
+    for (size_t i = 0; i < args.size() - 1; i++) {
+      block.AddLine(StringPrintf("%s,", GetParamString(args[i]).c_str()));
+    }
+    block.AddLine(StringPrintf("%s) :", GetParamString(args.back()).c_str()));
+  }
+  block.PushOffset(kLineContinuationOffset);
+  for (const auto& arg : args) {
+    block.AddLine(StringPrintf("%s_{%s},", arg.name.c_str(),
+                               arg.name.c_str()));
+  }
+  block.AddLine("dbus_object_proxy_{");
+  block.AddLineWithOffset(
+      "bus_->GetObjectProxy(service_name_, object_path_)} {",
+      kLineContinuationOffset);
+  block.PopOffset();
+  if (args.size() > 1)
+    block.PopOffset();
+  block.AddLine("}");
+  block.AddBlankLine();
+  text->AddBlock(block);
+}
+
+// static
+void ProxyGenerator::AddDestructor(const string& class_name,
+                                   IndentedText* text) {
+  IndentedText block;
+  block.AddLine(StringPrintf("~%s() override {", class_name.c_str()));
+  block.AddLine("}");
+  text->AddBlock(block);
+}
+
+// static
+void ProxyGenerator::AddReleaseObjectProxy(IndentedText* text) {
+  text->AddBlankLine();
+  text->AddLine("void ReleaseObjectProxy(const base::Closure& callback) {");
+  text->AddLineWithOffset(
+      "bus_->RemoveObjectProxy(service_name_, object_path_, callback);",
+      kBlockOffset);
+  text->AddLine("}");
+}
+
+// static
+void ProxyGenerator::AddGetObjectPath(IndentedText* text) {
+  text->AddBlankLine();
+  text->AddLine("const dbus::ObjectPath& GetObjectPath() const override {");
+  text->AddLineWithOffset("return object_path_;", kBlockOffset);
+  text->AddLine("}");
+}
+
+// static
+void ProxyGenerator::AddGetObjectProxy(IndentedText* text) {
+  text->AddBlankLine();
+  text->AddLine("dbus::ObjectProxy* GetObjectProxy() const { "
+                "return dbus_object_proxy_; }");
+}
+
+// static
+void ProxyGenerator::AddPropertyPublicMethods(const string& class_name,
+                                              bool declaration_only,
+                                              IndentedText* text) {
+  text->AddBlankLine();
+  text->AddLine(StringPrintf("%svoid SetPropertyChangedCallback(",
+                             declaration_only ? "virtual " : ""));
+  text->AddLineWithOffset(
+      StringPrintf("const base::Callback<void(%sInterface*, "
+                   "const std::string&)>& callback) %s",
+                   class_name.c_str(),
+                   declaration_only ? "= 0;" : "override {"),
+      kLineContinuationOffset);
+  if (!declaration_only) {
+    text->AddLineWithOffset("on_property_changed_ = callback;", kBlockOffset);
+    text->AddLine("}");
+    text->AddBlankLine();
+
+    text->AddLine(
+        "const PropertySet* GetProperties() const { return property_set_; }");
+    text->AddLine("PropertySet* GetProperties() { return property_set_; }");
+  }
+}
+
+// static
+void ProxyGenerator::AddOnPropertyChanged(IndentedText* text) {
+  text->AddLine("void OnPropertyChanged(const std::string& property_name) {");
+  text->PushOffset(kBlockOffset);
+  text->AddLine("if (!on_property_changed_.is_null())");
+  text->PushOffset(kBlockOffset);
+  text->AddLine("on_property_changed_.Run(this, property_name);");
+  text->PopOffset();
+  text->PopOffset();
+  text->AddLine("}");
+  text->AddBlankLine();
+}
+
+void ProxyGenerator::AddSignalHandlerRegistration(
+      const Interface::Signal& signal,
+      const string& interface_name,
+      bool declaration_only,
+      IndentedText* text) {
+  IndentedText block;
+  block.AddBlankLine();
+  block.AddLine(StringPrintf("%svoid Register%sSignalHandler(",
+                             declaration_only ? "virtual " : "",
+                             signal.name.c_str()));
+  block.PushOffset(kLineContinuationOffset);
+  AddSignalCallbackArg(signal, false, &block);
+  block.AddLine(StringPrintf(
+      "dbus::ObjectProxy::OnConnectedCallback on_connected_callback)%s",
+      declaration_only ? " = 0;" : " override {"));
+  if (!declaration_only) {
+    block.PopOffset();  // Method signature arguments
+    block.PushOffset(kBlockOffset);
+    block.AddLine("brillo::dbus_utils::ConnectToSignal(");
+    block.PushOffset(kLineContinuationOffset);
+    block.AddLine("dbus_object_proxy_,");
+    block.AddLine(StringPrintf("\"%s\",", interface_name.c_str()));
+    block.AddLine(StringPrintf("\"%s\",", signal.name.c_str()));
+    block.AddLine("signal_callback,");
+    block.AddLine("on_connected_callback);");
+    block.PopOffset();  // Function call line continuation
+    block.PopOffset();  // Method body
+    block.AddLine("}");
+  }
+  text->AddBlock(block);
+}
+
+// static
+void ProxyGenerator::AddPropertySet(const ServiceConfig& config,
+                                    const Interface& interface,
+                                    IndentedText* text) {
+  // Must have ObjectManager in order for property system to work correctly.
+  if (config.object_manager.name.empty())
+    return;
+
+  IndentedText block;
+  block.AddLine("class PropertySet : public dbus::PropertySet {");
+  block.AddLineWithOffset("public:", kScopeOffset);
+  block.PushOffset(kBlockOffset);
+  block.AddLineAndPushOffsetTo("PropertySet(dbus::ObjectProxy* object_proxy,",
+                               1, '(');
+  block.AddLine("const PropertyChangedCallback& callback)");
+  block.PopOffset();
+  block.PushOffset(kLineContinuationOffset);
+  block.AddLineAndPushOffsetTo(": dbus::PropertySet{object_proxy,", 1, '{');
+  block.AddLine(StringPrintf("\"%s\",", interface.name.c_str()));
+  block.AddLine("callback} {");
+  block.PopOffset();
+  block.PopOffset();
+  block.PushOffset(kBlockOffset);
+  for (const auto& prop : interface.properties) {
+    block.AddLine(
+        StringPrintf("RegisterProperty(%sName(), &%s);",
+                     prop.name.c_str(),
+                     NameParser{prop.name}.MakeVariableName().c_str()));
+  }
+  block.PopOffset();
+  block.AddLine("}");
+  block.AddBlankLine();
+
+  DbusSignature signature;
+  for (const auto& prop : interface.properties) {
+    string type;
+    CHECK(signature.Parse(prop.type, &type));
+    block.AddLine(
+        StringPrintf("brillo::dbus_utils::Property<%s> %s;",
+                     type.c_str(),
+                     NameParser{prop.name}.MakeVariableName().c_str()));
+  }
+  block.AddBlankLine();
+
+  block.PopOffset();
+  block.AddLineWithOffset("private:", kScopeOffset);
+  block.AddLineWithOffset("DISALLOW_COPY_AND_ASSIGN(PropertySet);",
+                          kBlockOffset);
+  block.AddLine("};");
+  block.AddBlankLine();
+
+  text->AddBlock(block);
+}
+
+// static
+void ProxyGenerator::AddProperties(const ServiceConfig& config,
+                                   const Interface& interface,
+                                   bool declaration_only,
+                                   IndentedText* text) {
+  // Must have ObjectManager in order for property system to work correctly.
+  if (config.object_manager.name.empty())
+    return;
+
+  if (declaration_only && !interface.properties.empty())
+    text->AddBlankLine();
+
+  DbusSignature signature;
+  for (const auto& prop : interface.properties) {
+    if (declaration_only) {
+      text->AddLine(
+          StringPrintf("static const char* %sName() { return \"%s\"; }",
+                       prop.name.c_str(),
+                       prop.name.c_str()));
+    }
+    string type;
+    CHECK(signature.Parse(prop.type, &type));
+    MakeConstReferenceIfNeeded(&type);
+    string name = NameParser{prop.name}.MakeVariableName();
+    if (!declaration_only)
+      text->AddBlankLine();
+    text->AddLine(
+        StringPrintf("%s%s %s() const%s",
+                     declaration_only ? "virtual " : "",
+                     type.c_str(),
+                     name.c_str(),
+                     declaration_only ? " = 0;" : " override {"));
+    if (!declaration_only) {
+      text->AddLineWithOffset(
+          StringPrintf("return property_set_->%s.value();", name.c_str()),
+          kBlockOffset);
+      text->AddLine("}");
+    }
+    if (prop.access == "readwrite") {
+      if (!declaration_only)
+        text->AddBlankLine();
+      text->AddLineAndPushOffsetTo(
+          StringPrintf("%svoid set_%s(%s value,",
+                       declaration_only ? "virtual " : "",
+                       name.c_str(),
+                       type.c_str()),
+          1, '(');
+      text->AddLine(
+          StringPrintf("const base::Callback<void(bool)>& callback)%s",
+                       declaration_only ? " = 0;" : " override {"));
+      text->PopOffset();
+      if (!declaration_only) {
+        text->AddLineWithOffset(
+            StringPrintf("property_set_->%s.Set(value, callback);", name.c_str()),
+            kBlockOffset);
+        text->AddLine("}");
+      }
+    }
+  }
+}
+
+// static
+void ProxyGenerator::AddMethodProxy(const Interface::Method& method,
+                                    const string& interface_name,
+                                    bool declaration_only,
+                                    IndentedText* text) {
+  IndentedText block;
+  DbusSignature signature;
+  block.AddBlankLine();
+  block.AddComments(method.doc_string);
+  block.AddLine(StringPrintf("%sbool %s(",
+                             declaration_only ? "virtual " : "",
+                             method.name.c_str()));
+  block.PushOffset(kLineContinuationOffset);
+  vector<string> argument_names;
+  int argument_number = 0;
+  for (const auto& argument : method.input_arguments) {
+    string argument_type;
+    CHECK(signature.Parse(argument.type, &argument_type));
+    MakeConstReferenceIfNeeded(&argument_type);
+    string argument_name = GetArgName("in", argument.name, ++argument_number);
+    argument_names.push_back(argument_name);
+    block.AddLine(StringPrintf(
+        "%s %s,", argument_type.c_str(), argument_name.c_str()));
+  }
+  vector<string> out_param_names{"response.get()", "error"};
+  for (const auto& argument : method.output_arguments) {
+    string argument_type;
+    CHECK(signature.Parse(argument.type, &argument_type));
+    string argument_name = GetArgName("out", argument.name, ++argument_number);
+    out_param_names.push_back(argument_name);
+    block.AddLine(StringPrintf(
+        "%s* %s,", argument_type.c_str(), argument_name.c_str()));
+  }
+  block.AddLine("brillo::ErrorPtr* error,");
+  block.AddLine(
+      StringPrintf("int timeout_ms = dbus::ObjectProxy::TIMEOUT_USE_DEFAULT)%s",
+                   declaration_only ? " = 0;" : " override {"));
+  block.PopOffset();
+  if (!declaration_only) {
+    block.PushOffset(kBlockOffset);
+
+    block.AddLine(
+        "auto response = brillo::dbus_utils::CallMethodAndBlockWithTimeout(");
+    block.PushOffset(kLineContinuationOffset);
+    block.AddLine("timeout_ms,");
+    block.AddLine("dbus_object_proxy_,");
+    block.AddLine(StringPrintf("\"%s\",", interface_name.c_str()));
+    block.AddLine(StringPrintf("\"%s\",", method.name.c_str()));
+    string last_argument = "error";
+    for (const auto& argument_name : argument_names) {
+      block.AddLine(StringPrintf("%s,", last_argument.c_str()));
+      last_argument = argument_name;
+    }
+    block.AddLine(StringPrintf("%s);", last_argument.c_str()));
+    block.PopOffset();
+
+    block.AddLine("return response && "
+                  "brillo::dbus_utils::ExtractMethodCallResults(");
+    block.PushOffset(kLineContinuationOffset);
+    block.AddLine(brillo::string_utils::Join(", ", out_param_names) + ");");
+    block.PopOffset();
+    block.PopOffset();
+    block.AddLine("}");
+  }
+  text->AddBlock(block);
+}
+
+// static
+void ProxyGenerator::AddAsyncMethodProxy(const Interface::Method& method,
+                                         const string& interface_name,
+                                         bool declaration_only,
+                                         IndentedText* text) {
+  IndentedText block;
+  DbusSignature signature;
+  block.AddBlankLine();
+  block.AddComments(method.doc_string);
+  block.AddLine(StringPrintf("%svoid %sAsync(",
+                             declaration_only ? "virtual " : "",
+                             method.name.c_str()));
+  block.PushOffset(kLineContinuationOffset);
+  vector<string> argument_names;
+  int argument_number = 0;
+  for (const auto& argument : method.input_arguments) {
+    string argument_type;
+    CHECK(signature.Parse(argument.type, &argument_type));
+    MakeConstReferenceIfNeeded(&argument_type);
+    string argument_name = GetArgName("in", argument.name, ++argument_number);
+    argument_names.push_back(argument_name);
+    block.AddLine(StringPrintf(
+        "%s %s,", argument_type.c_str(), argument_name.c_str()));
+  }
+  vector<string> out_params;
+  for (const auto& argument : method.output_arguments) {
+    string argument_type;
+    CHECK(signature.Parse(argument.type, &argument_type));
+    MakeConstReferenceIfNeeded(&argument_type);
+    if (!argument.name.empty())
+      base::StringAppendF(&argument_type, " /*%s*/", argument.name.c_str());
+    out_params.push_back(argument_type);
+  }
+  block.AddLine(StringPrintf(
+      "const base::Callback<void(%s)>& success_callback,",
+      brillo::string_utils::Join(", ", out_params).c_str()));
+  block.AddLine(
+      "const base::Callback<void(brillo::Error*)>& error_callback,");
+  block.AddLine(
+      StringPrintf("int timeout_ms = dbus::ObjectProxy::TIMEOUT_USE_DEFAULT)%s",
+                   declaration_only ? " = 0;" : " override {"));
+  block.PopOffset();
+  if (!declaration_only) {
+    block.PushOffset(kBlockOffset);
+
+    block.AddLine("brillo::dbus_utils::CallMethodWithTimeout(");
+    block.PushOffset(kLineContinuationOffset);
+    block.AddLine("timeout_ms,");
+    block.AddLine("dbus_object_proxy_,");
+    block.AddLine(StringPrintf("\"%s\",", interface_name.c_str()));
+    block.AddLine(StringPrintf("\"%s\",", method.name.c_str()));
+    block.AddLine("success_callback,");
+    string last_argument = "error_callback";
+    for (const auto& argument_name : argument_names) {
+      block.AddLine(StringPrintf("%s,", last_argument.c_str()));
+      last_argument = argument_name;
+    }
+    block.AddLine(StringPrintf("%s);", last_argument.c_str()));
+    block.PopOffset();
+
+    block.PopOffset();
+    block.AddLine("}");
+  }
+  text->AddBlock(block);
+}
+
+// static
+void ProxyGenerator::AddMethodMock(const Interface::Method& method,
+                                   const string& /* interface_name */,
+                                   IndentedText* text) {
+  DbusSignature signature;
+  vector<string> arguments;
+  for (const auto& argument : method.input_arguments) {
+    string argument_type;
+    CHECK(signature.Parse(argument.type, &argument_type));
+    MakeConstReferenceIfNeeded(&argument_type);
+    if (!argument.name.empty())
+      base::StringAppendF(&argument_type, " /*in_%s*/", argument.name.c_str());
+    arguments.push_back(argument_type);
+  }
+  for (const auto& argument : method.output_arguments) {
+    string argument_type;
+    CHECK(signature.Parse(argument.type, &argument_type));
+    argument_type += '*';
+    if (!argument.name.empty())
+      base::StringAppendF(&argument_type, " /*out_%s*/", argument.name.c_str());
+    arguments.push_back(argument_type);
+  }
+  arguments.push_back("brillo::ErrorPtr* /*error*/");
+  arguments.push_back("int /*timeout_ms*/");
+  AddMockMethodDeclaration(method.name, "bool", arguments, text);
+}
+
+// static
+void ProxyGenerator::AddAsyncMethodMock(const Interface::Method& method,
+                                        const string& /* interface_name */,
+                                        IndentedText* text) {
+  DbusSignature signature;
+  vector<string> arguments;
+  for (const auto& argument : method.input_arguments) {
+    string argument_type;
+    CHECK(signature.Parse(argument.type, &argument_type));
+    MakeConstReferenceIfNeeded(&argument_type);
+    if (!argument.name.empty())
+      base::StringAppendF(&argument_type, " /*in_%s*/", argument.name.c_str());
+    arguments.push_back(argument_type);
+  }
+  vector<string> out_params;
+  for (const auto& argument : method.output_arguments) {
+    string argument_type;
+    CHECK(signature.Parse(argument.type, &argument_type));
+    MakeConstReferenceIfNeeded(&argument_type);
+    if (!argument.name.empty())
+      base::StringAppendF(&argument_type, " /*%s*/", argument.name.c_str());
+    out_params.push_back(argument_type);
+  }
+  arguments.push_back(StringPrintf(
+      "const base::Callback<void(%s)>& /*success_callback*/",
+      brillo::string_utils::Join(", ", out_params).c_str()));
+  arguments.push_back(
+      "const base::Callback<void(brillo::Error*)>& /*error_callback*/");
+  arguments.push_back("int /*timeout_ms*/");
+  AddMockMethodDeclaration(method.name + "Async", "void", arguments, text);
+}
+
+void ProxyGenerator::AddMockMethodDeclaration(const string& method_name,
+                                              const string& return_type,
+                                              const vector<string>& arguments,
+                                              IndentedText* text) {
+  IndentedText block;
+  // GMOCK doesn't go all the way up to 11, so we need to handle methods with
+  // 11 arguments or more in a different way.
+  if (arguments.size() >= 11) {
+    block.AddLineAndPushOffsetTo(
+        StringPrintf("%s %s(%s,",
+                     return_type.c_str(),
+                     method_name.c_str(),
+                     arguments.front().c_str()),
+        1, '(');
+    for (size_t i = 1; i < arguments.size() - 1; i++)
+      block.AddLine(StringPrintf("%s,", arguments[i].c_str()));
+    block.AddLine(StringPrintf("%s) override {", arguments.back().c_str()));
+    block.PopOffset();
+    block.PushOffset(kBlockOffset);
+    block.AddLine(StringPrintf(
+        "LOG(WARNING) << \"%s(): gmock can't handle methods with %" PRIuS
+        " arguments. You can override this method in a subclass if you need"
+        " to.\";",
+        method_name.c_str(), arguments.size()));
+    if (return_type == "void") {
+      // No return added here.
+    } else if (return_type == "bool") {
+      block.AddLine("return false;");
+    } else {
+      LOG(FATAL) << "The return type is not supported.";
+    }
+    block.PopOffset();
+    block.AddLine("}");
+  } else {
+    block.AddLineAndPushOffsetTo(
+        StringPrintf("MOCK_METHOD%zu(%s,",
+                     arguments.size(), method_name.c_str()),
+        1, '(');
+    block.AddLineAndPushOffsetTo(
+        StringPrintf("%s(%s,", return_type.c_str(), arguments.front().c_str()),
+        1, '(');
+    for (size_t i = 1; i < arguments.size() - 1; i++)
+      block.AddLine(StringPrintf("%s,", arguments[i].c_str()));
+    block.AddLine(StringPrintf("%s));", arguments.back().c_str()));
+    block.PopOffset();
+    block.PopOffset();
+  }
+  text->AddBlock(block);
+}
+
+// static
+void ProxyGenerator::AddSignalHandlerRegistrationMock(
+    const Interface::Signal& signal,
+    IndentedText* text) {
+  IndentedText callback_arg_text;
+  AddSignalCallbackArg(signal, true, &callback_arg_text);
+  vector<string> arg_lines = callback_arg_text.GetLines();
+
+  IndentedText block;
+  block.AddLineAndPushOffsetTo(
+      StringPrintf("MOCK_METHOD2(Register%sSignalHandler,",
+                   signal.name.c_str()),
+      1, '(');
+  for (size_t i = 0; i < arg_lines.size(); ++i) {
+    if (i == 0)
+      block.AddLineAndPushOffsetTo("void(" + arg_lines[i], 1, '(');
+    else
+      block.AddLine(arg_lines[i]);
+  }
+  block.AddLine(
+      "dbus::ObjectProxy::OnConnectedCallback /*on_connected_callback*/));");
+  text->AddBlock(block);
+}
+
+// static
+void ProxyGenerator::AddSignalCallbackArg(const Interface::Signal& signal,
+                                          bool comment_arg_name,
+                                          IndentedText* block) {
+  DbusSignature signature;
+  string signal_callback = StringPrintf("%ssignal_callback%s",
+                                        comment_arg_name ? "/*" : "",
+                                        comment_arg_name ? "*/" : "");
+  if (signal.arguments.empty()) {
+    block->AddLine(StringPrintf("const base::Closure& %s,",
+                                signal_callback.c_str()));
+  } else {
+    string last_argument;
+    string prefix{"const base::Callback<void("};
+    for (const auto argument : signal.arguments) {
+      if (!last_argument.empty()) {
+        if (!prefix.empty()) {
+          block->AddLineAndPushOffsetTo(
+              StringPrintf("%s%s,", prefix.c_str(), last_argument.c_str()),
+              1, '(');
+          prefix.clear();
+        } else {
+          block->AddLine(StringPrintf("%s,", last_argument.c_str()));
+        }
+      }
+      CHECK(signature.Parse(argument.type, &last_argument));
+      MakeConstReferenceIfNeeded(&last_argument);
+    }
+    block->AddLine(StringPrintf("%s%s)>& %s,",
+                                prefix.c_str(),
+                                last_argument.c_str(),
+                                signal_callback.c_str()));
+    if (prefix.empty()) {
+      block->PopOffset();
+    }
+  }
+}
+
+// static
+void ProxyGenerator::ObjectManager::GenerateProxy(
+    const ServiceConfig& config,
+    const std::vector<Interface>& interfaces,
+    IndentedText* text) {
+  if (config.object_manager.name.empty())
+    return;
+
+  NameParser object_manager{config.object_manager.name};
+  object_manager.AddOpenNamespaces(text, false);
+  text->AddBlankLine();
+
+  string class_name = object_manager.type_name + "Proxy";
+  text->AddLine(StringPrintf("class %s : "
+                             "public dbus::ObjectManager::Interface {",
+                             class_name.c_str()));
+  text->AddLineWithOffset("public:", kScopeOffset);
+  text->PushOffset(kBlockOffset);
+
+  AddConstructor(config, class_name, interfaces, text);
+  AddDestructor(class_name, interfaces, text);
+  AddGetObjectManagerProxy(text);
+  for (const auto& itf : interfaces) {
+    AddInterfaceAccessors(itf, text);
+  }
+  text->PopOffset();
+
+  text->AddLineWithOffset("private:", kScopeOffset);
+  text->PushOffset(kBlockOffset);
+  AddOnPropertyChanged(interfaces, text);
+  AddObjectAdded(config, interfaces, text);
+  AddObjectRemoved(interfaces, text);
+  AddCreateProperties(interfaces, class_name, text);
+  AddDataMembers(config, interfaces, class_name, text);
+
+  text->AddLine(StringPrintf("DISALLOW_COPY_AND_ASSIGN(%s);",
+                              class_name.c_str()));
+  text->PopOffset();
+  text->AddLine("};");
+  text->AddBlankLine();
+  object_manager.AddCloseNamespaces(text, false);
+  text->AddBlankLine();
+}
+
+void ProxyGenerator::ObjectManager::AddConstructor(
+    const ServiceConfig& config,
+    const std::string& class_name,
+    const std::vector<Interface>& interfaces,
+    IndentedText* text) {
+  if (config.service_name.empty()) {
+    text->AddLineAndPushOffsetTo(
+        StringPrintf("%s(const scoped_refptr<dbus::Bus>& bus,",
+                     class_name.c_str()),
+        1, '(');
+    text->AddLine("const std::string& service_name)");
+    text->PopOffset();
+  } else {
+    text->AddLine(StringPrintf("%s(const scoped_refptr<dbus::Bus>& bus)",
+                               class_name.c_str()));
+  }
+  text->PushOffset(kLineContinuationOffset);
+  text->AddLine(": bus_{bus},");
+  text->PushOffset(kBlockOffset);
+  if (config.service_name.empty()) {
+    text->AddLine("service_name_{service_name},");
+  }
+  text->AddLine("dbus_object_manager_{bus->GetObjectManager(");
+  text->PushOffset(kLineContinuationOffset);
+  if (config.service_name.empty()) {
+    text->AddLine("service_name,");
+  } else {
+    text->AddLine(StringPrintf("\"%s\",", config.service_name.c_str()));
+  }
+  text->AddLine(StringPrintf("dbus::ObjectPath{\"%s\"})} {",
+                             config.object_manager.object_path.c_str()));
+  text->PopOffset();
+  text->PopOffset();
+  text->PopOffset();
+  text->PushOffset(kBlockOffset);
+  for (const auto& itf : interfaces) {
+    text->AddLine(
+        StringPrintf("dbus_object_manager_->RegisterInterface(\"%s\", this);",
+                     itf.name.c_str()));
+  }
+  text->PopOffset();
+  text->AddLine("}");
+  text->AddBlankLine();
+}
+
+void ProxyGenerator::ObjectManager::AddDestructor(
+    const std::string& class_name,
+    const std::vector<Interface>& interfaces,
+    IndentedText* text) {
+  text->AddLine(StringPrintf("~%s() override {", class_name.c_str()));
+  text->PushOffset(kBlockOffset);
+  for (const auto& itf : interfaces) {
+    text->AddLine(
+        StringPrintf("dbus_object_manager_->UnregisterInterface(\"%s\");",
+                     itf.name.c_str()));
+  }
+  text->PopOffset();
+  text->AddLine("}");
+  text->AddBlankLine();
+}
+
+void ProxyGenerator::ObjectManager::AddGetObjectManagerProxy(
+    IndentedText* text) {
+  text->AddLine("dbus::ObjectManager* GetObjectManagerProxy() const {");
+  text->AddLineWithOffset("return dbus_object_manager_;", kBlockOffset);
+  text->AddLine("}");
+  text->AddBlankLine();
+}
+
+void ProxyGenerator::ObjectManager::AddInterfaceAccessors(
+    const Interface& interface,
+    IndentedText* text) {
+  NameParser itf_name{interface.name};
+  string map_name = itf_name.MakeVariableName() + "_instances_";
+
+  // GetProxy().
+  if (interface.path.empty()) {
+    // We have no fixed path, so there could be multiple instances of this itf.
+    text->AddLine(StringPrintf("%sInterface* Get%s(",
+                                itf_name.MakeProxyName(true).c_str(),
+                                itf_name.MakeProxyName(false).c_str()));
+    text->PushOffset(kLineContinuationOffset);
+    text->AddLine("const dbus::ObjectPath& object_path) {");
+    text->PopOffset();
+    text->PushOffset(kBlockOffset);
+    text->AddLine(StringPrintf("auto p = %s.find(object_path);",
+                                map_name.c_str()));
+    text->AddLine(StringPrintf("if (p != %s.end())", map_name.c_str()));
+    text->PushOffset(kBlockOffset);
+    text->AddLine("return p->second.get();");
+    text->PopOffset();
+    text->AddLine("return nullptr;");
+    text->PopOffset();
+    text->AddLine("}");
+  } else {
+    // We have a fixed path, so the object could be considered a "singleton".
+    // Skip the object_path parameter and return the first available instance.
+    text->AddLine(StringPrintf("%sInterface* Get%s() {",
+                                itf_name.MakeProxyName(true).c_str(),
+                                itf_name.MakeProxyName(false).c_str()));
+    text->PushOffset(kBlockOffset);
+    text->AddLine(StringPrintf("if (%s.empty())", map_name.c_str()));
+    text->AddLineWithOffset("return nullptr;", kBlockOffset);
+    text->AddLine(StringPrintf("return %s.begin()->second.get();",
+                               map_name.c_str()));
+    text->PopOffset();
+    text->AddLine("}");
+  }
+
+  // GetInstances().
+  text->AddLine(
+      StringPrintf("std::vector<%sInterface*> Get%sInstances() const {",
+                   itf_name.MakeProxyName(true).c_str(),
+                   itf_name.type_name.c_str()));
+  text->PushOffset(kBlockOffset);
+  text->AddLine(StringPrintf("std::vector<%sInterface*> values;",
+                             itf_name.MakeProxyName(true).c_str()));
+  text->AddLine(StringPrintf("values.reserve(%s.size());", map_name.c_str()));
+  text->AddLine(StringPrintf("for (const auto& pair : %s)", map_name.c_str()));
+  text->AddLineWithOffset("values.push_back(pair.second.get());", kBlockOffset);
+  text->AddLine("return values;");
+  text->PopOffset();
+  text->AddLine("}");
+
+  // SetAddedCallback().
+  text->AddLine(StringPrintf("void Set%sAddedCallback(",
+                              itf_name.type_name.c_str()));
+  text->PushOffset(kLineContinuationOffset);
+  text->AddLine(
+      StringPrintf("const base::Callback<void(%sInterface*)>& callback) {",
+                   itf_name.MakeProxyName(true).c_str()));
+  text->PopOffset();
+  text->PushOffset(kBlockOffset);
+  text->AddLine(StringPrintf("on_%s_added_ = callback;",
+                             itf_name.MakeVariableName().c_str()));
+  text->PopOffset();
+  text->AddLine("}");
+
+  // SetRemovedCallback().
+  text->AddLine(StringPrintf("void Set%sRemovedCallback(",
+                             itf_name.type_name.c_str()));
+  text->PushOffset(kLineContinuationOffset);
+  text->AddLine("const base::Callback<void(const dbus::ObjectPath&)>& "
+                "callback) {");
+  text->PopOffset();
+  text->PushOffset(kBlockOffset);
+  text->AddLine(StringPrintf("on_%s_removed_ = callback;",
+                              itf_name.MakeVariableName().c_str()));
+  text->PopOffset();
+  text->AddLine("}");
+
+  text->AddBlankLine();
+}
+
+void ProxyGenerator::ObjectManager::AddOnPropertyChanged(
+    const std::vector<Interface>& interfaces,
+    IndentedText* text) {
+  // If there are no interfaces with properties, comment out parameter
+  // names for OnPropertyChanged() to prevent compiler warnings on unused
+  // function parameters.
+  auto has_props = [](const Interface& itf) { return !itf.properties.empty(); };
+  auto itf_with_props = std::find_if(interfaces.begin(), interfaces.end(),
+                                     has_props);
+  if (itf_with_props == interfaces.end()) {
+    text->AddLineAndPushOffsetTo("void OnPropertyChanged("
+                                 "const dbus::ObjectPath& /* object_path */,",
+                                 1, '(');
+    text->AddLine("const std::string& /* interface_name */,");
+    text->AddLine("const std::string& /* property_name */) {}");
+    text->PopOffset();
+    text->AddBlankLine();
+    return;
+  }
+  text->AddLineAndPushOffsetTo("void OnPropertyChanged("
+                               "const dbus::ObjectPath& object_path,",
+                               1, '(');
+  text->AddLine("const std::string& interface_name,");
+  text->AddLine("const std::string& property_name) {");
+  text->PopOffset();
+  text->PushOffset(kBlockOffset);
+  for (const auto& itf : interfaces) {
+    if (itf.properties.empty())
+      continue;
+
+    NameParser itf_name{itf.name};
+    text->AddLine(StringPrintf("if (interface_name == \"%s\") {",
+                               itf.name.c_str()));
+    text->PushOffset(kBlockOffset);
+    string map_name = itf_name.MakeVariableName() + "_instances_";
+    text->AddLine(StringPrintf("auto p = %s.find(object_path);",
+                               map_name.c_str()));
+    text->AddLine(StringPrintf("if (p == %s.end())", map_name.c_str()));
+    text->PushOffset(kBlockOffset);
+    text->AddLine("return;");
+    text->PopOffset();
+    text->AddLine("p->second->OnPropertyChanged(property_name);");
+    text->AddLine("return;");
+    text->PopOffset();
+    text->AddLine("}");
+  }
+  text->PopOffset();
+  text->AddLine("}");
+  text->AddBlankLine();
+}
+
+void ProxyGenerator::ObjectManager::AddObjectAdded(
+    const ServiceConfig& config,
+    const std::vector<Interface>& interfaces,
+    IndentedText* text) {
+  text->AddLine("void ObjectAdded(");
+  text->PushOffset(kLineContinuationOffset);
+  text->AddLine("const dbus::ObjectPath& object_path,");
+  text->AddLine("const std::string& interface_name) override {");
+  text->PopOffset();
+  text->PushOffset(kBlockOffset);
+  for (const auto& itf : interfaces) {
+    NameParser itf_name{itf.name};
+    string var_name = itf_name.MakeVariableName();
+    text->AddLine(StringPrintf("if (interface_name == \"%s\") {",
+                               itf.name.c_str()));
+    text->PushOffset(kBlockOffset);
+    if (!itf.properties.empty()) {
+      text->AddLine("auto property_set =");
+      text->PushOffset(kLineContinuationOffset);
+      text->AddLine(StringPrintf("static_cast<%s::PropertySet*>(",
+                                 itf_name.MakeProxyName(true).c_str()));
+      text->PushOffset(kLineContinuationOffset);
+      text->AddLine("dbus_object_manager_->GetProperties(object_path, "
+                    "interface_name));");
+      text->PopOffset();
+      text->PopOffset();
+    }
+    text->AddLine(StringPrintf("std::unique_ptr<%s> %s_proxy{",
+                               itf_name.MakeProxyName(true).c_str(),
+                               var_name.c_str()));
+    text->PushOffset(kBlockOffset);
+    string new_instance = StringPrintf("new %s{bus_",
+                                       itf_name.MakeProxyName(true).c_str());
+    if (config.service_name.empty()) {
+      new_instance += ", service_name_";
+    }
+    if (itf.path.empty())
+      new_instance += ", object_path";
+    if (!itf.properties.empty())
+      new_instance += ", property_set";
+    new_instance += "}";
+    text->AddLine(new_instance);
+    text->PopOffset();
+    text->AddLine("};");
+    text->AddLine(StringPrintf("auto p = %s_instances_.emplace(object_path, "
+                               "std::move(%s_proxy));",
+                               var_name.c_str(), var_name.c_str()));
+    text->AddLine(StringPrintf("if (!on_%s_added_.is_null())",
+                               var_name.c_str()));
+    text->PushOffset(kBlockOffset);
+    text->AddLine(StringPrintf("on_%s_added_.Run(p.first->second.get());",
+                               var_name.c_str()));
+    text->PopOffset();
+    text->AddLine("return;");
+    text->PopOffset();
+    text->AddLine("}");
+  }
+  text->PopOffset();
+  text->AddLine("}");
+  text->AddBlankLine();
+}
+
+void ProxyGenerator::ObjectManager::AddObjectRemoved(
+    const std::vector<Interface>& interfaces,
+    IndentedText* text) {
+  text->AddLine("void ObjectRemoved(");
+  text->PushOffset(kLineContinuationOffset);
+  text->AddLine("const dbus::ObjectPath& object_path,");
+  text->AddLine("const std::string& interface_name) override {");
+  text->PopOffset();
+  text->PushOffset(kBlockOffset);
+  for (const auto& itf : interfaces) {
+    NameParser itf_name{itf.name};
+    string var_name = itf_name.MakeVariableName();
+    text->AddLine(StringPrintf("if (interface_name == \"%s\") {",
+                               itf.name.c_str()));
+    text->PushOffset(kBlockOffset);
+    text->AddLine(StringPrintf("auto p = %s_instances_.find(object_path);",
+                               var_name.c_str()));
+    text->AddLine(StringPrintf("if (p != %s_instances_.end()) {",
+                               var_name.c_str()));
+    text->PushOffset(kBlockOffset);
+    text->AddLine(StringPrintf("if (!on_%s_removed_.is_null())",
+                               var_name.c_str()));
+    text->PushOffset(kBlockOffset);
+    text->AddLine(StringPrintf("on_%s_removed_.Run(object_path);",
+                               var_name.c_str()));
+    text->PopOffset();
+    text->AddLine(StringPrintf("%s_instances_.erase(p);",
+                               var_name.c_str()));
+    text->PopOffset();
+    text->AddLine("}");
+    text->AddLine("return;");
+    text->PopOffset();
+    text->AddLine("}");
+  }
+  text->PopOffset();
+  text->AddLine("}");
+  text->AddBlankLine();
+}
+
+void ProxyGenerator::ObjectManager::AddCreateProperties(
+    const std::vector<Interface>& interfaces,
+    const std::string& class_name,
+    IndentedText* text) {
+  text->AddLine("dbus::PropertySet* CreateProperties(");
+  text->PushOffset(kLineContinuationOffset);
+  text->AddLine("dbus::ObjectProxy* object_proxy,");
+  text->AddLine("const dbus::ObjectPath& object_path,");
+  text->AddLine("const std::string& interface_name) override {");
+  text->PopOffset();
+  text->PushOffset(kBlockOffset);
+  for (const auto& itf : interfaces) {
+    NameParser itf_name{itf.name};
+    text->AddLine(StringPrintf("if (interface_name == \"%s\") {",
+                               itf.name.c_str()));
+    text->PushOffset(kBlockOffset);
+    text->AddLine(StringPrintf("return new %s::PropertySet{",
+                               itf_name.MakeProxyName(true).c_str()));
+    text->PushOffset(kLineContinuationOffset);
+    text->AddLine("object_proxy,");
+    text->AddLineAndPushOffsetTo(
+        StringPrintf("base::Bind(&%s::OnPropertyChanged,",
+                     class_name.c_str()),
+        1, '(');
+    text->AddLine("weak_ptr_factory_.GetWeakPtr(),");
+    text->AddLine("object_path,");
+    text->AddLine("interface_name)");
+    text->PopOffset();
+    text->PopOffset();
+    text->AddLine("};");
+    text->PopOffset();
+    text->AddLine("}");
+  }
+  text->AddLineAndPushOffsetTo("LOG(FATAL) << \"Creating properties for "
+                               "unsupported interface \"", 1, ' ');
+  text->AddLine("<< interface_name;");
+  text->PopOffset();
+  text->AddLine("return nullptr;");
+  text->PopOffset();
+  text->AddLine("}");
+  text->AddBlankLine();
+}
+
+void ProxyGenerator::ObjectManager::AddDataMembers(
+    const ServiceConfig& config,
+    const std::vector<Interface>& interfaces,
+    const std::string& class_name,
+    IndentedText* text) {
+  text->AddLine("scoped_refptr<dbus::Bus> bus_;");
+  if (config.service_name.empty()) {
+    text->AddLine("std::string service_name_;");
+  }
+  text->AddLine("dbus::ObjectManager* dbus_object_manager_;");
+  for (const auto& itf : interfaces) {
+    NameParser itf_name{itf.name};
+    string var_name = itf_name.MakeVariableName();
+    text->AddLineAndPushOffsetTo("std::map<dbus::ObjectPath,", 1, '<');
+    text->AddLine(StringPrintf("std::unique_ptr<%s>> %s_instances_;",
+                               itf_name.MakeProxyName(true).c_str(),
+                               var_name.c_str()));
+    text->PopOffset();
+    text->AddLine(
+        StringPrintf("base::Callback<void(%sInterface*)> on_%s_added_;",
+                     itf_name.MakeProxyName(true).c_str(),
+                     var_name.c_str()));
+    text->AddLine(StringPrintf("base::Callback<void(const dbus::ObjectPath&)> "
+                               "on_%s_removed_;",
+                               var_name.c_str()));
+  }
+  text->AddLine(
+      StringPrintf("base::WeakPtrFactory<%s> weak_ptr_factory_{this};",
+                   class_name.c_str()));
+  text->AddBlankLine();
+}
+
+// static
+string ProxyGenerator::GetHandlerNameForSignal(const string& signal) {
+  return StringPrintf("On%sSignal", signal.c_str());
+}
+
+}  // namespace chromeos_dbus_bindings
diff --git a/dbus-binding-generator/chromeos-dbus-bindings/proxy_generator.h b/dbus-binding-generator/chromeos-dbus-bindings/proxy_generator.h
new file mode 100644
index 0000000..57af0e0
--- /dev/null
+++ b/dbus-binding-generator/chromeos-dbus-bindings/proxy_generator.h
@@ -0,0 +1,198 @@
+// Copyright 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMEOS_DBUS_BINDINGS_PROXY_GENERATOR_H_
+#define CHROMEOS_DBUS_BINDINGS_PROXY_GENERATOR_H_
+
+#include <string>
+#include <vector>
+
+#include <base/macros.h>
+
+#include "chromeos-dbus-bindings/header_generator.h"
+#include "chromeos-dbus-bindings/indented_text.h"
+#include "chromeos-dbus-bindings/interface.h"
+
+namespace base {
+
+class FilePath;
+
+}  // namespace base
+
+namespace chromeos_dbus_bindings {
+
+class IndentedText;
+struct Interface;
+
+class ProxyGenerator : public HeaderGenerator {
+ public:
+  static bool GenerateProxies(const ServiceConfig& config,
+                              const std::vector<Interface>& interfaces,
+                              const base::FilePath& output_file);
+
+  static bool GenerateMocks(const ServiceConfig& config,
+                            const std::vector<Interface>& interfaces,
+                            const base::FilePath& mock_file,
+                            const base::FilePath& proxy_file,
+                            bool use_literal_proxy_file);
+
+ private:
+  friend class ProxyGeneratorTest;
+
+  // Generates an abstract interface for one D-Bus interface proxy.
+  static void GenerateInterfaceProxyInterface(const ServiceConfig& config,
+                                              const Interface& interface,
+                                              IndentedText* text);
+
+  // Generates one interface proxy.
+  static void GenerateInterfaceProxy(const ServiceConfig& config,
+                                     const Interface& interface,
+                                     IndentedText* text);
+
+  // Generates one interface mock object.
+  static void GenerateInterfaceMock(const ServiceConfig& config,
+                                    const Interface& interface,
+                                    IndentedText* text);
+
+  // Generates the constructor and destructor for the proxy.
+  static void AddConstructor(const ServiceConfig& config,
+                             const Interface& interface,
+                             const std::string& class_name,
+                             IndentedText* text);
+  static void AddDestructor(const std::string& class_name,
+                            IndentedText* text);
+
+  // Generates ReleaseObjectProxy() method to release ownership
+  // of the object proxy.
+  static void AddReleaseObjectProxy(IndentedText* text);
+
+  // Generates AddGetObjectPath() method.
+  static void AddGetObjectPath(IndentedText* text);
+
+  // Generates GetObjectProxy() method.
+  static void AddGetObjectProxy(IndentedText* text);
+
+  // Generates SetPropertyChangedCallback/GetProperties() methods.
+  static void AddPropertyPublicMethods(const std::string& class_name,
+                                       bool declaration_only,
+                                       IndentedText* text);
+
+  // Generates OnPropertyChanged() method.
+  static void AddOnPropertyChanged(IndentedText* text);
+
+  // Generates logic permitting users to register handlers for signals.
+  static void AddSignalHandlerRegistration(const Interface::Signal& signal,
+                                           const std::string& interface_name,
+                                           bool declaration_only,
+                                           IndentedText* text);
+
+  // Generates the property set class to contain interface properties.
+  static void AddPropertySet(const ServiceConfig& config,
+                             const Interface& interface,
+                             IndentedText* text);
+
+  // Generates the property accessors.
+  static void AddProperties(const ServiceConfig& config,
+                            const Interface& interface,
+                            bool declaration_only,
+                            IndentedText* text);
+
+  // Generates a native C++ method which calls a D-Bus method on the proxy.
+  static void AddMethodProxy(const Interface::Method& interface,
+                             const std::string& interface_name,
+                             bool declaration_only,
+                             IndentedText* text);
+
+  // Generates a native C++ method which calls a D-Bus method asynchronously.
+  static void AddAsyncMethodProxy(const Interface::Method& interface,
+                                  const std::string& interface_name,
+                                  bool declaration_only,
+                                  IndentedText* text);
+
+  // Generates a mock for blocking D-Bus method.
+  static void AddMethodMock(const Interface::Method& interface,
+                            const std::string& interface_name,
+                            IndentedText* text);
+
+  // Generates a mock for asynchronous D-Bus method.
+  static void AddAsyncMethodMock(const Interface::Method& interface,
+                                 const std::string& interface_name,
+                                 IndentedText* text);
+
+  // Generates the MOCK_METHOD entry for the given arguments handling methods
+  // with more than 10 arguments.
+  static void AddMockMethodDeclaration(
+      const std::string& method_name,
+      const std::string& return_type,
+      const std::vector<std::string>& arguments,
+      IndentedText* text);
+
+  // Generates a mock for the signal handler registration method.
+  static void AddSignalHandlerRegistrationMock(
+      const Interface::Signal& signal,
+      IndentedText* text);
+
+  // Generate the signal callback argument of a signal handler.
+  static void AddSignalCallbackArg(const Interface::Signal& signal,
+                                   bool comment_arg_name,
+                                   IndentedText* block);
+
+  // Generates the Object Manager proxy class.
+  struct ObjectManager {
+    // Generates the top-level class for Object Manager proxy.
+    static void GenerateProxy(const ServiceConfig& config,
+                              const std::vector<Interface>& interfaces,
+                              IndentedText* text);
+
+    // Generates Object Manager constructor.
+    static void AddConstructor(const ServiceConfig& config,
+                               const std::string& class_name,
+                               const std::vector<Interface>& interfaces,
+                               IndentedText* text);
+
+    // Generates Object Manager destructor.
+    static void AddDestructor(const std::string& class_name,
+                              const std::vector<Interface>& interfaces,
+                              IndentedText* text);
+
+    // Generates GetObjectManagerProxy() method.
+    static void AddGetObjectManagerProxy(IndentedText* text);
+
+    // Generates code for interface-specific accessor methods
+    static void AddInterfaceAccessors(const Interface& interface,
+                                      IndentedText* text);
+
+    // Generates OnPropertyChanged() method.
+    static void AddOnPropertyChanged(const std::vector<Interface>& interfaces,
+                                     IndentedText* text);
+
+    // Generates ObjectAdded() method.
+    static void AddObjectAdded(const ServiceConfig& config,
+                               const std::vector<Interface>& interfaces,
+                               IndentedText* text);
+
+    // Generates ObjectRemoved() method.
+    static void AddObjectRemoved(const std::vector<Interface>& interfaces,
+                                 IndentedText* text);
+
+    // Generates CreateProperties() method.
+    static void AddCreateProperties(const std::vector<Interface>& interfaces,
+                                    const std::string& class_name,
+                                    IndentedText* text);
+
+    // Generates data members of the class.
+    static void AddDataMembers(const ServiceConfig& config,
+                               const std::vector<Interface>& interfaces,
+                               const std::string& class_name,
+                               IndentedText* text);
+  };
+  // Generates the signal handler name for a given signal name.
+  static std::string GetHandlerNameForSignal(const std::string& signal);
+
+  DISALLOW_COPY_AND_ASSIGN(ProxyGenerator);
+};
+
+}  // namespace chromeos_dbus_bindings
+
+#endif  // CHROMEOS_DBUS_BINDINGS_PROXY_GENERATOR_H_
diff --git a/dbus-binding-generator/chromeos-dbus-bindings/proxy_generator_mock_unittest.cc b/dbus-binding-generator/chromeos-dbus-bindings/proxy_generator_mock_unittest.cc
new file mode 100644
index 0000000..c71d1b0
--- /dev/null
+++ b/dbus-binding-generator/chromeos-dbus-bindings/proxy_generator_mock_unittest.cc
@@ -0,0 +1,250 @@
+// Copyright 2015 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chromeos-dbus-bindings/proxy_generator.h"
+
+#include <string>
+#include <vector>
+
+#include <base/files/file_path.h>
+#include <base/files/file_util.h>
+#include <base/files/scoped_temp_dir.h>
+#include <gtest/gtest.h>
+
+#include "chromeos-dbus-bindings/interface.h"
+#include "chromeos-dbus-bindings/test_utils.h"
+
+using std::string;
+using std::vector;
+using testing::Test;
+
+namespace chromeos_dbus_bindings {
+
+namespace {
+
+const char kDBusTypeArryOfObjects[] = "ao";
+const char kDBusTypeArryOfStrings[] = "as";
+const char kDBusTypeBool[] = "b";
+const char kDBusTypeByte[] = "y";
+const char kDBusTypeInt32[] = "i";
+const char kDBusTypeInt64[] = "x";
+const char kDBusTypeString[] = "s";
+
+const char kExpectedContent[] = R"literal_string(
+#include <string>
+#include <vector>
+
+#include <base/callback_forward.h>
+#include <base/logging.h>
+#include <base/macros.h>
+#include <brillo/any.h>
+#include <brillo/errors/error.h>
+#include <brillo/variant_dictionary.h>
+#include <gmock/gmock.h>
+
+#include "proxies.h"
+
+namespace org {
+namespace chromium {
+
+// Mock object for TestInterfaceProxyInterface.
+class TestInterfaceProxyMock : public TestInterfaceProxyInterface {
+ public:
+  TestInterfaceProxyMock() = default;
+
+  MOCK_METHOD5(Elements,
+               bool(const std::string& /*in_space_walk*/,
+                    const std::vector<dbus::ObjectPath>& /*in_ramblin_man*/,
+                    std::string*,
+                    brillo::ErrorPtr* /*error*/,
+                    int /*timeout_ms*/));
+  MOCK_METHOD5(ElementsAsync,
+               void(const std::string& /*in_space_walk*/,
+                    const std::vector<dbus::ObjectPath>& /*in_ramblin_man*/,
+                    const base::Callback<void(const std::string&)>& /*success_callback*/,
+                    const base::Callback<void(brillo::Error*)>& /*error_callback*/,
+                    int /*timeout_ms*/));
+  MOCK_METHOD3(ReturnToPatagonia,
+               bool(int64_t*,
+                    brillo::ErrorPtr* /*error*/,
+                    int /*timeout_ms*/));
+  MOCK_METHOD3(ReturnToPatagoniaAsync,
+               void(const base::Callback<void(int64_t)>& /*success_callback*/,
+                    const base::Callback<void(brillo::Error*)>& /*error_callback*/,
+                    int /*timeout_ms*/));
+  MOCK_METHOD3(NiceWeatherForDucks,
+               bool(bool,
+                    brillo::ErrorPtr* /*error*/,
+                    int /*timeout_ms*/));
+  MOCK_METHOD4(NiceWeatherForDucksAsync,
+               void(bool,
+                    const base::Callback<void()>& /*success_callback*/,
+                    const base::Callback<void(brillo::Error*)>& /*error_callback*/,
+                    int /*timeout_ms*/));
+  MOCK_METHOD2(ExperimentNumberSix,
+               bool(brillo::ErrorPtr* /*error*/,
+                    int /*timeout_ms*/));
+  MOCK_METHOD3(ExperimentNumberSixAsync,
+               void(const base::Callback<void()>& /*success_callback*/,
+                    const base::Callback<void(brillo::Error*)>& /*error_callback*/,
+                    int /*timeout_ms*/));
+  bool AllTheWayUpToEleven(bool /*in_arg1*/,
+                           bool /*in_arg2*/,
+                           bool /*in_arg3*/,
+                           bool /*in_arg4*/,
+                           bool /*in_arg5*/,
+                           bool /*in_arg6*/,
+                           bool /*in_arg7*/,
+                           bool /*in_arg8*/,
+                           bool* /*out_arg9*/,
+                           brillo::ErrorPtr* /*error*/,
+                           int /*timeout_ms*/) override {
+    LOG(WARNING) << "AllTheWayUpToEleven(): gmock can't handle methods with 11 arguments. You can override this method in a subclass if you need to.";
+    return false;
+  }
+  void AllTheWayUpToElevenAsync(bool /*in_arg1*/,
+                                bool /*in_arg2*/,
+                                bool /*in_arg3*/,
+                                bool /*in_arg4*/,
+                                bool /*in_arg5*/,
+                                bool /*in_arg6*/,
+                                bool /*in_arg7*/,
+                                bool /*in_arg8*/,
+                                const base::Callback<void(bool /*arg9*/)>& /*success_callback*/,
+                                const base::Callback<void(brillo::Error*)>& /*error_callback*/,
+                                int /*timeout_ms*/) override {
+    LOG(WARNING) << "AllTheWayUpToElevenAsync(): gmock can't handle methods with 11 arguments. You can override this method in a subclass if you need to.";
+  }
+  MOCK_METHOD2(RegisterCloserSignalHandler,
+               void(const base::Closure& /*signal_callback*/,
+                    dbus::ObjectProxy::OnConnectedCallback /*on_connected_callback*/));
+  MOCK_METHOD2(RegisterTheCurseOfKaZarSignalHandler,
+               void(const base::Callback<void(const std::vector<std::string>&,
+                                              uint8_t)>& /*signal_callback*/,
+                    dbus::ObjectProxy::OnConnectedCallback /*on_connected_callback*/));
+  MOCK_CONST_METHOD0(GetObjectPath, const dbus::ObjectPath&());
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(TestInterfaceProxyMock);
+};
+}  // namespace chromium
+}  // namespace org
+
+namespace org {
+namespace chromium {
+
+// Mock object for TestInterface2ProxyInterface.
+class TestInterface2ProxyMock : public TestInterface2ProxyInterface {
+ public:
+  TestInterface2ProxyMock() = default;
+
+  MOCK_METHOD4(GetPersonInfo,
+               bool(std::string* /*out_name*/,
+                    int32_t* /*out_age*/,
+                    brillo::ErrorPtr* /*error*/,
+                    int /*timeout_ms*/));
+  MOCK_METHOD3(GetPersonInfoAsync,
+               void(const base::Callback<void(const std::string& /*name*/, int32_t /*age*/)>& /*success_callback*/,
+                    const base::Callback<void(brillo::Error*)>& /*error_callback*/,
+                    int /*timeout_ms*/));
+  MOCK_CONST_METHOD0(data, const std::string&());
+  MOCK_CONST_METHOD0(name, const std::string&());
+  MOCK_METHOD2(set_name, void(const std::string&, const base::Callback<bool>&));
+  MOCK_CONST_METHOD0(GetObjectPath, const dbus::ObjectPath&());
+  MOCK_METHOD1(SetPropertyChangedCallback,
+               void(const base::Callback<void(TestInterface2ProxyInterface*, const std::string&)>&));
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(TestInterface2ProxyMock);
+};
+}  // namespace chromium
+}  // namespace org
+)literal_string";
+
+}  // namespace
+
+class ProxyGeneratorMockTest : public Test {
+ public:
+  void SetUp() override {
+    ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+  }
+
+ protected:
+  base::FilePath CreateInputFile(const string& contents) {
+    base::FilePath path;
+    EXPECT_TRUE(base::CreateTemporaryFileInDir(temp_dir_.path(), &path));
+    int written = base::WriteFile(path, contents.c_str(), contents.size());
+    EXPECT_EQ(contents.size(), static_cast<size_t>(written));
+    return path;
+  }
+
+  base::ScopedTempDir temp_dir_;
+};
+
+TEST_F(ProxyGeneratorMockTest, GenerateMocks) {
+  Interface interface;
+  interface.name = "org.chromium.TestInterface";
+  interface.path = "/org/chromium/Test";
+  interface.methods.emplace_back(
+      "Elements",
+      vector<Interface::Argument>{
+          {"space_walk", kDBusTypeString},
+          {"ramblin_man", kDBusTypeArryOfObjects}},
+      vector<Interface::Argument>{{"", kDBusTypeString}});
+  interface.methods.emplace_back(
+      "ReturnToPatagonia",
+      vector<Interface::Argument>{},
+      vector<Interface::Argument>{{"", kDBusTypeInt64}});
+  interface.methods.emplace_back(
+      "NiceWeatherForDucks",
+      vector<Interface::Argument>{{"", kDBusTypeBool}},
+      vector<Interface::Argument>{});
+  interface.methods.emplace_back("ExperimentNumberSix");
+  // gmock can't handle more than 10 args. The generated method will also
+  // include the timeout and error arguments in the synchronous case, and two
+  // callbacks and the timeout in the asynchronous case.
+  interface.methods.emplace_back(
+      "AllTheWayUpToEleven",
+      vector<Interface::Argument>{
+          {"arg1", kDBusTypeBool},
+          {"arg2", kDBusTypeBool},
+          {"arg3", kDBusTypeBool},
+          {"arg4", kDBusTypeBool},
+          {"arg5", kDBusTypeBool},
+          {"arg6", kDBusTypeBool},
+          {"arg7", kDBusTypeBool},
+          {"arg8", kDBusTypeBool}},
+      vector<Interface::Argument>{{"arg9", kDBusTypeBool}});
+  interface.signals.emplace_back("Closer");
+  interface.signals.emplace_back(
+      "TheCurseOfKaZar",
+      vector<Interface::Argument>{
+          {"", kDBusTypeArryOfStrings},
+          {"", kDBusTypeByte}});
+  interface.methods.back().doc_string = "Comment line1\nline2";
+  Interface interface2;
+  interface2.name = "org.chromium.TestInterface2";
+  interface2.methods.emplace_back(
+      "GetPersonInfo",
+      vector<Interface::Argument>{},
+      vector<Interface::Argument>{
+          {"name", kDBusTypeString},
+          {"age", kDBusTypeInt32}});
+  interface2.properties.emplace_back("Data", "s", "read");
+  interface2.properties.emplace_back("Name", "s", "readwrite");
+  vector<Interface> interfaces{interface, interface2};
+  base::FilePath output_path = temp_dir_.path().Append("output.h");
+  base::FilePath proxy_path = temp_dir_.path().Append("proxies.h");
+  ServiceConfig config;
+  config.object_manager.name = "ObjectManager";
+  EXPECT_TRUE(ProxyGenerator::GenerateMocks(config, interfaces, output_path,
+                                            proxy_path, false));
+  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.
+  test_utils::EXPECT_TEXT_CONTAINED(kExpectedContent, contents);
+}
+
+}  // namespace chromeos_dbus_bindings
diff --git a/dbus-binding-generator/chromeos-dbus-bindings/proxy_generator_unittest.cc b/dbus-binding-generator/chromeos-dbus-bindings/proxy_generator_unittest.cc
new file mode 100644
index 0000000..728e977
--- /dev/null
+++ b/dbus-binding-generator/chromeos-dbus-bindings/proxy_generator_unittest.cc
@@ -0,0 +1,1423 @@
+// Copyright 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chromeos-dbus-bindings/proxy_generator.h"
+
+#include <string>
+#include <vector>
+
+#include <base/files/file_path.h>
+#include <base/files/file_util.h>
+#include <base/files/scoped_temp_dir.h>
+#include <gtest/gtest.h>
+
+#include "chromeos-dbus-bindings/interface.h"
+#include "chromeos-dbus-bindings/test_utils.h"
+
+using std::string;
+using std::vector;
+using testing::Test;
+
+namespace chromeos_dbus_bindings {
+
+namespace {
+
+const char kDBusTypeArryOfObjects[] = "ao";
+const char kDBusTypeArryOfStrings[] = "as";
+const char kDBusTypeBool[] = "b";
+const char kDBusTypeByte[] = "y";
+const char kDBusTypeInt32[] = "i";
+const char kDBusTypeInt64[] = "x";
+const char kDBusTypeString[] = "s";
+
+const char kExpectedContent[] = R"literal_string(
+#include <memory>
+#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 <brillo/any.h>
+#include <brillo/dbus/dbus_method_invoker.h>
+#include <brillo/dbus/dbus_property.h>
+#include <brillo/dbus/dbus_signal_handler.h>
+#include <brillo/errors/error.h>
+#include <brillo/variant_dictionary.h>
+#include <dbus/bus.h>
+#include <dbus/message.h>
+#include <dbus/object_manager.h>
+#include <dbus/object_path.h>
+#include <dbus/object_proxy.h>
+
+namespace org {
+namespace chromium {
+
+// Abstract interface proxy for org::chromium::TestInterface.
+class TestInterfaceProxyInterface {
+ public:
+  virtual ~TestInterfaceProxyInterface() = default;
+
+  virtual bool Elements(
+      const std::string& in_space_walk,
+      const std::vector<dbus::ObjectPath>& in_ramblin_man,
+      std::string* out_3,
+      brillo::ErrorPtr* error,
+      int timeout_ms = dbus::ObjectProxy::TIMEOUT_USE_DEFAULT) = 0;
+
+  virtual void ElementsAsync(
+      const std::string& in_space_walk,
+      const std::vector<dbus::ObjectPath>& in_ramblin_man,
+      const base::Callback<void(const std::string&)>& success_callback,
+      const base::Callback<void(brillo::Error*)>& error_callback,
+      int timeout_ms = dbus::ObjectProxy::TIMEOUT_USE_DEFAULT) = 0;
+
+  virtual bool ReturnToPatagonia(
+      int64_t* out_1,
+      brillo::ErrorPtr* error,
+      int timeout_ms = dbus::ObjectProxy::TIMEOUT_USE_DEFAULT) = 0;
+
+  virtual void ReturnToPatagoniaAsync(
+      const base::Callback<void(int64_t)>& success_callback,
+      const base::Callback<void(brillo::Error*)>& error_callback,
+      int timeout_ms = dbus::ObjectProxy::TIMEOUT_USE_DEFAULT) = 0;
+
+  virtual bool NiceWeatherForDucks(
+      bool in_1,
+      brillo::ErrorPtr* error,
+      int timeout_ms = dbus::ObjectProxy::TIMEOUT_USE_DEFAULT) = 0;
+
+  virtual void NiceWeatherForDucksAsync(
+      bool in_1,
+      const base::Callback<void()>& success_callback,
+      const base::Callback<void(brillo::Error*)>& error_callback,
+      int timeout_ms = dbus::ObjectProxy::TIMEOUT_USE_DEFAULT) = 0;
+
+  // Comment line1
+  // line2
+  virtual bool ExperimentNumberSix(
+      brillo::ErrorPtr* error,
+      int timeout_ms = dbus::ObjectProxy::TIMEOUT_USE_DEFAULT) = 0;
+
+  // Comment line1
+  // line2
+  virtual void ExperimentNumberSixAsync(
+      const base::Callback<void()>& success_callback,
+      const base::Callback<void(brillo::Error*)>& error_callback,
+      int timeout_ms = dbus::ObjectProxy::TIMEOUT_USE_DEFAULT) = 0;
+
+  virtual void RegisterCloserSignalHandler(
+      const base::Closure& signal_callback,
+      dbus::ObjectProxy::OnConnectedCallback on_connected_callback) = 0;
+
+  virtual void RegisterTheCurseOfKaZarSignalHandler(
+      const base::Callback<void(const std::vector<std::string>&,
+                                uint8_t)>& signal_callback,
+      dbus::ObjectProxy::OnConnectedCallback on_connected_callback) = 0;
+
+  virtual const dbus::ObjectPath& GetObjectPath() const = 0;
+};
+
+}  // namespace chromium
+}  // namespace org
+
+namespace org {
+namespace chromium {
+
+// Interface proxy for org::chromium::TestInterface.
+class TestInterfaceProxy final : public TestInterfaceProxyInterface {
+ public:
+  TestInterfaceProxy(
+      const scoped_refptr<dbus::Bus>& bus,
+      const std::string& service_name) :
+          bus_{bus},
+          service_name_{service_name},
+          dbus_object_proxy_{
+              bus_->GetObjectProxy(service_name_, object_path_)} {
+  }
+
+  ~TestInterfaceProxy() override {
+  }
+
+  void RegisterCloserSignalHandler(
+      const base::Closure& signal_callback,
+      dbus::ObjectProxy::OnConnectedCallback on_connected_callback) override {
+    brillo::dbus_utils::ConnectToSignal(
+        dbus_object_proxy_,
+        "org.chromium.TestInterface",
+        "Closer",
+        signal_callback,
+        on_connected_callback);
+  }
+
+  void RegisterTheCurseOfKaZarSignalHandler(
+      const base::Callback<void(const std::vector<std::string>&,
+                                uint8_t)>& signal_callback,
+      dbus::ObjectProxy::OnConnectedCallback on_connected_callback) override {
+    brillo::dbus_utils::ConnectToSignal(
+        dbus_object_proxy_,
+        "org.chromium.TestInterface",
+        "TheCurseOfKaZar",
+        signal_callback,
+        on_connected_callback);
+  }
+
+  void ReleaseObjectProxy(const base::Closure& callback) {
+    bus_->RemoveObjectProxy(service_name_, object_path_, callback);
+  }
+
+  const dbus::ObjectPath& GetObjectPath() const override {
+    return object_path_;
+  }
+
+  dbus::ObjectProxy* GetObjectProxy() const { return dbus_object_proxy_; }
+
+  bool Elements(
+      const std::string& in_space_walk,
+      const std::vector<dbus::ObjectPath>& in_ramblin_man,
+      std::string* out_3,
+      brillo::ErrorPtr* error,
+      int timeout_ms = dbus::ObjectProxy::TIMEOUT_USE_DEFAULT) override {
+    auto response = brillo::dbus_utils::CallMethodAndBlockWithTimeout(
+        timeout_ms,
+        dbus_object_proxy_,
+        "org.chromium.TestInterface",
+        "Elements",
+        error,
+        in_space_walk,
+        in_ramblin_man);
+    return response && brillo::dbus_utils::ExtractMethodCallResults(
+        response.get(), error, out_3);
+  }
+
+  void ElementsAsync(
+      const std::string& in_space_walk,
+      const std::vector<dbus::ObjectPath>& in_ramblin_man,
+      const base::Callback<void(const std::string&)>& success_callback,
+      const base::Callback<void(brillo::Error*)>& error_callback,
+      int timeout_ms = dbus::ObjectProxy::TIMEOUT_USE_DEFAULT) override {
+    brillo::dbus_utils::CallMethodWithTimeout(
+        timeout_ms,
+        dbus_object_proxy_,
+        "org.chromium.TestInterface",
+        "Elements",
+        success_callback,
+        error_callback,
+        in_space_walk,
+        in_ramblin_man);
+  }
+
+  bool ReturnToPatagonia(
+      int64_t* out_1,
+      brillo::ErrorPtr* error,
+      int timeout_ms = dbus::ObjectProxy::TIMEOUT_USE_DEFAULT) override {
+    auto response = brillo::dbus_utils::CallMethodAndBlockWithTimeout(
+        timeout_ms,
+        dbus_object_proxy_,
+        "org.chromium.TestInterface",
+        "ReturnToPatagonia",
+        error);
+    return response && brillo::dbus_utils::ExtractMethodCallResults(
+        response.get(), error, out_1);
+  }
+
+  void ReturnToPatagoniaAsync(
+      const base::Callback<void(int64_t)>& success_callback,
+      const base::Callback<void(brillo::Error*)>& error_callback,
+      int timeout_ms = dbus::ObjectProxy::TIMEOUT_USE_DEFAULT) override {
+    brillo::dbus_utils::CallMethodWithTimeout(
+        timeout_ms,
+        dbus_object_proxy_,
+        "org.chromium.TestInterface",
+        "ReturnToPatagonia",
+        success_callback,
+        error_callback);
+  }
+
+  bool NiceWeatherForDucks(
+      bool in_1,
+      brillo::ErrorPtr* error,
+      int timeout_ms = dbus::ObjectProxy::TIMEOUT_USE_DEFAULT) override {
+    auto response = brillo::dbus_utils::CallMethodAndBlockWithTimeout(
+        timeout_ms,
+        dbus_object_proxy_,
+        "org.chromium.TestInterface",
+        "NiceWeatherForDucks",
+        error,
+        in_1);
+    return response && brillo::dbus_utils::ExtractMethodCallResults(
+        response.get(), error);
+  }
+
+  void NiceWeatherForDucksAsync(
+      bool in_1,
+      const base::Callback<void()>& success_callback,
+      const base::Callback<void(brillo::Error*)>& error_callback,
+      int timeout_ms = dbus::ObjectProxy::TIMEOUT_USE_DEFAULT) override {
+    brillo::dbus_utils::CallMethodWithTimeout(
+        timeout_ms,
+        dbus_object_proxy_,
+        "org.chromium.TestInterface",
+        "NiceWeatherForDucks",
+        success_callback,
+        error_callback,
+        in_1);
+  }
+
+  // Comment line1
+  // line2
+  bool ExperimentNumberSix(
+      brillo::ErrorPtr* error,
+      int timeout_ms = dbus::ObjectProxy::TIMEOUT_USE_DEFAULT) override {
+    auto response = brillo::dbus_utils::CallMethodAndBlockWithTimeout(
+        timeout_ms,
+        dbus_object_proxy_,
+        "org.chromium.TestInterface",
+        "ExperimentNumberSix",
+        error);
+    return response && brillo::dbus_utils::ExtractMethodCallResults(
+        response.get(), error);
+  }
+
+  // Comment line1
+  // line2
+  void ExperimentNumberSixAsync(
+      const base::Callback<void()>& success_callback,
+      const base::Callback<void(brillo::Error*)>& error_callback,
+      int timeout_ms = dbus::ObjectProxy::TIMEOUT_USE_DEFAULT) override {
+    brillo::dbus_utils::CallMethodWithTimeout(
+        timeout_ms,
+        dbus_object_proxy_,
+        "org.chromium.TestInterface",
+        "ExperimentNumberSix",
+        success_callback,
+        error_callback);
+  }
+
+ private:
+  scoped_refptr<dbus::Bus> bus_;
+  std::string service_name_;
+  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 {
+
+// Abstract interface proxy for org::chromium::TestInterface2.
+class TestInterface2ProxyInterface {
+ public:
+  virtual ~TestInterface2ProxyInterface() = default;
+
+  virtual bool GetPersonInfo(
+      std::string* out_name,
+      int32_t* out_age,
+      brillo::ErrorPtr* error,
+      int timeout_ms = dbus::ObjectProxy::TIMEOUT_USE_DEFAULT) = 0;
+
+  virtual void GetPersonInfoAsync(
+      const base::Callback<void(const std::string& /*name*/, int32_t /*age*/)>& success_callback,
+      const base::Callback<void(brillo::Error*)>& error_callback,
+      int timeout_ms = dbus::ObjectProxy::TIMEOUT_USE_DEFAULT) = 0;
+
+  virtual const dbus::ObjectPath& GetObjectPath() const = 0;
+};
+
+}  // namespace chromium
+}  // namespace org
+
+namespace org {
+namespace chromium {
+
+// Interface proxy for org::chromium::TestInterface2.
+class TestInterface2Proxy final : public TestInterface2ProxyInterface {
+ public:
+  TestInterface2Proxy(
+      const scoped_refptr<dbus::Bus>& bus,
+      const std::string& service_name,
+      const dbus::ObjectPath& object_path) :
+          bus_{bus},
+          service_name_{service_name},
+          object_path_{object_path},
+          dbus_object_proxy_{
+              bus_->GetObjectProxy(service_name_, object_path_)} {
+  }
+
+  ~TestInterface2Proxy() override {
+  }
+
+  void ReleaseObjectProxy(const base::Closure& callback) {
+    bus_->RemoveObjectProxy(service_name_, object_path_, callback);
+  }
+
+  const dbus::ObjectPath& GetObjectPath() const override {
+    return object_path_;
+  }
+
+  dbus::ObjectProxy* GetObjectProxy() const { return dbus_object_proxy_; }
+
+  bool GetPersonInfo(
+      std::string* out_name,
+      int32_t* out_age,
+      brillo::ErrorPtr* error,
+      int timeout_ms = dbus::ObjectProxy::TIMEOUT_USE_DEFAULT) override {
+    auto response = brillo::dbus_utils::CallMethodAndBlockWithTimeout(
+        timeout_ms,
+        dbus_object_proxy_,
+        "org.chromium.TestInterface2",
+        "GetPersonInfo",
+        error);
+    return response && brillo::dbus_utils::ExtractMethodCallResults(
+        response.get(), error, out_name, out_age);
+  }
+
+  void GetPersonInfoAsync(
+      const base::Callback<void(const std::string& /*name*/, int32_t /*age*/)>& success_callback,
+      const base::Callback<void(brillo::Error*)>& error_callback,
+      int timeout_ms = dbus::ObjectProxy::TIMEOUT_USE_DEFAULT) override {
+    brillo::dbus_utils::CallMethodWithTimeout(
+        timeout_ms,
+        dbus_object_proxy_,
+        "org.chromium.TestInterface2",
+        "GetPersonInfo",
+        success_callback,
+        error_callback);
+  }
+
+ private:
+  scoped_refptr<dbus::Bus> bus_;
+  std::string service_name_;
+  dbus::ObjectPath object_path_;
+  dbus::ObjectProxy* dbus_object_proxy_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestInterface2Proxy);
+};
+
+}  // namespace chromium
+}  // namespace org
+)literal_string";
+
+const char kExpectedContentWithService[] = R"literal_string(
+#include <memory>
+#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 <brillo/any.h>
+#include <brillo/dbus/dbus_method_invoker.h>
+#include <brillo/dbus/dbus_property.h>
+#include <brillo/dbus/dbus_signal_handler.h>
+#include <brillo/errors/error.h>
+#include <brillo/variant_dictionary.h>
+#include <dbus/bus.h>
+#include <dbus/message.h>
+#include <dbus/object_manager.h>
+#include <dbus/object_path.h>
+#include <dbus/object_proxy.h>
+
+namespace org {
+namespace chromium {
+
+// Abstract interface proxy for org::chromium::TestInterface.
+class TestInterfaceProxyInterface {
+ public:
+  virtual ~TestInterfaceProxyInterface() = default;
+
+  virtual void RegisterCloserSignalHandler(
+      const base::Closure& signal_callback,
+      dbus::ObjectProxy::OnConnectedCallback on_connected_callback) = 0;
+
+  virtual const dbus::ObjectPath& GetObjectPath() const = 0;
+};
+
+}  // namespace chromium
+}  // namespace org
+
+namespace org {
+namespace chromium {
+
+// Interface proxy for org::chromium::TestInterface.
+class TestInterfaceProxy final : public TestInterfaceProxyInterface {
+ public:
+  TestInterfaceProxy(const scoped_refptr<dbus::Bus>& bus) :
+      bus_{bus},
+      dbus_object_proxy_{
+          bus_->GetObjectProxy(service_name_, object_path_)} {
+  }
+
+  ~TestInterfaceProxy() override {
+  }
+
+  void RegisterCloserSignalHandler(
+      const base::Closure& signal_callback,
+      dbus::ObjectProxy::OnConnectedCallback on_connected_callback) override {
+    brillo::dbus_utils::ConnectToSignal(
+        dbus_object_proxy_,
+        "org.chromium.TestInterface",
+        "Closer",
+        signal_callback,
+        on_connected_callback);
+  }
+
+  void ReleaseObjectProxy(const base::Closure& callback) {
+    bus_->RemoveObjectProxy(service_name_, object_path_, callback);
+  }
+
+  const dbus::ObjectPath& GetObjectPath() const override {
+    return object_path_;
+  }
+
+  dbus::ObjectProxy* GetObjectProxy() const { return dbus_object_proxy_; }
+
+ 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 {
+
+// Abstract interface proxy for org::chromium::TestInterface2.
+class TestInterface2ProxyInterface {
+ public:
+  virtual ~TestInterface2ProxyInterface() = default;
+
+  virtual const dbus::ObjectPath& GetObjectPath() const = 0;
+};
+
+}  // namespace chromium
+}  // namespace org
+
+namespace org {
+namespace chromium {
+
+// Interface proxy for org::chromium::TestInterface2.
+class TestInterface2Proxy final : public TestInterface2ProxyInterface {
+ public:
+  TestInterface2Proxy(
+      const scoped_refptr<dbus::Bus>& bus,
+      const dbus::ObjectPath& object_path) :
+          bus_{bus},
+          object_path_{object_path},
+          dbus_object_proxy_{
+              bus_->GetObjectProxy(service_name_, object_path_)} {
+  }
+
+  ~TestInterface2Proxy() override {
+  }
+
+  void ReleaseObjectProxy(const base::Closure& callback) {
+    bus_->RemoveObjectProxy(service_name_, object_path_, callback);
+  }
+
+  const dbus::ObjectPath& GetObjectPath() const override {
+    return object_path_;
+  }
+
+  dbus::ObjectProxy* GetObjectProxy() const { return dbus_object_proxy_; }
+
+ 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";
+
+const char kExpectedContentWithObjectManager[] = R"literal_string(
+#include <memory>
+#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 <brillo/any.h>
+#include <brillo/dbus/dbus_method_invoker.h>
+#include <brillo/dbus/dbus_property.h>
+#include <brillo/dbus/dbus_signal_handler.h>
+#include <brillo/errors/error.h>
+#include <brillo/variant_dictionary.h>
+#include <dbus/bus.h>
+#include <dbus/message.h>
+#include <dbus/object_manager.h>
+#include <dbus/object_path.h>
+#include <dbus/object_proxy.h>
+
+namespace org {
+namespace chromium {
+class ObjectManagerProxy;
+}  // namespace chromium
+}  // namespace org
+
+namespace org {
+namespace chromium {
+
+// Abstract interface proxy for org::chromium::Itf1.
+class Itf1ProxyInterface {
+ public:
+  virtual ~Itf1ProxyInterface() = default;
+
+  virtual void RegisterCloserSignalHandler(
+      const base::Closure& signal_callback,
+      dbus::ObjectProxy::OnConnectedCallback on_connected_callback) = 0;
+
+  static const char* DataName() { return "Data"; }
+  virtual const std::string& data() const = 0;
+  static const char* NameName() { return "Name"; }
+  virtual const std::string& name() const = 0;
+  virtual void set_name(const std::string& value,
+                        const base::Callback<void(bool)>& callback) = 0;
+
+  virtual const dbus::ObjectPath& GetObjectPath() const = 0;
+
+  virtual void SetPropertyChangedCallback(
+      const base::Callback<void(Itf1ProxyInterface*, const std::string&)>& callback) = 0;
+};
+
+}  // namespace chromium
+}  // namespace org
+
+namespace org {
+namespace chromium {
+
+// Interface proxy for org::chromium::Itf1.
+class Itf1Proxy final : public Itf1ProxyInterface {
+ public:
+  class PropertySet : public dbus::PropertySet {
+   public:
+    PropertySet(dbus::ObjectProxy* object_proxy,
+                const PropertyChangedCallback& callback)
+        : dbus::PropertySet{object_proxy,
+                            "org.chromium.Itf1",
+                            callback} {
+      RegisterProperty(DataName(), &data);
+      RegisterProperty(NameName(), &name);
+    }
+
+    brillo::dbus_utils::Property<std::string> data;
+    brillo::dbus_utils::Property<std::string> name;
+
+   private:
+    DISALLOW_COPY_AND_ASSIGN(PropertySet);
+  };
+
+  Itf1Proxy(
+      const scoped_refptr<dbus::Bus>& bus,
+      const std::string& service_name,
+      PropertySet* property_set) :
+          bus_{bus},
+          service_name_{service_name},
+          property_set_{property_set},
+          dbus_object_proxy_{
+              bus_->GetObjectProxy(service_name_, object_path_)} {
+  }
+
+  ~Itf1Proxy() override {
+  }
+
+  void RegisterCloserSignalHandler(
+      const base::Closure& signal_callback,
+      dbus::ObjectProxy::OnConnectedCallback on_connected_callback) override {
+    brillo::dbus_utils::ConnectToSignal(
+        dbus_object_proxy_,
+        "org.chromium.Itf1",
+        "Closer",
+        signal_callback,
+        on_connected_callback);
+  }
+
+  void ReleaseObjectProxy(const base::Closure& callback) {
+    bus_->RemoveObjectProxy(service_name_, object_path_, callback);
+  }
+
+  const dbus::ObjectPath& GetObjectPath() const override {
+    return object_path_;
+  }
+
+  dbus::ObjectProxy* GetObjectProxy() const { return dbus_object_proxy_; }
+
+  void SetPropertyChangedCallback(
+      const base::Callback<void(Itf1ProxyInterface*, const std::string&)>& callback) override {
+    on_property_changed_ = callback;
+  }
+
+  const PropertySet* GetProperties() const { return property_set_; }
+  PropertySet* GetProperties() { return property_set_; }
+
+  const std::string& data() const override {
+    return property_set_->data.value();
+  }
+
+  const std::string& name() const override {
+    return property_set_->name.value();
+  }
+
+  void set_name(const std::string& value,
+                const base::Callback<void(bool)>& callback) override {
+    property_set_->name.Set(value, callback);
+  }
+
+ private:
+  void OnPropertyChanged(const std::string& property_name) {
+    if (!on_property_changed_.is_null())
+      on_property_changed_.Run(this, property_name);
+  }
+
+  scoped_refptr<dbus::Bus> bus_;
+  std::string service_name_;
+  const dbus::ObjectPath object_path_{"/org/chromium/Test/Object"};
+  PropertySet* property_set_;
+  base::Callback<void(Itf1ProxyInterface*, const std::string&)> on_property_changed_;
+  dbus::ObjectProxy* dbus_object_proxy_;
+
+  friend class org::chromium::ObjectManagerProxy;
+  DISALLOW_COPY_AND_ASSIGN(Itf1Proxy);
+};
+
+}  // namespace chromium
+}  // namespace org
+
+namespace org {
+namespace chromium {
+
+// Abstract interface proxy for org::chromium::Itf2.
+class Itf2ProxyInterface {
+ public:
+  virtual ~Itf2ProxyInterface() = default;
+
+  virtual const dbus::ObjectPath& GetObjectPath() const = 0;
+};
+
+}  // namespace chromium
+}  // namespace org
+
+namespace org {
+namespace chromium {
+
+// Interface proxy for org::chromium::Itf2.
+class Itf2Proxy final : public Itf2ProxyInterface {
+ public:
+  class PropertySet : public dbus::PropertySet {
+   public:
+    PropertySet(dbus::ObjectProxy* object_proxy,
+                const PropertyChangedCallback& callback)
+        : dbus::PropertySet{object_proxy,
+                            "org.chromium.Itf2",
+                            callback} {
+    }
+
+
+   private:
+    DISALLOW_COPY_AND_ASSIGN(PropertySet);
+  };
+
+  Itf2Proxy(
+      const scoped_refptr<dbus::Bus>& bus,
+      const std::string& service_name,
+      const dbus::ObjectPath& object_path) :
+          bus_{bus},
+          service_name_{service_name},
+          object_path_{object_path},
+          dbus_object_proxy_{
+              bus_->GetObjectProxy(service_name_, object_path_)} {
+  }
+
+  ~Itf2Proxy() override {
+  }
+
+  void ReleaseObjectProxy(const base::Closure& callback) {
+    bus_->RemoveObjectProxy(service_name_, object_path_, callback);
+  }
+
+  const dbus::ObjectPath& GetObjectPath() const override {
+    return object_path_;
+  }
+
+  dbus::ObjectProxy* GetObjectProxy() const { return dbus_object_proxy_; }
+
+ private:
+  scoped_refptr<dbus::Bus> bus_;
+  std::string service_name_;
+  dbus::ObjectPath object_path_;
+  dbus::ObjectProxy* dbus_object_proxy_;
+
+  DISALLOW_COPY_AND_ASSIGN(Itf2Proxy);
+};
+
+}  // namespace chromium
+}  // namespace org
+
+namespace org {
+namespace chromium {
+
+class ObjectManagerProxy : public dbus::ObjectManager::Interface {
+ public:
+  ObjectManagerProxy(const scoped_refptr<dbus::Bus>& bus,
+                     const std::string& service_name)
+      : bus_{bus},
+        service_name_{service_name},
+        dbus_object_manager_{bus->GetObjectManager(
+            service_name,
+            dbus::ObjectPath{"/org/chromium/Test"})} {
+    dbus_object_manager_->RegisterInterface("org.chromium.Itf1", this);
+    dbus_object_manager_->RegisterInterface("org.chromium.Itf2", this);
+  }
+
+  ~ObjectManagerProxy() override {
+    dbus_object_manager_->UnregisterInterface("org.chromium.Itf1");
+    dbus_object_manager_->UnregisterInterface("org.chromium.Itf2");
+  }
+
+  dbus::ObjectManager* GetObjectManagerProxy() const {
+    return dbus_object_manager_;
+  }
+
+  org::chromium::Itf1ProxyInterface* GetItf1Proxy() {
+    if (itf1_instances_.empty())
+      return nullptr;
+    return itf1_instances_.begin()->second.get();
+  }
+  std::vector<org::chromium::Itf1ProxyInterface*> GetItf1Instances() const {
+    std::vector<org::chromium::Itf1ProxyInterface*> values;
+    values.reserve(itf1_instances_.size());
+    for (const auto& pair : itf1_instances_)
+      values.push_back(pair.second.get());
+    return values;
+  }
+  void SetItf1AddedCallback(
+      const base::Callback<void(org::chromium::Itf1ProxyInterface*)>& callback) {
+    on_itf1_added_ = callback;
+  }
+  void SetItf1RemovedCallback(
+      const base::Callback<void(const dbus::ObjectPath&)>& callback) {
+    on_itf1_removed_ = callback;
+  }
+
+  org::chromium::Itf2ProxyInterface* GetItf2Proxy(
+      const dbus::ObjectPath& object_path) {
+    auto p = itf2_instances_.find(object_path);
+    if (p != itf2_instances_.end())
+      return p->second.get();
+    return nullptr;
+  }
+  std::vector<org::chromium::Itf2ProxyInterface*> GetItf2Instances() const {
+    std::vector<org::chromium::Itf2ProxyInterface*> values;
+    values.reserve(itf2_instances_.size());
+    for (const auto& pair : itf2_instances_)
+      values.push_back(pair.second.get());
+    return values;
+  }
+  void SetItf2AddedCallback(
+      const base::Callback<void(org::chromium::Itf2ProxyInterface*)>& callback) {
+    on_itf2_added_ = callback;
+  }
+  void SetItf2RemovedCallback(
+      const base::Callback<void(const dbus::ObjectPath&)>& callback) {
+    on_itf2_removed_ = callback;
+  }
+
+ private:
+  void OnPropertyChanged(const dbus::ObjectPath& object_path,
+                         const std::string& interface_name,
+                         const std::string& property_name) {
+    if (interface_name == "org.chromium.Itf1") {
+      auto p = itf1_instances_.find(object_path);
+      if (p == itf1_instances_.end())
+        return;
+      p->second->OnPropertyChanged(property_name);
+      return;
+    }
+  }
+
+  void ObjectAdded(
+      const dbus::ObjectPath& object_path,
+      const std::string& interface_name) override {
+    if (interface_name == "org.chromium.Itf1") {
+      auto property_set =
+          static_cast<org::chromium::Itf1Proxy::PropertySet*>(
+              dbus_object_manager_->GetProperties(object_path, interface_name));
+      std::unique_ptr<org::chromium::Itf1Proxy> itf1_proxy{
+        new org::chromium::Itf1Proxy{bus_, service_name_, property_set}
+      };
+      auto p = itf1_instances_.emplace(object_path, std::move(itf1_proxy));
+      if (!on_itf1_added_.is_null())
+        on_itf1_added_.Run(p.first->second.get());
+      return;
+    }
+    if (interface_name == "org.chromium.Itf2") {
+      std::unique_ptr<org::chromium::Itf2Proxy> itf2_proxy{
+        new org::chromium::Itf2Proxy{bus_, service_name_, object_path}
+      };
+      auto p = itf2_instances_.emplace(object_path, std::move(itf2_proxy));
+      if (!on_itf2_added_.is_null())
+        on_itf2_added_.Run(p.first->second.get());
+      return;
+    }
+  }
+
+  void ObjectRemoved(
+      const dbus::ObjectPath& object_path,
+      const std::string& interface_name) override {
+    if (interface_name == "org.chromium.Itf1") {
+      auto p = itf1_instances_.find(object_path);
+      if (p != itf1_instances_.end()) {
+        if (!on_itf1_removed_.is_null())
+          on_itf1_removed_.Run(object_path);
+        itf1_instances_.erase(p);
+      }
+      return;
+    }
+    if (interface_name == "org.chromium.Itf2") {
+      auto p = itf2_instances_.find(object_path);
+      if (p != itf2_instances_.end()) {
+        if (!on_itf2_removed_.is_null())
+          on_itf2_removed_.Run(object_path);
+        itf2_instances_.erase(p);
+      }
+      return;
+    }
+  }
+
+  dbus::PropertySet* CreateProperties(
+      dbus::ObjectProxy* object_proxy,
+      const dbus::ObjectPath& object_path,
+      const std::string& interface_name) override {
+    if (interface_name == "org.chromium.Itf1") {
+      return new org::chromium::Itf1Proxy::PropertySet{
+          object_proxy,
+          base::Bind(&ObjectManagerProxy::OnPropertyChanged,
+                     weak_ptr_factory_.GetWeakPtr(),
+                     object_path,
+                     interface_name)
+      };
+    }
+    if (interface_name == "org.chromium.Itf2") {
+      return new org::chromium::Itf2Proxy::PropertySet{
+          object_proxy,
+          base::Bind(&ObjectManagerProxy::OnPropertyChanged,
+                     weak_ptr_factory_.GetWeakPtr(),
+                     object_path,
+                     interface_name)
+      };
+    }
+    LOG(FATAL) << "Creating properties for unsupported interface "
+               << interface_name;
+    return nullptr;
+  }
+
+  scoped_refptr<dbus::Bus> bus_;
+  std::string service_name_;
+  dbus::ObjectManager* dbus_object_manager_;
+  std::map<dbus::ObjectPath,
+           std::unique_ptr<org::chromium::Itf1Proxy>> itf1_instances_;
+  base::Callback<void(org::chromium::Itf1ProxyInterface*)> on_itf1_added_;
+  base::Callback<void(const dbus::ObjectPath&)> on_itf1_removed_;
+  std::map<dbus::ObjectPath,
+           std::unique_ptr<org::chromium::Itf2Proxy>> itf2_instances_;
+  base::Callback<void(org::chromium::Itf2ProxyInterface*)> on_itf2_added_;
+  base::Callback<void(const dbus::ObjectPath&)> on_itf2_removed_;
+  base::WeakPtrFactory<ObjectManagerProxy> weak_ptr_factory_{this};
+
+  DISALLOW_COPY_AND_ASSIGN(ObjectManagerProxy);
+};
+
+}  // namespace chromium
+}  // namespace org
+)literal_string";
+
+const char kExpectedContentWithObjectManagerAndServiceName[] = R"literal_string(
+#include <memory>
+#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 <brillo/any.h>
+#include <brillo/dbus/dbus_method_invoker.h>
+#include <brillo/dbus/dbus_property.h>
+#include <brillo/dbus/dbus_signal_handler.h>
+#include <brillo/errors/error.h>
+#include <brillo/variant_dictionary.h>
+#include <dbus/bus.h>
+#include <dbus/message.h>
+#include <dbus/object_manager.h>
+#include <dbus/object_path.h>
+#include <dbus/object_proxy.h>
+
+namespace org {
+namespace chromium {
+class ObjectManagerProxy;
+}  // namespace chromium
+}  // namespace org
+
+namespace org {
+namespace chromium {
+
+// Abstract interface proxy for org::chromium::Itf1.
+class Itf1ProxyInterface {
+ public:
+  virtual ~Itf1ProxyInterface() = default;
+
+  virtual void RegisterCloserSignalHandler(
+      const base::Closure& signal_callback,
+      dbus::ObjectProxy::OnConnectedCallback on_connected_callback) = 0;
+
+  virtual const dbus::ObjectPath& GetObjectPath() const = 0;
+};
+
+}  // namespace chromium
+}  // namespace org
+
+namespace org {
+namespace chromium {
+
+// Interface proxy for org::chromium::Itf1.
+class Itf1Proxy final : public Itf1ProxyInterface {
+ public:
+  class PropertySet : public dbus::PropertySet {
+   public:
+    PropertySet(dbus::ObjectProxy* object_proxy,
+                const PropertyChangedCallback& callback)
+        : dbus::PropertySet{object_proxy,
+                            "org.chromium.Itf1",
+                            callback} {
+    }
+
+
+   private:
+    DISALLOW_COPY_AND_ASSIGN(PropertySet);
+  };
+
+  Itf1Proxy(const scoped_refptr<dbus::Bus>& bus) :
+      bus_{bus},
+      dbus_object_proxy_{
+          bus_->GetObjectProxy(service_name_, object_path_)} {
+  }
+
+  ~Itf1Proxy() override {
+  }
+
+  void RegisterCloserSignalHandler(
+      const base::Closure& signal_callback,
+      dbus::ObjectProxy::OnConnectedCallback on_connected_callback) override {
+    brillo::dbus_utils::ConnectToSignal(
+        dbus_object_proxy_,
+        "org.chromium.Itf1",
+        "Closer",
+        signal_callback,
+        on_connected_callback);
+  }
+
+  void ReleaseObjectProxy(const base::Closure& callback) {
+    bus_->RemoveObjectProxy(service_name_, object_path_, callback);
+  }
+
+  const dbus::ObjectPath& GetObjectPath() const override {
+    return object_path_;
+  }
+
+  dbus::ObjectProxy* GetObjectProxy() const { return dbus_object_proxy_; }
+
+ private:
+  scoped_refptr<dbus::Bus> bus_;
+  const std::string service_name_{"org.chromium.Test"};
+  const dbus::ObjectPath object_path_{"/org/chromium/Test/Object"};
+  dbus::ObjectProxy* dbus_object_proxy_;
+
+  DISALLOW_COPY_AND_ASSIGN(Itf1Proxy);
+};
+
+}  // namespace chromium
+}  // namespace org
+
+namespace org {
+namespace chromium {
+
+// Abstract interface proxy for org::chromium::Itf2.
+class Itf2ProxyInterface {
+ public:
+  virtual ~Itf2ProxyInterface() = default;
+
+  virtual const dbus::ObjectPath& GetObjectPath() const = 0;
+};
+
+}  // namespace chromium
+}  // namespace org
+
+namespace org {
+namespace chromium {
+
+// Interface proxy for org::chromium::Itf2.
+class Itf2Proxy final : public Itf2ProxyInterface {
+ public:
+  class PropertySet : public dbus::PropertySet {
+   public:
+    PropertySet(dbus::ObjectProxy* object_proxy,
+                const PropertyChangedCallback& callback)
+        : dbus::PropertySet{object_proxy,
+                            "org.chromium.Itf2",
+                            callback} {
+    }
+
+
+   private:
+    DISALLOW_COPY_AND_ASSIGN(PropertySet);
+  };
+
+  Itf2Proxy(
+      const scoped_refptr<dbus::Bus>& bus,
+      const dbus::ObjectPath& object_path) :
+          bus_{bus},
+          object_path_{object_path},
+          dbus_object_proxy_{
+              bus_->GetObjectProxy(service_name_, object_path_)} {
+  }
+
+  ~Itf2Proxy() override {
+  }
+
+  void ReleaseObjectProxy(const base::Closure& callback) {
+    bus_->RemoveObjectProxy(service_name_, object_path_, callback);
+  }
+
+  const dbus::ObjectPath& GetObjectPath() const override {
+    return object_path_;
+  }
+
+  dbus::ObjectProxy* GetObjectProxy() const { return dbus_object_proxy_; }
+
+ 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(Itf2Proxy);
+};
+
+}  // namespace chromium
+}  // namespace org
+
+namespace org {
+namespace chromium {
+
+class ObjectManagerProxy : public dbus::ObjectManager::Interface {
+ public:
+  ObjectManagerProxy(const scoped_refptr<dbus::Bus>& bus)
+      : bus_{bus},
+        dbus_object_manager_{bus->GetObjectManager(
+            "org.chromium.Test",
+            dbus::ObjectPath{"/org/chromium/Test"})} {
+    dbus_object_manager_->RegisterInterface("org.chromium.Itf1", this);
+    dbus_object_manager_->RegisterInterface("org.chromium.Itf2", this);
+  }
+
+  ~ObjectManagerProxy() override {
+    dbus_object_manager_->UnregisterInterface("org.chromium.Itf1");
+    dbus_object_manager_->UnregisterInterface("org.chromium.Itf2");
+  }
+
+  dbus::ObjectManager* GetObjectManagerProxy() const {
+    return dbus_object_manager_;
+  }
+
+  org::chromium::Itf1ProxyInterface* GetItf1Proxy() {
+    if (itf1_instances_.empty())
+      return nullptr;
+    return itf1_instances_.begin()->second.get();
+  }
+  std::vector<org::chromium::Itf1ProxyInterface*> GetItf1Instances() const {
+    std::vector<org::chromium::Itf1ProxyInterface*> values;
+    values.reserve(itf1_instances_.size());
+    for (const auto& pair : itf1_instances_)
+      values.push_back(pair.second.get());
+    return values;
+  }
+  void SetItf1AddedCallback(
+      const base::Callback<void(org::chromium::Itf1ProxyInterface*)>& callback) {
+    on_itf1_added_ = callback;
+  }
+  void SetItf1RemovedCallback(
+      const base::Callback<void(const dbus::ObjectPath&)>& callback) {
+    on_itf1_removed_ = callback;
+  }
+
+  org::chromium::Itf2ProxyInterface* GetItf2Proxy(
+      const dbus::ObjectPath& object_path) {
+    auto p = itf2_instances_.find(object_path);
+    if (p != itf2_instances_.end())
+      return p->second.get();
+    return nullptr;
+  }
+  std::vector<org::chromium::Itf2ProxyInterface*> GetItf2Instances() const {
+    std::vector<org::chromium::Itf2ProxyInterface*> values;
+    values.reserve(itf2_instances_.size());
+    for (const auto& pair : itf2_instances_)
+      values.push_back(pair.second.get());
+    return values;
+  }
+  void SetItf2AddedCallback(
+      const base::Callback<void(org::chromium::Itf2ProxyInterface*)>& callback) {
+    on_itf2_added_ = callback;
+  }
+  void SetItf2RemovedCallback(
+      const base::Callback<void(const dbus::ObjectPath&)>& callback) {
+    on_itf2_removed_ = callback;
+  }
+
+ private:
+  void OnPropertyChanged(const dbus::ObjectPath& /* object_path */,
+                         const std::string& /* interface_name */,
+                         const std::string& /* property_name */) {}
+
+  void ObjectAdded(
+      const dbus::ObjectPath& object_path,
+      const std::string& interface_name) override {
+    if (interface_name == "org.chromium.Itf1") {
+      std::unique_ptr<org::chromium::Itf1Proxy> itf1_proxy{
+        new org::chromium::Itf1Proxy{bus_}
+      };
+      auto p = itf1_instances_.emplace(object_path, std::move(itf1_proxy));
+      if (!on_itf1_added_.is_null())
+        on_itf1_added_.Run(p.first->second.get());
+      return;
+    }
+    if (interface_name == "org.chromium.Itf2") {
+      std::unique_ptr<org::chromium::Itf2Proxy> itf2_proxy{
+        new org::chromium::Itf2Proxy{bus_, object_path}
+      };
+      auto p = itf2_instances_.emplace(object_path, std::move(itf2_proxy));
+      if (!on_itf2_added_.is_null())
+        on_itf2_added_.Run(p.first->second.get());
+      return;
+    }
+  }
+
+  void ObjectRemoved(
+      const dbus::ObjectPath& object_path,
+      const std::string& interface_name) override {
+    if (interface_name == "org.chromium.Itf1") {
+      auto p = itf1_instances_.find(object_path);
+      if (p != itf1_instances_.end()) {
+        if (!on_itf1_removed_.is_null())
+          on_itf1_removed_.Run(object_path);
+        itf1_instances_.erase(p);
+      }
+      return;
+    }
+    if (interface_name == "org.chromium.Itf2") {
+      auto p = itf2_instances_.find(object_path);
+      if (p != itf2_instances_.end()) {
+        if (!on_itf2_removed_.is_null())
+          on_itf2_removed_.Run(object_path);
+        itf2_instances_.erase(p);
+      }
+      return;
+    }
+  }
+
+  dbus::PropertySet* CreateProperties(
+      dbus::ObjectProxy* object_proxy,
+      const dbus::ObjectPath& object_path,
+      const std::string& interface_name) override {
+    if (interface_name == "org.chromium.Itf1") {
+      return new org::chromium::Itf1Proxy::PropertySet{
+          object_proxy,
+          base::Bind(&ObjectManagerProxy::OnPropertyChanged,
+                     weak_ptr_factory_.GetWeakPtr(),
+                     object_path,
+                     interface_name)
+      };
+    }
+    if (interface_name == "org.chromium.Itf2") {
+      return new org::chromium::Itf2Proxy::PropertySet{
+          object_proxy,
+          base::Bind(&ObjectManagerProxy::OnPropertyChanged,
+                     weak_ptr_factory_.GetWeakPtr(),
+                     object_path,
+                     interface_name)
+      };
+    }
+    LOG(FATAL) << "Creating properties for unsupported interface "
+               << interface_name;
+    return nullptr;
+  }
+
+  scoped_refptr<dbus::Bus> bus_;
+  dbus::ObjectManager* dbus_object_manager_;
+  std::map<dbus::ObjectPath,
+           std::unique_ptr<org::chromium::Itf1Proxy>> itf1_instances_;
+  base::Callback<void(org::chromium::Itf1ProxyInterface*)> on_itf1_added_;
+  base::Callback<void(const dbus::ObjectPath&)> on_itf1_removed_;
+  std::map<dbus::ObjectPath,
+           std::unique_ptr<org::chromium::Itf2Proxy>> itf2_instances_;
+  base::Callback<void(org::chromium::Itf2ProxyInterface*)> on_itf2_added_;
+  base::Callback<void(const dbus::ObjectPath&)> on_itf2_removed_;
+  base::WeakPtrFactory<ObjectManagerProxy> weak_ptr_factory_{this};
+
+  DISALLOW_COPY_AND_ASSIGN(ObjectManagerProxy);
+};
+
+}  // namespace chromium
+}  // namespace org
+)literal_string";
+}  // namespace
+
+class ProxyGeneratorTest : public Test {
+ public:
+  void SetUp() override {
+    ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+  }
+
+ protected:
+  base::FilePath CreateInputFile(const string& contents) {
+    base::FilePath path;
+    EXPECT_TRUE(base::CreateTemporaryFileInDir(temp_dir_.path(), &path));
+    int written = base::WriteFile(path, contents.c_str(), contents.size());
+    EXPECT_EQ(contents.size(), static_cast<size_t>(written));
+    return path;
+  }
+
+  base::ScopedTempDir temp_dir_;
+};
+
+TEST_F(ProxyGeneratorTest, GenerateAdaptors) {
+  Interface interface;
+  interface.name = "org.chromium.TestInterface";
+  interface.path = "/org/chromium/Test";
+  interface.methods.emplace_back(
+      "Elements",
+      vector<Interface::Argument>{
+          {"space_walk", kDBusTypeString},
+          {"ramblin_man", kDBusTypeArryOfObjects}},
+      vector<Interface::Argument>{{"", kDBusTypeString}});
+  interface.methods.emplace_back(
+      "ReturnToPatagonia",
+      vector<Interface::Argument>{},
+      vector<Interface::Argument>{{"", kDBusTypeInt64}});
+  interface.methods.emplace_back(
+      "NiceWeatherForDucks",
+      vector<Interface::Argument>{{"", kDBusTypeBool}},
+      vector<Interface::Argument>{});
+  interface.methods.emplace_back("ExperimentNumberSix");
+  interface.signals.emplace_back("Closer");
+  interface.signals.emplace_back(
+      "TheCurseOfKaZar",
+      vector<Interface::Argument>{
+          {"", kDBusTypeArryOfStrings},
+          {"", kDBusTypeByte}});
+  interface.methods.back().doc_string = "Comment line1\nline2";
+  Interface interface2;
+  interface2.name = "org.chromium.TestInterface2";
+  interface2.methods.emplace_back(
+      "GetPersonInfo",
+      vector<Interface::Argument>{},
+      vector<Interface::Argument>{
+          {"name", kDBusTypeString},
+          {"age", kDBusTypeInt32}});
+  vector<Interface> interfaces{interface, interface2};
+  base::FilePath output_path = temp_dir_.path().Append("output.h");
+  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
+  // the content we need within the string.
+  test_utils::EXPECT_TEXT_CONTAINED(kExpectedContent, contents);
+}
+
+TEST_F(ProxyGeneratorTest, GenerateAdaptorsWithServiceName) {
+  Interface interface;
+  interface.name = "org.chromium.TestInterface";
+  interface.path = "/org/chromium/Test";
+  interface.signals.emplace_back("Closer");
+  Interface interface2;
+  interface2.name = "org.chromium.TestInterface2";
+  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.
+  test_utils::EXPECT_TEXT_CONTAINED(kExpectedContentWithService, contents);
+}
+
+TEST_F(ProxyGeneratorTest, GenerateAdaptorsWithObjectManager) {
+  Interface interface;
+  interface.name = "org.chromium.Itf1";
+  interface.path = "/org/chromium/Test/Object";
+  interface.signals.emplace_back("Closer");
+  interface.properties.emplace_back("Data", "s", "read");
+  interface.properties.emplace_back("Name", "s", "readwrite");
+  Interface interface2;
+  interface2.name = "org.chromium.Itf2";
+  vector<Interface> interfaces{interface, interface2};
+  base::FilePath output_path = temp_dir_.path().Append("output3.h");
+  ServiceConfig config;
+  config.object_manager.name = "org.chromium.ObjectManager";
+  config.object_manager.object_path = "/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.
+  test_utils::EXPECT_TEXT_CONTAINED(
+      kExpectedContentWithObjectManager, contents);
+}
+
+TEST_F(ProxyGeneratorTest, GenerateAdaptorsWithObjectManagerAndServiceName) {
+  Interface interface;
+  interface.name = "org.chromium.Itf1";
+  interface.path = "/org/chromium/Test/Object";
+  interface.signals.emplace_back("Closer");
+  Interface interface2;
+  interface2.name = "org.chromium.Itf2";
+  vector<Interface> interfaces{interface, interface2};
+  base::FilePath output_path = temp_dir_.path().Append("output4.h");
+  ServiceConfig config;
+  config.service_name = "org.chromium.Test";
+  config.object_manager.name = "org.chromium.ObjectManager";
+  config.object_manager.object_path = "/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.
+  test_utils::EXPECT_TEXT_CONTAINED(
+      kExpectedContentWithObjectManagerAndServiceName, contents);
+}
+
+}  // namespace chromeos_dbus_bindings
diff --git a/dbus-binding-generator/chromeos-dbus-bindings/test_utils.cc b/dbus-binding-generator/chromeos-dbus-bindings/test_utils.cc
new file mode 100644
index 0000000..34d8a22
--- /dev/null
+++ b/dbus-binding-generator/chromeos-dbus-bindings/test_utils.cc
@@ -0,0 +1,81 @@
+// Copyright 2015 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chromeos-dbus-bindings/test_utils.h"
+
+#include <string>
+#include <vector>
+
+#include <base/files/file_path.h>
+#include <base/files/file_util.h>
+#include <base/logging.h>
+#include <brillo/process.h>
+#include <gtest/gtest.h>
+
+using std::string;
+using std::vector;
+
+namespace {
+
+// Return the diff between the texts |a| and |b|.
+string GetUnifiedDiff(const string& a, const string& b) {
+  base::FilePath path_a, path_b;
+  if (!base::CreateTemporaryFile(&path_a) ||
+      !base::CreateTemporaryFile(&path_b)) {
+    return "Error creating temporary file";
+  }
+  WriteFile(path_a, a.data(), a.size());
+  WriteFile(path_b, b.data(), b.size());
+
+  brillo::ProcessImpl proc;
+  proc.AddArg("diff");
+  proc.AddArg("-u");
+  proc.AddArg(path_a.value());
+  proc.AddArg(path_b.value());
+  proc.SetSearchPath(true);
+  proc.RedirectUsingPipe(STDOUT_FILENO, false);
+  proc.Start();
+
+  int fd = proc.GetPipe(STDOUT_FILENO);
+  vector<char> buffer(32 * 1024);
+  string output;
+  while (true) {
+    int rc = read(fd, buffer.data(), buffer.size());
+    if (rc < 0) {
+      PLOG(ERROR) << "Reading from diff.";
+      break;
+    } else if (rc == 0) {
+      break;
+    } else {
+      output.append(buffer.data(), rc);
+    }
+  }
+  proc.Wait();
+
+  base::DeleteFile(path_a, false);
+  base::DeleteFile(path_b, false);
+  return output;
+}
+
+}  // namespace
+
+namespace chromeos_dbus_bindings {
+namespace test_utils {
+
+void ExpectTextContained(const tracked_objects::Location& from_here,
+                         const string& expected_str,
+                         const string& expected_expr,
+                         const string& actual_str,
+                         const string& actual_expr) {
+  if (string::npos != actual_str.find(expected_str))
+    return;
+
+  ADD_FAILURE_AT(from_here.file_name(), from_here.line_number())
+      << "Expected to find " << expected_expr << " within " << actual_expr
+      << ".\nHere is the diff:\n"
+      << GetUnifiedDiff(expected_str, actual_str);
+}
+
+}  // namespace test_utils
+}  // namespace chromeos_dbus_bindings
diff --git a/dbus-binding-generator/chromeos-dbus-bindings/test_utils.h b/dbus-binding-generator/chromeos-dbus-bindings/test_utils.h
new file mode 100644
index 0000000..5619bc1
--- /dev/null
+++ b/dbus-binding-generator/chromeos-dbus-bindings/test_utils.h
@@ -0,0 +1,33 @@
+// Copyright 2015 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMEOS_DBUS_BINDINGS_TEST_UTILS_H_
+#define CHROMEOS_DBUS_BINDINGS_TEST_UTILS_H_
+
+#include <string>
+
+#include <base/location.h>
+
+namespace chromeos_dbus_bindings {
+namespace test_utils {
+
+// Helper macro to call ExpectTextContained().
+#define EXPECT_TEXT_CONTAINED(expected, actual) \
+  ExpectTextContained(FROM_HERE, expected, #expected, actual, #actual)
+
+// Checks that the text |actual_str| is contained in the text |expected_str| and
+// fails the current test if not. If the |actual_str| text is not contained, a
+// meaningful line diff between |actual_str| and |expected_str| is displayed in
+// stderr. Use this function instead of EXPECT_EQ() when the compared values are
+// long texts.
+void ExpectTextContained(const tracked_objects::Location& from_here,
+                         const std::string& expected_str,
+                         const std::string& expected_expr,
+                         const std::string& actual_str,
+                         const std::string& actual_expr);
+
+}  // namespace test_utils
+}  // namespace chromeos_dbus_bindings
+
+#endif  // CHROMEOS_DBUS_BINDINGS_TEST_UTILS_H_
diff --git a/dbus-binding-generator/chromeos-dbus-bindings/testrunner.cc b/dbus-binding-generator/chromeos-dbus-bindings/testrunner.cc
new file mode 100644
index 0000000..a51db6d
--- /dev/null
+++ b/dbus-binding-generator/chromeos-dbus-bindings/testrunner.cc
@@ -0,0 +1,16 @@
+// Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <base/at_exit.h>
+#include <base/command_line.h>
+#include <brillo/syslog_logging.h>
+#include <gtest/gtest.h>
+
+int main(int argc, char** argv) {
+  base::AtExitManager exit_manager;
+  base::CommandLine::Init(argc, argv);
+  brillo::InitLog(brillo::kLogToStderr);
+  ::testing::InitGoogleTest(&argc, argv);
+  return RUN_ALL_TESTS();
+}
diff --git a/dbus-binding-generator/chromeos-dbus-bindings/xml_interface_parser.cc b/dbus-binding-generator/chromeos-dbus-bindings/xml_interface_parser.cc
new file mode 100644
index 0000000..3f574e1
--- /dev/null
+++ b/dbus-binding-generator/chromeos-dbus-bindings/xml_interface_parser.cc
@@ -0,0 +1,351 @@
+// Copyright 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chromeos-dbus-bindings/xml_interface_parser.h"
+
+#include <utility>
+
+#include <base/files/file_path.h>
+#include <base/files/file_util.h>
+#include <base/logging.h>
+#include <base/strings/string_util.h>
+#include <brillo/strings/string_utils.h>
+
+using std::string;
+using std::vector;
+
+namespace chromeos_dbus_bindings {
+
+// static
+const char XmlInterfaceParser::kArgumentTag[] = "arg";
+const char XmlInterfaceParser::kInterfaceTag[] = "interface";
+const char XmlInterfaceParser::kMethodTag[] = "method";
+const char XmlInterfaceParser::kNodeTag[] = "node";
+const char XmlInterfaceParser::kSignalTag[] = "signal";
+const char XmlInterfaceParser::kPropertyTag[] = "property";
+const char XmlInterfaceParser::kAnnotationTag[] = "annotation";
+const char XmlInterfaceParser::kDocStringTag[] = "tp:docstring";
+const char XmlInterfaceParser::kNameAttribute[] = "name";
+const char XmlInterfaceParser::kTypeAttribute[] = "type";
+const char XmlInterfaceParser::kValueAttribute[] = "value";
+const char XmlInterfaceParser::kDirectionAttribute[] = "direction";
+const char XmlInterfaceParser::kAccessAttribute[] = "access";
+const char XmlInterfaceParser::kArgumentDirectionIn[] = "in";
+const char XmlInterfaceParser::kArgumentDirectionOut[] = "out";
+
+const char XmlInterfaceParser::kTrue[] = "true";
+const char XmlInterfaceParser::kFalse[] = "false";
+
+const char XmlInterfaceParser::kMethodConst[] =
+    "org.chromium.DBus.Method.Const";
+const char XmlInterfaceParser::kMethodAsync[] =
+    "org.freedesktop.DBus.GLib.Async";
+const char XmlInterfaceParser::kMethodIncludeDBusMessage[] =
+    "org.chromium.DBus.Method.IncludeDBusMessage";
+
+const char XmlInterfaceParser::kMethodKind[] = "org.chromium.DBus.Method.Kind";
+const char XmlInterfaceParser::kMethodKindSimple[] = "simple";
+const char XmlInterfaceParser::kMethodKindNormal[] = "normal";
+const char XmlInterfaceParser::kMethodKindAsync[] = "async";
+const char XmlInterfaceParser::kMethodKindRaw[] = "raw";
+
+namespace {
+
+string GetElementPath(const vector<string>& path) {
+  return brillo::string_utils::Join("/", path);
+}
+
+}  // anonymous namespace
+
+bool XmlInterfaceParser::ParseXmlInterfaceFile(
+    const std::string& contents,
+    const std::vector<std::string>& ignore_interfaces) {
+  auto parser = XML_ParserCreate(nullptr);
+  XML_SetUserData(parser, this);
+  XML_SetElementHandler(parser,
+                        &XmlInterfaceParser::HandleElementStart,
+                        &XmlInterfaceParser::HandleElementEnd);
+  XML_SetCharacterDataHandler(parser, &XmlInterfaceParser::HandleCharData);
+  const int kIsFinal = XML_TRUE;
+
+  element_path_.clear();
+  XML_Status res = XML_Parse(parser,
+                             contents.c_str(),
+                             contents.size(),
+                             kIsFinal);
+  XML_ParserFree(parser);
+
+  if (res != XML_STATUS_OK) {
+    LOG(ERROR) << "XML parse failure";
+    return false;
+  }
+
+  CHECK(element_path_.empty());
+
+  if (!ignore_interfaces.empty()) {
+    // Remove interfaces whose names are in |ignore_interfaces| list.
+    auto condition = [&ignore_interfaces](const Interface& itf) {
+      return std::find(ignore_interfaces.begin(), ignore_interfaces.end(),
+                       itf.name) != ignore_interfaces.end();
+    };
+    auto p = std::remove_if(interfaces_.begin(), interfaces_.end(), condition);
+    interfaces_.erase(p, interfaces_.end());
+  }
+  return true;
+}
+
+void XmlInterfaceParser::OnOpenElement(
+    const string& element_name, const XmlAttributeMap& attributes) {
+  string prev_element;
+  if (!element_path_.empty())
+    prev_element = element_path_.back();
+  element_path_.push_back(element_name);
+  if (element_name == kNodeTag) {
+    CHECK(prev_element.empty() || prev_element == kNodeTag)
+        << "Unexpected tag " << element_name << " inside " << prev_element;
+    // 'name' attribute is optional for <node> element.
+    string name;
+    GetElementAttribute(attributes, element_path_, kNameAttribute, &name);
+    base::TrimWhitespaceASCII(name, base::TRIM_ALL, &name);
+    node_names_.push_back(name);
+  } else if (element_name == kInterfaceTag) {
+    CHECK_EQ(kNodeTag, prev_element)
+        << "Unexpected tag " << element_name << " inside " << prev_element;
+    string interface_name = GetValidatedElementName(attributes, element_path_);
+    Interface itf(interface_name,
+                  std::vector<Interface::Method>{},
+                  std::vector<Interface::Signal>{},
+                  std::vector<Interface::Property>{});
+    itf.path = node_names_.back();
+    interfaces_.push_back(std::move(itf));
+  } else if (element_name == kMethodTag) {
+    CHECK_EQ(kInterfaceTag, prev_element)
+        << "Unexpected tag " << element_name << " inside " << prev_element;
+    interfaces_.back().methods.push_back(
+        Interface::Method(GetValidatedElementName(attributes, element_path_)));
+  } else if (element_name == kSignalTag) {
+    CHECK_EQ(kInterfaceTag, prev_element)
+        << "Unexpected tag " << element_name << " inside " << prev_element;
+    interfaces_.back().signals.push_back(
+        Interface::Signal(GetValidatedElementName(attributes, element_path_)));
+  } else if (element_name == kPropertyTag) {
+    CHECK_EQ(kInterfaceTag, prev_element)
+        << "Unexpected tag " << element_name << " inside " << prev_element;
+    interfaces_.back().properties.push_back(ParseProperty(attributes,
+                                                          element_path_));
+  } else if (element_name == kArgumentTag) {
+    if (prev_element == kMethodTag) {
+      AddMethodArgument(attributes);
+    } else if (prev_element == kSignalTag) {
+      AddSignalArgument(attributes);
+    } else {
+      LOG(FATAL) << "Unexpected tag " << element_name
+                 << " inside " << prev_element;
+    }
+  } else if (element_name == kAnnotationTag) {
+    string name = GetValidatedElementAttribute(attributes, element_path_,
+                                               kNameAttribute);
+    // Value is optional. Default to empty string if omitted.
+    string value;
+    GetElementAttribute(attributes, element_path_, kValueAttribute, &value);
+    if (prev_element == kInterfaceTag) {
+      // Parse interface annotations...
+    } else if (prev_element == kMethodTag) {
+      // Parse method annotations...
+      Interface::Method& method = interfaces_.back().methods.back();
+      if (name == kMethodConst) {
+        CHECK(value == kTrue || value == kFalse);
+        method.is_const = (value == kTrue);
+      } else if (name == kMethodIncludeDBusMessage) {
+        CHECK(value == kTrue || value == kFalse);
+        method.include_dbus_message = (value == kTrue);
+      } else if (name == kMethodAsync) {
+        // Support GLib.Async annotation as well.
+        method.kind = Interface::Method::Kind::kAsync;
+      } else if (name == kMethodKind) {
+        if (value == kMethodKindSimple) {
+          method.kind = Interface::Method::Kind::kSimple;
+        } else if (value == kMethodKindNormal) {
+          method.kind = Interface::Method::Kind::kNormal;
+        } else if (value == kMethodKindAsync) {
+          method.kind = Interface::Method::Kind::kAsync;
+        } else if (value == kMethodKindRaw) {
+          method.kind = Interface::Method::Kind::kRaw;
+        } else {
+          LOG(FATAL) << "Invalid method kind: " << value;
+        }
+      }
+    } else if (prev_element == kSignalTag) {
+      // Parse signal annotations...
+    } else if (prev_element == kPropertyTag) {
+      // Parse property annotations...
+    } else {
+      LOG(FATAL) << "Unexpected tag " << element_name
+                 << " inside " << prev_element;
+    }
+  } else if (element_name == kDocStringTag) {
+    CHECK(!prev_element.empty() && prev_element != kNodeTag)
+        << "Unexpected tag " << element_name << " inside " << prev_element;
+  }
+}
+
+void XmlInterfaceParser::OnCharData(const std::string& content) {
+  // Handle the text data only for <tp:docstring> element.
+  if (element_path_.back() != kDocStringTag)
+    return;
+
+  CHECK_GT(element_path_.size(), 1u);
+  string* doc_string_ptr = nullptr;
+  string target_element = element_path_[element_path_.size() - 2];
+  if (target_element == kInterfaceTag) {
+    doc_string_ptr = &(interfaces_.back().doc_string);
+  } else if (target_element == kMethodTag) {
+    doc_string_ptr = &(interfaces_.back().methods.back().doc_string);
+  } else if (target_element == kSignalTag) {
+    doc_string_ptr = &(interfaces_.back().signals.back().doc_string);
+  } else if (target_element == kPropertyTag) {
+    doc_string_ptr = &(interfaces_.back().properties.back().doc_string);
+  }
+
+  // If <tp:docstring> is attached to elements we don't care about, do nothing.
+  if (doc_string_ptr == nullptr)
+    return;
+
+  (*doc_string_ptr) += content;
+}
+
+
+void XmlInterfaceParser::AddMethodArgument(const XmlAttributeMap& attributes) {
+  string argument_direction;
+  vector<string> path = element_path_;
+  path.push_back(kArgumentTag);
+  bool is_direction_paramter_present = GetElementAttribute(
+      attributes, path, kDirectionAttribute, &argument_direction);
+  vector<Interface::Argument>* argument_list = nullptr;
+  if (!is_direction_paramter_present ||
+      argument_direction == kArgumentDirectionIn) {
+    argument_list = &interfaces_.back().methods.back().input_arguments;
+  } else if (argument_direction == kArgumentDirectionOut) {
+    argument_list = &interfaces_.back().methods.back().output_arguments;
+  } else {
+    LOG(FATAL) << "Unknown method argument direction " << argument_direction;
+  }
+  argument_list->push_back(ParseArgument(attributes, element_path_));
+}
+
+void XmlInterfaceParser::AddSignalArgument(const XmlAttributeMap& attributes) {
+  interfaces_.back().signals.back().arguments.push_back(
+      ParseArgument(attributes, element_path_));
+}
+
+void XmlInterfaceParser::OnCloseElement(const string& element_name) {
+  VLOG(1) << "Close Element " << element_name;
+  CHECK(!element_path_.empty());
+  CHECK_EQ(element_path_.back(), element_name);
+  element_path_.pop_back();
+  if (element_name == kNodeTag) {
+    CHECK(!node_names_.empty());
+    node_names_.pop_back();
+  }
+}
+
+// static
+bool XmlInterfaceParser::GetElementAttribute(
+    const XmlAttributeMap& attributes,
+    const vector<string>& element_path,
+    const string& element_key,
+    string* element_value) {
+  if (attributes.find(element_key) == attributes.end()) {
+    return false;
+  }
+  *element_value = attributes.find(element_key)->second;
+  VLOG(1) << "Got " << GetElementPath(element_path) << " element with "
+          << element_key << " = " << *element_value;
+  return true;
+}
+
+// static
+string XmlInterfaceParser::GetValidatedElementAttribute(
+    const XmlAttributeMap& attributes,
+    const vector<string>& element_path,
+    const string& element_key) {
+  string element_value;
+  CHECK(GetElementAttribute(attributes,
+                            element_path,
+                            element_key,
+                            &element_value))
+      << GetElementPath(element_path) << " does not contain a " << element_key
+      << " attribute";
+  CHECK(!element_value.empty()) << GetElementPath(element_path) << " "
+                                << element_key << " attribute is empty";
+  return element_value;
+}
+
+// static
+string XmlInterfaceParser::GetValidatedElementName(
+    const XmlAttributeMap& attributes,
+    const vector<string>& element_path) {
+  return GetValidatedElementAttribute(attributes, element_path, kNameAttribute);
+}
+
+// static
+Interface::Argument XmlInterfaceParser::ParseArgument(
+    const XmlAttributeMap& attributes, const vector<string>& element_path) {
+  vector<string> path = element_path;
+  path.push_back(kArgumentTag);
+  string argument_name;
+  // Since the "name" field is optional, use the un-validated variant.
+  GetElementAttribute(attributes, path, kNameAttribute, &argument_name);
+
+  string argument_type = GetValidatedElementAttribute(
+      attributes, path, kTypeAttribute);
+  return Interface::Argument(argument_name, argument_type);
+}
+
+// static
+Interface::Property XmlInterfaceParser::ParseProperty(
+    const XmlAttributeMap& attributes,
+    const std::vector<std::string>& element_path) {
+  vector<string> path = element_path;
+  path.push_back(kPropertyTag);
+  string property_name = GetValidatedElementName(attributes, path);
+  string property_type = GetValidatedElementAttribute(attributes, path,
+                                                      kTypeAttribute);
+  string property_access = GetValidatedElementAttribute(attributes, path,
+                                                        kAccessAttribute);
+  return Interface::Property(property_name, property_type, property_access);
+}
+
+// static
+void XmlInterfaceParser::HandleElementStart(void* user_data,
+                                            const XML_Char* element,
+                                            const XML_Char** attr) {
+  XmlAttributeMap attributes;
+  if (attr != nullptr) {
+    for (size_t n = 0; attr[n] != nullptr && attr[n+1] != nullptr; n += 2) {
+      auto key = attr[n];
+      auto value = attr[n + 1];
+      attributes.insert(std::make_pair(key, value));
+    }
+  }
+  auto parser = reinterpret_cast<XmlInterfaceParser*>(user_data);
+  parser->OnOpenElement(element, attributes);
+}
+
+// static
+void XmlInterfaceParser::HandleElementEnd(void* user_data,
+                                          const XML_Char* element) {
+  auto parser = reinterpret_cast<XmlInterfaceParser*>(user_data);
+  parser->OnCloseElement(element);
+}
+
+// static
+void XmlInterfaceParser::HandleCharData(void* user_data,
+                                        const char *content,
+                                        int length) {
+  auto parser = reinterpret_cast<XmlInterfaceParser*>(user_data);
+  parser->OnCharData(string(content, length));
+}
+
+}  // namespace chromeos_dbus_bindings
diff --git a/dbus-binding-generator/chromeos-dbus-bindings/xml_interface_parser.h b/dbus-binding-generator/chromeos-dbus-bindings/xml_interface_parser.h
new file mode 100644
index 0000000..15ad857
--- /dev/null
+++ b/dbus-binding-generator/chromeos-dbus-bindings/xml_interface_parser.h
@@ -0,0 +1,136 @@
+// Copyright 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMEOS_DBUS_BINDINGS_XML_INTERFACE_PARSER_H_
+#define CHROMEOS_DBUS_BINDINGS_XML_INTERFACE_PARSER_H_
+
+#include <expat.h>
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include <base/macros.h>
+
+#include "chromeos-dbus-bindings/interface.h"
+
+namespace base {
+
+class FilePath;
+
+}  // namespace base
+
+namespace chromeos_dbus_bindings {
+
+class XmlInterfaceParser {
+ public:
+  using XmlAttributeMap = std::map<std::string, std::string>;
+
+  XmlInterfaceParser() = default;
+  virtual ~XmlInterfaceParser() = default;
+
+  bool ParseXmlInterfaceFile(const std::string& contents,
+                             const std::vector<std::string>& ignore_interfaces);
+  const std::vector<Interface>& interfaces() const { return interfaces_; }
+
+ private:
+  friend class XmlInterfaceParserTest;
+
+  // XML tag names.
+  static const char kArgumentTag[];
+  static const char kInterfaceTag[];
+  static const char kMethodTag[];
+  static const char kNodeTag[];
+  static const char kSignalTag[];
+  static const char kPropertyTag[];
+  static const char kAnnotationTag[];
+  static const char kDocStringTag[];
+
+  // XML attribute names.
+  static const char kNameAttribute[];
+  static const char kTypeAttribute[];
+  static const char kDirectionAttribute[];
+  static const char kAccessAttribute[];
+  static const char kValueAttribute[];
+
+  // XML argument directions.
+  static const char kArgumentDirectionIn[];
+  static const char kArgumentDirectionOut[];
+
+  // XML annotations.
+  static const char kTrue[];
+  static const char kFalse[];
+
+  static const char kMethodConst[];
+  static const char kMethodAsync[];
+  static const char kMethodIncludeDBusMessage[];
+
+  static const char kMethodKind[];
+  static const char kMethodKindSimple[];
+  static const char kMethodKindNormal[];
+  static const char kMethodKindAsync[];
+  static const char kMethodKindRaw[];
+
+  // Element callbacks on |this| called by HandleElementStart() and
+  // HandleElementEnd(), respectively.
+  void OnOpenElement(const std::string& element_name,
+                     const XmlAttributeMap& attributes);
+  void OnCloseElement(const std::string& element_name);
+  void OnCharData(const std::string& content);
+
+  // Methods for appending individual argument elements to the parser.
+  void AddMethodArgument(const XmlAttributeMap& attributes);
+  void AddSignalArgument(const XmlAttributeMap& attributes);
+
+  // Finds the |element_key| element in |attributes|.  Returns true and sets
+  // |element_value| on success.  Returns false otherwise.
+  static bool GetElementAttribute(const XmlAttributeMap& attributes,
+                                  const std::vector<std::string>& element_path,
+                                  const std::string& element_key,
+                                  std::string* element_value);
+
+  // Asserts that a non-empty |element_key| attribute appears in |attributes|.
+  // Returns the name on success, triggers a CHECK() otherwise.
+  static std::string GetValidatedElementAttribute(
+      const XmlAttributeMap& attributes,
+      const std::vector<std::string>& element_path,
+      const std::string& element_key);
+
+  // Calls GetValidatedElementAttribute() for the "name" property.
+  static std::string GetValidatedElementName(
+      const XmlAttributeMap& attributes,
+      const std::vector<std::string>& element_path);
+
+  // Method for extracting signal/method tag attributes to a struct.
+  static Interface::Argument ParseArgument(
+      const XmlAttributeMap& attributes,
+      const std::vector<std::string>& element_path);
+
+  // Method for extracting property tag attributes to a struct.
+  static Interface::Property ParseProperty(
+      const XmlAttributeMap& attributes,
+      const std::vector<std::string>& element_path);
+
+  // Expat element callback functions.
+  static void HandleElementStart(void* user_data,
+                                 const XML_Char* element,
+                                 const XML_Char** attr);
+  static void HandleElementEnd(void* user_data, const XML_Char* element);
+  static void HandleCharData(void* user_data, const char *content, int length);
+
+  // The output of the parse.
+  std::vector<Interface> interfaces_;
+
+  // A stack of <node> names used to track the object paths for interfaces.
+  std::vector<std::string> node_names_;
+
+  // Tracks where in the element traversal our parse has taken us.
+  std::vector<std::string> element_path_;
+
+  DISALLOW_COPY_AND_ASSIGN(XmlInterfaceParser);
+};
+
+}  // namespace chromeos_dbus_bindings
+
+#endif  // CHROMEOS_DBUS_BINDINGS_XML_INTERFACE_PARSER_H_
diff --git a/dbus-binding-generator/chromeos-dbus-bindings/xml_interface_parser_unittest.cc b/dbus-binding-generator/chromeos-dbus-bindings/xml_interface_parser_unittest.cc
new file mode 100644
index 0000000..69173ec
--- /dev/null
+++ b/dbus-binding-generator/chromeos-dbus-bindings/xml_interface_parser_unittest.cc
@@ -0,0 +1,129 @@
+// Copyright 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chromeos-dbus-bindings/xml_interface_parser.h"
+
+#include <base/files/file_path.h>
+#include <base/files/file_util.h>
+#include <base/files/scoped_temp_dir.h>
+#include <gtest/gtest.h>
+
+#include "chromeos-dbus-bindings/interface.h"
+
+using std::string;
+using std::vector;
+using testing::Test;
+
+namespace chromeos_dbus_bindings {
+
+namespace {
+
+const char kBadInterfaceFileContents0[] = "This has no resemblance to XML";
+const char kBadInterfaceFileContents1[] = "<node>";
+const char kGoodInterfaceFileContents[] = R"literal_string(
+<node name="/org/chromium/Test">
+  <interface name="fi.w1.wpa_supplicant1.Interface">
+    <method name="Scan">
+      <arg name="args" type="a{sv}" direction="in"/>
+      <annotation name="org.chromium.DBus.Method.Kind" value="async"/>
+      <annotation name="org.chromium.DBus.Method.IncludeDBusMessage"
+                  value="true"/>
+    </method>
+    <method name="GetBlob">
+      <arg name="name" type="s"/>
+      <arg name="data" type="ay" direction="out"/>
+      <annotation name="org.chromium.DBus.Method.Const" value="true"/>
+    </method>
+    <property name="Capabilities" type="a{sv}" access="read"/>
+    <signal name="BSSRemoved">
+      <arg name="BSS" type="o"/>
+    </signal>
+  </interface>
+  <interface name="DummyInterface" />
+  <node name="/"/>
+  <node/>
+</node>
+)literal_string";
+const char kInterfaceName[] = "fi.w1.wpa_supplicant1.Interface";
+const char kScanMethod[] = "Scan";
+const char kArgsArgument[] = "args";
+const char kArrayStringVariantType[] = "a{sv}";
+const char kGetBlobMethod[] = "GetBlob";
+const char kNameArgument[] = "name";
+const char kDataArgument[] = "data";
+const char kStringType[] = "s";
+const char kArrayByteType[] = "ay";
+const char kBssRemovedSignal[] = "BSSRemoved";
+const char kBssArgument[] = "BSS";
+const char kObjectType[] = "o";
+const char kCapabilitiesProperty[] = "Capabilities";
+const char kReadAccess[] = "read";
+}  // namespace
+
+class XmlInterfaceParserTest : public Test {
+ protected:
+  XmlInterfaceParser parser_;
+};
+
+TEST_F(XmlInterfaceParserTest, BadInputFile) {
+  EXPECT_FALSE(parser_.ParseXmlInterfaceFile(kBadInterfaceFileContents0, {}));
+  EXPECT_FALSE(parser_.ParseXmlInterfaceFile(kBadInterfaceFileContents1, {}));
+}
+
+TEST_F(XmlInterfaceParserTest, GoodInputFile) {
+  EXPECT_TRUE(parser_.ParseXmlInterfaceFile(kGoodInterfaceFileContents,
+                                            {"DummyInterface"}));
+  const vector<Interface>& interfaces = parser_.interfaces();
+  ASSERT_EQ(1u, interfaces.size());
+  const Interface& interface = interfaces.back();
+
+  EXPECT_EQ(kInterfaceName, interface.name);
+  EXPECT_EQ("/org/chromium/Test", interface.path);
+  ASSERT_EQ(2u, interface.methods.size());
+  ASSERT_EQ(1u, interface.signals.size());
+
+  // <method name="Scan">
+  EXPECT_EQ(kScanMethod, interface.methods[0].name);
+  EXPECT_EQ(Interface::Method::Kind::kAsync, interface.methods[0].kind);
+  EXPECT_FALSE(interface.methods[0].is_const);
+  EXPECT_TRUE(interface.methods[0].include_dbus_message);
+  ASSERT_EQ(1u, interface.methods[0].input_arguments.size());
+
+  // <arg name="args" type="a{sv}" direction="in"/>
+  EXPECT_EQ(kArgsArgument, interface.methods[0].input_arguments[0].name);
+  EXPECT_EQ(kArrayStringVariantType,
+            interface.methods[0].input_arguments[0].type);
+  EXPECT_EQ(0u, interface.methods[0].output_arguments.size());
+
+  // <method name="GetBlob">
+  EXPECT_EQ(kGetBlobMethod, interface.methods[1].name);
+  EXPECT_EQ(Interface::Method::Kind::kNormal, interface.methods[1].kind);
+  EXPECT_TRUE(interface.methods[1].is_const);
+  EXPECT_FALSE(interface.methods[1].include_dbus_message);
+  EXPECT_EQ(1u, interface.methods[1].input_arguments.size());
+  EXPECT_EQ(1u, interface.methods[1].output_arguments.size());
+
+  // <arg name="name" type="s"/>  (direction="in" is implicit)
+  EXPECT_EQ(kNameArgument, interface.methods[1].input_arguments[0].name);
+  EXPECT_EQ(kStringType, interface.methods[1].input_arguments[0].type);
+
+  // <arg name="data" type="ay" direction="out"/>
+  EXPECT_EQ(kDataArgument, interface.methods[1].output_arguments[0].name);
+  EXPECT_EQ(kArrayByteType, interface.methods[1].output_arguments[0].type);
+
+  // <signal name="BSSRemoved">
+  EXPECT_EQ(kBssRemovedSignal, interface.signals[0].name);
+  EXPECT_EQ(1u, interface.signals[0].arguments.size());
+
+  // <arg name="BSS" type="o"/>
+  EXPECT_EQ(kBssArgument, interface.signals[0].arguments[0].name);
+  EXPECT_EQ(kObjectType, interface.signals[0].arguments[0].type);
+
+  // <property name="Capabilities" type="s" access="read"/>
+  EXPECT_EQ(kCapabilitiesProperty, interface.properties[0].name);
+  EXPECT_EQ(kArrayStringVariantType, interface.properties[0].type);
+  EXPECT_EQ(kReadAccess, interface.properties[0].access);
+}
+
+}  // namespace chromeos_dbus_bindings