Add Binder support to weaved and remove D-Bus interface

Added binder-based IPC to weaved instead of D-Bus. Removed the
old weave commands based on D-Bus and redesigned client library
interface to be more in line with how Binder operates.

BUG: 23782171, 25523591

Change-Id: Ic39a6a2edf2e033e506d233919c9d04e4fab8d01
diff --git a/common/binder_constants.cc b/common/binder_constants.cc
new file mode 100644
index 0000000..b17962b
--- /dev/null
+++ b/common/binder_constants.cc
@@ -0,0 +1,23 @@
+// Copyright 2016 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.
+
+#include "common/binder_constants.h"
+
+namespace weaved {
+namespace binder {
+
+const char kWeaveServiceName[] = "weave_service";
+
+}  // namespace binder
+}  // namespace weaved
diff --git a/common/binder_constants.h b/common/binder_constants.h
new file mode 100644
index 0000000..82935cd
--- /dev/null
+++ b/common/binder_constants.h
@@ -0,0 +1,26 @@
+// Copyright 2016 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.
+
+#ifndef COMMON_BINDER_CONSTANTS_H_
+#define COMMON_BINDER_CONSTANTS_H_
+
+namespace weaved {
+namespace binder {
+
+extern const char kWeaveServiceName[];
+
+}  // namespace binder
+}  // namespace weaved
+
+#endif  // COMMON_BINDER_CONSTANTS_H_
diff --git a/common/binder_utils.cc b/common/binder_utils.cc
new file mode 100644
index 0000000..6f66040
--- /dev/null
+++ b/common/binder_utils.cc
@@ -0,0 +1,65 @@
+// Copyright 2016 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.
+
+#include "common/binder_utils.h"
+
+#include <base/json/json_reader.h>
+#include <base/json/json_writer.h>
+
+namespace weaved {
+namespace binder_utils {
+
+android::binder::Status ToStatus(bool success, weave::ErrorPtr* error) {
+  if (success)
+    return android::binder::Status::ok();
+  return android::binder::Status::fromServiceSpecificError(
+      1, android::String8{error->get()->GetMessage().c_str()});
+}
+
+bool StatusToError(android::binder::Status status, brillo::ErrorPtr* error) {
+  if (status.isOk())
+    return true;
+  brillo::Error::AddTo(error, FROM_HERE, "binder",
+                       std::to_string(status.exceptionCode()),
+                       status.exceptionMessage().string());
+  return false;
+}
+
+android::String16 ToString16(const base::Value& value) {
+  std::string json;
+  base::JSONWriter::Write(value, &json);
+  return ToString16(json);
+}
+
+android::binder::Status ParseDictionary(
+    const android::String16& json,
+    std::unique_ptr<base::DictionaryValue>* dict) {
+  int error = 0;
+  std::string message;
+  std::unique_ptr<base::Value> value{
+      base::JSONReader::ReadAndReturnError(ToString(json), base::JSON_PARSE_RFC,
+                                           &error, &message)
+          .release()};
+  base::DictionaryValue* dict_value = nullptr;
+  if (!value || !value->GetAsDictionary(&dict_value)) {
+    return android::binder::Status::fromServiceSpecificError(
+        error, android::String8{message.c_str()});
+  }
+  dict->reset(dict_value);
+  value.release();  // |dict| now owns the object.
+  return android::binder::Status::ok();
+}
+
+}  // namespace binder_utils
+}  // namespace weaved
diff --git a/common/binder_utils.h b/common/binder_utils.h
new file mode 100644
index 0000000..65b462d
--- /dev/null
+++ b/common/binder_utils.h
@@ -0,0 +1,63 @@
+// Copyright 2016 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.
+
+#ifndef COMMON_BINDER_UTILS_H_
+#define COMMON_BINDER_UTILS_H_
+
+#include <memory>
+#include <string>
+
+#include <base/values.h>
+#include <binder/Status.h>
+#include <utils/String8.h>
+#include <utils/String16.h>
+#include <weave/error.h>
+#include <brillo/errors/error.h>
+
+namespace weaved {
+namespace binder_utils {
+
+// Converts the result of weave API call into a binder Status object.
+// If |success| is true, return binder::Status::ok(), otherwise the method
+// constructs a service-specific failure status with an error message obtained
+// from the |error| object.
+android::binder::Status ToStatus(bool success, weave::ErrorPtr* error);
+
+// Converts a binder status code to a Brillo error object. Returns true if the
+// status was isOk(), otherwise returns false and provides error information
+// in the |error| object.
+bool StatusToError(android::binder::Status status, brillo::ErrorPtr* error);
+
+// Converts binder's UTF16 string into a regular UTF8-encoded standard string.
+inline std::string ToString(const android::String16& value) {
+  return android::String8{value}.string();
+}
+
+// Converts regular UTF8-encoded standard string into a binder's UTF16 string.
+inline android::String16 ToString16(const std::string& value) {
+  return android::String16{value.c_str()};
+}
+
+// Serializes a dictionary to a string for transferring over binder.
+android::String16 ToString16(const base::Value& value);
+
+// De-serializes a dictionary from a binder string.
+android::binder::Status ParseDictionary(
+    const android::String16& json,
+    std::unique_ptr<base::DictionaryValue>* dict);
+
+}  // namespace binder_utils
+}  // namespace weaved
+
+#endif  // COMMON_BINDER_UTILS_H_
diff --git a/common/data_conversion.cc b/common/data_conversion.cc
new file mode 100644
index 0000000..fd20ad4
--- /dev/null
+++ b/common/data_conversion.cc
@@ -0,0 +1,263 @@
+// Copyright 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.
+
+#include "common/data_conversion.h"
+
+#include <string>
+#include <vector>
+
+#include <brillo/type_name_undecorate.h>
+
+namespace weaved {
+
+namespace {
+
+// Helpers for JsonToAny().
+template <typename T>
+brillo::Any ValueToAny(const base::Value& json,
+                       bool (base::Value::*fnc)(T*) const) {
+  T val;
+  CHECK((json.*fnc)(&val));
+  return val;
+}
+
+brillo::Any ValueToAny(const base::Value& json);
+
+template <typename T>
+brillo::Any ListToAny(const base::ListValue& list,
+                      bool (base::Value::*fnc)(T*) const) {
+  std::vector<T> result;
+  result.reserve(list.GetSize());
+  for (const base::Value* v : list) {
+    T val;
+    CHECK((v->*fnc)(&val));
+    result.push_back(val);
+  }
+  return result;
+}
+
+brillo::Any DictListToAny(const base::ListValue& list) {
+  std::vector<brillo::VariantDictionary> result;
+  result.reserve(list.GetSize());
+  for (const base::Value* v : list) {
+    const base::DictionaryValue* dict = nullptr;
+    CHECK(v->GetAsDictionary(&dict));
+    result.push_back(details::DictionaryValueToVariantDictionary(*dict));
+  }
+  return result;
+}
+
+brillo::Any ListListToAny(const base::ListValue& list) {
+  std::vector<brillo::Any> result;
+  result.reserve(list.GetSize());
+  for (const base::Value* v : list)
+    result.push_back(ValueToAny(*v));
+  return result;
+}
+
+// Converts a JSON value into an Any so it can be sent over D-Bus using
+// UpdateState D-Bus method from Buffet.
+brillo::Any ValueToAny(const base::Value& json) {
+  brillo::Any prop_value;
+  switch (json.GetType()) {
+    case base::Value::TYPE_BOOLEAN:
+      prop_value = ValueToAny<bool>(json, &base::Value::GetAsBoolean);
+      break;
+    case base::Value::TYPE_INTEGER:
+      prop_value = ValueToAny<int>(json, &base::Value::GetAsInteger);
+      break;
+    case base::Value::TYPE_DOUBLE:
+      prop_value = ValueToAny<double>(json, &base::Value::GetAsDouble);
+      break;
+    case base::Value::TYPE_STRING:
+      prop_value = ValueToAny<std::string>(json, &base::Value::GetAsString);
+      break;
+    case base::Value::TYPE_DICTIONARY: {
+      const base::DictionaryValue* dict = nullptr;
+      CHECK(json.GetAsDictionary(&dict));
+      prop_value = details::DictionaryValueToVariantDictionary(*dict);
+      break;
+    }
+    case base::Value::TYPE_LIST: {
+      const base::ListValue* list = nullptr;
+      CHECK(json.GetAsList(&list));
+      if (list->empty()) {
+        // We don't know type of objects this list intended for, so we just use
+        // vector<brillo::Any>.
+        prop_value = ListListToAny(*list);
+        break;
+      }
+      auto type = (*list->begin())->GetType();
+      for (const base::Value* v : *list)
+        CHECK_EQ(v->GetType(), type) << "Unsupported different type elements";
+
+      switch (type) {
+        case base::Value::TYPE_BOOLEAN:
+          prop_value = ListToAny<bool>(*list, &base::Value::GetAsBoolean);
+          break;
+        case base::Value::TYPE_INTEGER:
+          prop_value = ListToAny<int>(*list, &base::Value::GetAsInteger);
+          break;
+        case base::Value::TYPE_DOUBLE:
+          prop_value = ListToAny<double>(*list, &base::Value::GetAsDouble);
+          break;
+        case base::Value::TYPE_STRING:
+          prop_value = ListToAny<std::string>(*list, &base::Value::GetAsString);
+          break;
+        case base::Value::TYPE_DICTIONARY:
+          prop_value = DictListToAny(*list);
+          break;
+        case base::Value::TYPE_LIST:
+          // We can't support Any{vector<vector<>>} as the type is only known
+          // in runtime when we need to instantiate templates in compile time.
+          // We can use Any{vector<Any>} instead.
+          prop_value = ListListToAny(*list);
+          break;
+        default:
+          LOG(FATAL) << "Unsupported JSON value type for list element: "
+                     << (*list->begin())->GetType();
+      }
+      break;
+    }
+    default:
+      LOG(FATAL) << "Unexpected JSON value type: " << json.GetType();
+      break;
+  }
+  return prop_value;
+}
+
+template <typename T>
+std::unique_ptr<base::Value> CreateValue(const T& value,
+                                         brillo::ErrorPtr* error) {
+  return std::unique_ptr<base::Value>{new base::FundamentalValue{value}};
+}
+
+std::unique_ptr<base::Value> CreateValue(const std::string& value,
+                                         brillo::ErrorPtr* error) {
+  return std::unique_ptr<base::Value>{new base::StringValue{value}};
+}
+
+std::unique_ptr<base::Value> CreateValue(const char* value,
+                                         brillo::ErrorPtr* error) {
+  return std::unique_ptr<base::Value>{new base::StringValue{value}};
+}
+
+template <>
+std::unique_ptr<base::Value> CreateValue<brillo::VariantDictionary>(
+    const brillo::VariantDictionary& value,
+    brillo::ErrorPtr* error) {
+  return details::VariantDictionaryToDictionaryValue(value, error);
+}
+
+template <typename T>
+std::unique_ptr<base::ListValue> CreateListValue(const std::vector<T>& value,
+                                                 brillo::ErrorPtr* error) {
+  std::unique_ptr<base::ListValue> list{new base::ListValue};
+
+  for (const T& i : value) {
+    auto item = CreateValue(i, error);
+    if (!item)
+      return nullptr;
+    list->Append(item.release());
+  }
+
+  return list;
+}
+
+// Returns false only in case of error. True can be returned if type is not
+// matched.
+template <typename T>
+bool TryCreateValue(const brillo::Any& any,
+                    std::unique_ptr<base::Value>* value,
+                    brillo::ErrorPtr* error) {
+  if (any.IsTypeCompatible<T>()) {
+    *value = CreateValue(any.Get<T>(), error);
+    return *value != nullptr;
+  }
+
+  if (any.IsTypeCompatible<std::vector<T>>()) {
+    *value = CreateListValue(any.Get<std::vector<T>>(), error);
+    return *value != nullptr;
+  }
+
+  return true;  // Not an error, we will try different type.
+}
+
+template <>
+std::unique_ptr<base::Value> CreateValue<brillo::Any>(
+    const brillo::Any& any,
+    brillo::ErrorPtr* error) {
+  std::unique_ptr<base::Value> result;
+  if (!TryCreateValue<bool>(any, &result, error) || result)
+    return result;
+
+  if (!TryCreateValue<int>(any, &result, error) || result)
+    return result;
+
+  if (!TryCreateValue<double>(any, &result, error) || result)
+    return result;
+
+  if (!TryCreateValue<std::string>(any, &result, error) || result)
+    return result;
+
+  if (any.IsTypeCompatible<const char*>())
+    return CreateValue(any.Get<const char*>(), error);
+
+  if (!TryCreateValue<brillo::VariantDictionary>(any, &result, error) ||
+      result) {
+    return result;
+  }
+
+  // This will collapse Any{Any{T}} and vector{Any{T}}.
+  if (!TryCreateValue<brillo::Any>(any, &result, error) || result)
+    return result;
+
+  brillo::Error::AddToPrintf(
+      error, FROM_HERE, "buffet", "unknown_type", "Type '%s' is not supported.",
+      any.GetUndecoratedTypeName().c_str());
+
+  return nullptr;
+}
+
+}  // namespace
+
+namespace details {
+
+brillo::VariantDictionary DictionaryValueToVariantDictionary(
+    const base::DictionaryValue& object) {
+  brillo::VariantDictionary result;
+
+  for (base::DictionaryValue::Iterator it(object); !it.IsAtEnd(); it.Advance())
+    result.emplace(it.key(), ValueToAny(it.value()));
+
+  return result;
+}
+
+std::unique_ptr<base::DictionaryValue> VariantDictionaryToDictionaryValue(
+    const brillo::VariantDictionary& object,
+    brillo::ErrorPtr* error) {
+  std::unique_ptr<base::DictionaryValue> result{new base::DictionaryValue};
+
+  for (const auto& pair : object) {
+    auto value = CreateValue(pair.second, error);
+    if (!value)
+      return nullptr;
+    result->Set(pair.first, value.release());
+  }
+
+  return result;
+}
+
+}  // namespace details
+}  // namespace weaved
diff --git a/common/data_conversion.h b/common/data_conversion.h
new file mode 100644
index 0000000..accc520
--- /dev/null
+++ b/common/data_conversion.h
@@ -0,0 +1,38 @@
+// Copyright 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.
+
+#ifndef COMMON_DATA_CONVERSION_H_
+#define COMMON_DATA_CONVERSION_H_
+
+#include <base/values.h>
+#include <brillo/any.h>
+#include <brillo/errors/error.h>
+#include <brillo/variant_dictionary.h>
+
+namespace weaved {
+namespace details {
+
+// Converts DictionaryValue to variant dictionary.
+brillo::VariantDictionary DictionaryValueToVariantDictionary(
+    const base::DictionaryValue& object);
+
+// Converts variant dictionary to DictionaryValue.
+std::unique_ptr<base::DictionaryValue> VariantDictionaryToDictionaryValue(
+    const brillo::VariantDictionary& object,
+    brillo::ErrorPtr* error);
+
+}  // namespace details
+}  // namespace weaved
+
+#endif  // COMMON_DATA_CONVERSION_H_
diff --git a/common/data_conversion_unittest.cc b/common/data_conversion_unittest.cc
new file mode 100644
index 0000000..832fffb
--- /dev/null
+++ b/common/data_conversion_unittest.cc
@@ -0,0 +1,200 @@
+// Copyright 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.
+
+#include "common/data_conversion.h"
+
+#include <limits>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include <base/guid.h>
+#include <base/rand_util.h>
+#include <base/values.h>
+#include <brillo/variant_dictionary.h>
+#include <gtest/gtest.h>
+#include <weave/test/unittest_utils.h>
+
+namespace weaved {
+
+namespace {
+
+using brillo::Any;
+using brillo::VariantDictionary;
+using weave::test::CreateDictionaryValue;
+using weave::test::IsEqualValue;
+
+brillo::VariantDictionary ToVariant(const base::DictionaryValue& object) {
+  return details::DictionaryValueToVariantDictionary(object);
+}
+
+std::unique_ptr<base::DictionaryValue> FromVariant(
+    const brillo::VariantDictionary& object) {
+  brillo::ErrorPtr error;
+  auto result = details::VariantDictionaryToDictionaryValue(object, &error);
+  EXPECT_TRUE(result || error);
+  return result;
+}
+
+std::unique_ptr<base::Value> CreateRandomValue(int children);
+std::unique_ptr<base::Value> CreateRandomValue(int children,
+                                               base::Value::Type type);
+
+const base::Value::Type kRandomTypes[] = {
+    base::Value::TYPE_BOOLEAN,    base::Value::TYPE_INTEGER,
+    base::Value::TYPE_DOUBLE,     base::Value::TYPE_STRING,
+    base::Value::TYPE_DICTIONARY, base::Value::TYPE_LIST,
+};
+
+const base::Value::Type kRandomTypesWithChildren[] = {
+    base::Value::TYPE_DICTIONARY, base::Value::TYPE_LIST,
+};
+
+base::Value::Type CreateRandomValueType(bool with_children) {
+  if (with_children) {
+    return kRandomTypesWithChildren[base::RandInt(
+        0, arraysize(kRandomTypesWithChildren) - 1)];
+  }
+  return kRandomTypes[base::RandInt(0, arraysize(kRandomTypes) - 1)];
+}
+
+std::unique_ptr<base::DictionaryValue> CreateRandomDictionary(int children) {
+  std::unique_ptr<base::DictionaryValue> result{new base::DictionaryValue};
+
+  while (children > 0) {
+    int sub_children = base::RandInt(1, children);
+    children -= sub_children;
+    result->Set(base::GenerateGUID(),
+                CreateRandomValue(sub_children).release());
+  }
+
+  return result;
+}
+
+std::unique_ptr<base::ListValue> CreateRandomList(int children) {
+  std::unique_ptr<base::ListValue> result{new base::ListValue};
+
+  base::Value::Type type = CreateRandomValueType(children > 0);
+  while (children > 0) {
+    size_t max_children =
+        (type != base::Value::TYPE_DICTIONARY && type != base::Value::TYPE_LIST)
+            ? 1
+            : children;
+    size_t sub_children = base::RandInt(1, max_children);
+    children -= sub_children;
+    result->Append(CreateRandomValue(sub_children, type).release());
+  }
+
+  return result;
+}
+
+std::unique_ptr<base::Value> CreateRandomValue(int children,
+                                               base::Value::Type type) {
+  CHECK_GE(children, 1);
+  switch (type) {
+    case base::Value::TYPE_INTEGER:
+      return std::unique_ptr<base::Value>{new base::FundamentalValue{
+          base::RandInt(std::numeric_limits<int>::min(),
+                        std::numeric_limits<int>::max())}};
+    case base::Value::TYPE_DOUBLE:
+      return std::unique_ptr<base::Value>{
+          new base::FundamentalValue{base::RandDouble()}};
+    case base::Value::TYPE_STRING:
+      return std::unique_ptr<base::Value>{
+          new base::StringValue{base::GenerateGUID()}};
+    case base::Value::TYPE_DICTIONARY:
+      CHECK_GE(children, 1);
+      return CreateRandomDictionary(children - 1);
+    case base::Value::TYPE_LIST:
+      CHECK_GE(children, 1);
+      return CreateRandomList(children - 1);
+    default:
+      return std::unique_ptr<base::Value>{
+          new base::FundamentalValue{base::RandInt(0, 1) != 0}};
+  }
+}
+
+std::unique_ptr<base::Value> CreateRandomValue(int children) {
+  return CreateRandomValue(children, CreateRandomValueType(children > 0));
+}
+
+}  // namespace
+
+TEST(DBusConversionTest, DictionaryToDBusVariantDictionary) {
+  EXPECT_EQ((VariantDictionary{{"bool", true}}),
+            ToVariant(*CreateDictionaryValue("{'bool': true}")));
+  EXPECT_EQ((VariantDictionary{{"int", 5}}),
+            ToVariant(*CreateDictionaryValue("{'int': 5}")));
+  EXPECT_EQ((VariantDictionary{{"double", 6.7}}),
+            ToVariant(*CreateDictionaryValue("{'double': 6.7}")));
+  EXPECT_EQ((VariantDictionary{{"string", std::string{"abc"}}}),
+            ToVariant(*CreateDictionaryValue("{'string': 'abc'}")));
+  EXPECT_EQ((VariantDictionary{{"object", VariantDictionary{{"bool", true}}}}),
+            ToVariant(*CreateDictionaryValue("{'object': {'bool': true}}")));
+  EXPECT_EQ((VariantDictionary{{"emptyList", std::vector<Any>{}}}),
+            ToVariant(*CreateDictionaryValue("{'emptyList': []}")));
+  EXPECT_EQ((VariantDictionary{{"intList", std::vector<int>{5}}}),
+            ToVariant(*CreateDictionaryValue("{'intList': [5]}")));
+  EXPECT_EQ((VariantDictionary{
+                {"intListList", std::vector<Any>{std::vector<int>{5},
+                                                 std::vector<int>{6, 7}}}}),
+            ToVariant(*CreateDictionaryValue(
+                "{'intListList': [[5], [6, 7]]}")));
+  EXPECT_EQ((VariantDictionary{{"objList",
+                                std::vector<VariantDictionary>{
+                                    {{"string", std::string{"abc"}}}}}}),
+            ToVariant(*CreateDictionaryValue(
+                "{'objList': [{'string': 'abc'}]}")));
+}
+
+TEST(DBusConversionTest, VariantDictionaryToDictionaryValue) {
+  EXPECT_JSON_EQ("{'bool': true}", *FromVariant({{"bool", true}}));
+  EXPECT_JSON_EQ("{'int': 5}", *FromVariant({{"int", 5}}));
+  EXPECT_JSON_EQ("{'double': 6.7}", *FromVariant({{"double", 6.7}}));
+  EXPECT_JSON_EQ("{'string': 'abc'}",
+                 *FromVariant({{"string", std::string{"abc"}}}));
+  EXPECT_JSON_EQ("{'object': {'bool': true}}",
+                 *FromVariant({{"object", VariantDictionary{{"bool", true}}}}));
+  EXPECT_JSON_EQ("{'emptyList': []}",
+                 *FromVariant({{"emptyList", std::vector<bool>{}}}));
+  EXPECT_JSON_EQ("{'intList': [5]}",
+                 *FromVariant({{"intList", std::vector<int>{5}}}));
+  EXPECT_JSON_EQ(
+      "{'intListList': [[5], [6, 7]]}",
+      *FromVariant({{"intListList",
+                   std::vector<Any>{std::vector<int>{5},
+                                    std::vector<int>{6, 7}}}}));
+  EXPECT_JSON_EQ(
+      "{'objList': [{'string': 'abc'}]}",
+      *FromVariant({{"objList", std::vector<VariantDictionary>{
+                                    {{"string", std::string{"abc"}}}}}}));
+  EXPECT_JSON_EQ("{'int': 5}", *FromVariant({{"int", Any{Any{5}}}}));
+}
+
+TEST(DBusConversionTest, VariantDictionaryToDictionaryValueErrors) {
+  EXPECT_FALSE(FromVariant({{"cString", "abc"}}));
+  EXPECT_FALSE(FromVariant({{"float", 1.0f}}));
+  EXPECT_FALSE(FromVariant({{"listList", std::vector<std::vector<int>>{}}}));
+  EXPECT_FALSE(FromVariant({{"any", Any{}}}));
+  EXPECT_FALSE(FromVariant({{"null", nullptr}}));
+}
+
+TEST(DBusConversionTest, DBusRandomDictionaryConversion) {
+  auto dict = CreateRandomDictionary(10000);
+  auto varian_dict = ToVariant(*dict);
+  auto dict_restored = FromVariant(varian_dict);
+  EXPECT_PRED2(IsEqualValue, *dict, *dict_restored);
+}
+
+}  // namespace buffet