update_engine: Don't do force updates after rollback.
If the device was rolled back via enterprise policy since the
last update check where policy was present, we shouldn't do a
forced update, because this could lead to an infinite
rollback-update loop.
This is achieved by adding a new pref 'rollback-happened' to
'powerwash_safe_prefs'. This creates a file at '/mnt/
stateful_partition/unencrypted/preserve/update_engine/prefs/
rollback-happened', which is not deleted during powerwash
(crrev.com/c/1005180). If this file exists after powerwash and
its content is 'true', it means the device was rolled back, and
forced updates must not be applied before the device is enrolled
and policy is available again.
When an update check happens and policy is available or device
becomes a consumer device, the file is deleted.
BUG=chromium:831266
TEST='cros_run_unit_tests --board=cyan --packages update_engine'
Change-Id: I0a06696701530c93d4ed388c42e43b65fe78f777
Reviewed-on: https://chromium-review.googlesource.com/1005181
Commit-Ready: Marton Hunyady <hunyadym@chromium.org>
Tested-by: Marton Hunyady <hunyadym@chromium.org>
Reviewed-by: Amin Hassani <ahassani@chromium.org>
diff --git a/update_attempter_unittest.cc b/update_attempter_unittest.cc
index dd61fa5..9dfc008 100644
--- a/update_attempter_unittest.cc
+++ b/update_attempter_unittest.cc
@@ -29,6 +29,7 @@
#include <gtest/gtest.h>
#include <policy/libpolicy.h>
#include <policy/mock_device_policy.h>
+#include <policy/mock_libpolicy.h>
#include "update_engine/common/fake_clock.h"
#include "update_engine/common/fake_prefs.h"
@@ -64,6 +65,7 @@
using testing::Property;
using testing::Return;
using testing::ReturnPointee;
+using testing::ReturnRef;
using testing::SaveArg;
using testing::SetArgPointee;
using update_engine::UpdateAttemptFlags;
@@ -166,6 +168,9 @@
void P2PEnabledInteractiveStart();
void P2PEnabledStartingFailsStart();
void P2PEnabledHousekeepingFailsStart();
+ void ResetRollbackHappenedStart(bool is_consumer,
+ bool is_policy_available,
+ bool expected_reset);
bool actual_using_p2p_for_downloading() {
return actual_using_p2p_for_downloading_;
@@ -1140,4 +1145,56 @@
attempter_.GetCurrentUpdateAttemptFlags());
}
+void UpdateAttempterTest::ResetRollbackHappenedStart(bool is_consumer,
+ bool is_policy_loaded,
+ bool expected_reset) {
+ EXPECT_CALL(*fake_system_state_.mock_payload_state(), GetRollbackHappened())
+ .WillRepeatedly(Return(true));
+ auto mock_policy_provider =
+ std::make_unique<NiceMock<policy::MockPolicyProvider>>();
+ EXPECT_CALL(*mock_policy_provider, IsConsumerDevice())
+ .WillRepeatedly(Return(is_consumer));
+ EXPECT_CALL(*mock_policy_provider, device_policy_is_loaded())
+ .WillRepeatedly(Return(is_policy_loaded));
+ const policy::MockDevicePolicy device_policy;
+ EXPECT_CALL(*mock_policy_provider, GetDevicePolicy())
+ .WillRepeatedly(ReturnRef(device_policy));
+ EXPECT_CALL(*fake_system_state_.mock_payload_state(),
+ SetRollbackHappened(false))
+ .Times(expected_reset ? 1 : 0);
+ attempter_.policy_provider_ = std::move(mock_policy_provider);
+ attempter_.Update("", "", "", "", false, /*interactive=*/true);
+ ScheduleQuitMainLoop();
+}
+
+TEST_F(UpdateAttempterTest, ResetRollbackHappenedOobe) {
+ loop_.PostTask(FROM_HERE,
+ base::Bind(&UpdateAttempterTest::ResetRollbackHappenedStart,
+ base::Unretained(this),
+ /*is_consumer=*/false,
+ /*is_policy_loaded=*/false,
+ /*expected_reset=*/false));
+ loop_.Run();
+}
+
+TEST_F(UpdateAttempterTest, ResetRollbackHappenedConsumer) {
+ loop_.PostTask(FROM_HERE,
+ base::Bind(&UpdateAttempterTest::ResetRollbackHappenedStart,
+ base::Unretained(this),
+ /*is_consumer=*/true,
+ /*is_policy_loaded=*/false,
+ /*expected_reset=*/true));
+ loop_.Run();
+}
+
+TEST_F(UpdateAttempterTest, ResetRollbackHappenedEnterprise) {
+ loop_.PostTask(FROM_HERE,
+ base::Bind(&UpdateAttempterTest::ResetRollbackHappenedStart,
+ base::Unretained(this),
+ /*is_consumer=*/false,
+ /*is_policy_loaded=*/true,
+ /*expected_reset=*/true));
+ loop_.Run();
+}
+
} // namespace chromeos_update_engine