PolicyManager: New System provider.

The system provider exposes information about the device from
crossystem and the kernel boot command line options.

BUG=chromium:338587
TEST=Unit tests.

Change-Id: I2837a97740b63562155717cfe6a12fad69fd8cea
Reviewed-on: https://chromium-review.googlesource.com/191121
Reviewed-by: Alex Deymo <[email protected]>
Tested-by: Alex Deymo <[email protected]>
Commit-Queue: Alex Deymo <[email protected]>
diff --git a/policy_manager/fake_state.cc b/policy_manager/fake_state.cc
index 19df440..3dcec18 100644
--- a/policy_manager/fake_state.cc
+++ b/policy_manager/fake_state.cc
@@ -5,6 +5,7 @@
 #include "update_engine/policy_manager/fake_random_provider.h"
 #include "update_engine/policy_manager/fake_shill_provider.h"
 #include "update_engine/policy_manager/fake_state.h"
+#include "update_engine/policy_manager/fake_system_provider.h"
 #include "update_engine/policy_manager/fake_time_provider.h"
 
 namespace chromeos_policy_manager {
@@ -12,6 +13,7 @@
 FakeState::FakeState() {
   set_random_provider(new FakeRandomProvider());
   set_shill_provider(new FakeShillProvider());
+  set_system_provider(new FakeSystemProvider());
   set_time_provider(new FakeTimeProvider());
 }
 
diff --git a/policy_manager/fake_system_provider.h b/policy_manager/fake_system_provider.h
new file mode 100644
index 0000000..8e6b92a
--- /dev/null
+++ b/policy_manager/fake_system_provider.h
@@ -0,0 +1,33 @@
+// Copyright (c) 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 CHROMEOS_PLATFORM_UPDATE_ENGINE_POLICY_MANAGER_FAKE_SYSTEM_PROVIDER_H_
+#define CHROMEOS_PLATFORM_UPDATE_ENGINE_POLICY_MANAGER_FAKE_SYSTEM_PROVIDER_H_
+
+#include "update_engine/policy_manager/fake_variable.h"
+#include "update_engine/policy_manager/system_provider.h"
+
+namespace chromeos_policy_manager {
+
+// Fake implementation of the SystemProvider base class.
+class FakeSystemProvider : public SystemProvider {
+ public:
+  FakeSystemProvider() {}
+
+ protected:
+  virtual bool DoInit() {
+    set_var_is_normal_boot_mode(
+        new FakeVariable<bool>("is_normal_boot_mode", kVariableModeConst));
+    set_var_is_official_build(
+        new FakeVariable<bool>("is_official_build", kVariableModeConst));
+    return true;
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(FakeSystemProvider);
+};
+
+}  // namespace chromeos_policy_manager
+
+#endif  // CHROMEOS_PLATFORM_UPDATE_ENGINE_POLICY_MANAGER_FAKE_SYSTEM_PROVIDER_H_
diff --git a/policy_manager/generic_variables.h b/policy_manager/generic_variables.h
index f874b3b..2f9b996 100644
--- a/policy_manager/generic_variables.h
+++ b/policy_manager/generic_variables.h
@@ -59,6 +59,32 @@
   const T& ref_;
 };
 
+// Variable class returning a constant value that is cached on the variable when
+// it is created.
+template<typename T>
+class ConstCopyVariable : public Variable<T> {
+ public:
+  // Creates the variable returning copies of the passed |obj|. The value passed
+  // is copied in this variable, and new copies of it will be returned by
+  // GetValue().
+  ConstCopyVariable(const std::string& name, const T& obj)
+      : Variable<T>(name, kVariableModeConst), obj_(obj) {}
+
+ protected:
+  friend class PmConstCopyVariableTest;
+  FRIEND_TEST(PmConstCopyVariableTest, SimpleTest);
+
+  // Variable override.
+  virtual const T* GetValue(base::TimeDelta /* timeout */,
+                            std::string* /* errmsg */) {
+    return new T(obj_);
+  }
+
+ private:
+  // Value to be copied by GetValue().
+  const T obj_;
+};
+
 }  // namespace chromeos_policy_manager
 
 #endif  // CHROMEOS_PLATFORM_UPDATE_ENGINE_POLICY_MANAGER_GENERIC_VARIABLES_H_
