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_manager.h b/buffet/states/state_manager.h
new file mode 100644
index 0000000..19212f0
--- /dev/null
+++ b/buffet/states/state_manager.h
@@ -0,0 +1,101 @@
+// 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.
+
+#ifndef BUFFET_STATES_STATE_MANAGER_H_
+#define BUFFET_STATES_STATE_MANAGER_H_
+
+#include <map>
+#include <memory>
+#include <set>
+#include <string>
+
+#include <base/macros.h>
+#include <chromeos/dbus/data_serialization.h>
+#include <chromeos/errors/error.h>
+
+#include "buffet/states/state_package.h"
+
+namespace base {
+class DictionaryValue;
+class FilePath;
+}  // namespace base
+
+namespace buffet {
+
+// StateManager is the class that aggregates the device state fragments
+// provided by device daemons and makes the aggregate device state available
+// to the GCD cloud server and local clients.
+class StateManager final {
+ public:
+  StateManager() = default;
+
+  // Initializes the state manager and load device state fragments.
+  // Called by Buffet daemon at startup.
+  void Startup();
+
+  // Returns aggregated state properties across all registered packages as
+  // a JSON object that can be used to send the device state to the GCD server.
+  std::unique_ptr<base::DictionaryValue> GetStateValuesAsJson(
+      chromeos::ErrorPtr* error) const;
+
+  // Updates a single property value. |full_property_name| must be the full
+  // name of the property to update in format "package.property".
+  bool SetPropertyValue(const std::string& full_property_name,
+                        const chromeos::Any& value,
+                        chromeos::ErrorPtr* error);
+
+  // Updates a number of state properties in one shot.
+  // |property_set| is a (full_property_name)-to-(property_value) map.
+  bool UpdateProperties(const chromeos::dbus_utils::Dictionary& property_set,
+                        chromeos::ErrorPtr* error);
+
+  // Returns all the categories the state properties are registered from.
+  // As with GCD command handling, the category normally represent a device
+  // service (daemon) that is responsible for a set of properties.
+  const std::set<std::string>& GetCategories() const {
+    return categories_;
+  }
+
+ private:
+  // Loads a device state fragment from a JSON object. |category| represents
+  // a device daemon providing the state fragment or empty string for the
+  // base state fragment.
+  bool LoadStateDefinition(const base::DictionaryValue& json,
+                           const std::string& category,
+                           chromeos::ErrorPtr* error);
+
+  // Loads a device state fragment JSON file. The file name (without extension)
+  // is used as the state fragment category.
+  bool LoadStateDefinition(const base::FilePath& json_file_path,
+                           chromeos::ErrorPtr* error);
+
+  // Loads the base device state fragment JSON file. This state fragment
+  // defines the standard state properties from the 'base' package as defined
+  // by GCD specification.
+  bool LoadBaseStateDefinition(const base::FilePath& json_file_path,
+                               chromeos::ErrorPtr* error);
+
+  // Loads state default values from JSON object.
+  bool LoadStateDefaults(const base::DictionaryValue& json,
+                         chromeos::ErrorPtr* error);
+
+  // Loads state default values from JSON file.
+  bool LoadStateDefaults(const base::FilePath& json_file_path,
+                         chromeos::ErrorPtr* error);
+
+  // Finds a package by its name. Returns nullptr if not found.
+  StatePackage* FindPackage(const std::string& package_name);
+  // Finds a package by its name. If none exists, one will be created.
+  StatePackage* FindOrCreatePackage(const std::string& package_name);
+
+  std::map<std::string, std::unique_ptr<StatePackage>> packages_;
+  std::set<std::string> categories_;
+
+  friend class StateManagerTest;
+  DISALLOW_COPY_AND_ASSIGN(StateManager);
+};
+
+}  // namespace buffet
+
+#endif  // BUFFET_STATES_STATE_MANAGER_H_