libchromeos: Fix DBus data serialization to work with custom types

The previous implementation suffered from C++ binding rules for
non-dependent names in templates. Template functions such as
AppendValueToWriter and PopValueFromReader for template types such
as std::vector<T> and std::map<K,V> are limited to the types defined
in libchromeos because the implementations calling the inner overloads
for types such as T would only select functions defined before the
overloads for vector and map are defined.

This forced the custom implementations of user-provided types to
be included before chromeos/dbus/data_serialization.h and having
the code depend on the order of includes is a very dangerous thing.

To make the problem worse, generic AppendValueToWriter<T> is always
a default fall-back for any unknown types and it simply fails at run-time
which makes it very difficult to detect unintended problems.

The reason why the generic AppendValueToWriter<T>() was provided is to
allow chromeos::Any to contain any C++ type but still be able to use
with D-Bus subset of types to implement the D-Bus's VARIANT type.

This change addresses the above problems as follows:

- The template functionality depending on custom overloads of
  AppendValueToWriter and PopValueFromReader now call them indirectly
  through DBusType<T>::Write and DBusType<T>::Read helpers that delay
  binding to the correct overload of Append... and Pop... until the
  template instantiation.
- Marked the generic AppendValueToWriter<T> and PopValueFromReader<T>
  as "deleted" functions so the compilation would break as soon as
  these functions are called with an unsupported types.
- Provided IsTypeSupported<T...> type trait to help specialize the
  implementation for only supported D-Bus types. This allows, for
  example, specialization of vector<T> to work for supported types
  T and fail immediately for T that are not supported by D-Bus.
- Used IsTypeSupported<T> in chromeos::Any to disable calls to
  AppendValueToWriter at compile time for unsupported types.
- Made AppendValueToWriter() a void function. Now it doesn't fail.
  The internal implementation inside chromeos::Any uses CHECK() to
  ensure the contained class which will abort as soon as Any,
  containing datat of an unsupported type, is being written to
  D-Bus message buffer.

BUG=chromium:431744
TEST=FEATURES=test emerge-link libchromeos attestation buffet peerd

Change-Id: I13431f74797b8b92082f172a067ea1515a7aa73e
Reviewed-on: https://chromium-review.googlesource.com/228731
Reviewed-by: Christopher Wiley <wiley@chromium.org>
Commit-Queue: Alex Vakulenko <avakulenko@chromium.org>
Tested-by: Alex Vakulenko <avakulenko@chromium.org>
diff --git a/chromeos/any.cc b/chromeos/any.cc
index 2f54871..4cedff6 100644
--- a/chromeos/any.cc
+++ b/chromeos/any.cc
@@ -72,10 +72,9 @@
   return data_buffer_.GetDataPtr()->GetAsInteger();
 }
 
-bool Any::AppendToDBusMessageWriter(dbus::MessageWriter* writer) const {
-  if (IsEmpty())
-    return false;
-  return data_buffer_.GetDataPtr()->AppendToDBusMessage(writer);
+void Any::AppendToDBusMessageWriter(dbus::MessageWriter* writer) const {
+  CHECK(!IsEmpty()) << "Must not be called on an empty Any";
+  data_buffer_.GetDataPtr()->AppendToDBusMessage(writer);
 }
 
 }  // namespace chromeos
diff --git a/chromeos/any.h b/chromeos/any.h
index 3f0197b..bda7e60 100644
--- a/chromeos/any.h
+++ b/chromeos/any.h
@@ -174,7 +174,7 @@
   // (an appropriate specialization of AppendValueToWriter<T>() is available).
   // Returns false if the Any is empty or if there is no serialization method
   // defined for the contained data.
-  bool AppendToDBusMessageWriter(dbus::MessageWriter* writer) const;
+  void AppendToDBusMessageWriter(dbus::MessageWriter* writer) const;
 
  private:
   // The data buffer for contained object.
diff --git a/chromeos/any_internal_impl.h b/chromeos/any_internal_impl.h
index 828905c..13aef03 100644
--- a/chromeos/any_internal_impl.h
+++ b/chromeos/any_internal_impl.h
@@ -148,7 +148,7 @@
   // Gets the contained integral value as an integer.
   virtual intmax_t GetAsInteger() const = 0;
   // Writes the contained value to the D-Bus message buffer.
-  virtual bool AppendToDBusMessage(dbus::MessageWriter* writer) const = 0;
+  virtual void AppendToDBusMessage(dbus::MessageWriter* writer) const = 0;
   // Compares if the two data containers have objects of the same value.
   virtual bool CompareEqual(const Data* other_data) const = 0;
 };
@@ -174,8 +174,21 @@
                      << "' to integer";
     return int_val;
   }
