Merge latest version of libweave and update weaved to reflect changes

libweave has a number of interafce changes which need to be reflected in
weaved's implementation of the interfaces. This commit brings weaved in
sync with the current version of libweave.

Change-Id: If6355ef2c19e38b56f96b027038e2d6da0f44709
diff --git a/Android.mk b/Android.mk
index de005d1..a54cd09 100644
--- a/Android.mk
+++ b/Android.mk
@@ -88,7 +88,6 @@
 LOCAL_MODULE := weaved
 LOCAL_REQUIRED_MODULES := \
 	avahi-daemon \
-	weaved.json \
 	com.android.Weave.conf \
 	webservd \
 
@@ -153,15 +152,6 @@
 
 include $(BUILD_NATIVE_TEST)
 
-# Config files for /etc/weaved
-# ========================================================
-include $(CLEAR_VARS)
-LOCAL_MODULE := weaved.json
-LOCAL_MODULE_CLASS := ETC
-LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/weaved/commands
-LOCAL_SRC_FILES := buffet/etc/weaved/commands/weaved.json
-include $(BUILD_PREBUILT)
-
 # DBus config files for /etc/dbus-1
 # ========================================================
 include $(CLEAR_VARS)
diff --git a/buffet/buffet_config.cc b/buffet/buffet_config.cc
index a31dde8..fde6f0e 100644
--- a/buffet/buffet_config.cc
+++ b/buffet/buffet_config.cc
@@ -7,7 +7,6 @@
 #include <map>
 #include <set>
 
-#include <base/files/file_enumerator.h>
 #include <base/files/file_util.h>
 #include <base/files/important_file_writer.h>
 #include <base/logging.h>
