Snap for 15110852 from c58ca616ec15ef60ac5e51802b8fb4f3b40874e6 to 26Q2-release Change-Id: Ic89d3e83d86e77dd92869590c4c6e00540986572
diff --git a/common/prefs.cc b/common/prefs.cc index 3d69238..fe163f7 100644 --- a/common/prefs.cc +++ b/common/prefs.cc
@@ -199,13 +199,17 @@ LOG(ERROR) << "prefs directory does not exist: " << source_directory; return false; } - // Copy the directory. std::error_code e; - std::filesystem::copy(source_directory, destination_directory, e); + std::filesystem::copy(source_directory, + destination_directory, + std::filesystem::copy_options::recursive, + e); if (e) { LOG(ERROR) << "failed to copy prefs to prefs_tmp: " << e.message(); + DeleteTemporaryPrefs(); return false; } + utils::FsyncDirectoryContents(destination_directory.c_str()); return true; }
diff --git a/common/prefs_unittest.cc b/common/prefs_unittest.cc index f0d620f..1cdccf0 100644 --- a/common/prefs_unittest.cc +++ b/common/prefs_unittest.cc
@@ -581,6 +581,79 @@ prefs_.RemoveObserver(kInvalidKey, &mock_obserser); } +TEST_F(PrefsTest, TransactionAcidTest) { + const char kKey1[] = "key1"; + const char kKey2[] = "key2"; + const char kValue1[] = "value1"; + const char kValue2[] = "value2"; + const char kNewValue1[] = "new-value1"; + + // Initial state + ASSERT_TRUE(prefs_.SetString(kKey1, kValue1)); + ASSERT_TRUE(prefs_.SetString(kKey2, kValue2)); + + // Start transaction + ASSERT_TRUE(prefs_.StartTransaction()); + + // Modify key1 in transaction + ASSERT_TRUE(prefs_.SetString(kKey1, kNewValue1)); + + // Verify Isolation: The original directory should remain UNCHANGED until commit. + string val; + ASSERT_TRUE(base::ReadFileToString(prefs_dir_.Append(kKey1), &val)); + ASSERT_EQ(kValue1, val); + + // Unmodified key2 should also be preserved in the original directory. + ASSERT_TRUE(base::ReadFileToString(prefs_dir_.Append(kKey2), &val)); + ASSERT_EQ(kValue2, val); + + // Current prefs object should see the new value (it reads from the transaction state). + ASSERT_TRUE(prefs_.GetString(kKey1, &val)); + ASSERT_EQ(kNewValue1, val); + + // Submit transaction (Atomicity & Durability) + ASSERT_TRUE(prefs_.SubmitTransaction()); + + // After submit, the main directory should have the new values. + ASSERT_TRUE(prefs_.GetString(kKey1, &val)); + ASSERT_EQ(kNewValue1, val); + ASSERT_TRUE(prefs_.GetString(kKey2, &val)); + ASSERT_EQ(kValue2, val); + + // Verify persistence with a fresh Prefs object + Prefs fresh_prefs; + ASSERT_TRUE(fresh_prefs.Init(prefs_dir_)); + ASSERT_TRUE(fresh_prefs.GetString(kKey1, &val)); + ASSERT_EQ(kNewValue1, val); +} + +TEST_F(PrefsTest, TransactionCancelAcidTest) { + const char kKey[] = "cancel-key"; + const char kOldValue[] = "old"; + const char kNewValue[] = "new"; + + ASSERT_TRUE(prefs_.SetString(kKey, kOldValue)); + ASSERT_TRUE(prefs_.StartTransaction()); + ASSERT_TRUE(prefs_.SetString(kKey, kNewValue)); + + // Should see new value in current context + string val; + ASSERT_TRUE(prefs_.GetString(kKey, &val)); + ASSERT_EQ(kNewValue, val); + + // Cancel transaction + ASSERT_TRUE(prefs_.CancelTransaction()); + + // Should be back to old value everywhere + ASSERT_TRUE(prefs_.GetString(kKey, &val)); + ASSERT_EQ(kOldValue, val); + + Prefs fresh_prefs; + ASSERT_TRUE(fresh_prefs.Init(prefs_dir_)); + ASSERT_TRUE(fresh_prefs.GetString(kKey, &val)); + ASSERT_EQ(kOldValue, val); +} + TEST_F(PrefsTest, MultiNamespaceKeyTest) { MultiNamespaceKeyTest(); }
diff --git a/payload_consumer/delta_performer.cc b/payload_consumer/delta_performer.cc index a6144f7..dab6b5d 100644 --- a/payload_consumer/delta_performer.cc +++ b/payload_consumer/delta_performer.cc
@@ -84,7 +84,6 @@ const uint64_t DeltaPerformer::kCheckpointFrequencySeconds = 1; namespace { -const int kUpdateStateOperationInvalid = -1; const int kMaxResumedUpdateFailures = 10; } // namespace
diff --git a/payload_consumer/delta_performer.h b/payload_consumer/delta_performer.h index 75f24d1..6a2c273 100644 --- a/payload_consumer/delta_performer.h +++ b/payload_consumer/delta_performer.h
@@ -62,6 +62,7 @@ static const unsigned kProgressDownloadWeight; static const unsigned kProgressOperationsWeight; static const uint64_t kCheckpointFrequencySeconds; + static constexpr int64_t kUpdateStateOperationInvalid = -1; DeltaPerformer( PrefsInterface* prefs,
diff --git a/payload_consumer/delta_performer_unittest.cc b/payload_consumer/delta_performer_unittest.cc index 40221bd..9b6ba4b 100644 --- a/payload_consumer/delta_performer_unittest.cc +++ b/payload_consumer/delta_performer_unittest.cc
@@ -1369,4 +1369,36 @@ performer_.VerifyPayload(payload_hash, payload_data.size())); } +TEST_F(DeltaPerformerTest, CanResumeUpdateRelaxedCheckTest) { + const std::string payload_id = "test-payload-id"; + const std::string wrong_payload_id = "wrong-payload-id"; + + // Set up mandatory prefs for resumption + ASSERT_TRUE(prefs_.SetInt64(kPrefsManifestMetadataSize, 100)); + ASSERT_TRUE(prefs_.SetInt64(kPrefsManifestSignatureSize, 50)); + ASSERT_TRUE(prefs_.SetInt64(kPrefsUpdateStateNextDataOffset, 0)); + ASSERT_TRUE(prefs_.SetString(kPrefsUpdateStateSHA256Context, "some-context")); + + // 1. next_operation = 0 (initial state), should SUCCEED now + ASSERT_TRUE(prefs_.SetInt64(kPrefsUpdateStateNextOperation, 1)); + ASSERT_TRUE(prefs_.SetString(kPrefsUpdateCheckResponseHash, payload_id)); + ASSERT_TRUE(DeltaPerformer::CanResumeUpdate(&prefs_, payload_id)); + + // 2. next_operation = 100, should SUCCEED + ASSERT_TRUE(prefs_.SetInt64(kPrefsUpdateStateNextOperation, 100)); + ASSERT_TRUE(DeltaPerformer::CanResumeUpdate(&prefs_, payload_id)); + + // 3. Hash mismatch, should FAIL + ASSERT_FALSE(DeltaPerformer::CanResumeUpdate(&prefs_, wrong_payload_id)); + + // 4. Empty hash in prefs, should FAIL + ASSERT_TRUE(prefs_.Delete(kPrefsUpdateCheckResponseHash)); + ASSERT_FALSE(DeltaPerformer::CanResumeUpdate(&prefs_, payload_id)); + + // 5. Missing mandatory metadata size, should FAIL + ASSERT_TRUE(prefs_.SetString(kPrefsUpdateCheckResponseHash, payload_id)); + ASSERT_TRUE(prefs_.Delete(kPrefsManifestMetadataSize)); + ASSERT_FALSE(DeltaPerformer::CanResumeUpdate(&prefs_, payload_id)); +} + } // namespace chromeos_update_engine