diff --git a/policy_manager/generic_variables_unittest.cc b/policy_manager/generic_variables_unittest.cc
index 0e909f5..96de97e 100644
--- a/policy_manager/generic_variables_unittest.cc
+++ b/policy_manager/generic_variables_unittest.cc
@@ -2,10 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "update_engine/policy_manager/generic_variables.h"
+
 #include <base/memory/scoped_ptr.h>
 #include <gtest/gtest.h>
 
-#include "update_engine/policy_manager/generic_variables.h"
 #include "update_engine/policy_manager/pmtest_utils.h"
 
 using base::TimeDelta;
@@ -14,11 +15,7 @@
 
 class PmCopyVariableTest : public ::testing::Test {
  protected:
-  virtual void SetUp() {
-    default_timeout_ = TimeDelta::FromSeconds(1);
-  }
-
-  TimeDelta default_timeout_;
+  TimeDelta default_timeout_ = TimeDelta::FromSeconds(1);
 };
 
 
@@ -68,4 +65,24 @@
   EXPECT_TRUE(copy->copied_);
 }
 
+
+class PmConstCopyVariableTest : public ::testing::Test {
+ protected:
+  TimeDelta default_timeout_ = TimeDelta::FromSeconds(1);
+};
+
+TEST_F(PmConstCopyVariableTest, SimpleTest) {
+  int source = 5;
+  ConstCopyVariable<int> var("var", source);
+  scoped_ptr<const int> copy(var.GetValue(default_timeout_, NULL));
+  PMTEST_ASSERT_NOT_NULL(copy.get());
+  EXPECT_EQ(5, *copy);
+
+  // Ensure the value is cached.
+  source = 42;
+  copy.reset(var.GetValue(default_timeout_, NULL));
+  PMTEST_ASSERT_NOT_NULL(copy.get());
+  EXPECT_EQ(5, *copy);
+}
+
 }  // namespace chromeos_policy_manager
diff --git a/policy_manager/real_state.cc b/policy_manager/real_state.cc
index 2f9f3cc..8b0086f 100644
--- a/policy_manager/real_state.cc
+++ b/policy_manager/real_state.cc
@@ -12,9 +12,11 @@
 
 RealState::RealState(RandomProvider* random_provider,
                      ShillProvider* shill_provider,
+                     SystemProvider* system_provider,
                      TimeProvider* time_provider) {
   set_random_provider(random_provider);
   set_shill_provider(shill_provider);
+  set_system_provider(system_provider);
   set_time_provider(time_provider);
 }
 
diff --git a/policy_manager/real_state.h b/policy_manager/real_state.h
index c0f1ac6..b080c2d 100644
--- a/policy_manager/real_state.h
+++ b/policy_manager/real_state.h
@@ -5,9 +5,7 @@
 #ifndef CHROMEOS_PLATFORM_UPDATE_ENGINE_POLICY_MANAGER_REAL_STATE_H_
 #define CHROMEOS_PLATFORM_UPDATE_ENGINE_POLICY_MANAGER_REAL_STATE_H_
 
-#include "update_engine/clock.h"
 #include "update_engine/policy_manager/state.h"
-#include "update_engine/real_dbus_wrapper.h"
 
 namespace chromeos_policy_manager {
 
@@ -15,7 +13,9 @@
 class RealState : public State {
  public:
   // Instantiate with given providers, assuming ownership of them.
-  RealState(RandomProvider* random_provider, ShillProvider* shill_provider,
+  RealState(RandomProvider* random_provider,
+            ShillProvider* shill_provider,
+            SystemProvider* system_provider,
             TimeProvider* time_provider);
 
   ~RealState() {}
diff --git a/policy_manager/real_state_unittest.cc b/policy_manager/real_state_unittest.cc
index 0362688..792d4d8 100644
--- a/policy_manager/real_state_unittest.cc
+++ b/policy_manager/real_state_unittest.cc
@@ -2,18 +2,22 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "update_engine/policy_manager/real_state.h"
+
 #include <gtest/gtest.h>
 
 #include "update_engine/policy_manager/fake_random_provider.h"
 #include "update_engine/policy_manager/fake_shill_provider.h"
+#include "update_engine/policy_manager/fake_system_provider.h"
 #include "update_engine/policy_manager/fake_time_provider.h"
-#include "update_engine/policy_manager/real_state.h"
 #include "update_engine/policy_manager/pmtest_utils.h"
 
 namespace chromeos_policy_manager {
 
 TEST(PmRealStateTest, InitTest) {
-  RealState state(new FakeRandomProvider(), new FakeShillProvider(),
+  RealState state(new FakeRandomProvider(),
+                  new FakeShillProvider(),
+                  new FakeSystemProvider(),
                   new FakeTimeProvider());
   EXPECT_TRUE(state.Init());
 
@@ -24,6 +28,8 @@
   PMTEST_EXPECT_NOT_NULL(state.random_provider()->var_seed());
   PMTEST_ASSERT_NOT_NULL(state.shill_provider());
   PMTEST_EXPECT_NOT_NULL(state.shill_provider()->var_is_connected());
+  PMTEST_ASSERT_NOT_NULL(state.system_provider());
+  PMTEST_ASSERT_NOT_NULL(state.system_provider()->var_is_normal_boot_mode());
   PMTEST_ASSERT_NOT_NULL(state.time_provider());
   PMTEST_ASSERT_NOT_NULL(state.time_provider()->var_curr_date());
 }
diff --git a/policy_manager/real_system_provider.cc b/policy_manager/real_system_provider.cc
new file mode 100644
index 0000000..72669ff
--- /dev/null
+++ b/policy_manager/real_system_provider.cc
@@ -0,0 +1,33 @@
+// Copyright (c) 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 "update_engine/policy_manager/real_system_provider.h"
+
+#include <string>
+#include <vector>
+
+#include <base/logging.h>
+#include <vboot/crossystem.h>
+
+#include "update_engine/policy_manager/generic_variables.h"
+#include "update_engine/utils.h"
+
+using std::string;
+using std::vector;
+
+namespace chromeos_policy_manager {
+
+bool RealSystemProvider::DoInit() {
+  set_var_is_normal_boot_mode(
+      new ConstCopyVariable<bool>("is_normal_boot_mode",
+                                  VbGetSystemPropertyInt("devsw_boot") != 0));
+
+  set_var_is_official_build(
+      new ConstCopyVariable<bool>("var_is_official_build",
+                                  VbGetSystemPropertyInt("debug_build") == 0));
+
+  return true;
+}
+
+}  // namespace chromeos_policy_manager
diff --git a/policy_manager/real_system_provider.h b/policy_manager/real_system_provider.h
new file mode 100644
index 0000000..d5534cb
--- /dev/null
+++ b/policy_manager/real_system_provider.h
@@ -0,0 +1,27 @@
+// Copyright (c) 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 CHROMEOS_PLATFORM_UPDATE_ENGINE_POLICY_MANAGER_REAL_SYSTEM_PROVIDER_H_
+#define CHROMEOS_PLATFORM_UPDATE_ENGINE_POLICY_MANAGER_REAL_SYSTEM_PROVIDER_H_
+
+#include <string>
+
+#include "update_engine/policy_manager/system_provider.h"
+
+namespace chromeos_policy_manager {
+
+// SystemProvider concrete implementation.
+class RealSystemProvider : public SystemProvider {
+ public:
+  RealSystemProvider() {}
+
+ private:
+  virtual bool DoInit() override;
+
+  DISALLOW_COPY_AND_ASSIGN(RealSystemProvider);
+};
+
+}  // namespace chromeos_policy_manager
+
+#endif  // CHROMEOS_PLATFORM_UPDATE_ENGINE_POLICY_MANAGER_REAL_SYSTEM_PROVIDER_H_
diff --git a/policy_manager/real_system_provider_unittest.cc b/policy_manager/real_system_provider_unittest.cc
new file mode 100644
index 0000000..51406c3
--- /dev/null
+++ b/policy_manager/real_system_provider_unittest.cc
@@ -0,0 +1,28 @@
+// Copyright (c) 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 "update_engine/policy_manager/real_system_provider.h"
+
+#include <gtest/gtest.h>
+
+#include "update_engine/policy_manager/pmtest_utils.h"
+
+namespace chromeos_policy_manager {
+
+class PmRealSystemProviderTest : public ::testing::Test {
+ protected:
+  virtual void SetUp() {
+    provider_.reset(new RealSystemProvider());
+    EXPECT_TRUE(provider_->Init());
+  }
+
+  scoped_ptr<RealSystemProvider> provider_;
+};
+
+TEST_F(PmRealSystemProviderTest, InitTest) {
+  PMTEST_EXPECT_NOT_NULL(provider_->var_is_normal_boot_mode());
+  PMTEST_EXPECT_NOT_NULL(provider_->var_is_official_build());
+}
+
+}  // namespace chromeos_policy_manager
diff --git a/policy_manager/state.h b/policy_manager/state.h
index fb847a7..dd1e6af 100644
--- a/policy_manager/state.h
+++ b/policy_manager/state.h
@@ -7,6 +7,7 @@
 
 #include "update_engine/policy_manager/random_provider.h"
 #include "update_engine/policy_manager/shill_provider.h"
+#include "update_engine/policy_manager/system_provider.h"
 #include "update_engine/policy_manager/time_provider.h"
 
 namespace chromeos_policy_manager {
@@ -22,6 +23,7 @@
   bool Init() {
     return (random_provider_ && random_provider_->Init() &&
             shill_provider_ && shill_provider_->Init() &&
+            system_provider_ && system_provider_->Init() &&
             time_provider_ && time_provider_->Init());
   }
 
@@ -29,6 +31,7 @@
   RandomProvider* random_provider() { return random_provider_.get(); }
   ShillProvider* shill_provider() { return shill_provider_.get(); }
   TimeProvider* time_provider() { return time_provider_.get(); }
+  SystemProvider* system_provider() { return system_provider_.get(); }
 
  protected:
   // Initialize the private scoped_ptr for each provider.
@@ -40,6 +43,10 @@
     return shill_provider_.reset(shill_provider);
   }
 
+  void set_system_provider(SystemProvider* system_provider) {
+    return system_provider_.reset(system_provider);
+  }
+
   void set_time_provider(TimeProvider* time_provider) {
     return time_provider_.reset(time_provider);
   }
@@ -48,6 +55,7 @@
   // Instances of the providers.
   scoped_ptr<RandomProvider> random_provider_;
   scoped_ptr<ShillProvider> shill_provider_;
+  scoped_ptr<SystemProvider> system_provider_;
   scoped_ptr<TimeProvider> time_provider_;
 };
 
diff --git a/policy_manager/system_provider.h b/policy_manager/system_provider.h
new file mode 100644
index 0000000..b7f93c0
--- /dev/null
+++ b/policy_manager/system_provider.h
@@ -0,0 +1,51 @@
+// Copyright (c) 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 CHROMEOS_PLATFORM_UPDATE_ENGINE_POLICY_MANAGER_SYSTEM_PROVIDER_H_
+#define CHROMEOS_PLATFORM_UPDATE_ENGINE_POLICY_MANAGER_SYSTEM_PROVIDER_H_
+
+#include <base/memory/scoped_ptr.h>
+
+#include "update_engine/policy_manager/provider.h"
+#include "update_engine/policy_manager/variable.h"
+
+namespace chromeos_policy_manager {
+
+// Provider for system information, mostly constant, such as the information
+// reported by crossystem, the kernel boot command line and the partition table.
+class SystemProvider : public Provider {
+ public:
+  // Returns true if the boot mode is normal or if it's unable to
+  // determine the boot mode. Returns false if the boot mode is
+  // developer.
+  Variable<bool>* var_is_normal_boot_mode() const {
+    return var_is_normal_boot_mode_.get();
+  }
+
+  // Returns whether this is an official Chrome OS build.
+  Variable<bool>* var_is_official_build() const {
+    return var_is_official_build_.get();
+  }
+
+ protected:
+  SystemProvider() {}
+
+  void set_var_is_normal_boot_mode(Variable<bool>* var_is_normal_boot_mode) {
+    var_is_normal_boot_mode_.reset(var_is_normal_boot_mode);
+  }
+
+  void set_var_is_official_build(Variable<bool>* var_is_official_build) {
+    var_is_official_build_.reset(var_is_official_build);
+  }
+
+ private:
+  scoped_ptr<Variable<bool>> var_is_normal_boot_mode_;
+  scoped_ptr<Variable<bool>> var_is_official_build_;
+
+  DISALLOW_COPY_AND_ASSIGN(SystemProvider);
+};
+
+}  // namespace chromeos_policy_manager
+
+#endif  // CHROMEOS_PLATFORM_UPDATE_ENGINE_POLICY_MANAGER_SYSTEM_PROVIDER_H_