-  bool AppendToDBusMessage(dbus::MessageWriter* writer) const override {
-    return chromeos::dbus_utils::AppendValueToWriterAsVariant(writer, value_);
+
+  template<typename U>
+  static typename std::enable_if<dbus_utils::IsTypeSupported<U>::value>::type
+  AppendValueHelper(dbus::MessageWriter* writer, const U& value) {
+    chromeos::dbus_utils::AppendValueToWriterAsVariant(writer, value);
+  }
+  template<typename U>
+  static typename std::enable_if<!dbus_utils::IsTypeSupported<U>::value>::type
+  AppendValueHelper(dbus::MessageWriter* writer, const U& value) {
+    LOG(FATAL) << "Type '" << GetUndecoratedTypeName<U>()
+               << "' is not supported by D-Bus";
+  }
+
+  void AppendToDBusMessage(dbus::MessageWriter* writer) const override {
+    return AppendValueHelper(writer, value_);
   }
 
   bool CompareEqual(const Data* other_data) const override {
diff --git a/chromeos/dbus/data_serialization.cc b/chromeos/dbus/data_serialization.cc
index 30c09df..b389ce0 100644
--- a/chromeos/dbus/data_serialization.cc
+++ b/chromeos/dbus/data_serialization.cc
@@ -10,76 +10,64 @@
 namespace chromeos {
 namespace dbus_utils {
 
-bool AppendValueToWriter(dbus::MessageWriter* writer, bool value) {
+void AppendValueToWriter(dbus::MessageWriter* writer, bool value) {
   writer->AppendBool(value);
-  return true;
 }
 
-bool AppendValueToWriter(dbus::MessageWriter* writer, uint8_t value) {
+void AppendValueToWriter(dbus::MessageWriter* writer, uint8_t value) {
   writer->AppendByte(value);
-  return true;
 }
 
-bool AppendValueToWriter(dbus::MessageWriter* writer, int16_t value) {
+void AppendValueToWriter(dbus::MessageWriter* writer, int16_t value) {
   writer->AppendInt16(value);
-  return true;
 }
 
-bool AppendValueToWriter(dbus::MessageWriter* writer, uint16_t value) {
+void AppendValueToWriter(dbus::MessageWriter* writer, uint16_t value) {
   writer->AppendUint16(value);
-  return true;
 }
 
-bool AppendValueToWriter(dbus::MessageWriter* writer, int32_t value) {
+void AppendValueToWriter(dbus::MessageWriter* writer, int32_t value) {
   writer->AppendInt32(value);
-  return true;
 }
 
-bool AppendValueToWriter(dbus::MessageWriter* writer, uint32_t value) {
+void AppendValueToWriter(dbus::MessageWriter* writer, uint32_t value) {
   writer->AppendUint32(value);
-  return true;
 }
 
-bool AppendValueToWriter(dbus::MessageWriter* writer, int64_t value) {
+void AppendValueToWriter(dbus::MessageWriter* writer, int64_t value) {
   writer->AppendInt64(value);
-  return true;
 }
 
-bool AppendValueToWriter(dbus::MessageWriter* writer, uint64_t value) {
+void AppendValueToWriter(dbus::MessageWriter* writer, uint64_t value) {
   writer->AppendUint64(value);
-  return true;
 }
 
-bool AppendValueToWriter(dbus::MessageWriter* writer, double value) {
+void AppendValueToWriter(dbus::MessageWriter* writer, double value) {
   writer->AppendDouble(value);
-  return true;
 }
 
-bool AppendValueToWriter(dbus::MessageWriter* writer,
+void AppendValueToWriter(dbus::MessageWriter* writer,
                          const std::string& value) {
   writer->AppendString(value);
-  return true;
 }
 
-bool AppendValueToWriter(dbus::MessageWriter* writer, const char* value) {
-  return AppendValueToWriter(writer, std::string(value));
+void AppendValueToWriter(dbus::MessageWriter* writer, const char* value) {
+  AppendValueToWriter(writer, std::string(value));
 }
 
-bool AppendValueToWriter(dbus::MessageWriter* writer,
+void AppendValueToWriter(dbus::MessageWriter* writer,
                          const dbus::ObjectPath& value) {
   writer->AppendObjectPath(value);
-  return true;
 }
 
-bool AppendValueToWriter(dbus::MessageWriter* writer,
+void AppendValueToWriter(dbus::MessageWriter* writer,
                          const dbus::FileDescriptor& value) {
   writer->AppendFileDescriptor(value);
-  return true;
 }
 
-bool AppendValueToWriter(dbus::MessageWriter* writer,
+void AppendValueToWriter(dbus::MessageWriter* writer,
                          const chromeos::Any& value) {
-  return value.AppendToDBusMessageWriter(writer);
+  value.AppendToDBusMessageWriter(writer);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/chromeos/dbus/data_serialization.h b/chromeos/dbus/data_serialization.h
index 9a96ecd..3a31adf 100644
--- a/chromeos/dbus/data_serialization.h
+++ b/chromeos/dbus/data_serialization.h
@@ -10,8 +10,8 @@
 // - Methods to get the D-Bus signature for a given C++ type:
 //     std::string GetDBusSignature<T>();
 // - Methods to write arbitrary C++ data to D-Bus MessageWriter:
-//     bool AppendValueToWriter(dbus::MessageWriter* writer, const T& value);
-//     bool AppendValueToWriterAsVariant(dbus::MessageWriter*, const T&);
+//     void AppendValueToWriter(dbus::MessageWriter* writer, const T& value);
+//     void AppendValueToWriterAsVariant(dbus::MessageWriter*, const T&);
 // - Methods to read arbitrary C++ data from D-Bus MessageReader:
 //     bool PopValueFromReader(dbus::MessageReader* reader, T* value);
 //     bool PopVariantValueFromReader(dbus::MessageReader* reader, T* value);
@@ -40,9 +40,18 @@
 //
 // (*) - Currently, only 2 element STRUCTs are supported as std::pair. In the
 // future we can add a generic std::tuple<...> support for arbitrary number
-// of struct members. Implementations could also provide specializations for
-// custom C++ structures for AppendValueToWriter/PopValueFromReader.
-// See an example in DBusUtils.CustomStruct unit test in dbus_utils_unittest.cc.
+// of struct members.
+//
+// Additional overloads/specialization can be provided for custom types.
+// In order to do that, provide overloads of AppendValueToWriter() and
+// PopValueFromReader() functions in chromeos::dbus_utils namespace for the
+// CustomType. As well as a template specialization of DBusType<> for the same
+// CustomType. This specialization must provide three static functions:
+//  - static std::string GetSignature();
+//  - static void Write(dbus::MessageWriter* writer, const CustomType& value);
+//  - static bool Read(dbus::MessageReader* reader, CustomType* value);
+// See an example in DBusUtils.CustomStruct unit test in
+// chromeos/dbus/data_serialization_unittest.cc.
 
 #include <map>
 #include <memory>
@@ -69,29 +78,94 @@
 
 namespace dbus_utils {
 
+// Base class for DBusType<T> for T not supported by D-Bus. This used to
+// implement IsTypeSupported<> below.
+struct Unsupported {};
+
+// Generic definition of DBusType<T> which will be specialized for particular
+// types later.
+template<typename T>
+struct DBusType : public Unsupported {};
+
+// A helper type trait to determine if all of the types listed in Types... are
+// supported by D-Bus. This is a generic forward-declaration which will be
+// specialized for different type combinations.
+template<typename... Types>
+struct IsTypeSupported;
+
+// Both T and the Types... must be supported for the complete set to be
+// supported.
+template<typename T, typename... Types>
+struct IsTypeSupported<T, Types...>
+    : public std::integral_constant<bool, IsTypeSupported<T>::value &&
+                                          IsTypeSupported<Types...>::value> {};
+
+// For a single type T, check if DBusType<T> derives from Unsupported.
+// If it does, then the type is not supported by the D-Bus.
+template<typename T>
+struct IsTypeSupported<T> : public std::integral_constant<
+    bool, !std::is_base_of<Unsupported, DBusType<T>>::value> {};
+
+// Empty set is not supported.
+template<>
+struct IsTypeSupported<> : public std::false_type {};
+
+//----------------------------------------------------------------------------
+// AppendValueToWriter<T>(dbus::MessageWriter* writer, const T& value)
+// Write the |value| of type T to D-Bus message.
+// The default implementation is marked as "deleted". This method must be
+// overloaded for specific types to allow serialization over D-Bus.
+// If this function causes compile-time error, this means that either
+// the type T is not supported by D-Bus or you haven't provided an overload
+// for custom types you want to serialize over D-Bus. See the comment at the
+// top of this file for explanation of how to add custom data serialization
+// code.
+template<typename T>
+void AppendValueToWriter(dbus::MessageWriter* writer, const T& value) = delete;
+
+//----------------------------------------------------------------------------
+// PopValueFromReader<T>(dbus::MessageWriter* writer, T* value)
+// Reads the |value| of type T from D-Bus message. These methods can read both
+// actual data of type T and data of type T sent over D-Bus as a Variant.
+// This allows it, for example, to read a generic dictionary ("a{sv}") as
+// a specific map type (e.g. "a{ss}", if a map of string-to-string is expected).
+// The default implementation is marked as "deleted". This method must be
+// overloaded for specific types to allow serialization over D-Bus.
+// If this function causes compile-time error, this means that either
+// the type T is not supported by D-Bus or you haven't provided an overload
+// for custom types you want to serialize over D-Bus. See the comment at the
+// top of this file for explanation of how to add custom data serialization
+// code.
+template<typename T>
+void PopValueFromReader(dbus::MessageReader* reader, T* value) = delete;
+
 //----------------------------------------------------------------------------
 // Get D-Bus data signature from C++ data types.
 // Specializations of a generic GetDBusSignature<T>() provide signature strings
-// for native C++ types.
-
-// It is not possible to provide partial specialization for template functions,
-// so we are using a helper template struct with a static member getter,
-// DBusSignature<T>::get(), to work around this problem. So, we do partial
-// specialization of DBusSignature<T> instead, and have GetDBusSignature<T>()
-// just call DBusSignature<T>::get().
-
-template<typename T> std::string GetDBusSignature();  // Forward declaration.
-
-// Generic template getter that fails for all types unless an explicit
-// specialization is provided for.
+// for native C++ types. This function is available only for type supported
+// by D-Bus.
 template<typename T>
-struct DBusSignature {
-  inline static std::string get() {
-    LOG(ERROR) << "Type '" << GetUndecoratedTypeName<T>()
-               << "' is not supported by D-Bus";
-    return std::string();
-  }
-};
+inline typename std::enable_if<IsTypeSupported<T>::value, std::string>::type
+GetDBusSignature() {
+  return DBusType<T>::GetSignature();
+}
+
+namespace details {
+// Helper method used by the many overloads of PopValueFromReader().
+// If the current value in the reader is of Variant type, the method descends
+// into the Variant and updates the |*reader_ref| with the transient
+// |variant_reader| MessageReader instance passed in.
+// Returns false if it fails to descend into the Variant.
+inline bool DescendIntoVariantIfPresent(
+    dbus::MessageReader** reader_ref,
+    dbus::MessageReader* variant_reader) {
+  if ((*reader_ref)->GetDataType() != dbus::Message::VARIANT)
+    return true;
+  if (!(*reader_ref)->PopVariant(variant_reader))
+    return false;
+  *reader_ref = variant_reader;
+  return true;
+}
 
 // Helper method to format the type string of an array.
 // Essentially it adds "a" in front of |element_signature|.
@@ -110,297 +184,309 @@
          DBUS_DICT_ENTRY_END_CHAR_AS_STRING;
 }
 
-// Specializations of DBusSignature<T> for basic D-Bus types.
-template<> struct DBusSignature<bool> {
-  inline static std::string get() { return DBUS_TYPE_BOOLEAN_AS_STRING; }
-};
-template<> struct DBusSignature<uint8_t> {
-  inline static std::string get() { return DBUS_TYPE_BYTE_AS_STRING; }
-};
-template<> struct DBusSignature<int16_t> {
-  inline static std::string get() { return DBUS_TYPE_INT16_AS_STRING; }
-};
-template<> struct DBusSignature<uint16_t> {
-  inline static std::string get() { return DBUS_TYPE_UINT16_AS_STRING; }
-};
-template<> struct DBusSignature<int32_t> {
-  inline static std::string get() { return DBUS_TYPE_INT32_AS_STRING; }
-};
-template<> struct DBusSignature<uint32_t> {
-  inline static std::string get() { return DBUS_TYPE_UINT32_AS_STRING; }
-};
-template<> struct DBusSignature<int64_t> {
-  inline static std::string get() { return DBUS_TYPE_INT64_AS_STRING; }
-};
-template<> struct DBusSignature<uint64_t> {
-  inline static std::string get() { return DBUS_TYPE_UINT64_AS_STRING; }
-};
-template<> struct DBusSignature<double> {
-  inline static std::string get() { return DBUS_TYPE_DOUBLE_AS_STRING; }
-};
-template<> struct DBusSignature<const char*> {
-  inline static std::string get() { return DBUS_TYPE_STRING_AS_STRING; }
-};
-template<> struct DBusSignature<const char[]> {
-  inline static std::string get() { return DBUS_TYPE_STRING_AS_STRING; }
-};
-template<> struct DBusSignature<std::string> {
-  inline static std::string get() { return DBUS_TYPE_STRING_AS_STRING; }
-};
-template<> struct DBusSignature<dbus::ObjectPath> {
-  inline static std::string get() { return DBUS_TYPE_OBJECT_PATH_AS_STRING; }
-};
-template<> struct DBusSignature<dbus::FileDescriptor> {
-  inline static std::string get() { return DBUS_TYPE_UNIX_FD_AS_STRING; }
-};
-template<> struct DBusSignature<chromeos::Any> {
-  inline static std::string get() { return DBUS_TYPE_VARIANT_AS_STRING; }
-};
-
-// Specializations of DBusSignature<T> for some compound data types such
-// as ARRAYs, STRUCTs, DICTs.
-
-// std::vector = D-Bus ARRAY.
-template<typename T>
-struct DBusSignature<std::vector<T>> {
-  // Returns "aT", where "T" is the signature string for type T.
-  inline static std::string get() {
-    return GetArrayDBusSignature(GetDBusSignature<T>());
-  }
-};
-
-// std::pair = D-Bus STRUCT with two elements.
-template<typename U, typename V>
-struct DBusSignature<std::pair<U, V>> {
-  // Returns "(UV)", where "U" and "V" are the signature strings for types U/V.
-  inline static std::string get() {
-    return DBUS_STRUCT_BEGIN_CHAR_AS_STRING + GetDBusSignature<U>() +
-           GetDBusSignature<V>() + DBUS_STRUCT_END_CHAR_AS_STRING;
-  }
-};
-
-// std::map = D-Bus ARRAY of DICT_ENTRY.
-template<typename KEY, typename VALUE>
-struct DBusSignature<std::map<KEY, VALUE>> {
-  // Returns "a{KV}", where "K" and "V" are the signature strings for types
-  // KEY/VALUE.
-  inline static std::string get() {
-    return GetArrayDBusSignature(GetDBusDictEntryType<KEY, VALUE>());
-  }
-};
-
-// google::protobuf::MessageLite = D-Bus ARRAY of BYTE
-template<> struct DBusSignature<google::protobuf::MessageLite> {
-  inline static std::string get() {
-    return DBusSignature<std::vector<uint8_t>>::get();
-  }
-};
-
-// The main worker function that returns a signature string for given type T.
-// For example, GetDBusSignature<std::map<int, bool>>() would return "a{ib}".
-template<typename T>
-inline std::string GetDBusSignature() { return DBusSignature<T>::get(); }
-
-//----------------------------------------------------------------------------
-// AppendValueToWriter<T>(dbus::MessageWriter* writer, const T& value)
-// Write the |value| of type T to D-Bus message.
-
-// Generic template method that fails for all types unless specifically
-// specialized for that type.
-template<typename T>
-inline bool AppendValueToWriter(dbus::MessageWriter* writer, const T& value) {
-  LOG(ERROR) << "Serialization of type '"
-             << GetUndecoratedTypeName<T>() << "' not supported";
-  return false;
-}
-
-// Numerous overloads for various native data types are provided below.
-
-// Basic types.
-CHROMEOS_EXPORT bool AppendValueToWriter(dbus::MessageWriter* writer,
-                                         bool value);
-CHROMEOS_EXPORT bool AppendValueToWriter(dbus::MessageWriter* writer,
-                                         uint8_t value);
-CHROMEOS_EXPORT bool AppendValueToWriter(dbus::MessageWriter* writer,
-                                         int16_t value);
-CHROMEOS_EXPORT bool AppendValueToWriter(dbus::MessageWriter* writer,
-                                         uint16_t value);
-CHROMEOS_EXPORT bool AppendValueToWriter(dbus::MessageWriter* writer,
-                                         int32_t value);
-CHROMEOS_EXPORT bool AppendValueToWriter(dbus::MessageWriter* writer,
-                                         uint32_t value);
-CHROMEOS_EXPORT bool AppendValueToWriter(dbus::MessageWriter* writer,
-                                         int64_t value);
-CHROMEOS_EXPORT bool AppendValueToWriter(dbus::MessageWriter* writer,
-                                         uint64_t value);
-CHROMEOS_EXPORT bool AppendValueToWriter(dbus::MessageWriter* writer,
-                                         double value);
-CHROMEOS_EXPORT bool AppendValueToWriter(dbus::MessageWriter* writer,
-                                         const std::string& value);
-CHROMEOS_EXPORT bool AppendValueToWriter(dbus::MessageWriter* writer,
-                                         const char* value);
-CHROMEOS_EXPORT bool AppendValueToWriter(dbus::MessageWriter* writer,
-                                         const dbus::ObjectPath& value);
-CHROMEOS_EXPORT bool AppendValueToWriter(dbus::MessageWriter* writer,
-                                         const dbus::FileDescriptor& value);
-CHROMEOS_EXPORT bool AppendValueToWriter(dbus::MessageWriter* writer,
-                                         const chromeos::Any& value);
-
-// Overloads of AppendValueToWriter for some compound data types such
-// as ARRAYs, STRUCTs, DICTs.
-
-// std::vector = D-Bus ARRAY.
-template<typename T>
-inline bool AppendValueToWriter(dbus::MessageWriter* writer,
-                         const std::vector<T>& value) {
-  std::string data_type = GetDBusSignature<T>();
-  if (data_type.empty())
-    return false;
-  dbus::MessageWriter array_writer(nullptr);
-  writer->OpenArray(data_type, &array_writer);
-  bool success = true;
-  for (const auto& element : value) {
-    if (!AppendValueToWriter(&array_writer, element)) {
-      success = false;
-      break;
-    }
-  }
-  writer->CloseContainer(&array_writer);
-  return success;
-}
-
-// std::pair = D-Bus STRUCT with two elements.
-template<typename U, typename V>
-inline bool AppendValueToWriter(dbus::MessageWriter* writer,
-                         const std::pair<U, V>& value) {
-  dbus::MessageWriter struct_writer(nullptr);
-  writer->OpenStruct(&struct_writer);
-  bool success = AppendValueToWriter(&struct_writer, value.first) &&
-                 AppendValueToWriter(&struct_writer, value.second);
-  writer->CloseContainer(&struct_writer);
-  return success;
-}
-
-// std::map = D-Bus ARRAY of DICT_ENTRY.
-template<typename KEY, typename VALUE>
-inline bool AppendValueToWriter(dbus::MessageWriter* writer,
-                                const std::map<KEY, VALUE>& value) {
-  dbus::MessageWriter dict_writer(nullptr);
-  writer->OpenArray(GetDBusDictEntryType<KEY, VALUE>(), &dict_writer);
-  bool success = true;
-  for (const auto& pair : value) {
-    dbus::MessageWriter entry_writer(nullptr);
-    dict_writer.OpenDictEntry(&entry_writer);
-    success = AppendValueToWriter(&entry_writer, pair.first) &&
-              AppendValueToWriter(&entry_writer, pair.second);
-    dict_writer.CloseContainer(&entry_writer);
-    if (!success)
-      break;
-  }
-  writer->CloseContainer(&dict_writer);
-  return success;
-}
-
-// google::protobuf::MessageLite = D-Bus ARRAY of BYTE
-inline bool AppendValueToWriter(dbus::MessageWriter* writer,
-                                const google::protobuf::MessageLite& value) {
-  writer->AppendProtoAsArrayOfBytes(value);
-  return true;
-}
-
-//----------------------------------------------------------------------------
-// AppendValueToWriterAsVariant<T>(dbus::MessageWriter* writer, const T& value)
-// Write the |value| of type T to D-Bus message as a VARIANT
-template<typename T>
-inline bool AppendValueToWriterAsVariant(dbus::MessageWriter* writer,
-                                         const T& value) {
-  std::string data_type = GetDBusSignature<T>();
-  if (data_type.empty())
-    return false;
-  dbus::MessageWriter variant_writer(nullptr);
-  writer->OpenVariant(data_type, &variant_writer);
-  bool success = AppendValueToWriter(&variant_writer, value);
-  writer->CloseContainer(&variant_writer);
-  return success;
-}
-
-// Special case: do not allow to write a Variant containing a Variant.
-// Just redirect to normal AppendValueToWriter().
-inline bool AppendValueToWriterAsVariant(dbus::MessageWriter* writer,
-                                         const chromeos::Any& value) {
-  return AppendValueToWriter(writer, value);
-}
-
-//----------------------------------------------------------------------------
-// PopValueFromReader<T>(dbus::MessageWriter* writer, T* value)
-// Reads the |value| of type T from D-Bus message. These methods can read both
-// actual data of type T and data of type T sent over D-Bus as a Variant.
-// This allows it, for example, to read a generic dictionary ("a{sv}") as
-// a specific map type (e.g. "a{ss}", if a map of string-to-string is expected).
-
-namespace details {
-// Helper method used by the many overloads of PopValueFromReader().
-// If the current value in the reader is of Variant type, the method descends
-// into the Variant and updates the |*reader_ref| with the transient
-// |variant_reader| MessageReader instance passed in.
-// Returns false if it fails to descend into the Variant.
-inline bool DescendIntoVariantIfPresent(
-    dbus::MessageReader** reader_ref,
-    dbus::MessageReader* variant_reader) {
-  if ((*reader_ref)->GetDataType() != dbus::Message::VARIANT)
-    return true;
-  if (!(*reader_ref)->PopVariant(variant_reader))
-    return false;
-  *reader_ref = variant_reader;
-  return true;
-}
 }  // namespace details
 
-// Generic template method that fails for all types unless specifically
-// specialized for that type.
-template<typename T>
-inline bool PopValueFromReader(dbus::MessageReader* reader, T* value) {
-  LOG(ERROR) << "De-serialization of type '"
-             << GetUndecoratedTypeName<T>() << "' not supported";
-  return false;
+//=============================================================================
+// Specializations/overloads for AppendValueToWriter, PopValueFromReader and
+// DBusType<T> for various C++ types that can be serialized over D-Bus.
+
+// bool -----------------------------------------------------------------------
+CHROMEOS_EXPORT void AppendValueToWriter(
+    dbus::MessageWriter* writer, bool value);
+CHROMEOS_EXPORT bool PopValueFromReader(
+    dbus::MessageReader* reader, bool* value);
+
+template<>
+struct DBusType<bool> {
+  inline static std::string GetSignature() {
+    return DBUS_TYPE_BOOLEAN_AS_STRING;
+  }
+  inline static void Write(dbus::MessageWriter* writer, bool value) {
+    AppendValueToWriter(writer, value);
+  }
+  inline static bool Read(dbus::MessageReader* reader, bool* value) {
+    return PopValueFromReader(reader, value);
+  }
+};
+
+// uint8_t --------------------------------------------------------------------
+CHROMEOS_EXPORT void AppendValueToWriter(
+    dbus::MessageWriter* writer, uint8_t value);
+CHROMEOS_EXPORT bool PopValueFromReader(
+    dbus::MessageReader* reader, uint8_t* value);
+
+template<>
+struct DBusType<uint8_t> {
+  inline static std::string GetSignature() {
+    return DBUS_TYPE_BYTE_AS_STRING;
+  }
+  inline static void Write(dbus::MessageWriter* writer, uint8_t value) {
+    AppendValueToWriter(writer, value);
+  }
+  inline static bool Read(dbus::MessageReader* reader, uint8_t* value) {
+    return PopValueFromReader(reader, value);
+  }
+};
+
+// int16_t --------------------------------------------------------------------
+CHROMEOS_EXPORT void AppendValueToWriter(
+    dbus::MessageWriter* writer, int16_t value);
+CHROMEOS_EXPORT bool PopValueFromReader(
+    dbus::MessageReader* reader, int16_t* value);
+
+template<>
+struct DBusType<int16_t> {
+  inline static std::string GetSignature() {
+    return DBUS_TYPE_INT16_AS_STRING;
+  }
+  inline static void Write(dbus::MessageWriter* writer, int16_t value) {
+    AppendValueToWriter(writer, value);
+  }
+  inline static bool Read(dbus::MessageReader* reader, int16_t* value) {
+    return PopValueFromReader(reader, value);
+  }
+};
+
+// uint16_t -------------------------------------------------------------------
+CHROMEOS_EXPORT void AppendValueToWriter(
+    dbus::MessageWriter* writer, uint16_t value);
+CHROMEOS_EXPORT bool PopValueFromReader(
+    dbus::MessageReader* reader, uint16_t* value);
+
+template<>
+struct DBusType<uint16_t> {
+  inline static std::string GetSignature() {
+    return DBUS_TYPE_UINT16_AS_STRING;
+  }
+  inline static void Write(dbus::MessageWriter* writer, uint16_t value) {
+    AppendValueToWriter(writer, value);
+  }
+  inline static bool Read(dbus::MessageReader* reader, uint16_t* value) {
+    return PopValueFromReader(reader, value);
+  }
+};
+
+// int32_t --------------------------------------------------------------------
+CHROMEOS_EXPORT void AppendValueToWriter(
+    dbus::MessageWriter* writer, int32_t value);
+CHROMEOS_EXPORT bool PopValueFromReader(
+    dbus::MessageReader* reader, int32_t* value);
+
+template<>
+struct DBusType<int32_t> {
+  inline static std::string GetSignature() {
+    return DBUS_TYPE_INT32_AS_STRING;
+  }
+  inline static void Write(dbus::MessageWriter* writer, int32_t value) {
+    AppendValueToWriter(writer, value);
+  }
+  inline static bool Read(dbus::MessageReader* reader, int32_t* value) {
+    return PopValueFromReader(reader, value);
+  }
+};
+
+// uint32_t -------------------------------------------------------------------
+CHROMEOS_EXPORT void AppendValueToWriter(
+    dbus::MessageWriter* writer, uint32_t value);
+CHROMEOS_EXPORT bool PopValueFromReader(
+    dbus::MessageReader* reader, uint32_t* value);
+
+template<>
+struct DBusType<uint32_t> {
+  inline static std::string GetSignature() {
+    return DBUS_TYPE_UINT32_AS_STRING;
+  }
+  inline static void Write(dbus::MessageWriter* writer, uint32_t value) {
+    AppendValueToWriter(writer, value);
+  }
+  inline static bool Read(dbus::MessageReader* reader, uint32_t* value) {
+    return PopValueFromReader(reader, value);
+  }
+};
+
+// int64_t --------------------------------------------------------------------
+CHROMEOS_EXPORT void AppendValueToWriter(
+    dbus::MessageWriter* writer, int64_t value);
+CHROMEOS_EXPORT bool PopValueFromReader(
+    dbus::MessageReader* reader, int64_t* value);
+
+template<>
+struct DBusType<int64_t> {
+  inline static std::string GetSignature() {
+    return DBUS_TYPE_INT64_AS_STRING;
+  }
+  inline static void Write(dbus::MessageWriter* writer, int64_t value) {
+    AppendValueToWriter(writer, value);
+  }
+  inline static bool Read(dbus::MessageReader* reader, int64_t* value) {
+    return PopValueFromReader(reader, value);
+  }
+};
+
+// uint64_t -------------------------------------------------------------------
+CHROMEOS_EXPORT void AppendValueToWriter(
+    dbus::MessageWriter* writer, uint64_t value);
+CHROMEOS_EXPORT bool PopValueFromReader(
+    dbus::MessageReader* reader, uint64_t* value);
+
+template<>
+struct DBusType<uint64_t> {
+  inline static std::string GetSignature() {
+    return DBUS_TYPE_UINT64_AS_STRING;
+  }
+  inline static void Write(dbus::MessageWriter* writer, uint64_t value) {
+    AppendValueToWriter(writer, value);
+  }
+  inline static bool Read(dbus::MessageReader* reader, uint64_t* value) {
+    return PopValueFromReader(reader, value);
+  }
+};
+
+// double ---------------------------------------------------------------------
+CHROMEOS_EXPORT void AppendValueToWriter(
+    dbus::MessageWriter* writer, double value);
+CHROMEOS_EXPORT bool PopValueFromReader(
+    dbus::MessageReader* reader, double* value);
+
+template<>
+struct DBusType<double> {
+  inline static std::string GetSignature() {
+    return DBUS_TYPE_DOUBLE_AS_STRING;
+  }
+  inline static void Write(dbus::MessageWriter* writer, double value) {
+    AppendValueToWriter(writer, value);
+  }
+  inline static bool Read(dbus::MessageReader* reader, double* value) {
+    return PopValueFromReader(reader, value);
+  }
+};
+
+// std::string ----------------------------------------------------------------
+CHROMEOS_EXPORT void AppendValueToWriter(
+    dbus::MessageWriter* writer, const std::string& value);
+CHROMEOS_EXPORT bool PopValueFromReader(
+    dbus::MessageReader* reader, std::string* value);
+
+template<>
+struct DBusType<std::string> {
+  inline static std::string GetSignature() {
+    return DBUS_TYPE_STRING_AS_STRING;
+  }
+  inline static void Write(dbus::MessageWriter* writer,
+                           const std::string& value) {
+    AppendValueToWriter(writer, value);
+  }
+  inline static bool Read(dbus::MessageReader* reader, std::string* value) {
+    return PopValueFromReader(reader, value);
+  }
+};
+
+// const char*
+CHROMEOS_EXPORT void AppendValueToWriter(
+    dbus::MessageWriter* writer, const char* value);
+
+template<>
+struct DBusType<const char*> {
+  inline static std::string GetSignature() {
+    return DBUS_TYPE_STRING_AS_STRING;
+  }
+  inline static void Write(dbus::MessageWriter* writer, const char* value) {
+    AppendValueToWriter(writer, value);
+  }
+};
+
+// const char[]
+template<>
+struct DBusType<const char[]> {
+  inline static std::string GetSignature() {
+    return DBUS_TYPE_STRING_AS_STRING;
+  }
+  inline static void Write(dbus::MessageWriter* writer, const char* value) {
+    AppendValueToWriter(writer, value);
+  }
+};
+
+// dbus::ObjectPath -----------------------------------------------------------
+CHROMEOS_EXPORT void AppendValueToWriter(
+    dbus::MessageWriter* writer, const dbus::ObjectPath& value);
+CHROMEOS_EXPORT bool PopValueFromReader(
+    dbus::MessageReader* reader, dbus::ObjectPath* value);
+
+template<>
+struct DBusType<dbus::ObjectPath> {
+  inline static std::string GetSignature() {
+    return DBUS_TYPE_OBJECT_PATH_AS_STRING;
+  }
+  inline static void Write(dbus::MessageWriter* writer,
+                           const dbus::ObjectPath& value) {
+    AppendValueToWriter(writer, value);
+  }
+  inline static bool Read(dbus::MessageReader* reader,
+                          dbus::ObjectPath* value) {
+    return PopValueFromReader(reader, value);
+  }
+};
+
+// dbus::FileDescriptor -------------------------------------------------------
+CHROMEOS_EXPORT void AppendValueToWriter(
+    dbus::MessageWriter* writer, const dbus::FileDescriptor& value);
+CHROMEOS_EXPORT bool PopValueFromReader(
+    dbus::MessageReader* reader, dbus::FileDescriptor* value);
+
+template<>
+struct DBusType<dbus::FileDescriptor> {
+  inline static std::string GetSignature() {
+    return DBUS_TYPE_UNIX_FD_AS_STRING;
+  }
+  inline static void Write(dbus::MessageWriter* writer,
+                           const dbus::FileDescriptor& value) {
+    AppendValueToWriter(writer, value);
+  }
+  inline static bool Read(dbus::MessageReader* reader,
+                          dbus::FileDescriptor* value) {
+    return PopValueFromReader(reader, value);
+  }
+};
+
+// chromeos::Any --------------------------------------------------------------
+CHROMEOS_EXPORT void AppendValueToWriter(dbus::MessageWriter* writer,
+                                         const chromeos::Any& value);
+CHROMEOS_EXPORT bool PopValueFromReader(
+    dbus::MessageReader* reader, chromeos::Any* value);
+
+template<>
+struct DBusType<chromeos::Any> {
+  inline static std::string GetSignature() {
+    return DBUS_TYPE_VARIANT_AS_STRING;
+  }
+  inline static void Write(dbus::MessageWriter* writer,
+                           const chromeos::Any& value) {
+    AppendValueToWriter(writer, value);
+  }
+  inline static bool Read(dbus::MessageReader* reader, chromeos::Any* value) {
+    return PopValueFromReader(reader, value);
+  }
+};
+
+// std::vector = D-Bus ARRAY. -------------------------------------------------
+template<typename T, typename ALLOC>
+typename std::enable_if<IsTypeSupported<T>::value>::type
+AppendValueToWriter(dbus::MessageWriter* writer,
+                    const std::vector<T, ALLOC>& value) {
+  dbus::MessageWriter array_writer(nullptr);
+  writer->OpenArray(GetDBusSignature<T>(), &array_writer);
+  for (const auto& element : value) {
+    // Use DBusType<T>::Write() instead of AppendValueToWriter() to delay
+    // binding to AppendValueToWriter() to the point of instantiation of this
+    // template.
+    DBusType<T>::Write(&array_writer, element);
+  }
+  writer->CloseContainer(&array_writer);
 }
 
-// Numerous overloads for various native data types are provided below.
-
-CHROMEOS_EXPORT bool PopValueFromReader(dbus::MessageReader* reader,
-                                        bool* value);
-CHROMEOS_EXPORT bool PopValueFromReader(dbus::MessageReader* reader,
-                                        uint8_t* value);
-CHROMEOS_EXPORT bool PopValueFromReader(dbus::MessageReader* reader,
-                                        int16_t* value);
-CHROMEOS_EXPORT bool PopValueFromReader(dbus::MessageReader* reader,
-                                        uint16_t* value);
-CHROMEOS_EXPORT bool PopValueFromReader(dbus::MessageReader* reader,
-                                        int32_t* value);
-CHROMEOS_EXPORT bool PopValueFromReader(dbus::MessageReader* reader,
-                                        uint32_t* value);
-CHROMEOS_EXPORT bool PopValueFromReader(dbus::MessageReader* reader,
-                                        int64_t* value);
-CHROMEOS_EXPORT bool PopValueFromReader(dbus::MessageReader* reader,
-                                        uint64_t* value);
-CHROMEOS_EXPORT bool PopValueFromReader(dbus::MessageReader* reader,
-                                        double* value);
-CHROMEOS_EXPORT bool PopValueFromReader(dbus::MessageReader* reader,
-                                        std::string* value);
-CHROMEOS_EXPORT bool PopValueFromReader(dbus::MessageReader* reader,
-                                        dbus::ObjectPath* value);
-CHROMEOS_EXPORT bool PopValueFromReader(dbus::MessageReader* reader,
-                                        dbus::FileDescriptor* value);
-CHROMEOS_EXPORT bool PopValueFromReader(dbus::MessageReader* reader,
-                                        chromeos::Any* value);
-
-// Overloads of PopValueFromReader for some compound data types such
-// as ARRAYs, STRUCTs, DICTs.
-
-// std::vector = D-Bus ARRAY.
-template<typename T>
-inline bool PopValueFromReader(dbus::MessageReader* reader,
-                               std::vector<T>* value) {
+template<typename T, typename ALLOC>
+typename std::enable_if<IsTypeSupported<T>::value, bool>::type
+PopValueFromReader(dbus::MessageReader* reader, std::vector<T, ALLOC>* value) {
   dbus::MessageReader variant_reader(nullptr);
   dbus::MessageReader array_reader(nullptr);
   if (!details::DescendIntoVariantIfPresent(&reader, &variant_reader) ||
@@ -409,30 +495,164 @@
   value->clear();
   while (array_reader.HasMoreData()) {
     T data;
-    if (!PopValueFromReader(&array_reader, &data))
+    // Use DBusType<T>::Read() instead of PopValueFromReader() to delay
+    // binding to PopValueFromReader() to the point of instantiation of this
+    // template.
+    if (!DBusType<T>::Read(&array_reader, &data))
       return false;
     value->push_back(std::move(data));
   }
   return true;
 }
 
-// std::pair = D-Bus STRUCT with two elements.
+namespace details {
+// DBusArrayType<> is a helper base class for DBusType<vector<T>> that provides
+// GetSignature/Write/Read methods for T types that are supported by D-Bus
+// and not having those methods for types that are not supported by D-Bus.
+template<bool inner_type_supported, typename T, typename ALLOC>
+struct DBusArrayType {
+  // Returns "aT", where "T" is the signature string for type T.
+  inline static std::string GetSignature() {
+    return GetArrayDBusSignature(GetDBusSignature<T>());
+  }
+  inline static void Write(dbus::MessageWriter* writer,
+                           const std::vector<T, ALLOC>& value) {
+    AppendValueToWriter(writer, value);
+  }
+  inline static bool Read(dbus::MessageReader* reader,
+                          std::vector<T, ALLOC>* value) {
+    return PopValueFromReader(reader, value);
+  }
+};
+
+// Explicit specialization for unsupported type T.
+template<typename T, typename ALLOC>
+struct DBusArrayType<false, T, ALLOC> : public Unsupported {};
+
+}  // namespace details
+
+template<typename T, typename ALLOC>
+struct DBusType<std::vector<T, ALLOC>>
+    : public details::DBusArrayType<IsTypeSupported<T>::value, T, ALLOC> {};
+
+// std::pair = D-Bus STRUCT with two elements. --------------------------------
+namespace details {
+
+// Helper class to get a D-Bus signature of a list of types.
+// For example, TupleTraits<int32_t, bool, std::string>::GetSignature() will
+// return "ibs".
+template<typename... Types>
+struct TupleTraits;
+
+template<typename FirstType, typename... RestOfTypes>
+struct TupleTraits<FirstType, RestOfTypes...> {
+  static std::string GetSignature() {
+    return GetDBusSignature<FirstType>() +
+           TupleTraits<RestOfTypes...>::GetSignature();
+  }
+};
+
+template<>
+struct TupleTraits<> {
+  static std::string GetSignature() {
+    return std::string{};
+  }
+};
+
+}  // namespace details
+
+template<typename... Types>
+inline std::string GetStructDBusSignature() {
+  // Returns "(T...)", where "T..." is the signature strings for types T...
+    return DBUS_STRUCT_BEGIN_CHAR_AS_STRING +
+           details::TupleTraits<Types...>::GetSignature() +
+           DBUS_STRUCT_END_CHAR_AS_STRING;
+}
+
 template<typename U, typename V>
-inline bool PopValueFromReader(dbus::MessageReader* reader,
-                               std::pair<U, V>* value) {
+typename std::enable_if<IsTypeSupported<U, V>::value>::type
+AppendValueToWriter(dbus::MessageWriter* writer, const std::pair<U, V>& value) {
+  dbus::MessageWriter struct_writer(nullptr);
+  writer->OpenStruct(&struct_writer);
+  // Use DBusType<T>::Write() instead of AppendValueToWriter() to delay
+  // binding to AppendValueToWriter() to the point of instantiation of this
+  // template.
+  DBusType<U>::Write(&struct_writer, value.first);
+  DBusType<V>::Write(&struct_writer, value.second);
+  writer->CloseContainer(&struct_writer);
+}
+
+template<typename U, typename V>
+typename std::enable_if<IsTypeSupported<U, V>::value, bool>::type
+PopValueFromReader(dbus::MessageReader* reader, std::pair<U, V>* value) {
   dbus::MessageReader variant_reader(nullptr);
   dbus::MessageReader struct_reader(nullptr);
   if (!details::DescendIntoVariantIfPresent(&reader, &variant_reader) ||
       !reader->PopStruct(&struct_reader))
     return false;
-  return PopValueFromReader(&struct_reader, &value->first) &&
-         PopValueFromReader(&struct_reader, &value->second);
+  // Use DBusType<T>::Read() instead of PopValueFromReader() to delay
+  // binding to PopValueFromReader() to the point of instantiation of this
+  // template.
+  return DBusType<U>::Read(&struct_reader, &value->first) &&
+         DBusType<V>::Read(&struct_reader, &value->second);
 }
 
-// std::map = D-Bus ARRAY of DICT_ENTRY.
-template<typename KEY, typename VALUE>
-inline bool PopValueFromReader(dbus::MessageReader* reader,
-                               std::map<KEY, VALUE>* value) {
+namespace details {
+
+// DBusArrayType<> is a helper base class for DBusType<pair<U, V>> that provides
+// GetSignature/Write/Read methods for types that are supported by D-Bus
+// and not having those methods for types that are not supported by D-Bus.
+template<bool inner_type_supported, typename U, typename V>
+struct DBusPairType {
+  // Returns "(UV)", where "U" and "V" are the signature strings for types U, V.
+  inline static std::string GetSignature() {
+    return GetStructDBusSignature<U, V>();
+  }
+  inline static void Write(dbus::MessageWriter* writer,
+                           const std::pair<U, V>& value) {
+    AppendValueToWriter(writer, value);
+  }
+  inline static bool Read(dbus::MessageReader* reader, std::pair<U, V>* value) {
+    return PopValueFromReader(reader, value);
+  }
+};
+
+// Either U, or V, or both are not supported by D-Bus.
+template<typename U, typename V>
+struct DBusPairType<false, U, V> : public Unsupported {};
+
+}  // namespace details
+
+template<typename U, typename V>
+struct DBusType<std::pair<U, V>>
+    : public details::DBusPairType<IsTypeSupported<U, V>::value, U, V> {
+};
+
+// std::map = D-Bus ARRAY of DICT_ENTRY. --------------------------------------
+template<typename KEY, typename VALUE, typename PRED, typename ALLOC>
+typename std::enable_if<IsTypeSupported<KEY, VALUE>::value>::type
+AppendValueToWriter(
+    dbus::MessageWriter* writer,
+    const std::map<KEY, VALUE, PRED, ALLOC>& value) {
+  dbus::MessageWriter dict_writer(nullptr);
+  writer->OpenArray(details::GetDBusDictEntryType<KEY, VALUE>(), &dict_writer);
+  for (const auto& pair : value) {
+    dbus::MessageWriter entry_writer(nullptr);
+    dict_writer.OpenDictEntry(&entry_writer);
+    // Use DBusType<T>::Write() instead of AppendValueToWriter() to delay
+    // binding to AppendValueToWriter() to the point of instantiation of this
+    // template.
+    DBusType<KEY>::Write(&entry_writer, pair.first);
+    DBusType<VALUE>::Write(&entry_writer, pair.second);
+    dict_writer.CloseContainer(&entry_writer);
+  }
+  writer->CloseContainer(&dict_writer);
+}
+
+template<typename KEY, typename VALUE, typename PRED, typename ALLOC>
+typename std::enable_if<IsTypeSupported<KEY, VALUE>::value, bool>::type
+PopValueFromReader(dbus::MessageReader* reader,
+                   std::map<KEY, VALUE, PRED, ALLOC>* value) {
   dbus::MessageReader variant_reader(nullptr);
   dbus::MessageReader array_reader(nullptr);
   if (!details::DescendIntoVariantIfPresent(&reader, &variant_reader) ||
@@ -445,20 +665,101 @@
       return false;
     KEY key;
     VALUE data;
-    if (!PopValueFromReader(&dict_entry_reader, &key) ||
-        !PopValueFromReader(&dict_entry_reader, &data))
+    // Use DBusType<T>::Read() instead of PopValueFromReader() to delay
+    // binding to PopValueFromReader() to the point of instantiation of this
+    // template.
+    if (!DBusType<KEY>::Read(&dict_entry_reader, &key) ||
+        !DBusType<VALUE>::Read(&dict_entry_reader, &data))
       return false;
-    value->insert(std::make_pair(std::move(key), std::move(data)));
+    value->emplace(std::move(key), std::move(data));
   }
   return true;
 }
 
-// google::protobuf::MessageLite = D-Bus ARRAY of BYTE
+namespace details {
+
+// DBusArrayType<> is a helper base class for DBusType<map<K, V>> that provides
+// GetSignature/Write/Read methods for T types that are supported by D-Bus
+// and not having those methods for types that are not supported by D-Bus.
+template<bool inner_types_supported,
+         typename KEY, typename VALUE, typename PRED, typename ALLOC>
+struct DBusMapType {
+  // Returns "a{KV}", where "K" and "V" are the signature strings for types
+  // KEY/VALUE.
+  inline static std::string GetSignature() {
+    return GetArrayDBusSignature(GetDBusDictEntryType<KEY, VALUE>());
+  }
+  inline static void Write(dbus::MessageWriter* writer,
+                           const std::map<KEY, VALUE, PRED, ALLOC>& value) {
+    AppendValueToWriter(writer, value);
+  }
+  inline static bool Read(dbus::MessageReader* reader,
+                          std::map<KEY, VALUE, PRED, ALLOC>* value) {
+    return PopValueFromReader(reader, value);
+  }
+};
+
+// Types KEY, VALUE or both are not supported by D-Bus.
+template<typename KEY, typename VALUE, typename PRED, typename ALLOC>
+struct DBusMapType<false, KEY, VALUE, PRED, ALLOC> : public Unsupported {};
+
+}  // namespace details
+
+template<typename KEY, typename VALUE, typename PRED, typename ALLOC>
+struct DBusType<std::map<KEY, VALUE, PRED, ALLOC>>
+    : public details::DBusMapType<IsTypeSupported<KEY, VALUE>::value,
+                                  KEY, VALUE, PRED, ALLOC> {};
+
+// google::protobuf::MessageLite = D-Bus ARRAY of BYTE ------------------------
+inline void AppendValueToWriter(dbus::MessageWriter* writer,
+                                const google::protobuf::MessageLite& value) {
+  writer->AppendProtoAsArrayOfBytes(value);
+}
+
 inline bool PopValueFromReader(dbus::MessageReader* reader,
                                google::protobuf::MessageLite* value) {
   return reader->PopArrayOfBytesAsProto(value);
 }
 
+template<>
+struct DBusType<google::protobuf::MessageLite> {
+  inline static std::string GetSignature() {
+    return GetDBusSignature<std::vector<uint8_t>>();
+  }
+  inline static void Write(dbus::MessageWriter* writer,
+                           const google::protobuf::MessageLite& value) {
+    AppendValueToWriter(writer, value);
+  }
+  inline static bool Read(dbus::MessageReader* reader,
+                          google::protobuf::MessageLite* value) {
+    return PopValueFromReader(reader, value);
+  }
+};
+
+//----------------------------------------------------------------------------
+// AppendValueToWriterAsVariant<T>(dbus::MessageWriter* writer, const T& value)
+// Write the |value| of type T to D-Bus message as a VARIANT.
+// This overload is provided only if T is supported by D-Bus.
+template<typename T>
+typename std::enable_if<IsTypeSupported<T>::value>::type
+AppendValueToWriterAsVariant(dbus::MessageWriter* writer, const T& value) {
+  std::string data_type = GetDBusSignature<T>();
+  dbus::MessageWriter variant_writer(nullptr);
+  writer->OpenVariant(data_type, &variant_writer);
+  // Use DBusType<T>::Write() instead of AppendValueToWriter() to delay
+  // binding to AppendValueToWriter() to the point of instantiation of this
+  // template.
+  DBusType<T>::Write(&variant_writer, value);
+  writer->CloseContainer(&variant_writer);
+}
+
+// Special case: do not allow to write a Variant containing a Variant.
+// Just redirect to normal AppendValueToWriter().
+inline void AppendValueToWriterAsVariant(dbus::MessageWriter* writer,
+                                         const chromeos::Any& value) {
+  return AppendValueToWriter(writer, value);
+}
+
 //----------------------------------------------------------------------------
 // PopVariantValueFromReader<T>(dbus::MessageWriter* writer, T* value)
 // Reads a Variant containing the |value| of type T from D-Bus message.
@@ -467,12 +768,17 @@
 //   1. For API symmetry with AppendValueToWriter/AppendValueToWriterAsVariant.
 //   2. To be used when it is important to assert that the data was sent
 //      specifically as a Variant.
+// This overload is provided only if T is supported by D-Bus.
 template<typename T>
-inline bool PopVariantValueFromReader(dbus::MessageReader* reader, T* value) {
+typename std::enable_if<IsTypeSupported<T>::value, bool>::type
+PopVariantValueFromReader(dbus::MessageReader* reader, T* value) {
   dbus::MessageReader variant_reader(nullptr);
   if (!reader->PopVariant(&variant_reader))
     return false;
-  return PopValueFromReader(&variant_reader, value);
+  // Use DBusType<T>::Read() instead of PopValueFromReader() to delay
+  // binding to PopValueFromReader() to the point of instantiation of this
+  // template.
+  return DBusType<T>::Read(&variant_reader, value);
 }
 
 // Special handling of request to read a Variant of Variant.
diff --git a/chromeos/dbus/data_serialization_unittest.cc b/chromeos/dbus/data_serialization_unittest.cc
index 4a465af..d10e8c8 100644
--- a/chromeos/dbus/data_serialization_unittest.cc
+++ b/chromeos/dbus/data_serialization_unittest.cc
@@ -19,6 +19,56 @@
 namespace chromeos {
 namespace dbus_utils {
 
+TEST(DBusUtils, Supported_BasicTypes) {
+  EXPECT_TRUE(IsTypeSupported<bool>::value);
+  EXPECT_TRUE(IsTypeSupported<uint8_t>::value);
+  EXPECT_TRUE(IsTypeSupported<int16_t>::value);
+  EXPECT_TRUE(IsTypeSupported<uint16_t>::value);
+  EXPECT_TRUE(IsTypeSupported<int32_t>::value);
+  EXPECT_TRUE(IsTypeSupported<uint32_t>::value);
+  EXPECT_TRUE(IsTypeSupported<int64_t>::value);
+  EXPECT_TRUE(IsTypeSupported<uint64_t>::value);
+  EXPECT_TRUE(IsTypeSupported<double>::value);
+  EXPECT_TRUE(IsTypeSupported<std::string>::value);
+  EXPECT_TRUE(IsTypeSupported<ObjectPath>::value);
+  EXPECT_TRUE(IsTypeSupported<FileDescriptor>::value);
+  EXPECT_TRUE(IsTypeSupported<Any>::value);
+}
+
+TEST(DBusUtils, Unsupported_BasicTypes) {
+  EXPECT_FALSE(IsTypeSupported<char>::value);
+  EXPECT_FALSE(IsTypeSupported<float>::value);
+}
+
+TEST(DBusUtils, Supported_ComplexTypes) {
+  EXPECT_TRUE(IsTypeSupported<std::vector<bool>>::value);
+  EXPECT_TRUE(IsTypeSupported<std::vector<uint8_t>>::value);
+  EXPECT_TRUE((IsTypeSupported<std::pair<int16_t, double>>::value));
+  EXPECT_TRUE((IsTypeSupported<std::map<uint16_t,
+                                        std::vector<int64_t>>>::value));
+}
+
+TEST(DBusUtils, Unsupported_ComplexTypes) {
+  EXPECT_FALSE(IsTypeSupported<std::vector<char>>::value);
+  EXPECT_FALSE((IsTypeSupported<std::pair<int16_t, float>>::value));
+  EXPECT_FALSE((IsTypeSupported<std::pair<char, int32_t>>::value));
+  EXPECT_FALSE((IsTypeSupported<std::map<int16_t, float>>::value));
+  EXPECT_FALSE((IsTypeSupported<std::map<char, int32_t>>::value));
+}
+
+TEST(DBusUtils, Supported_TypeSet) {
+  EXPECT_TRUE((IsTypeSupported<int32_t, double, std::string>::value));
+  EXPECT_TRUE((IsTypeSupported<bool, std::vector<int32_t>, uint8_t>::value));
+}
+
+TEST(DBusUtils, Unupported_TypeSet) {
+  EXPECT_FALSE((IsTypeSupported<int32_t, double, std::string, char>::value));
+  EXPECT_FALSE(
+      (IsTypeSupported<bool, std::pair<std::vector<float>, uint8_t>>::value));
+  EXPECT_FALSE((IsTypeSupported<char, double, std::string, int16_t>::value));
+  EXPECT_FALSE((IsTypeSupported<char, std::vector<float>, float>::value));
+}
+
 TEST(DBusUtils, Signatures_BasicTypes) {
   EXPECT_EQ("b", GetDBusSignature<bool>());
   EXPECT_EQ("y", GetDBusSignature<uint8_t>());
@@ -74,7 +124,7 @@
 TEST(DBusUtils, AppendAndPopByte) {
   std::unique_ptr<Response> message(Response::CreateEmpty().release());
   MessageWriter writer(message.get());
-  EXPECT_TRUE(AppendValueToWriter(&writer, uint8_t{123}));
+  AppendValueToWriter(&writer, uint8_t{123});
   EXPECT_EQ("y", message->GetSignature());
 
   MessageReader reader(message.get());
@@ -100,17 +150,17 @@
   MessageWriter writer(message.get());
 
   // Append 0, true, 2, 3, 4, 5, 6, 7, 8.0, "string", "/object/path".
-  EXPECT_TRUE(AppendValueToWriter(&writer, uint8_t{0}));
-  EXPECT_TRUE(AppendValueToWriter(&writer, bool{true}));
-  EXPECT_TRUE(AppendValueToWriter(&writer, int16_t{2}));
-  EXPECT_TRUE(AppendValueToWriter(&writer, uint16_t{3}));
-  EXPECT_TRUE(AppendValueToWriter(&writer, int32_t{4}));
-  EXPECT_TRUE(AppendValueToWriter(&writer, uint32_t{5}));
-  EXPECT_TRUE(AppendValueToWriter(&writer, int64_t{6}));
-  EXPECT_TRUE(AppendValueToWriter(&writer, uint64_t{7}));
-  EXPECT_TRUE(AppendValueToWriter(&writer, double{8.0}));
-  EXPECT_TRUE(AppendValueToWriter(&writer, std::string{"string"}));
-  EXPECT_TRUE(AppendValueToWriter(&writer, ObjectPath{"/object/path"}));
+  AppendValueToWriter(&writer, uint8_t{0});
+  AppendValueToWriter(&writer, bool{true});
+  AppendValueToWriter(&writer, int16_t{2});
+  AppendValueToWriter(&writer, uint16_t{3});
+  AppendValueToWriter(&writer, int32_t{4});
+  AppendValueToWriter(&writer, uint32_t{5});
+  AppendValueToWriter(&writer, int64_t{6});
+  AppendValueToWriter(&writer, uint64_t{7});
+  AppendValueToWriter(&writer, double{8.0});
+  AppendValueToWriter(&writer, std::string{"string"});
+  AppendValueToWriter(&writer, ObjectPath{"/object/path"});
 
   EXPECT_EQ("ybnqiuxtdso", message->GetSignature());
 
@@ -172,7 +222,7 @@
   // NB: thread IO requirements not relevant for unit tests.
   temp.CheckValidity();
   EXPECT_TRUE(temp.is_valid());
-  EXPECT_TRUE(AppendValueToWriter(&writer, temp));
+  AppendValueToWriter(&writer, temp);
 
   EXPECT_EQ("h", message->GetSignature());
 
@@ -193,18 +243,18 @@
   MessageWriter writer(message.get());
 
   // Append 10, false, 12, 13, 14, 15, 16, 17, 18.5, "data", "/obj/path".
-  EXPECT_TRUE(AppendValueToWriterAsVariant(&writer, uint8_t{10}));
-  EXPECT_TRUE(AppendValueToWriterAsVariant(&writer, bool{false}));
-  EXPECT_TRUE(AppendValueToWriterAsVariant(&writer, int16_t{12}));
-  EXPECT_TRUE(AppendValueToWriterAsVariant(&writer, uint16_t{13}));
-  EXPECT_TRUE(AppendValueToWriterAsVariant(&writer, int32_t{14}));
-  EXPECT_TRUE(AppendValueToWriterAsVariant(&writer, uint32_t{15}));
-  EXPECT_TRUE(AppendValueToWriterAsVariant(&writer, int64_t{16}));
-  EXPECT_TRUE(AppendValueToWriterAsVariant(&writer, uint64_t{17}));
-  EXPECT_TRUE(AppendValueToWriterAsVariant(&writer, double{18.5}));
-  EXPECT_TRUE(AppendValueToWriterAsVariant(&writer, std::string{"data"}));
-  EXPECT_TRUE(AppendValueToWriterAsVariant(&writer, ObjectPath{"/obj/path"}));
-  EXPECT_TRUE(AppendValueToWriterAsVariant(&writer, Any{17}));
+  AppendValueToWriterAsVariant(&writer, uint8_t{10});
+  AppendValueToWriterAsVariant(&writer, bool{false});
+  AppendValueToWriterAsVariant(&writer, int16_t{12});
+  AppendValueToWriterAsVariant(&writer, uint16_t{13});
+  AppendValueToWriterAsVariant(&writer, int32_t{14});
+  AppendValueToWriterAsVariant(&writer, uint32_t{15});
+  AppendValueToWriterAsVariant(&writer, int64_t{16});
+  AppendValueToWriterAsVariant(&writer, uint64_t{17});
+  AppendValueToWriterAsVariant(&writer, double{18.5});
+  AppendValueToWriterAsVariant(&writer, std::string{"data"});
+  AppendValueToWriterAsVariant(&writer, ObjectPath{"/obj/path"});
+  AppendValueToWriterAsVariant(&writer, Any{17});
 
   EXPECT_EQ("vvvvvvvvvvvv", message->GetSignature());
 
@@ -257,18 +307,17 @@
   MessageWriter writer(message.get());
 
   // Append 10, true, 12, 13, 14, 15, 16, 17, 18.5, "data", "/obj/path".
-  EXPECT_TRUE(AppendValueToWriter(&writer, Any(uint8_t{10})));
-  EXPECT_TRUE(AppendValueToWriter(&writer, Any(bool{true})));
-  EXPECT_TRUE(AppendValueToWriter(&writer, Any(int16_t{12})));
-  EXPECT_TRUE(AppendValueToWriter(&writer, Any(uint16_t{13})));
-  EXPECT_TRUE(AppendValueToWriter(&writer, Any(int32_t{14})));
-  EXPECT_TRUE(AppendValueToWriter(&writer, Any(uint32_t{15})));
-  EXPECT_TRUE(AppendValueToWriter(&writer, Any(int64_t{16})));
-  EXPECT_TRUE(AppendValueToWriter(&writer, Any(uint64_t{17})));
-  EXPECT_TRUE(AppendValueToWriter(&writer, Any(double{18.5})));
-  EXPECT_TRUE(AppendValueToWriter(&writer, Any(std::string{"data"})));
-  EXPECT_TRUE(AppendValueToWriter(&writer, Any(ObjectPath{"/obj/path"})));
-
+  AppendValueToWriter(&writer, Any(uint8_t{10}));
+  AppendValueToWriter(&writer, Any(bool{true}));
+  AppendValueToWriter(&writer, Any(int16_t{12}));
+  AppendValueToWriter(&writer, Any(uint16_t{13}));
+  AppendValueToWriter(&writer, Any(int32_t{14}));
+  AppendValueToWriter(&writer, Any(uint32_t{15}));
+  AppendValueToWriter(&writer, Any(int64_t{16}));
+  AppendValueToWriter(&writer, Any(uint64_t{17}));
+  AppendValueToWriter(&writer, Any(double{18.5}));
+  AppendValueToWriter(&writer, Any(std::string{"data"}));
+  AppendValueToWriter(&writer, Any(ObjectPath{"/obj/path"}));
   EXPECT_EQ("vvvvvvvvvvv", message->GetSignature());
 
   Any byte_value;
@@ -316,7 +365,7 @@
   std::unique_ptr<Response> message(Response::CreateEmpty().release());
   MessageWriter writer(message.get());
   std::vector<uint8_t> bytes{1, 2, 3};
-  EXPECT_TRUE(AppendValueToWriter(&writer, bytes));
+  AppendValueToWriter(&writer, bytes);
 
   EXPECT_EQ("ay", message->GetSignature());
 
@@ -331,7 +380,7 @@
   std::unique_ptr<Response> message(Response::CreateEmpty().release());
   MessageWriter writer(message.get());
   std::vector<uint8_t> bytes;
-  EXPECT_TRUE(AppendValueToWriter(&writer, bytes));
+  AppendValueToWriter(&writer, bytes);
 
   EXPECT_EQ("ay", message->GetSignature());
 
@@ -346,7 +395,7 @@
   std::unique_ptr<Response> message(Response::CreateEmpty().release());
   MessageWriter writer(message.get());
   std::vector<std::string> strings{"foo", "bar", "baz"};
-  EXPECT_TRUE(AppendValueToWriter(&writer, strings));
+  AppendValueToWriter(&writer, strings);
 
   EXPECT_EQ("as", message->GetSignature());
 
@@ -363,7 +412,7 @@
   std::vector<int64_t> values{-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5,
                               std::numeric_limits<int64_t>::min(),
                               std::numeric_limits<int64_t>::max()};
-  EXPECT_TRUE(AppendValueToWriter(&writer, values));
+  AppendValueToWriter(&writer, values);
 
   EXPECT_EQ("ax", message->GetSignature());
 
@@ -382,7 +431,7 @@
     ObjectPath("/object/path/2"),
     ObjectPath("/object/path/3"),
   };
-  EXPECT_TRUE(AppendValueToWriter(&writer, object_paths));
+  AppendValueToWriter(&writer, object_paths);
 
   EXPECT_EQ("ao", message->GetSignature());
 
@@ -401,11 +450,11 @@
   std::vector<double> dbl_array_empty{};
   std::map<std::string, std::string> dict_ss{{"k1", "v1"}, {"k2", "v2"}};
   VariantDictionary dict_sv{{"k1", 1}, {"k2", "v2"}};
-  EXPECT_TRUE(AppendValueToWriterAsVariant(&writer, int_array));
-  EXPECT_TRUE(AppendValueToWriterAsVariant(&writer, str_array));
-  EXPECT_TRUE(AppendValueToWriterAsVariant(&writer, dbl_array_empty));
-  EXPECT_TRUE(AppendValueToWriterAsVariant(&writer, dict_ss));
-  EXPECT_TRUE(AppendValueToWriterAsVariant(&writer, dict_sv));
+  AppendValueToWriterAsVariant(&writer, int_array);
+  AppendValueToWriterAsVariant(&writer, str_array);
+  AppendValueToWriterAsVariant(&writer, dbl_array_empty);
+  AppendValueToWriterAsVariant(&writer, dict_ss);
+  AppendValueToWriterAsVariant(&writer, dict_sv);
 
   EXPECT_EQ("vvvvv", message->GetSignature());
 
@@ -449,7 +498,7 @@
       {"keyA", std::string{"data"}},
       {"keyB", ObjectPath{"/obj/path"}},
   };
-  EXPECT_TRUE(AppendValueToWriter(&writer, values));
+  AppendValueToWriter(&writer, values);
 
   EXPECT_EQ("a{sv}", message->GetSignature());
 
@@ -492,7 +541,7 @@
       {"key4", "value4"},
       {"key5", "value5"},
   };
-  EXPECT_TRUE(AppendValueToWriter(&writer, values));
+  AppendValueToWriter(&writer, values);
 
   EXPECT_EQ("a{ss}", message->GetSignature());
 
@@ -507,9 +556,9 @@
   std::unique_ptr<Response> message(Response::CreateEmpty().release());
   MessageWriter writer(message.get());
   std::pair<std::string, int> struct1{"value2", 3};
-  EXPECT_TRUE(AppendValueToWriter(&writer, struct1));
+  AppendValueToWriter(&writer, struct1);
   std::pair<int, std::pair<int, int>> struct2{1, {2, 3}};
-  EXPECT_TRUE(AppendValueToWriter(&writer, struct2));
+  AppendValueToWriter(&writer, struct2);
 
   EXPECT_EQ("(si)(i(ii))", message->GetSignature());
 
@@ -530,11 +579,11 @@
   std::vector<std::string> str_array{"foo", "bar", "baz"};
   std::map<std::string, std::string> dict_ss{{"k1", "v1"}, {"k2", "v2"}};
   VariantDictionary dict_sv{{"k1", "v1"}, {"k2", "v2"}};
-  EXPECT_TRUE(AppendValueToWriterAsVariant(&writer, 123));
-  EXPECT_TRUE(AppendValueToWriterAsVariant(&writer, str_array));
-  EXPECT_TRUE(AppendValueToWriterAsVariant(&writer, 1.7));
-  EXPECT_TRUE(AppendValueToWriterAsVariant(&writer, dict_ss));
-  EXPECT_TRUE(AppendValueToWriter(&writer, dict_sv));
+  AppendValueToWriterAsVariant(&writer, 123);
+  AppendValueToWriterAsVariant(&writer, str_array);
+  AppendValueToWriterAsVariant(&writer, 1.7);
+  AppendValueToWriterAsVariant(&writer, dict_ss);
+  AppendValueToWriter(&writer, dict_sv);
 
   EXPECT_EQ("vvvva{sv}", message->GetSignature());
 
@@ -573,20 +622,14 @@
   }
 };
 
-// Specialize DBusSignature<T>::get() for "Person" structure.
-template<> struct DBusSignature<Person> {
-  static std::string get() { return "(ssi)"; }
-};
-
 // Overload AppendValueToWriter() for "Person" structure.
-bool AppendValueToWriter(dbus::MessageWriter* writer, const Person& value) {
+void AppendValueToWriter(dbus::MessageWriter* writer, const Person& value) {
   dbus::MessageWriter struct_writer(nullptr);
   writer->OpenStruct(&struct_writer);
-  bool success = AppendValueToWriter(&struct_writer, value.first_name) &&
-                 AppendValueToWriter(&struct_writer, value.last_name) &&
-                 AppendValueToWriter(&struct_writer, value.age);
+  AppendValueToWriter(&struct_writer, value.first_name);
+  AppendValueToWriter(&struct_writer, value.last_name);
+  AppendValueToWriter(&struct_writer, value.age);
   writer->CloseContainer(&struct_writer);
-  return success;
 }
 
 // Overload PopValueFromReader() for "Person" structure.
@@ -601,13 +644,27 @@
          PopValueFromReader(&struct_reader, &value->age);
 }
 
+// Specialize DBusType<T> for "Person" structure.
+template<>
+struct DBusType<Person> {
+  inline static std::string GetSignature() {
+    return GetStructDBusSignature<std::string, std::string, int>();
+  }
+  inline static void Write(dbus::MessageWriter* writer, const Person& value) {
+    AppendValueToWriter(writer, value);
+  }
+  inline static bool Read(dbus::MessageReader* reader, Person* value) {
+    return PopValueFromReader(reader, value);
+  }
+};
+
 TEST(DBusUtils, CustomStruct) {
   std::unique_ptr<Response> message(Response::CreateEmpty().release());
   MessageWriter writer(message.get());
   std::vector<Person> people{{"John", "Doe", 32}, {"Jane", "Smith", 48}};
-  EXPECT_TRUE(AppendValueToWriter(&writer, people));
-  EXPECT_TRUE(AppendValueToWriterAsVariant(&writer, people));
-  EXPECT_TRUE(AppendValueToWriterAsVariant(&writer, people));
+  AppendValueToWriter(&writer, people);
+  AppendValueToWriterAsVariant(&writer, people);
+  AppendValueToWriterAsVariant(&writer, people);
 
   EXPECT_EQ("a(ssi)vv", message->GetSignature());
 
@@ -626,5 +683,42 @@
   EXPECT_EQ(people, people_out3);
 }
 
+TEST(DBusUtils, CustomStructInComplexTypes) {
+  std::unique_ptr<Response> message(Response::CreateEmpty().release());
+  MessageWriter writer(message.get());
+  std::vector<Person> people{{"John", "Doe", 32}, {"Jane", "Smith", 48}};
+  std::vector<std::map<int, Person>> data{
+    {
+      {1, Person{"John", "Doe", 32}},
+      {2, Person{"Jane", "Smith", 48}},
+    }
+  };
+  AppendValueToWriter(&writer, data);
+
+  EXPECT_EQ("aa{i(ssi)}", message->GetSignature());
+
+  std::vector<std::map<int, Person>> data_out;;
+
+  MessageReader reader(message.get());
+  EXPECT_TRUE(PopValueFromReader(&reader, &data_out));
+  EXPECT_FALSE(reader.HasMoreData());
+
+  EXPECT_EQ(data, data_out);
+}
+
+TEST(DBusUtils, EmptyVariant) {
+  std::unique_ptr<Response> message(Response::CreateEmpty().release());
+  MessageWriter writer(message.get());
+  EXPECT_DEATH(AppendValueToWriter(&writer, Any{}),
+               "Must not be called on an empty Any");
+}
+
+TEST(DBusUtils, IncompatibleVariant) {
+  std::unique_ptr<Response> message(Response::CreateEmpty().release());
+  MessageWriter writer(message.get());
+  EXPECT_DEATH(AppendValueToWriter(&writer, Any{2.2f}),
+               "Type 'float' is not supported by D-Bus");
+}
+
 }  // namespace dbus_utils
 }  // namespace chromeos
diff --git a/chromeos/dbus/dbus_param_reader.h b/chromeos/dbus/dbus_param_reader.h
index 361713b..429ac48 100644
--- a/chromeos/dbus/dbus_param_reader.h
+++ b/chromeos/dbus/dbus_param_reader.h
@@ -90,7 +90,7 @@
     // The variable to hold the value of the current parameter we reading from
     // the message buffer.
     ParamValueType current_param;
-    if (!PopValueFromReader(reader, &current_param)) {
+    if (!DBusType<ParamValueType>::Read(reader, &current_param)) {
       Error::AddTo(error, errors::dbus::kDomain, DBUS_ERROR_INVALID_ARGS,
                    "Method parameter type mismatch");
       return false;
diff --git a/chromeos/dbus/dbus_param_writer.h b/chromeos/dbus/dbus_param_writer.h
index 8805fd0..40e2263 100644
--- a/chromeos/dbus/dbus_param_writer.h
+++ b/chromeos/dbus/dbus_param_writer.h
@@ -25,31 +25,32 @@
   // Generic writer method that takes 1 or more arguments. It recursively calls
   // itself (each time with one fewer arguments) until no more is left.
   template<typename ParamType, typename... RestOfParams>
-  static bool Append(dbus::MessageWriter* writer,
+  static void Append(dbus::MessageWriter* writer,
                      const ParamType& param,
                      const RestOfParams&... rest) {
     // Append the current |param| to D-Bus, then call Append() with one
     // fewer arguments, until none is left and stand-alone version of
     // Append(dbus::MessageWriter*) is called to end the iteration.
-    return AppendValueToWriter(writer, param) && Append(writer, rest...);
+    DBusType<ParamType>::Write(writer, param);
+    Append(writer, rest...);
   }
 
   // The final overload of DBusParamWriter::Append() used when no more
   // parameters are remaining to be written.
   // Does nothing and finishes meta-recursion.
-  static bool Append(dbus::MessageWriter* writer) { return true; }
+  static void Append(dbus::MessageWriter* writer) {}
 
   // Generic writer method that takes 1 or more arguments. It recursively calls
   // itself (each time with one fewer arguments) until no more is left.
   // Handles non-pointer parameter by just skipping over it.
   template<typename ParamType, typename... RestOfParams>
-  static bool AppendDBusOutParams(dbus::MessageWriter* writer,
+  static void AppendDBusOutParams(dbus::MessageWriter* writer,
                                   const ParamType& param,
                                   const RestOfParams&... rest) {
     // Skip the current |param| and call Append() with one fewer arguments,
     // until none is left and stand-alone version of
     // AppendDBusOutParams(dbus::MessageWriter*) is called to end the iteration.
-    return AppendDBusOutParams(writer, rest...);
+    AppendDBusOutParams(writer, rest...);
   }
 
   // Generic writer method that takes 1 or more arguments. It recursively calls
@@ -57,20 +58,20 @@
   // Handles only a parameter of pointer type and writes the data pointed to
   // to the output message buffer.
   template<typename ParamType, typename... RestOfParams>
-  static bool AppendDBusOutParams(dbus::MessageWriter* writer,
+  static void AppendDBusOutParams(dbus::MessageWriter* writer,
                                   ParamType* param,
                                   const RestOfParams&... rest) {
     // Append the current |param| to D-Bus, then call Append() with one
     // fewer arguments, until none is left and stand-alone version of
     // Append(dbus::MessageWriter*) is called to end the iteration.
-    return AppendValueToWriter(writer, *param) &&
-           AppendDBusOutParams(writer, rest...);
+    DBusType<ParamType>::Write(writer, *param);
+    AppendDBusOutParams(writer, rest...);
   }
 
   // The final overload of DBusParamWriter::AppendDBusOutParams() used when no
   // more parameters are remaining to be written.
   // Does nothing and finishes meta-recursion.
-  static bool AppendDBusOutParams(dbus::MessageWriter* writer) { return true; }
+  static void AppendDBusOutParams(dbus::MessageWriter* writer) {}
 };
 
 }  // namespace dbus_utils
diff --git a/chromeos/dbus/dbus_param_writer_unittest.cc b/chromeos/dbus/dbus_param_writer_unittest.cc
index 7d0ed53..cdedf5e 100644
--- a/chromeos/dbus/dbus_param_writer_unittest.cc
+++ b/chromeos/dbus/dbus_param_writer_unittest.cc
@@ -20,18 +20,18 @@
 TEST(DBusParamWriter, Append_NoArgs) {
   std::unique_ptr<Response> message(Response::CreateEmpty().release());
   MessageWriter writer(message.get());
-  EXPECT_TRUE(DBusParamWriter::Append(&writer));
+  DBusParamWriter::Append(&writer);
   EXPECT_EQ("", message->GetSignature());
 }
 
 TEST(DBusParamWriter, Append_OneArg) {
   std::unique_ptr<Response> message(Response::CreateEmpty().release());
   MessageWriter writer(message.get());
-  EXPECT_TRUE(DBusParamWriter::Append(&writer, int32_t{2}));
+  DBusParamWriter::Append(&writer, int32_t{2});
   EXPECT_EQ("i", message->GetSignature());
-  EXPECT_TRUE(DBusParamWriter::Append(&writer, std::string{"foo"}));
+  DBusParamWriter::Append(&writer, std::string{"foo"});
   EXPECT_EQ("is", message->GetSignature());
-  EXPECT_TRUE(DBusParamWriter::Append(&writer, ObjectPath{"/o"}));
+  DBusParamWriter::Append(&writer, ObjectPath{"/o"});
   EXPECT_EQ("iso", message->GetSignature());
 
   int32_t int_value = 0;
@@ -51,7 +51,7 @@
 TEST(DBusParamWriter, Append_ManyArgs) {
   std::unique_ptr<Response> message(Response::CreateEmpty().release());
   MessageWriter writer(message.get());
-  EXPECT_TRUE(DBusParamWriter::Append(&writer, int32_t{9}, Any{7.5}, true));
+  DBusParamWriter::Append(&writer, int32_t{9}, Any{7.5}, true);
   EXPECT_EQ("ivb", message->GetSignature());
 
   int32_t int_value = 0;
@@ -68,18 +68,10 @@
   EXPECT_TRUE(bool_value);
 }
 
-TEST(DBusParamWriter, Append_UnsupportedType) {
-  std::unique_ptr<Response> message(Response::CreateEmpty().release());
-  MessageWriter writer(message.get());
-  // 'char' (AKA int8_t) is not supported by D-Bus.
-  EXPECT_FALSE(DBusParamWriter::Append(&writer, char{'s'}));
-  EXPECT_EQ("", message->GetSignature());
-}
-
 TEST(DBusParamWriter, AppendDBusOutParams_NoArgs) {
   std::unique_ptr<Response> message(Response::CreateEmpty().release());
   MessageWriter writer(message.get());
-  EXPECT_TRUE(DBusParamWriter::AppendDBusOutParams(&writer));
+  DBusParamWriter::AppendDBusOutParams(&writer);
   EXPECT_EQ("", message->GetSignature());
 }
 
@@ -90,11 +82,11 @@
   std::string string_value_in{"bar"};
   ObjectPath path_value_in{"/obj/path"};
 
-  EXPECT_TRUE(DBusParamWriter::AppendDBusOutParams(&writer, &int_value_in));
+  DBusParamWriter::AppendDBusOutParams(&writer, &int_value_in);
   EXPECT_EQ("i", message->GetSignature());
-  EXPECT_TRUE(DBusParamWriter::AppendDBusOutParams(&writer, &string_value_in));
+  DBusParamWriter::AppendDBusOutParams(&writer, &string_value_in);
   EXPECT_EQ("is", message->GetSignature());
-  EXPECT_TRUE(DBusParamWriter::AppendDBusOutParams(&writer, &path_value_in));
+  DBusParamWriter::AppendDBusOutParams(&writer, &path_value_in);
   EXPECT_EQ("iso", message->GetSignature());
 
   int32_t int_value = 0;
@@ -117,10 +109,10 @@
   int32_t int_value_in{8};
   Any variant_value_in{8.5};
   bool bool_value_in{true};
-  EXPECT_TRUE(DBusParamWriter::AppendDBusOutParams(&writer,
-                                                   &int_value_in,
-                                                   &variant_value_in,
-                                                   &bool_value_in));
+  DBusParamWriter::AppendDBusOutParams(&writer,
+                                       &int_value_in,
+                                       &variant_value_in,
+                                       &bool_value_in);
   EXPECT_EQ("ivb", message->GetSignature());
 
   int32_t int_value = 0;
@@ -140,7 +132,7 @@
 TEST(DBusParamWriter, AppendDBusOutParams_Mixed_NoArgs) {
   std::unique_ptr<Response> message(Response::CreateEmpty().release());
   MessageWriter writer(message.get());
-  EXPECT_TRUE(DBusParamWriter::AppendDBusOutParams(&writer, 3, 5));
+  DBusParamWriter::AppendDBusOutParams(&writer, 3, 5);
   EXPECT_EQ("", message->GetSignature());
 }
 
@@ -151,12 +143,11 @@
   std::string str_value_in{"bar"};
   ObjectPath path_value_in{"/obj"};
 
-  EXPECT_TRUE(DBusParamWriter::AppendDBusOutParams(&writer, 2, &int_value_in));
+  DBusParamWriter::AppendDBusOutParams(&writer, 2, &int_value_in);
   EXPECT_EQ("i", message->GetSignature());
-  EXPECT_TRUE(DBusParamWriter::AppendDBusOutParams(&writer, &str_value_in, 0));
+  DBusParamWriter::AppendDBusOutParams(&writer, &str_value_in, 0);
   EXPECT_EQ("is", message->GetSignature());
-  EXPECT_TRUE(DBusParamWriter::AppendDBusOutParams(&writer, 1, &path_value_in,
-                                                   2));
+  DBusParamWriter::AppendDBusOutParams(&writer, 1, &path_value_in, 2);
   EXPECT_EQ("iso", message->GetSignature());
 
   int32_t int_value = 0;
@@ -179,14 +170,14 @@
   int32_t int_value_in{8};
   Any variant_value_in{7.5};
   bool bool_value_in{true};
-  EXPECT_TRUE(DBusParamWriter::AppendDBusOutParams(&writer,
-                                                   0,
-                                                   &int_value_in,
-                                                   1,
-                                                   &variant_value_in,
-                                                   2,
-                                                   &bool_value_in,
-                                                   3));
+  DBusParamWriter::AppendDBusOutParams(&writer,
+                                       0,
+                                       &int_value_in,
+                                       1,
+                                       &variant_value_in,
+                                       2,
+                                       &bool_value_in,
+                                       3);
   EXPECT_EQ("ivb", message->GetSignature());
 
   int32_t int_value = 0;
diff --git a/chromeos/dbus/dbus_signal.h b/chromeos/dbus/dbus_signal.h
index 17e7442..ed7e129 100644
--- a/chromeos/dbus/dbus_signal.h
+++ b/chromeos/dbus/dbus_signal.h
@@ -54,8 +54,8 @@
   bool Send(const Args&... args) const {
     dbus::Signal signal(interface_name_, signal_name_);
     dbus::MessageWriter signal_writer(&signal);
-    return DBusParamWriter::Append(&signal_writer, args...) &&
-           SendSignal(&signal);
+    DBusParamWriter::Append(&signal_writer, args...);
+    return SendSignal(&signal);
   }
 
  private: