buffet: Add callback to notify about state changes

Callback could be used to expose state as D-Bus property or
for smarter server updates.
SetProperties replaced SetPropertyValue to avoid multiple callbacks
for complex state updates.

BUG=brillo:1124,brillo:810,brillo:427
TEST=`FEATURES=test emerge-gizmo buffet`

Change-Id: I899b14fd41b0a45cabe149431a3bebeba9c50320
Reviewed-on: https://chromium-review.googlesource.com/273341
Tested-by: Vitaly Buka <vitalybuka@chromium.org>
Trybot-Ready: Vitaly Buka <vitalybuka@chromium.org>
Reviewed-by: Alex Vakulenko <avakulenko@chromium.org>
Commit-Queue: Vitaly Buka <vitalybuka@chromium.org>
diff --git a/buffet/states/state_manager.cc b/buffet/states/state_manager.cc
index 827cd7f..57330f4 100644
--- a/buffet/states/state_manager.cc
+++ b/buffet/states/state_manager.cc
@@ -30,6 +30,11 @@
   CHECK(state_change_queue_) << "State change queue not specified";
 }
 
+void StateManager::AddOnChangedCallback(const base::Closure& callback) {
+  on_changed_.push_back(callback);
+  callback.Run();  // Force to read current state.
+}
+
 void StateManager::Startup() {
   LOG(INFO) << "Initializing StateManager.";
 
@@ -88,6 +93,9 @@
                          firmware_version,
                          base::Time::Now(),
                          nullptr));
+
+  for (const auto& cb : on_changed_)
+    cb.Run();
 }
 
 std::unique_ptr<base::DictionaryValue> StateManager::GetStateValuesAsJson(
@@ -104,6 +112,23 @@
   return dict;
 }
 
+bool StateManager::SetProperties(
+    const chromeos::VariantDictionary& property_set,
+    chromeos::ErrorPtr* error) {
+  base::Time timestamp = base::Time::Now();
+  bool all_success = true;
+  for (const auto& pair : property_set) {
+    if (!SetPropertyValue(pair.first, pair.second, timestamp, error)) {
+      // Remember that an error occurred but keep going and update the rest of
+      // the properties if possible.
+      all_success = false;
+    }
+  }
+  for (const auto& cb : on_changed_)
+    cb.Run();
+  return all_success;
+}
+
 bool StateManager::SetPropertyValue(const std::string& full_property_name,
                                     const chromeos::Any& value,
                                     const base::Time& timestamp,