@@ -19,26 +18,6 @@
 
 namespace buffet {
 
-namespace {
-
-const char kErrorDomain[] = "buffet";
-const char kFileReadError[] = "file_read_error";
-
-bool LoadFile(const base::FilePath& file_path,
-              std::string* data,
-              chromeos::ErrorPtr* error) {
-  if (!base::ReadFileToString(file_path, data)) {
-    chromeos::errors::system::AddSystemError(error, FROM_HERE, errno);
-    chromeos::Error::AddToPrintf(error, FROM_HERE, kErrorDomain, kFileReadError,
-                                 "Failed to read file '%s'",
-                                 file_path.value().c_str());
-    return false;
-  }
-  return true;
-}
-
-}  // namespace
-
 namespace config_keys {
 
 const char kClientId[] = "client_id";
@@ -64,8 +43,8 @@
 BuffetConfig::BuffetConfig(const Options& options) : options_(options) {}
 
 bool BuffetConfig::LoadDefaults(weave::Settings* settings) {
-  // Keep this hard coded default for sometime. This previously was set by
-  // libweave. It should be set by overlays buffet.conf.
+  // Keep this hardcoded default for sometime. This previously was set by
+  // libweave. It should be set by overlay's buffet.conf.
   settings->client_id = "58855907228.apps.googleusercontent.com";
   settings->client_secret = "eHSAREAHrIqPsHBxCE9zPPBi";
   settings->api_key = "AIzaSyDSq46gG-AxUnC3zoqD9COIPrjolFsMfMA";
@@ -83,57 +62,18 @@
   bool result = LoadDefaults(store, settings);
   settings->disable_security = options_.disable_security;
   settings->test_privet_ssid = options_.test_privet_ssid;
-  return result;
-}
 
-std::map<std::string, std::string> BuffetConfig::LoadCommandDefs() {
-  std::map<std::string, std::string> result;
-  auto load_packages = [&result](const base::FilePath& root,
-                                 const base::FilePath::StringType& pattern) {
-    base::FilePath dir{root.Append("commands")};
-    VLOG(2) << "Looking for commands in " << dir.value();
-    base::FileEnumerator enumerator(dir, false, base::FileEnumerator::FILES,
-                                    pattern);
-    for (base::FilePath path = enumerator.Next(); !path.empty();
-         path = enumerator.Next()) {
-      LOG(INFO) << "Loading command schema from " << path.value();
-      std::string category = path.BaseName().RemoveExtension().value();
-      CHECK(LoadFile(path, &result[category], nullptr));
-    }
-  };
-  load_packages(options_.definitions, FILE_PATH_LITERAL("*.json"));
-  load_packages(options_.test_definitions, FILE_PATH_LITERAL("*test.json"));
-  return result;
-}
+  if (!options_.client_id.empty())
+    settings->client_id = options_.client_id;
+  if (!options_.client_secret.empty())
+    settings->client_secret = options_.client_secret;
+  if (!options_.api_key.empty())
+    settings->api_key = options_.api_key;
+  if (!options_.oauth_url.empty())
+    settings->oauth_url = options_.oauth_url;
+  if (!options_.service_url.empty())
+    settings->service_url = options_.service_url;
 
-std::map<std::string, std::string> BuffetConfig::LoadStateDefs() {
-  // Load component-specific device state definitions.
-  base::FilePath dir{options_.definitions.Append("states")};
-  base::FileEnumerator enumerator(dir, false, base::FileEnumerator::FILES,
-                                  FILE_PATH_LITERAL("*.schema.json"));
-  std::map<std::string, std::string> result;
-  for (base::FilePath path = enumerator.Next(); !path.empty();
-       path = enumerator.Next()) {
-    LOG(INFO) << "Loading state definition from " << path.value();
-    std::string category = path.BaseName().RemoveExtension().value();
-    CHECK(LoadFile(path, &result[category], nullptr));
-  }
-  return result;
-}
-
-std::vector<std::string> BuffetConfig::LoadStateDefaults() {
-  // Load component-specific device state defaults.
-  base::FilePath dir{options_.definitions.Append("states")};
-  base::FileEnumerator enumerator(dir, false, base::FileEnumerator::FILES,
-                                  FILE_PATH_LITERAL("*.defaults.json"));
-  std::vector<std::string> result;
-  for (base::FilePath path = enumerator.Next(); !path.empty();
-       path = enumerator.Next()) {
-    LOG(INFO) << "Loading state defaults from " << path.value();
-    std::string json;
-    CHECK(LoadFile(path, &json, nullptr));
-    result.push_back(json);
-  }
   return result;
 }
 
diff --git a/buffet/buffet_config.h b/buffet/buffet_config.h
index 20dea47..a286bf8 100644
--- a/buffet/buffet_config.h
+++ b/buffet/buffet_config.h
@@ -23,6 +23,12 @@
 class BuffetConfig final : public weave::provider::ConfigStore {
  public:
   struct Options {
+    std::string client_id;
+    std::string client_secret;
+    std::string api_key;
+    std::string oauth_url;
+    std::string service_url;
+
     base::FilePath defaults;
     base::FilePath settings;
 
@@ -41,9 +47,6 @@
   bool LoadDefaults(weave::Settings* settings) override;
   std::string LoadSettings() override;
   void SaveSettings(const std::string& settings) override;
-  std::map<std::string, std::string> LoadCommandDefs() override;
-  std::map<std::string, std::string> LoadStateDefs() override;
-  std::vector<std::string> LoadStateDefaults() override;
 
   bool LoadDefaults(const chromeos::KeyValueStore& store,
                     weave::Settings* settings);
diff --git a/buffet/dbus_bindings/com.android.Weave.Command.dbus-xml b/buffet/dbus_bindings/com.android.Weave.Command.dbus-xml
index 8bb519a..5fb2940 100644
--- a/buffet/dbus_bindings/com.android.Weave.Command.dbus-xml
+++ b/buffet/dbus_bindings/com.android.Weave.Command.dbus-xml
@@ -15,20 +15,20 @@
         Mark the command as aborted. This tells the cloud that the device did
         not successfully complete executing the command.
       </tp:docstring>
-      <annotation name="org.chromium.DBus.Method.Kind" value="simple"/>
+      <annotation name="org.chromium.DBus.Method.Kind" value="normal"/>
     </method>
     <method name="Cancel">
       <tp:docstring>
         Mark the command as cancelled. Unlike Abort() this should be used when
         the device detects a user request to cancel a command.
       </tp:docstring>
-      <annotation name="org.chromium.DBus.Method.Kind" value="simple"/>
+      <annotation name="org.chromium.DBus.Method.Kind" value="normal"/>
     </method>
     <method name="Done">
       <tp:docstring>
         Mark the command as successfully completed.
       </tp:docstring>
-      <annotation name="org.chromium.DBus.Method.Kind" value="simple"/>
+      <annotation name="org.chromium.DBus.Method.Kind" value="normal"/>
     </method>
     <property name="Name" type="s" access="read"/>
     <property name="Category" type="s" access="read"/>
diff --git a/buffet/dbus_command_dispatcher.cc b/buffet/dbus_command_dispatcher.cc
index 03f4789..0edb92a 100644
--- a/buffet/dbus_command_dispatcher.cc
+++ b/buffet/dbus_command_dispatcher.cc
@@ -6,6 +6,7 @@
 
 #include <chromeos/dbus/exported_object_manager.h>
 #include <weave/command.h>
+#include <weave/device.h>
 
 #include "buffet/dbus_command_proxy.h"
 #include "buffet/dbus_constants.h"
@@ -17,14 +18,16 @@
 
 DBusCommandDispacher::DBusCommandDispacher(
     const base::WeakPtr<ExportedObjectManager>& object_manager,
-    weave::Commands* command_manager)
+    weave::Device* device)
     : object_manager_{object_manager} {
-  command_manager->AddOnCommandAddedCallback(base::Bind(
+  device->AddCommandHandler("", base::Bind(
       &DBusCommandDispacher::OnCommandAdded, weak_ptr_factory_.GetWeakPtr()));
 }
 
-void DBusCommandDispacher::OnCommandAdded(weave::Command* command) {
-  if (!object_manager_)
+void DBusCommandDispacher::OnCommandAdded(
+    const std::weak_ptr<weave::Command>& cmd) {
+  auto command = cmd.lock();
+  if (!object_manager_ || !command)
     return;
   std::unique_ptr<DBusCommandProxy> proxy{new DBusCommandProxy(
       object_manager_.get(), object_manager_->GetBus(), command,
diff --git a/buffet/dbus_command_dispatcher.h b/buffet/dbus_command_dispatcher.h
index fa17ad6..082576a 100644
--- a/buffet/dbus_command_dispatcher.h
+++ b/buffet/dbus_command_dispatcher.h
@@ -10,7 +10,11 @@
 
 #include <base/macros.h>
 #include <base/memory/weak_ptr.h>
-#include <weave/commands.h>
+
+namespace weave {
+class Command;
+class Device;
+}
 
 namespace chromeos {
 namespace dbus_utils {
@@ -32,10 +36,10 @@
   explicit DBusCommandDispacher(
       const base::WeakPtr<chromeos::dbus_utils::ExportedObjectManager>&
           object_manager,
-      weave::Commands* command_manager);
+      weave::Device* device);
 
  private:
-  void OnCommandAdded(weave::Command* command);
+  void OnCommandAdded(const std::weak_ptr<weave::Command>& cmd);
 
   base::WeakPtr<chromeos::dbus_utils::ExportedObjectManager> object_manager_;
   int next_id_{0};
diff --git a/buffet/dbus_command_proxy.cc b/buffet/dbus_command_proxy.cc
index d079392..71196e8 100644
--- a/buffet/dbus_command_proxy.cc
+++ b/buffet/dbus_command_proxy.cc
@@ -14,103 +14,137 @@
 using chromeos::dbus_utils::AsyncEventSequencer;
 using chromeos::dbus_utils::ExportedObjectManager;
 
+namespace errors {
+namespace commands {
+const char kDomain[] = "weaved";
+const char kCommandDestroyed[] = "command_destroyed";
+}  // namespace commands
+}  // namespace errors
+
 namespace buffet {
 
+namespace {
+
+bool ReportDestroyedError(chromeos::ErrorPtr* error) {
+  chromeos::Error::AddTo(error, FROM_HERE, errors::commands::kDomain,
+                         errors::commands::kCommandDestroyed,
+                         "Command has been destroyed");
+  return false;
+}
+
+}  // anonymous namespace
+
 DBusCommandProxy::DBusCommandProxy(ExportedObjectManager* object_manager,
                                    const scoped_refptr<dbus::Bus>& bus,
-                                   weave::Command* command,
+                                   const std::weak_ptr<weave::Command>& command,
                                    std::string object_path)
     : command_{command},
-      dbus_object_{object_manager, bus, dbus::ObjectPath{object_path}} {
-  observer_.Add(command);
-}
+      dbus_object_{object_manager, bus, dbus::ObjectPath{object_path}} {}
 
 void DBusCommandProxy::RegisterAsync(
     const AsyncEventSequencer::CompletionAction& completion_callback) {
+  auto command = command_.lock();
+  if (!command)
+    return;
+
   dbus_adaptor_.RegisterWithDBusObject(&dbus_object_);
 
   // Set the initial property values before registering the DBus object.
-  dbus_adaptor_.SetName(command_->GetName());
-  dbus_adaptor_.SetCategory(command_->GetCategory());
-  dbus_adaptor_.SetId(command_->GetID());
-  dbus_adaptor_.SetStatus(EnumToString(command_->GetStatus()));
+  dbus_adaptor_.SetName(command->GetName());
+  dbus_adaptor_.SetId(command->GetID());
+  dbus_adaptor_.SetStatus(EnumToString(command->GetStatus()));
   dbus_adaptor_.SetProgress(
-      DictionaryToDBusVariantDictionary(*command_->GetProgress()));
-  dbus_adaptor_.SetOrigin(EnumToString(command_->GetOrigin()));
+      DictionaryToDBusVariantDictionary(*command->GetProgress()));
+  dbus_adaptor_.SetOrigin(EnumToString(command->GetOrigin()));
   dbus_adaptor_.SetParameters(
-      DictionaryToDBusVariantDictionary(*command_->GetParameters()));
+      DictionaryToDBusVariantDictionary(*command->GetParameters()));
   dbus_adaptor_.SetResults(
-      DictionaryToDBusVariantDictionary(*command_->GetResults()));
+      DictionaryToDBusVariantDictionary(*command->GetResults()));
 
   // Register the command DBus object and expose its methods and properties.
   dbus_object_.RegisterAsync(completion_callback);
 }
 
-void DBusCommandProxy::OnResultsChanged() {
-  dbus_adaptor_.SetResults(
-      DictionaryToDBusVariantDictionary(*command_->GetResults()));
-}
-
-void DBusCommandProxy::OnStatusChanged() {
-  dbus_adaptor_.SetStatus(EnumToString(command_->GetStatus()));
-}
-
-void DBusCommandProxy::OnProgressChanged() {
-  dbus_adaptor_.SetProgress(
-      DictionaryToDBusVariantDictionary(*command_->GetProgress()));
-}
-
-void DBusCommandProxy::OnCommandDestroyed() {
-  delete this;
-}
-
 bool DBusCommandProxy::SetProgress(
     chromeos::ErrorPtr* error,
     const chromeos::VariantDictionary& progress) {
-  LOG(INFO) << "Received call to Command<" << command_->GetName()
+  auto command = command_.lock();
+  if (!command)
+    return ReportDestroyedError(error);
+
+  LOG(INFO) << "Received call to Command<" << command->GetName()
             << ">::SetProgress()";
   auto dictionary = DictionaryFromDBusVariantDictionary(progress, error);
   if (!dictionary)
     return false;
   weave::ErrorPtr weave_error;
-  if (!command_->SetProgress(*dictionary, &weave_error)) {
+  if (!command->SetProgress(*dictionary, &weave_error)) {
     ConvertError(*weave_error, error);
     return false;
   }
+  dbus_adaptor_.SetProgress(
+      DictionaryToDBusVariantDictionary(*command->GetProgress()));
+  dbus_adaptor_.SetStatus(EnumToString(command->GetStatus()));
   return true;
 }
 
 bool DBusCommandProxy::SetResults(chromeos::ErrorPtr* error,
                                   const chromeos::VariantDictionary& results) {
-  LOG(INFO) << "Received call to Command<" << command_->GetName()
+  auto command = command_.lock();
+  if (!command)
+    return ReportDestroyedError(error);
+
+  LOG(INFO) << "Received call to Command<" << command->GetName()
             << ">::SetResults()";
   auto dictionary = DictionaryFromDBusVariantDictionary(results, error);
   if (!dictionary)
     return false;
   weave::ErrorPtr weave_error;
-  if (!command_->SetResults(*dictionary, &weave_error)) {
+  if (!command->SetResults(*dictionary, &weave_error)) {
     ConvertError(*weave_error, error);
     return false;
   }
+  dbus_adaptor_.SetProgress(
+      DictionaryToDBusVariantDictionary(*command->GetProgress()));
   return true;
 }
 
-void DBusCommandProxy::Abort() {
-  LOG(INFO) << "Received call to Command<" << command_->GetName()
+bool DBusCommandProxy::Abort(chromeos::ErrorPtr* error) {
+  auto command = command_.lock();
+  if (!command)
+    return ReportDestroyedError(error);
+
+  LOG(INFO) << "Received call to Command<" << command->GetName()
             << ">::Abort()";
-  command_->Abort();
+  command->Abort();
+  dbus_adaptor_.SetStatus(EnumToString(command->GetStatus()));
+  return true;
 }
 
-void DBusCommandProxy::Cancel() {
-  LOG(INFO) << "Received call to Command<" << command_->GetName()
+bool DBusCommandProxy::Cancel(chromeos::ErrorPtr* error) {
+  auto command = command_.lock();
+  if (!command)
+    return ReportDestroyedError(error);
+
+  LOG(INFO) << "Received call to Command<" << command->GetName()
             << ">::Cancel()";
-  command_->Cancel();
+  command->Cancel();
+  dbus_adaptor_.SetStatus(EnumToString(command->GetStatus()));
+  return true;
 }
 
-void DBusCommandProxy::Done() {
-  LOG(INFO) << "Received call to Command<" << command_->GetName()
+bool DBusCommandProxy::Done(chromeos::ErrorPtr* error) {
+  auto command = command_.lock();
+  if (!command)
+    return ReportDestroyedError(error);
+
+  LOG(INFO) << "Received call to Command<" << command->GetName()
             << ">::Done()";
-  command_->Done();
+  command->Done();
+  dbus_adaptor_.SetProgress(
+      DictionaryToDBusVariantDictionary(*command->GetProgress()));
+  dbus_adaptor_.SetStatus(EnumToString(command->GetStatus()));
+  return true;
 }
 
 }  // namespace buffet
diff --git a/buffet/dbus_command_proxy.h b/buffet/dbus_command_proxy.h
index dc45738..bf2868d 100644
--- a/buffet/dbus_command_proxy.h
+++ b/buffet/dbus_command_proxy.h
@@ -23,12 +23,11 @@
 
 namespace buffet {
 
-class DBusCommandProxy : public weave::Command::Observer,
-                         public com::android::Weave::CommandInterface {
+class DBusCommandProxy : public com::android::Weave::CommandInterface {
  public:
   DBusCommandProxy(chromeos::dbus_utils::ExportedObjectManager* object_manager,
                    const scoped_refptr<dbus::Bus>& bus,
-                   weave::Command* command,
+                   const std::weak_ptr<weave::Command>& command,
                    std::string object_path);
   ~DBusCommandProxy() override = default;
 
@@ -36,12 +35,6 @@
       const chromeos::dbus_utils::AsyncEventSequencer::CompletionAction&
           completion_callback);
 
-  // CommandProxyInterface implementation/overloads.
-  void OnResultsChanged() override;
-  void OnStatusChanged() override;
-  void OnProgressChanged() override;
-  void OnCommandDestroyed() override;
-
  private:
   // Handles calls to com.android.Weave.Command.SetProgress(progress).
   bool SetProgress(chromeos::ErrorPtr* error,
@@ -50,18 +43,16 @@
   bool SetResults(chromeos::ErrorPtr* error,
                   const chromeos::VariantDictionary& results) override;
   // Handles calls to com.android.Weave.Command.Abort().
-  void Abort() override;
+  bool Abort(chromeos::ErrorPtr* error) override;
   // Handles calls to com.android.Weave.Command.Cancel().
-  void Cancel() override;
+  bool Cancel(chromeos::ErrorPtr* error) override;
   // Handles calls to com.android.Weave.Command.Done().
-  void Done() override;
+  bool Done(chromeos::ErrorPtr* error) override;
 
-  weave::Command* command_;
+  std::weak_ptr<weave::Command> command_;
   com::android::Weave::CommandAdaptor dbus_adaptor_{this};
   chromeos::dbus_utils::DBusObject dbus_object_;
 
-  ScopedObserver<weave::Command, weave::Command::Observer> observer_{this};
-
   friend class DBusCommandProxyTest;
   friend class DBusCommandDispacherTest;
   DISALLOW_COPY_AND_ASSIGN(DBusCommandProxy);
diff --git a/buffet/dbus_command_proxy_unittest.cc b/buffet/dbus_command_proxy_unittest.cc
index 265e5f5..1e156e4 100644
--- a/buffet/dbus_command_proxy_unittest.cc
+++ b/buffet/dbus_command_proxy_unittest.cc
@@ -17,7 +17,6 @@
 #include <weave/command.h>
 #include <weave/enum_to_string.h>
 #include <weave/test/mock_command.h>
-#include <weave/test/mock_commands.h>
 #include <weave/test/unittest_utils.h>
 
 #include "buffet/dbus_constants.h"
@@ -37,7 +36,6 @@
 
 namespace {
 
-const char kTestCommandCategoty[] = "test_command_category";
 const char kTestCommandId[] = "cmd_1";
 
 MATCHER_P(EqualToJson, json, "") {
@@ -50,8 +48,7 @@
 class DBusCommandProxyTest : public ::testing::Test {
  public:
   void SetUp() override {
-    EXPECT_CALL(command_, AddObserver(_)).Times(1);
-    EXPECT_CALL(command_, RemoveObserver(_)).Times(1);
+    command_ = std::make_shared<StrictMock<weave::test::MockCommand>>();
     // Set up a mock DBus bus object.
     dbus::Bus::Options options;
     options.bus_type = dbus::Bus::SYSTEM;
@@ -60,25 +57,23 @@
     EXPECT_CALL(*bus_, AssertOnOriginThread()).Times(AnyNumber());
     EXPECT_CALL(*bus_, AssertOnDBusThread()).Times(AnyNumber());
 
-    EXPECT_CALL(command_, GetID())
+    EXPECT_CALL(*command_, GetID())
         .WillOnce(ReturnRefOfCopy<std::string>(kTestCommandId));
-    // Use WillRepeatedly becase GetName is used for logging.
-    EXPECT_CALL(command_, GetName())
+    // Use WillRepeatedly because GetName is used for logging.
+    EXPECT_CALL(*command_, GetName())
         .WillRepeatedly(ReturnRefOfCopy<std::string>("robot.jump"));
-    EXPECT_CALL(command_, GetCategory())
-        .WillOnce(ReturnRefOfCopy<std::string>(kTestCommandCategoty));
-    EXPECT_CALL(command_, GetStatus())
-        .WillOnce(Return(weave::CommandStatus::kQueued));
-    EXPECT_CALL(command_, GetOrigin())
+    EXPECT_CALL(*command_, GetStatus())
+        .WillRepeatedly(Return(weave::CommandStatus::kQueued));
+    EXPECT_CALL(*command_, GetOrigin())
         .WillOnce(Return(weave::CommandOrigin::kLocal));
-    EXPECT_CALL(command_, MockGetParameters())
+    EXPECT_CALL(*command_, MockGetParameters())
         .WillOnce(ReturnRefOfCopy<std::string>(R"({
           'height': 53,
           '_jumpType': '_withKick'
         })"));
-    EXPECT_CALL(command_, MockGetProgress())
-        .WillOnce(ReturnRefOfCopy<std::string>("{}"));
-    EXPECT_CALL(command_, MockGetResults())
+    EXPECT_CALL(*command_, MockGetProgress())
+        .WillRepeatedly(ReturnRefOfCopy<std::string>("{}"));
+    EXPECT_CALL(*command_, MockGetResults())
         .WillOnce(ReturnRefOfCopy<std::string>("{}"));
 
     // Set up a mock ExportedObject to be used with the DBus command proxy.
@@ -94,7 +89,8 @@
     EXPECT_CALL(*mock_exported_object_command_, ExportMethod(_, _, _, _))
         .Times(AnyNumber());
 
-    proxy_.reset(new DBusCommandProxy(nullptr, bus_, &command_, cmd_path));
+    proxy_.reset(new DBusCommandProxy{
+        nullptr, bus_, std::weak_ptr<weave::Command>{command_}, cmd_path});
     GetCommandProxy()->RegisterAsync(
         AsyncEventSequencer::GetDefaultCompletionAction());
   }
@@ -124,7 +120,7 @@
   scoped_refptr<dbus::MockExportedObject> mock_exported_object_command_;
   scoped_refptr<dbus::MockBus> bus_;
 
-  StrictMock<weave::test::MockCommand> command_;
+  std::shared_ptr<StrictMock<weave::test::MockCommand>> command_;
   std::unique_ptr<DBusCommandProxy> proxy_;
 };
 
@@ -137,42 +133,11 @@
   EXPECT_EQ(VariantDictionary{}, GetCommandAdaptor()->GetProgress());
   EXPECT_EQ(VariantDictionary{}, GetCommandAdaptor()->GetResults());
   EXPECT_EQ("robot.jump", GetCommandAdaptor()->GetName());
-  EXPECT_EQ(kTestCommandCategoty, GetCommandAdaptor()->GetCategory());
   EXPECT_EQ(kTestCommandId, GetCommandAdaptor()->GetId());
 }
 
-TEST_F(DBusCommandProxyTest, OnProgressChanged) {
-  EXPECT_CALL(*mock_exported_object_command_, SendSignal(_)).Times(1);
-  EXPECT_CALL(command_, MockGetProgress())
-      .WillOnce(ReturnRefOfCopy<std::string>("{'progress': 10}"));
-  proxy_->OnProgressChanged();
-  EXPECT_EQ((VariantDictionary{{"progress", int32_t{10}}}),
-            GetCommandAdaptor()->GetProgress());
-}
-
-TEST_F(DBusCommandProxyTest, OnResultsChanged) {
-  EXPECT_CALL(*mock_exported_object_command_, SendSignal(_)).Times(1);
-  EXPECT_CALL(command_, MockGetResults())
-      .WillOnce(ReturnRefOfCopy<std::string>(
-          "{'foo': 42, 'bar': 'foobar', 'resultList': [1, 2, 3]}"));
-  proxy_->OnResultsChanged();
-
-  EXPECT_EQ((VariantDictionary{{"foo", int32_t{42}},
-                               {"bar", std::string{"foobar"}},
-                               {"resultList", std::vector<int>{1, 2, 3}}}),
-            GetCommandAdaptor()->GetResults());
-}
-
-TEST_F(DBusCommandProxyTest, OnStatusChanged) {
-  EXPECT_CALL(*mock_exported_object_command_, SendSignal(_)).Times(1);
-  EXPECT_CALL(command_, GetStatus())
-      .WillOnce(Return(weave::CommandStatus::kInProgress));
-  proxy_->OnStatusChanged();
-  EXPECT_EQ(weave::CommandStatus::kInProgress, GetCommandStatus());
-}
-
 TEST_F(DBusCommandProxyTest, SetProgress) {
-  EXPECT_CALL(command_, SetProgress(EqualToJson("{'progress': 10}"), _))
+  EXPECT_CALL(*command_, SetProgress(EqualToJson("{'progress': 10}"), _))
       .WillOnce(Return(true));
   EXPECT_TRUE(
       GetCommandInterface()->SetProgress(nullptr, {{"progress", int32_t{10}}}));
@@ -180,7 +145,7 @@
 
 TEST_F(DBusCommandProxyTest, SetResults) {
   EXPECT_CALL(
-      command_,
+      *command_,
       SetResults(
           EqualToJson("{'foo': 42, 'bar': 'foobar', 'resultList': [1, 2, 3]}"),
           _))
@@ -192,18 +157,18 @@
 }
 
 TEST_F(DBusCommandProxyTest, Abort) {
-  EXPECT_CALL(command_, Abort());
-  GetCommandInterface()->Abort();
+  EXPECT_CALL(*command_, Abort());
+  EXPECT_TRUE(GetCommandInterface()->Abort(nullptr));
 }
 
 TEST_F(DBusCommandProxyTest, Cancel) {
-  EXPECT_CALL(command_, Cancel());
-  GetCommandInterface()->Cancel();
+  EXPECT_CALL(*command_, Cancel());
+  EXPECT_TRUE(GetCommandInterface()->Cancel(nullptr));
 }
 
 TEST_F(DBusCommandProxyTest, Done) {
-  EXPECT_CALL(command_, Done());
-  GetCommandInterface()->Done();
+  EXPECT_CALL(*command_, Done());
+  EXPECT_TRUE(GetCommandInterface()->Done(nullptr));
 }
 
 }  // namespace buffet
diff --git a/buffet/dbus_conversion.cc b/buffet/dbus_conversion.cc
index 51d35f1..e943ad7 100644
--- a/buffet/dbus_conversion.cc
+++ b/buffet/dbus_conversion.cc
@@ -237,7 +237,7 @@
     auto value = CreateValue(pair.second, error);
     if (!value)
       return nullptr;
-    result->SetWithoutPathExpansion(pair.first, value.release());
+    result->Set(pair.first, value.release());
   }
 
   return result;
diff --git a/buffet/etc/weaved/commands/weaved.json b/buffet/etc/weaved/commands/weaved.json
deleted file mode 100644
index 4196a22..0000000
--- a/buffet/etc/weaved/commands/weaved.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
-  "base": {
-    "updateBaseConfiguration": { },
-    "updateDeviceInfo": { }
-  }
-}
diff --git a/buffet/main.cc b/buffet/main.cc
index bda526b..616542d 100644
--- a/buffet/main.cc
+++ b/buffet/main.cc
@@ -27,26 +27,19 @@
 
 class Daemon final : public DBusServiceDaemon {
  public:
-  Daemon(const Manager::Options& options,
-         const BuffetConfig::Options& config_options,
-         const std::set<std::string>& device_whitelist)
-      : DBusServiceDaemon(kServiceName, kRootServicePath),
-        options_{options},
-        config_options_{config_options},
-        device_whitelist_{device_whitelist} {}
+  explicit Daemon(const Manager::Options& options)
+      : DBusServiceDaemon(kServiceName, kRootServicePath), options_{options} {}
 
  protected:
   void RegisterDBusObjectsAsync(AsyncEventSequencer* sequencer) override {
-    manager_.reset(new Manager(object_manager_->AsWeakPtr()));
-    manager_->Start(options_, config_options_, device_whitelist_, sequencer);
+    manager_.reset(new Manager(options_, object_manager_->AsWeakPtr()));
+    manager_->Start(sequencer);
   }
 
   void OnShutdown(int* return_code) override { manager_->Stop(); }
 
  private:
   Manager::Options options_;
-  BuffetConfig::Options config_options_;
-  std::set<std::string> device_whitelist_;
 
   std::unique_ptr<buffet::Manager> manager_;
   DISALLOW_COPY_AND_ASSIGN(Daemon);
@@ -101,21 +94,20 @@
   // Mark it to be ignored.
   signal(SIGPIPE, SIG_IGN);
 
-  buffet::BuffetConfig::Options config_options;
-  config_options.defaults = base::FilePath{FLAGS_config_path};
-  config_options.settings = base::FilePath{FLAGS_state_path};
-  config_options.definitions = base::FilePath{"/etc/weaved"};
-  config_options.test_definitions = base::FilePath{FLAGS_test_definitions_path};
-  config_options.disable_security = FLAGS_disable_security;
-  config_options.test_privet_ssid = FLAGS_test_privet_ssid;
-
   buffet::Manager::Options options;
   options.xmpp_enabled = FLAGS_enable_xmpp;
   options.disable_privet = FLAGS_disable_privet;
   options.enable_ping = FLAGS_enable_ping;
+  options.device_whitelist = {device_whitelist.begin(), device_whitelist.end()};
 
-  buffet::Daemon daemon{
-      options, config_options,
-      std::set<std::string>{device_whitelist.begin(), device_whitelist.end()}};
+  options.config_options.defaults = base::FilePath{FLAGS_config_path};
+  options.config_options.settings = base::FilePath{FLAGS_state_path};
+  options.config_options.definitions = base::FilePath{"/etc/weaved"};
+  options.config_options.test_definitions =
+      base::FilePath{FLAGS_test_definitions_path};
+  options.config_options.disable_security = FLAGS_disable_security;
+  options.config_options.test_privet_ssid = FLAGS_test_privet_ssid;
+
+  buffet::Daemon daemon{options};
   return daemon.Run();
 }
diff --git a/buffet/manager.cc b/buffet/manager.cc
index f471ded..c3cbc87 100644
--- a/buffet/manager.cc
+++ b/buffet/manager.cc
@@ -10,6 +10,8 @@
 
 #include <base/bind.h>
 #include <base/bind_helpers.h>
+#include <base/files/file_enumerator.h>
+#include <base/files/file_util.h>
 #include <base/json/json_reader.h>
 #include <base/json/json_writer.h>
 #include <base/message_loop/message_loop.h>
@@ -50,6 +52,74 @@
 const char kPairingCodeKey[] = "code";
 
 const char kErrorDomain[] = "buffet";
+const char kFileReadError[] = "file_read_error";
+
+bool LoadFile(const base::FilePath& file_path,
+              std::string* data,
+              chromeos::ErrorPtr* error) {
+  if (!base::ReadFileToString(file_path, data)) {
+    chromeos::errors::system::AddSystemError(error, FROM_HERE, errno);
+    chromeos::Error::AddToPrintf(error, FROM_HERE, kErrorDomain, kFileReadError,
+                                 "Failed to read file '%s'",
+                                 file_path.value().c_str());
+    return false;
+  }
+  return true;
+}
+
+void LoadCommandDefinitions(const BuffetConfig::Options& options,
+                            weave::Device* device) {
+  auto load_packages = [device](const base::FilePath& root,
+                                const base::FilePath::StringType& pattern) {
+    base::FilePath dir{root.Append("commands")};
+    LOG(INFO) << "Looking for command schemas in " << dir.value();
+    base::FileEnumerator enumerator(dir, false, base::FileEnumerator::FILES,
+                                    pattern);
+    for (base::FilePath path = enumerator.Next(); !path.empty();
+         path = enumerator.Next()) {
+      LOG(INFO) << "Loading command schema from " << path.value();
+      std::string json;
+      CHECK(LoadFile(path, &json, nullptr));
+      device->AddCommandDefinitionsFromJson(json);
+    }
+  };
+  load_packages(options.definitions, FILE_PATH_LITERAL("*.json"));
+  load_packages(options.test_definitions, FILE_PATH_LITERAL("*test.json"));
+}
+
+void LoadStateDefinitions(const BuffetConfig::Options& options,
+                          weave::Device* device) {
+  // Load component-specific device state definitions.
+  base::FilePath dir{options.definitions.Append("states")};
+  LOG(INFO) << "Looking for state definitions in " << dir.value();
+  base::FileEnumerator enumerator(dir, false, base::FileEnumerator::FILES,
+                                  FILE_PATH_LITERAL("*.schema.json"));
+  std::vector<std::string> result;
+  for (base::FilePath path = enumerator.Next(); !path.empty();
+       path = enumerator.Next()) {
+    LOG(INFO) << "Loading state definition from " << path.value();
+    std::string json;
+    CHECK(LoadFile(path, &json, nullptr));
+    device->AddStateDefinitionsFromJson(json);
+  }
+}
+
+void LoadStateDefaults(const BuffetConfig::Options& options,
+                       weave::Device* device) {
+  // Load component-specific device state defaults.
+  base::FilePath dir{options.definitions.Append("states")};
+  LOG(INFO) << "Looking for state defaults in " << dir.value();
+  base::FileEnumerator enumerator(dir, false, base::FileEnumerator::FILES,
+                                  FILE_PATH_LITERAL("*.defaults.json"));
+  std::vector<std::string> result;
+  for (base::FilePath path = enumerator.Next(); !path.empty();
+       path = enumerator.Next()) {
+    LOG(INFO) << "Loading state defaults from " << path.value();
+    std::string json;
+    CHECK(LoadFile(path, &json, nullptr));
+    CHECK(device->SetStatePropertiesFromJson(json, nullptr));
+  }
+}
 
 }  // anonymous namespace
 
@@ -62,32 +132,42 @@
   }
 };
 
-Manager::Manager(const base::WeakPtr<ExportedObjectManager>& object_manager)
-    : dbus_object_(object_manager.get(),
+Manager::Manager(const Options& options,
+                 const base::WeakPtr<ExportedObjectManager>& object_manager)
+    : options_{options},
+      dbus_object_(object_manager.get(),
                    object_manager->GetBus(),
-                   com::android::Weave::ManagerAdaptor::GetObjectPath()) {
-}
+                   com::android::Weave::ManagerAdaptor::GetObjectPath()) {}
 
 Manager::~Manager() {
 }
 
-void Manager::Start(const Options& options,
-                    const BuffetConfig::Options& paths,
-                    const std::set<std::string>& device_whitelist,
-                    AsyncEventSequencer* sequencer) {
+void Manager::Start(AsyncEventSequencer* sequencer) {
+  RestartWeave(sequencer);
+
+  dbus_adaptor_.RegisterWithDBusObject(&dbus_object_);
+  dbus_object_.RegisterAsync(
+      sequencer->GetHandler("Manager.RegisterAsync() failed.", true));
+}
+
+void Manager::RestartWeave(AsyncEventSequencer* sequencer) {
+  Stop();
+
   task_runner_.reset(new TaskRunner{});
+  config_.reset(new BuffetConfig{options_.config_options});
   http_client_.reset(new HttpTransportClient);
-  shill_client_.reset(new ShillClient{dbus_object_.GetBus(), device_whitelist,
-                                      !options.xmpp_enabled});
+  shill_client_.reset(new ShillClient{dbus_object_.GetBus(),
+                                      options_.device_whitelist,
+                                      !options_.xmpp_enabled});
   weave::provider::HttpServer* http_server{nullptr};
 #ifdef BUFFET_USE_WIFI_BOOTSTRAPPING
-  if (!options.disable_privet) {
+  if (!options_.disable_privet) {
     mdns_client_ = MdnsClient::CreateInstance(dbus_object_.GetBus());
     web_serv_client_.reset(new WebServClient{dbus_object_.GetBus(), sequencer});
     bluetooth_client_ = BluetoothClient::CreateInstance();
     http_server = web_serv_client_.get();
 
-    if (options.enable_ping) {
+    if (options_.enable_ping) {
       http_server->AddRequestHandler(
           "/privet/ping",
           base::Bind(
@@ -100,17 +180,20 @@
   }
 #endif  // BUFFET_USE_WIFI_BOOTSTRAPPING
 
-  config_.reset(new BuffetConfig{paths});
   device_ = weave::Device::Create(config_.get(), task_runner_.get(),
                                   http_client_.get(), shill_client_.get(),
                                   mdns_client_.get(), web_serv_client_.get(),
                                   shill_client_.get(), bluetooth_client_.get());
 
+  LoadCommandDefinitions(options_.config_options, device_.get());
+  LoadStateDefinitions(options_.config_options, device_.get());
+  LoadStateDefaults(options_.config_options, device_.get());
+
   device_->AddSettingsChangedCallback(
       base::Bind(&Manager::OnConfigChanged, weak_ptr_factory_.GetWeakPtr()));
 
-  command_dispatcher_.reset(new DBusCommandDispacher{
-      dbus_object_.GetObjectManager(), device_->GetCommands()});
+  command_dispatcher_.reset(
+      new DBusCommandDispacher{dbus_object_.GetObjectManager(), device_.get()});
 
   device_->AddStateChangedCallback(
       base::Bind(&Manager::OnStateChanged, weak_ptr_factory_.GetWeakPtr()));
@@ -118,19 +201,22 @@
   device_->AddGcdStateChangedCallback(
       base::Bind(&Manager::OnGcdStateChanged, weak_ptr_factory_.GetWeakPtr()));
 
-  if (!options.disable_privet) {
-    device_->AddPairingChangedCallbacks(
-        base::Bind(&Manager::OnPairingStart, weak_ptr_factory_.GetWeakPtr()),
-        base::Bind(&Manager::OnPairingEnd, weak_ptr_factory_.GetWeakPtr()));
-  }
-
-  dbus_adaptor_.RegisterWithDBusObject(&dbus_object_);
-  dbus_object_.RegisterAsync(
-      sequencer->GetHandler("Manager.RegisterAsync() failed.", true));
+  device_->AddPairingChangedCallbacks(
+      base::Bind(&Manager::OnPairingStart, weak_ptr_factory_.GetWeakPtr()),
+      base::Bind(&Manager::OnPairingEnd, weak_ptr_factory_.GetWeakPtr()));
 }
 
 void Manager::Stop() {
+  command_dispatcher_.reset();
   device_.reset();
+#ifdef BUFFET_USE_WIFI_BOOTSTRAPPING
+  web_serv_client_.reset();
+  mdns_client_.reset();
+#endif  // BUFFET_USE_WIFI_BOOTSTRAPPING
+  shill_client_.reset();
+  http_client_.reset();
+  config_.reset();
+  task_runner_.reset();
 }
 
 void Manager::RegisterDevice(DBusMethodResponsePtr<std::string> response,
@@ -188,7 +274,7 @@
 
   std::string id;
   weave::ErrorPtr error;
-  if (!device_->GetCommands()->AddCommand(*command, &id, &error)) {
+  if (!device_->AddCommand(*command, &id, &error)) {
     chromeos::ErrorPtr chromeos_error;
     ConvertError(*error, &chromeos_error);
     return response->ReplyWithError(chromeos_error.get());
@@ -199,7 +285,7 @@
 
 void Manager::GetCommand(DBusMethodResponsePtr<std::string> response,
                          const std::string& id) {
-  const weave::Command* command = device_->GetCommands()->FindCommand(id);
+  const weave::Command* command = device_->FindCommand(id);
   if (!command) {
     response->ReplyWithError(FROM_HERE, kErrorDomain, "unknown_command",
                              "Can't find command with id: " + id);
diff --git a/buffet/manager.h b/buffet/manager.h
index d7e8377..9ae5b17 100644
--- a/buffet/manager.h
+++ b/buffet/manager.h
@@ -55,21 +55,24 @@
     bool xmpp_enabled = true;
     bool disable_privet = false;
     bool enable_ping = false;
+    std::set<std::string> device_whitelist;
+
+    BuffetConfig::Options config_options;
   };
 
   explicit Manager(
+      const Options& options,
       const base::WeakPtr<chromeos::dbus_utils::ExportedObjectManager>&
           object_manager);
   ~Manager();
 
-  void Start(const Options& options,
-             const BuffetConfig::Options& config_options,
-             const std::set<std::string>& device_whitelist,
-             chromeos::dbus_utils::AsyncEventSequencer* sequencer);
+  void Start(chromeos::dbus_utils::AsyncEventSequencer* sequencer);
 
   void Stop();
 
  private:
+  void RestartWeave(chromeos::dbus_utils::AsyncEventSequencer* sequencer);
+
   // DBus methods:
   void RegisterDevice(DBusMethodResponsePtr<std::string> response,
                       const std::string& ticket_id) override;
@@ -93,17 +96,19 @@
                       const std::vector<uint8_t>& code);
   void OnPairingEnd(const std::string& session_id);
 
+  Options options_;
+
   com::android::Weave::ManagerAdaptor dbus_adaptor_{this};
   chromeos::dbus_utils::DBusObject dbus_object_;
 
   class TaskRunner;
   std::unique_ptr<TaskRunner> task_runner_;
   std::unique_ptr<BluetoothClient> bluetooth_client_;
+  std::unique_ptr<BuffetConfig> config_;
   std::unique_ptr<HttpTransportClient> http_client_;
   std::unique_ptr<ShillClient> shill_client_;
   std::unique_ptr<MdnsClient> mdns_client_;
   std::unique_ptr<WebServClient> web_serv_client_;
-  std::unique_ptr<BuffetConfig> config_;
   std::unique_ptr<weave::Device> device_;
   std::unique_ptr<DBusCommandDispacher> command_dispatcher_;
 
diff --git a/buffet/test_daemon/main.cc b/buffet/test_daemon/main.cc
index a25a4ac..5016b0b 100644
--- a/buffet/test_daemon/main.cc
+++ b/buffet/test_daemon/main.cc
@@ -22,7 +22,6 @@
 #include "buffet/dbus-proxies.h"
 
 namespace {
-const char kTestCommandCategory[] = "test";
 
 std::unique_ptr<base::DictionaryValue> DictionaryToJson(
     const chromeos::VariantDictionary& dictionary);
@@ -125,17 +124,14 @@
 
 void Daemon::OnBuffetCommand(com::android::Weave::CommandProxy* command) {
   // "Handle" only commands that belong to this daemon's category.
-  if (command->category() != kTestCommandCategory ||
-      command->status() == "done") {
+  if (command->status() == "done")
     return;
-  }
 
   command->SetPropertyChangedCallback(base::Bind(&Daemon::OnPropertyChange,
                                                  base::Unretained(this)));
   printf("++++++++++++++++++++++++++++++++++++++++++++++++\n");
   printf("Command received: %s\n", command->name().c_str());
   printf("DBus Object Path: %s\n", command->GetObjectPath().value().c_str());
-  printf("        category: %s\n", command->category().c_str());
   printf("              ID: %s\n", command->id().c_str());
   printf("          status: %s\n", command->status().c_str());
   printf("          origin: %s\n", command->origin().c_str());