buffet: Add device state manager
Added StateManager class to buffet and all the internals to
load vendor-provided state definition fragments, apply state
property defaults, expose the state property values over D-Bus
to be updated by daemons (using Buffet.UpdateState method) and
sent the current device state to GCD server as part of device
draft provided during device registration.
BUG=chromium:415364
TEST=FEATURES=test emerge-link buffet
Change-Id: I78e470c98d906064dfbe925614613ee6a91ff3cf
Reviewed-on: https://chromium-review.googlesource.com/218743
Tested-by: Alex Vakulenko <avakulenko@chromium.org>
Reviewed-by: Christopher Wiley <wiley@chromium.org>
Commit-Queue: Alex Vakulenko <avakulenko@chromium.org>
diff --git a/buffet/states/state_package.cc b/buffet/states/state_package.cc
new file mode 100644
index 0000000..ce71c50
--- /dev/null
+++ b/buffet/states/state_package.cc
@@ -0,0 +1,116 @@
+// Copyright 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "buffet/states/state_package.h"
+
+#include <base/logging.h>
+#include <base/values.h>
+#include <chromeos/dbus/data_serialization.h>
+
+#include "buffet/commands/prop_types.h"
+#include "buffet/commands/prop_values.h"
+#include "buffet/commands/schema_utils.h"
+#include "buffet/states/error_codes.h"
+
+namespace buffet {
+
+StatePackage::StatePackage(const std::string& name) : name_(name) {
+}
+
+bool StatePackage::AddSchemaFromJson(const base::DictionaryValue* json,
+ chromeos::ErrorPtr* error) {
+ ObjectSchema schema;
+ if (!schema.FromJson(json, nullptr, error))
+ return false;
+
+ // Scan first to make sure we have no property redefinitions.
+ for (const auto& pair : schema.GetProps()) {
+ if (types_.GetProp(pair.first)) {
+ chromeos::Error::AddToPrintf(error, errors::state::kDomain,
+ errors::state::kPropertyRedefinition,
+ "State property '%s.%s' is already defined",
+ name_.c_str(), pair.first.c_str());
+ return false;
+ }
+ }
+
+ // Now move all the properties to |types_| object.
+ for (const auto& pair : schema.GetProps()) {
+ types_.AddProp(pair.first, pair.second);
+ // Create default value for this state property.
+ values_.insert(std::make_pair(pair.first, pair.second->CreateValue()));
+ }
+
+ return true;
+}
+
+bool StatePackage::AddValuesFromJson(const base::DictionaryValue* json,
+ chromeos::ErrorPtr* error) {
+ base::DictionaryValue::Iterator iter(*json);
+ while (!iter.IsAtEnd()) {
+ std::string property_name = iter.key();
+ auto it = values_.find(property_name);
+ if (it == values_.end()) {
+ chromeos::Error::AddToPrintf(error, errors::state::kDomain,
+ errors::state::kPropertyNotDefined,
+ "State property '%s.%s' is not defined",
+ name_.c_str(), property_name.c_str());
+ return false;
+ }
+ auto new_value = it->second->GetPropType()->CreateValue();
+ if (!new_value->FromJson(&iter.value(), error))
+ return false;
+ it->second = new_value;
+ iter.Advance();
+ }
+ return true;
+}
+
+std::unique_ptr<base::DictionaryValue> StatePackage::GetValuesAsJson(
+ chromeos::ErrorPtr* error) const {
+ std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue);
+ for (const auto& pair : values_) {
+ auto value = pair.second->ToJson(error);
+ if (!value) {
+ dict.reset();
+ break;
+ }
+ dict->SetWithoutPathExpansion(pair.first, value.release());
+ }
+ return dict;
+}
+
+chromeos::Any StatePackage::GetPropertyValue(const std::string& property_name,
+ chromeos::ErrorPtr* error) const {
+ auto it = values_.find(property_name);
+ if (it == values_.end()) {
+ chromeos::Error::AddToPrintf(error, errors::state::kDomain,
+ errors::state::kPropertyNotDefined,
+ "State property '%s.%s' is not defined",
+ name_.c_str(), property_name.c_str());
+ return chromeos::Any();
+ }
+ return PropValueToDBusVariant(it->second.get());
+}
+
+bool StatePackage::SetPropertyValue(const std::string& property_name,
+ const chromeos::Any& value,
+ chromeos::ErrorPtr* error) {
+ auto it = values_.find(property_name);
+ if (it == values_.end()) {
+ chromeos::Error::AddToPrintf(error, errors::state::kDomain,
+ errors::state::kPropertyNotDefined,
+ "State property '%s.%s' is not defined",
+ name_.c_str(), property_name.c_str());
+ return false;
+ }
+ auto new_value = PropValueFromDBusVariant(it->second->GetPropType(),
+ value, error);
+ if (!new_value)
+ return false;
+ it->second = new_value;
+ return true;
+}
+
+} // namespace buffet