1 // Copyright (C) 2018 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include <libsnapshot/snapshot.h>
16
17 #include <fcntl.h>
18 #include <sys/file.h>
19 #include <sys/stat.h>
20 #include <sys/types.h>
21
22 #include <chrono>
23 #include <deque>
24 #include <future>
25 #include <iostream>
26
27 #include <android-base/file.h>
28 #include <android-base/logging.h>
29 #include <android-base/properties.h>
30 #include <android-base/strings.h>
31 #include <android-base/unique_fd.h>
32 #include <fs_mgr/roots.h>
33 #include <fs_mgr_dm_linear.h>
34 #include <gtest/gtest.h>
35 #include <libdm/dm.h>
36 #include <libfiemap/image_manager.h>
37 #include <liblp/builder.h>
38 #include <storage_literals/storage_literals.h>
39
40 #include <android/snapshot/snapshot.pb.h>
41 #include <libsnapshot/test_helpers.h>
42 #include "utility.h"
43
44 namespace android {
45 namespace snapshot {
46
47 using android::base::unique_fd;
48 using android::dm::DeviceMapper;
49 using android::dm::DmDeviceState;
50 using android::fiemap::FiemapStatus;
51 using android::fiemap::IImageManager;
52 using android::fs_mgr::BlockDeviceInfo;
53 using android::fs_mgr::CreateLogicalPartitionParams;
54 using android::fs_mgr::DestroyLogicalPartition;
55 using android::fs_mgr::EnsurePathMounted;
56 using android::fs_mgr::EnsurePathUnmounted;
57 using android::fs_mgr::Extent;
58 using android::fs_mgr::Fstab;
59 using android::fs_mgr::GetPartitionGroupName;
60 using android::fs_mgr::GetPartitionName;
61 using android::fs_mgr::Interval;
62 using android::fs_mgr::MetadataBuilder;
63 using android::fs_mgr::SlotSuffixForSlotNumber;
64 using chromeos_update_engine::DeltaArchiveManifest;
65 using chromeos_update_engine::DynamicPartitionGroup;
66 using chromeos_update_engine::PartitionUpdate;
67 using namespace ::testing;
68 using namespace android::storage_literals;
69 using namespace std::chrono_literals;
70 using namespace std::string_literals;
71
72 // Global states. See test_helpers.h.
73 std::unique_ptr<SnapshotManager> sm;
74 TestDeviceInfo* test_device = nullptr;
75 std::string fake_super;
76
77 void MountMetadata();
78
79 class SnapshotTest : public ::testing::Test {
80 public:
SnapshotTest()81 SnapshotTest() : dm_(DeviceMapper::Instance()) {}
82
83 // This is exposed for main.
Cleanup()84 void Cleanup() {
85 InitializeState();
86 CleanupTestArtifacts();
87 }
88
89 protected:
SetUp()90 void SetUp() override {
91 SKIP_IF_NON_VIRTUAL_AB();
92
93 SnapshotTestPropertyFetcher::SetUp();
94 InitializeState();
95 CleanupTestArtifacts();
96 FormatFakeSuper();
97 MountMetadata();
98 ASSERT_TRUE(sm->BeginUpdate());
99 }
100
TearDown()101 void TearDown() override {
102 RETURN_IF_NON_VIRTUAL_AB();
103
104 lock_ = nullptr;
105
106 CleanupTestArtifacts();
107 SnapshotTestPropertyFetcher::TearDown();
108 }
109
InitializeState()110 void InitializeState() {
111 ASSERT_TRUE(sm->EnsureImageManager());
112 image_manager_ = sm->image_manager();
113
114 test_device->set_slot_suffix("_a");
115 }
116
CleanupTestArtifacts()117 void CleanupTestArtifacts() {
118 // Normally cancelling inside a merge is not allowed. Since these
119 // are tests, we don't care, destroy everything that might exist.
120 // Note we hardcode this list because of an annoying quirk: when
121 // completing a merge, the snapshot stops existing, so we can't
122 // get an accurate list to remove.
123 lock_ = nullptr;
124
125 std::vector<std::string> snapshots = {"test-snapshot", "test_partition_a",
126 "test_partition_b"};
127 for (const auto& snapshot : snapshots) {
128 ASSERT_TRUE(DeleteSnapshotDevice(snapshot));
129 DeleteBackingImage(image_manager_, snapshot + "-cow-img");
130
131 auto status_file = sm->GetSnapshotStatusFilePath(snapshot);
132 android::base::RemoveFileIfExists(status_file);
133 }
134
135 // Remove stale partitions in fake super.
136 std::vector<std::string> partitions = {
137 "base-device",
138 "test_partition_b",
139 "test_partition_b-base",
140 };
141 for (const auto& partition : partitions) {
142 DeleteDevice(partition);
143 }
144
145 if (sm->GetUpdateState() != UpdateState::None) {
146 auto state_file = sm->GetStateFilePath();
147 unlink(state_file.c_str());
148 }
149 }
150
AcquireLock()151 bool AcquireLock() {
152 lock_ = sm->LockExclusive();
153 return !!lock_;
154 }
155
156 // This is so main() can instantiate this to invoke Cleanup.
TestBody()157 virtual void TestBody() override {}
158
FormatFakeSuper()159 void FormatFakeSuper() {
160 BlockDeviceInfo super_device("super", kSuperSize, 0, 0, 4096);
161 std::vector<BlockDeviceInfo> devices = {super_device};
162
163 auto builder = MetadataBuilder::New(devices, "super", 65536, 2);
164 ASSERT_NE(builder, nullptr);
165
166 auto metadata = builder->Export();
167 ASSERT_NE(metadata, nullptr);
168
169 TestPartitionOpener opener(fake_super);
170 ASSERT_TRUE(FlashPartitionTable(opener, fake_super, *metadata.get()));
171 }
172
173 // If |path| is non-null, the partition will be mapped after creation.
CreatePartition(const std::string & name,uint64_t size,std::string * path=nullptr)174 bool CreatePartition(const std::string& name, uint64_t size, std::string* path = nullptr) {
175 TestPartitionOpener opener(fake_super);
176 auto builder = MetadataBuilder::New(opener, "super", 0);
177 if (!builder) return false;
178
179 auto partition = builder->AddPartition(name, 0);
180 if (!partition) return false;
181 if (!builder->ResizePartition(partition, size)) {
182 return false;
183 }
184
185 // Update the source slot.
186 auto metadata = builder->Export();
187 if (!metadata) return false;
188 if (!UpdatePartitionTable(opener, "super", *metadata.get(), 0)) {
189 return false;
190 }
191
192 if (!path) return true;
193
194 CreateLogicalPartitionParams params = {
195 .block_device = fake_super,
196 .metadata = metadata.get(),
197 .partition_name = name,
198 .force_writable = true,
199 .timeout_ms = 10s,
200 };
201 return CreateLogicalPartition(params, path);
202 }
203
MapUpdatePartitions()204 bool MapUpdatePartitions() {
205 TestPartitionOpener opener(fake_super);
206 auto builder = MetadataBuilder::NewForUpdate(opener, "super", 0, 1);
207 if (!builder) return false;
208
209 auto metadata = builder->Export();
210 if (!metadata) return false;
211
212 // Update the destination slot, mark it as updated.
213 if (!UpdatePartitionTable(opener, "super", *metadata.get(), 1)) {
214 return false;
215 }
216
217 for (const auto& partition : metadata->partitions) {
218 CreateLogicalPartitionParams params = {
219 .block_device = fake_super,
220 .metadata = metadata.get(),
221 .partition = &partition,
222 .force_writable = true,
223 .timeout_ms = 10s,
224 .device_name = GetPartitionName(partition) + "-base",
225 };
226 std::string ignore_path;
227 if (!CreateLogicalPartition(params, &ignore_path)) {
228 return false;
229 }
230 }
231 return true;
232 }
233
DeleteSnapshotDevice(const std::string & snapshot)234 AssertionResult DeleteSnapshotDevice(const std::string& snapshot) {
235 AssertionResult res = AssertionSuccess();
236 if (!(res = DeleteDevice(snapshot))) return res;
237 if (!(res = DeleteDevice(snapshot + "-inner"))) return res;
238 if (!(res = DeleteDevice(snapshot + "-cow"))) return res;
239 if (!image_manager_->UnmapImageIfExists(snapshot + "-cow-img")) {
240 return AssertionFailure() << "Cannot unmap image " << snapshot << "-cow-img";
241 }
242 if (!(res = DeleteDevice(snapshot + "-base"))) return res;
243 return AssertionSuccess();
244 }
245
DeleteDevice(const std::string & device)246 AssertionResult DeleteDevice(const std::string& device) {
247 if (!dm_.DeleteDeviceIfExists(device)) {
248 return AssertionFailure() << "Can't delete " << device;
249 }
250 return AssertionSuccess();
251 }
252
CreateCowImage(const std::string & name)253 AssertionResult CreateCowImage(const std::string& name) {
254 if (!sm->CreateCowImage(lock_.get(), name)) {
255 return AssertionFailure() << "Cannot create COW image " << name;
256 }
257 std::string cow_device;
258 auto map_res = MapCowImage(name, 10s, &cow_device);
259 if (!map_res) {
260 return map_res;
261 }
262 if (!InitializeCow(cow_device)) {
263 return AssertionFailure() << "Cannot zero fill " << cow_device;
264 }
265 if (!sm->UnmapCowImage(name)) {
266 return AssertionFailure() << "Cannot unmap " << name << " after zero filling it";
267 }
268 return AssertionSuccess();
269 }
270
MapCowImage(const std::string & name,const std::chrono::milliseconds & timeout_ms,std::string * path)271 AssertionResult MapCowImage(const std::string& name,
272 const std::chrono::milliseconds& timeout_ms, std::string* path) {
273 auto cow_image_path = sm->MapCowImage(name, timeout_ms);
274 if (!cow_image_path.has_value()) {
275 return AssertionFailure() << "Cannot map cow image " << name;
276 }
277 *path = *cow_image_path;
278 return AssertionSuccess();
279 }
280
281 // Prepare A/B slot for a partition named "test_partition".
PrepareOneSnapshot(uint64_t device_size,std::string * out_snap_device=nullptr)282 AssertionResult PrepareOneSnapshot(uint64_t device_size,
283 std::string* out_snap_device = nullptr) {
284 std::string base_device, cow_device, snap_device;
285 if (!CreatePartition("test_partition_a", device_size)) {
286 return AssertionFailure();
287 }
288 if (!MapUpdatePartitions()) {
289 return AssertionFailure();
290 }
291 if (!dm_.GetDmDevicePathByName("test_partition_b-base", &base_device)) {
292 return AssertionFailure();
293 }
294 SnapshotStatus status;
295 status.set_name("test_partition_b");
296 status.set_device_size(device_size);
297 status.set_snapshot_size(device_size);
298 status.set_cow_file_size(device_size);
299 if (!sm->CreateSnapshot(lock_.get(), &status)) {
300 return AssertionFailure();
301 }
302 if (!CreateCowImage("test_partition_b")) {
303 return AssertionFailure();
304 }
305 if (!MapCowImage("test_partition_b", 10s, &cow_device)) {
306 return AssertionFailure();
307 }
308 if (!sm->MapSnapshot(lock_.get(), "test_partition_b", base_device, cow_device, 10s,
309 &snap_device)) {
310 return AssertionFailure();
311 }
312 if (out_snap_device) {
313 *out_snap_device = std::move(snap_device);
314 }
315 return AssertionSuccess();
316 }
317
318 // Simulate a reboot into the new slot.
SimulateReboot()319 AssertionResult SimulateReboot() {
320 lock_ = nullptr;
321 if (!sm->FinishedSnapshotWrites(false)) {
322 return AssertionFailure();
323 }
324 if (!dm_.DeleteDevice("test_partition_b")) {
325 return AssertionFailure();
326 }
327 if (!DestroyLogicalPartition("test_partition_b-base")) {
328 return AssertionFailure();
329 }
330 if (!sm->UnmapCowImage("test_partition_b")) {
331 return AssertionFailure();
332 }
333 return AssertionSuccess();
334 }
335
336 static constexpr std::chrono::milliseconds snapshot_timeout_ = 5s;
337 DeviceMapper& dm_;
338 std::unique_ptr<SnapshotManager::LockedFile> lock_;
339 android::fiemap::IImageManager* image_manager_ = nullptr;
340 std::string fake_super_;
341 };
342
TEST_F(SnapshotTest,CreateSnapshot)343 TEST_F(SnapshotTest, CreateSnapshot) {
344 ASSERT_TRUE(AcquireLock());
345
346 static const uint64_t kDeviceSize = 1024 * 1024;
347 SnapshotStatus status;
348 status.set_name("test-snapshot");
349 status.set_device_size(kDeviceSize);
350 status.set_snapshot_size(kDeviceSize);
351 status.set_cow_file_size(kDeviceSize);
352 ASSERT_TRUE(sm->CreateSnapshot(lock_.get(), &status));
353 ASSERT_TRUE(CreateCowImage("test-snapshot"));
354
355 std::vector<std::string> snapshots;
356 ASSERT_TRUE(sm->ListSnapshots(lock_.get(), &snapshots));
357 ASSERT_EQ(snapshots.size(), 1);
358 ASSERT_EQ(snapshots[0], "test-snapshot");
359
360 // Scope so delete can re-acquire the snapshot file lock.
361 {
362 SnapshotStatus status;
363 ASSERT_TRUE(sm->ReadSnapshotStatus(lock_.get(), "test-snapshot", &status));
364 ASSERT_EQ(status.state(), SnapshotState::CREATED);
365 ASSERT_EQ(status.device_size(), kDeviceSize);
366 ASSERT_EQ(status.snapshot_size(), kDeviceSize);
367 }
368
369 ASSERT_TRUE(sm->UnmapSnapshot(lock_.get(), "test-snapshot"));
370 ASSERT_TRUE(sm->UnmapCowImage("test-snapshot"));
371 ASSERT_TRUE(sm->DeleteSnapshot(lock_.get(), "test-snapshot"));
372 }
373
TEST_F(SnapshotTest,MapSnapshot)374 TEST_F(SnapshotTest, MapSnapshot) {
375 ASSERT_TRUE(AcquireLock());
376
377 static const uint64_t kDeviceSize = 1024 * 1024;
378 SnapshotStatus status;
379 status.set_name("test-snapshot");
380 status.set_device_size(kDeviceSize);
381 status.set_snapshot_size(kDeviceSize);
382 status.set_cow_file_size(kDeviceSize);
383 ASSERT_TRUE(sm->CreateSnapshot(lock_.get(), &status));
384 ASSERT_TRUE(CreateCowImage("test-snapshot"));
385
386 std::string base_device;
387 ASSERT_TRUE(CreatePartition("base-device", kDeviceSize, &base_device));
388
389 std::string cow_device;
390 ASSERT_TRUE(MapCowImage("test-snapshot", 10s, &cow_device));
391
392 std::string snap_device;
393 ASSERT_TRUE(sm->MapSnapshot(lock_.get(), "test-snapshot", base_device, cow_device, 10s,
394 &snap_device));
395 ASSERT_TRUE(android::base::StartsWith(snap_device, "/dev/block/dm-"));
396 }
397
TEST_F(SnapshotTest,MapPartialSnapshot)398 TEST_F(SnapshotTest, MapPartialSnapshot) {
399 ASSERT_TRUE(AcquireLock());
400
401 static const uint64_t kSnapshotSize = 1024 * 1024;
402 static const uint64_t kDeviceSize = 1024 * 1024 * 2;
403 SnapshotStatus status;
404 status.set_name("test-snapshot");
405 status.set_device_size(kDeviceSize);
406 status.set_snapshot_size(kSnapshotSize);
407 status.set_cow_file_size(kSnapshotSize);
408 ASSERT_TRUE(sm->CreateSnapshot(lock_.get(), &status));
409 ASSERT_TRUE(CreateCowImage("test-snapshot"));
410
411 std::string base_device;
412 ASSERT_TRUE(CreatePartition("base-device", kDeviceSize, &base_device));
413
414 std::string cow_device;
415 ASSERT_TRUE(MapCowImage("test-snapshot", 10s, &cow_device));
416
417 std::string snap_device;
418 ASSERT_TRUE(sm->MapSnapshot(lock_.get(), "test-snapshot", base_device, cow_device, 10s,
419 &snap_device));
420 ASSERT_TRUE(android::base::StartsWith(snap_device, "/dev/block/dm-"));
421 }
422
TEST_F(SnapshotTest,NoMergeBeforeReboot)423 TEST_F(SnapshotTest, NoMergeBeforeReboot) {
424 ASSERT_TRUE(sm->FinishedSnapshotWrites(false));
425
426 // Merge should fail, since the slot hasn't changed.
427 ASSERT_FALSE(sm->InitiateMerge());
428 }
429
TEST_F(SnapshotTest,CleanFirstStageMount)430 TEST_F(SnapshotTest, CleanFirstStageMount) {
431 // If there's no update in progress, there should be no first-stage mount
432 // needed.
433 TestDeviceInfo* info = new TestDeviceInfo(fake_super);
434 auto sm = SnapshotManager::NewForFirstStageMount(info);
435 ASSERT_NE(sm, nullptr);
436 ASSERT_FALSE(sm->NeedSnapshotsInFirstStageMount());
437 }
438
TEST_F(SnapshotTest,FirstStageMountAfterRollback)439 TEST_F(SnapshotTest, FirstStageMountAfterRollback) {
440 ASSERT_TRUE(sm->FinishedSnapshotWrites(false));
441
442 // We didn't change the slot, so we shouldn't need snapshots.
443 TestDeviceInfo* info = new TestDeviceInfo(fake_super);
444 auto sm = SnapshotManager::NewForFirstStageMount(info);
445 ASSERT_NE(sm, nullptr);
446 ASSERT_FALSE(sm->NeedSnapshotsInFirstStageMount());
447
448 auto indicator = sm->GetRollbackIndicatorPath();
449 ASSERT_EQ(access(indicator.c_str(), R_OK), 0);
450 }
451
TEST_F(SnapshotTest,Merge)452 TEST_F(SnapshotTest, Merge) {
453 ASSERT_TRUE(AcquireLock());
454
455 static const uint64_t kDeviceSize = 1024 * 1024;
456 std::string snap_device;
457 ASSERT_TRUE(PrepareOneSnapshot(kDeviceSize, &snap_device));
458
459 std::string test_string = "This is a test string.";
460 {
461 unique_fd fd(open(snap_device.c_str(), O_RDWR | O_CLOEXEC | O_SYNC));
462 ASSERT_GE(fd, 0);
463 ASSERT_TRUE(android::base::WriteFully(fd, test_string.data(), test_string.size()));
464 }
465
466 // Note: we know there is no inner/outer dm device since we didn't request
467 // a linear segment.
468 DeviceMapper::TargetInfo target;
469 ASSERT_TRUE(sm->IsSnapshotDevice("test_partition_b", &target));
470 ASSERT_EQ(DeviceMapper::GetTargetType(target.spec), "snapshot");
471
472 // Release the lock.
473 lock_ = nullptr;
474
475 // Done updating.
476 ASSERT_TRUE(sm->FinishedSnapshotWrites(false));
477
478 test_device->set_slot_suffix("_b");
479 ASSERT_TRUE(sm->InitiateMerge());
480
481 // The device should have been switched to a snapshot-merge target.
482 ASSERT_TRUE(sm->IsSnapshotDevice("test_partition_b", &target));
483 ASSERT_EQ(DeviceMapper::GetTargetType(target.spec), "snapshot-merge");
484
485 // We should not be able to cancel an update now.
486 ASSERT_FALSE(sm->CancelUpdate());
487
488 ASSERT_EQ(sm->ProcessUpdateState(), UpdateState::MergeCompleted);
489 ASSERT_EQ(sm->GetUpdateState(), UpdateState::None);
490
491 // The device should no longer be a snapshot or snapshot-merge.
492 ASSERT_FALSE(sm->IsSnapshotDevice("test_partition_b"));
493
494 // Test that we can read back the string we wrote to the snapshot. Note
495 // that the base device is gone now. |snap_device| contains the correct
496 // partition.
497 unique_fd fd(open(snap_device.c_str(), O_RDONLY | O_CLOEXEC));
498 ASSERT_GE(fd, 0);
499
500 std::string buffer(test_string.size(), '\0');
501 ASSERT_TRUE(android::base::ReadFully(fd, buffer.data(), buffer.size()));
502 ASSERT_EQ(test_string, buffer);
503 }
504
TEST_F(SnapshotTest,FirstStageMountAndMerge)505 TEST_F(SnapshotTest, FirstStageMountAndMerge) {
506 ASSERT_TRUE(AcquireLock());
507
508 static const uint64_t kDeviceSize = 1024 * 1024;
509 ASSERT_TRUE(PrepareOneSnapshot(kDeviceSize));
510 ASSERT_TRUE(SimulateReboot());
511
512 auto init = SnapshotManager::NewForFirstStageMount(new TestDeviceInfo(fake_super, "_b"));
513 ASSERT_NE(init, nullptr);
514 ASSERT_TRUE(init->NeedSnapshotsInFirstStageMount());
515 ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
516
517 ASSERT_TRUE(AcquireLock());
518
519 // Validate that we have a snapshot device.
520 SnapshotStatus status;
521 ASSERT_TRUE(init->ReadSnapshotStatus(lock_.get(), "test_partition_b", &status));
522 ASSERT_EQ(status.state(), SnapshotState::CREATED);
523
524 DeviceMapper::TargetInfo target;
525 auto dm_name = init->GetSnapshotDeviceName("test_partition_b", status);
526 ASSERT_TRUE(init->IsSnapshotDevice(dm_name, &target));
527 ASSERT_EQ(DeviceMapper::GetTargetType(target.spec), "snapshot");
528 }
529
TEST_F(SnapshotTest,FlashSuperDuringUpdate)530 TEST_F(SnapshotTest, FlashSuperDuringUpdate) {
531 ASSERT_TRUE(AcquireLock());
532
533 static const uint64_t kDeviceSize = 1024 * 1024;
534 ASSERT_TRUE(PrepareOneSnapshot(kDeviceSize));
535 ASSERT_TRUE(SimulateReboot());
536
537 // Reflash the super partition.
538 FormatFakeSuper();
539 ASSERT_TRUE(CreatePartition("test_partition_b", kDeviceSize));
540
541 auto init = SnapshotManager::NewForFirstStageMount(new TestDeviceInfo(fake_super, "_b"));
542 ASSERT_NE(init, nullptr);
543 ASSERT_TRUE(init->NeedSnapshotsInFirstStageMount());
544 ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
545
546 ASSERT_TRUE(AcquireLock());
547
548 SnapshotStatus status;
549 ASSERT_TRUE(init->ReadSnapshotStatus(lock_.get(), "test_partition_b", &status));
550
551 // We should not get a snapshot device now.
552 DeviceMapper::TargetInfo target;
553 auto dm_name = init->GetSnapshotDeviceName("test_partition_b", status);
554 ASSERT_FALSE(init->IsSnapshotDevice(dm_name, &target));
555
556 // We should see a cancelled update as well.
557 lock_ = nullptr;
558 ASSERT_EQ(sm->ProcessUpdateState(), UpdateState::Cancelled);
559 }
560
TEST_F(SnapshotTest,FlashSuperDuringMerge)561 TEST_F(SnapshotTest, FlashSuperDuringMerge) {
562 ASSERT_TRUE(AcquireLock());
563
564 static const uint64_t kDeviceSize = 1024 * 1024;
565 ASSERT_TRUE(PrepareOneSnapshot(kDeviceSize));
566 ASSERT_TRUE(SimulateReboot());
567
568 auto init = SnapshotManager::NewForFirstStageMount(new TestDeviceInfo(fake_super, "_b"));
569 ASSERT_NE(init, nullptr);
570 ASSERT_TRUE(init->NeedSnapshotsInFirstStageMount());
571 ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
572 ASSERT_TRUE(init->InitiateMerge());
573
574 // Now, reflash super. Note that we haven't called ProcessUpdateState, so the
575 // status is still Merging.
576 ASSERT_TRUE(DeleteSnapshotDevice("test_partition_b"));
577 ASSERT_TRUE(init->image_manager()->UnmapImageIfExists("test_partition_b-cow-img"));
578 FormatFakeSuper();
579 ASSERT_TRUE(CreatePartition("test_partition_b", kDeviceSize));
580 ASSERT_TRUE(init->NeedSnapshotsInFirstStageMount());
581 ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
582
583 // Because the status is Merging, we must call ProcessUpdateState, which should
584 // detect a cancelled update.
585 ASSERT_EQ(sm->ProcessUpdateState(), UpdateState::Cancelled);
586 ASSERT_EQ(sm->GetUpdateState(), UpdateState::None);
587 }
588
TEST_F(SnapshotTest,UpdateBootControlHal)589 TEST_F(SnapshotTest, UpdateBootControlHal) {
590 ASSERT_TRUE(AcquireLock());
591
592 ASSERT_TRUE(sm->WriteUpdateState(lock_.get(), UpdateState::None));
593 ASSERT_EQ(test_device->merge_status(), MergeStatus::NONE);
594
595 ASSERT_TRUE(sm->WriteUpdateState(lock_.get(), UpdateState::Initiated));
596 ASSERT_EQ(test_device->merge_status(), MergeStatus::NONE);
597
598 ASSERT_TRUE(sm->WriteUpdateState(lock_.get(), UpdateState::Unverified));
599 ASSERT_EQ(test_device->merge_status(), MergeStatus::SNAPSHOTTED);
600
601 ASSERT_TRUE(sm->WriteUpdateState(lock_.get(), UpdateState::Merging));
602 ASSERT_EQ(test_device->merge_status(), MergeStatus::MERGING);
603
604 ASSERT_TRUE(sm->WriteUpdateState(lock_.get(), UpdateState::MergeNeedsReboot));
605 ASSERT_EQ(test_device->merge_status(), MergeStatus::NONE);
606
607 ASSERT_TRUE(sm->WriteUpdateState(lock_.get(), UpdateState::MergeCompleted));
608 ASSERT_EQ(test_device->merge_status(), MergeStatus::NONE);
609
610 ASSERT_TRUE(sm->WriteUpdateState(lock_.get(), UpdateState::MergeFailed));
611 ASSERT_EQ(test_device->merge_status(), MergeStatus::MERGING);
612 }
613
614 enum class Request { UNKNOWN, LOCK_SHARED, LOCK_EXCLUSIVE, UNLOCK, EXIT };
operator <<(std::ostream & os,Request request)615 std::ostream& operator<<(std::ostream& os, Request request) {
616 switch (request) {
617 case Request::LOCK_SHARED:
618 return os << "Shared";
619 case Request::LOCK_EXCLUSIVE:
620 return os << "Exclusive";
621 case Request::UNLOCK:
622 return os << "Unlock";
623 case Request::EXIT:
624 return os << "Exit";
625 case Request::UNKNOWN:
626 [[fallthrough]];
627 default:
628 return os << "Unknown";
629 }
630 }
631
632 class LockTestConsumer {
633 public:
MakeRequest(Request new_request)634 AssertionResult MakeRequest(Request new_request) {
635 {
636 std::unique_lock<std::mutex> ulock(mutex_);
637 requests_.push_back(new_request);
638 }
639 cv_.notify_all();
640 return AssertionSuccess() << "Request " << new_request << " successful";
641 }
642
643 template <typename R, typename P>
WaitFulfill(std::chrono::duration<R,P> timeout)644 AssertionResult WaitFulfill(std::chrono::duration<R, P> timeout) {
645 std::unique_lock<std::mutex> ulock(mutex_);
646 if (cv_.wait_for(ulock, timeout, [this] { return requests_.empty(); })) {
647 return AssertionSuccess() << "All requests_ fulfilled.";
648 }
649 return AssertionFailure() << "Timeout waiting for fulfilling " << requests_.size()
650 << " request(s), first one is "
651 << (requests_.empty() ? Request::UNKNOWN : requests_.front());
652 }
653
StartHandleRequestsInBackground()654 void StartHandleRequestsInBackground() {
655 future_ = std::async(std::launch::async, &LockTestConsumer::HandleRequests, this);
656 }
657
658 private:
HandleRequests()659 void HandleRequests() {
660 static constexpr auto consumer_timeout = 3s;
661
662 auto next_request = Request::UNKNOWN;
663 do {
664 // Peek next request.
665 {
666 std::unique_lock<std::mutex> ulock(mutex_);
667 if (cv_.wait_for(ulock, consumer_timeout, [this] { return !requests_.empty(); })) {
668 next_request = requests_.front();
669 } else {
670 next_request = Request::EXIT;
671 }
672 }
673
674 // Handle next request.
675 switch (next_request) {
676 case Request::LOCK_SHARED: {
677 lock_ = sm->LockShared();
678 } break;
679 case Request::LOCK_EXCLUSIVE: {
680 lock_ = sm->LockExclusive();
681 } break;
682 case Request::EXIT:
683 [[fallthrough]];
684 case Request::UNLOCK: {
685 lock_.reset();
686 } break;
687 case Request::UNKNOWN:
688 [[fallthrough]];
689 default:
690 break;
691 }
692
693 // Pop next request. This thread is the only thread that
694 // pops from the front of the requests_ deque.
695 {
696 std::unique_lock<std::mutex> ulock(mutex_);
697 if (next_request == Request::EXIT) {
698 requests_.clear();
699 } else {
700 requests_.pop_front();
701 }
702 }
703 cv_.notify_all();
704 } while (next_request != Request::EXIT);
705 }
706
707 std::mutex mutex_;
708 std::condition_variable cv_;
709 std::deque<Request> requests_;
710 std::unique_ptr<SnapshotManager::LockedFile> lock_;
711 std::future<void> future_;
712 };
713
714 class LockTest : public ::testing::Test {
715 public:
SetUp()716 void SetUp() {
717 SKIP_IF_NON_VIRTUAL_AB();
718 first_consumer.StartHandleRequestsInBackground();
719 second_consumer.StartHandleRequestsInBackground();
720 }
721
TearDown()722 void TearDown() {
723 RETURN_IF_NON_VIRTUAL_AB();
724 EXPECT_TRUE(first_consumer.MakeRequest(Request::EXIT));
725 EXPECT_TRUE(second_consumer.MakeRequest(Request::EXIT));
726 }
727
728 static constexpr auto request_timeout = 500ms;
729 LockTestConsumer first_consumer;
730 LockTestConsumer second_consumer;
731 };
732
TEST_F(LockTest,SharedShared)733 TEST_F(LockTest, SharedShared) {
734 ASSERT_TRUE(first_consumer.MakeRequest(Request::LOCK_SHARED));
735 ASSERT_TRUE(first_consumer.WaitFulfill(request_timeout));
736 ASSERT_TRUE(second_consumer.MakeRequest(Request::LOCK_SHARED));
737 ASSERT_TRUE(second_consumer.WaitFulfill(request_timeout));
738 }
739
740 using LockTestParam = std::pair<Request, Request>;
741 class LockTestP : public LockTest, public ::testing::WithParamInterface<LockTestParam> {};
TEST_P(LockTestP,Test)742 TEST_P(LockTestP, Test) {
743 ASSERT_TRUE(first_consumer.MakeRequest(GetParam().first));
744 ASSERT_TRUE(first_consumer.WaitFulfill(request_timeout));
745 ASSERT_TRUE(second_consumer.MakeRequest(GetParam().second));
746 ASSERT_FALSE(second_consumer.WaitFulfill(request_timeout))
747 << "Should not be able to " << GetParam().second << " while separate thread "
748 << GetParam().first;
749 ASSERT_TRUE(first_consumer.MakeRequest(Request::UNLOCK));
750 ASSERT_TRUE(second_consumer.WaitFulfill(request_timeout))
751 << "Should be able to hold lock that is released by separate thread";
752 }
753 INSTANTIATE_TEST_SUITE_P(
754 LockTest, LockTestP,
755 testing::Values(LockTestParam{Request::LOCK_EXCLUSIVE, Request::LOCK_EXCLUSIVE},
756 LockTestParam{Request::LOCK_EXCLUSIVE, Request::LOCK_SHARED},
757 LockTestParam{Request::LOCK_SHARED, Request::LOCK_EXCLUSIVE}),
__anonbc7b12b90302(const testing::TestParamInfo<LockTestP::ParamType>& info) 758 [](const testing::TestParamInfo<LockTestP::ParamType>& info) {
759 std::stringstream ss;
760 ss << info.param.first << info.param.second;
761 return ss.str();
762 });
763
764 class SnapshotUpdateTest : public SnapshotTest {
765 public:
SetUp()766 void SetUp() override {
767 SKIP_IF_NON_VIRTUAL_AB();
768
769 SnapshotTest::SetUp();
770 Cleanup();
771
772 // Cleanup() changes slot suffix, so initialize it again.
773 test_device->set_slot_suffix("_a");
774
775 opener_ = std::make_unique<TestPartitionOpener>(fake_super);
776
777 // Create a fake update package metadata.
778 // Not using full name "system", "vendor", "product" because these names collide with the
779 // mapped partitions on the running device.
780 // Each test modifies manifest_ slightly to indicate changes to the partition layout.
781 group_ = manifest_.mutable_dynamic_partition_metadata()->add_groups();
782 group_->set_name("group");
783 group_->set_size(kGroupSize);
784 group_->add_partition_names("sys");
785 group_->add_partition_names("vnd");
786 group_->add_partition_names("prd");
787 sys_ = manifest_.add_partitions();
788 sys_->set_partition_name("sys");
789 SetSize(sys_, 3_MiB);
790 vnd_ = manifest_.add_partitions();
791 vnd_->set_partition_name("vnd");
792 SetSize(vnd_, 3_MiB);
793 prd_ = manifest_.add_partitions();
794 prd_->set_partition_name("prd");
795 SetSize(prd_, 3_MiB);
796
797 // Initialize source partition metadata using |manifest_|.
798 src_ = MetadataBuilder::New(*opener_, "super", 0);
799 ASSERT_NE(src_, nullptr);
800 ASSERT_TRUE(FillFakeMetadata(src_.get(), manifest_, "_a"));
801 // Add sys_b which is like system_other.
802 ASSERT_TRUE(src_->AddGroup("group_b", kGroupSize));
803 auto partition = src_->AddPartition("sys_b", "group_b", 0);
804 ASSERT_NE(nullptr, partition);
805 ASSERT_TRUE(src_->ResizePartition(partition, 1_MiB));
806 auto metadata = src_->Export();
807 ASSERT_NE(nullptr, metadata);
808 ASSERT_TRUE(UpdatePartitionTable(*opener_, "super", *metadata.get(), 0));
809
810 // Map source partitions. Additionally, map sys_b to simulate system_other after flashing.
811 std::string path;
812 for (const auto& name : {"sys_a", "vnd_a", "prd_a", "sys_b"}) {
813 ASSERT_TRUE(CreateLogicalPartition(
814 CreateLogicalPartitionParams{
815 .block_device = fake_super,
816 .metadata_slot = 0,
817 .partition_name = name,
818 .timeout_ms = 1s,
819 .partition_opener = opener_.get(),
820 },
821 &path));
822 ASSERT_TRUE(WriteRandomData(path));
823 auto hash = GetHash(path);
824 ASSERT_TRUE(hash.has_value());
825 hashes_[name] = *hash;
826 }
827 }
TearDown()828 void TearDown() override {
829 RETURN_IF_NON_VIRTUAL_AB();
830
831 Cleanup();
832 SnapshotTest::TearDown();
833 }
Cleanup()834 void Cleanup() {
835 if (!image_manager_) {
836 InitializeState();
837 }
838 MountMetadata();
839 for (const auto& suffix : {"_a", "_b"}) {
840 test_device->set_slot_suffix(suffix);
841 EXPECT_TRUE(sm->CancelUpdate()) << suffix;
842 }
843 EXPECT_TRUE(UnmapAll());
844 }
845
IsPartitionUnchanged(const std::string & name)846 AssertionResult IsPartitionUnchanged(const std::string& name) {
847 std::string path;
848 if (!dm_.GetDmDevicePathByName(name, &path)) {
849 return AssertionFailure() << "Path of " << name << " cannot be determined";
850 }
851 auto hash = GetHash(path);
852 if (!hash.has_value()) {
853 return AssertionFailure() << "Cannot read partition " << name << ": " << path;
854 }
855 auto it = hashes_.find(name);
856 if (it == hashes_.end()) {
857 return AssertionFailure() << "No existing hash for " << name << ". Bad test code?";
858 }
859 if (it->second != *hash) {
860 return AssertionFailure() << "Content of " << name << " has changed";
861 }
862 return AssertionSuccess();
863 }
864
GetSnapshotSize(const std::string & name)865 std::optional<uint64_t> GetSnapshotSize(const std::string& name) {
866 if (!AcquireLock()) {
867 return std::nullopt;
868 }
869 auto local_lock = std::move(lock_);
870
871 SnapshotStatus status;
872 if (!sm->ReadSnapshotStatus(local_lock.get(), name, &status)) {
873 return std::nullopt;
874 }
875 return status.snapshot_size();
876 }
877
UnmapAll()878 AssertionResult UnmapAll() {
879 for (const auto& name : {"sys", "vnd", "prd"}) {
880 if (!dm_.DeleteDeviceIfExists(name + "_a"s)) {
881 return AssertionFailure() << "Cannot unmap " << name << "_a";
882 }
883 if (!DeleteSnapshotDevice(name + "_b"s)) {
884 return AssertionFailure() << "Cannot delete snapshot " << name << "_b";
885 }
886 }
887 return AssertionSuccess();
888 }
889
MapUpdateSnapshot(const std::string & name,std::string * path=nullptr)890 AssertionResult MapUpdateSnapshot(const std::string& name, std::string* path = nullptr) {
891 std::string real_path;
892 if (!sm->MapUpdateSnapshot(
893 CreateLogicalPartitionParams{
894 .block_device = fake_super,
895 .metadata_slot = 1,
896 .partition_name = name,
897 .timeout_ms = 10s,
898 .partition_opener = opener_.get(),
899 },
900 &real_path)) {
901 return AssertionFailure() << "Unable to map snapshot " << name;
902 }
903 if (path) {
904 *path = real_path;
905 }
906 return AssertionSuccess() << "Mapped snapshot " << name << " to " << real_path;
907 }
908
WriteSnapshotAndHash(const std::string & name,std::optional<size_t> size=std::nullopt)909 AssertionResult WriteSnapshotAndHash(const std::string& name,
910 std::optional<size_t> size = std::nullopt) {
911 std::string path;
912 auto res = MapUpdateSnapshot(name, &path);
913 if (!res) {
914 return res;
915 }
916
917 std::string size_string = size ? (std::to_string(*size) + " bytes") : "";
918
919 if (!WriteRandomData(path, size, &hashes_[name])) {
920 return AssertionFailure() << "Unable to write " << size_string << " to " << path
921 << " for partition " << name;
922 }
923
924 return AssertionSuccess() << "Written " << size_string << " to " << path
925 << " for snapshot partition " << name
926 << ", hash: " << hashes_[name];
927 }
928
MapUpdateSnapshots(const std::vector<std::string> & names={"sys_b", "vnd_b", "prd_b"})929 AssertionResult MapUpdateSnapshots(const std::vector<std::string>& names = {"sys_b", "vnd_b",
930 "prd_b"}) {
931 for (const auto& name : names) {
932 auto res = MapUpdateSnapshot(name);
933 if (!res) {
934 return res;
935 }
936 }
937 return AssertionSuccess();
938 }
939
940 // Create fake install operations to grow the COW device size.
AddOperation(PartitionUpdate * partition_update,uint64_t size_bytes=0)941 void AddOperation(PartitionUpdate* partition_update, uint64_t size_bytes = 0) {
942 auto e = partition_update->add_operations()->add_dst_extents();
943 e->set_start_block(0);
944 if (size_bytes == 0) {
945 size_bytes = GetSize(partition_update);
946 }
947 e->set_num_blocks(size_bytes / manifest_.block_size());
948 }
949
AddOperationForPartitions(std::vector<PartitionUpdate * > partitions={})950 void AddOperationForPartitions(std::vector<PartitionUpdate*> partitions = {}) {
951 if (partitions.empty()) {
952 partitions = {sys_, vnd_, prd_};
953 }
954 for (auto* partition : partitions) {
955 AddOperation(partition);
956 }
957 }
958
959 std::unique_ptr<TestPartitionOpener> opener_;
960 DeltaArchiveManifest manifest_;
961 std::unique_ptr<MetadataBuilder> src_;
962 std::map<std::string, std::string> hashes_;
963
964 PartitionUpdate* sys_ = nullptr;
965 PartitionUpdate* vnd_ = nullptr;
966 PartitionUpdate* prd_ = nullptr;
967 DynamicPartitionGroup* group_ = nullptr;
968 };
969
970 // Test full update flow executed by update_engine. Some partitions uses super empty space,
971 // some uses images, and some uses both.
972 // Also test UnmapUpdateSnapshot unmaps everything.
973 // Also test first stage mount and merge after this.
TEST_F(SnapshotUpdateTest,FullUpdateFlow)974 TEST_F(SnapshotUpdateTest, FullUpdateFlow) {
975 // OTA client blindly unmaps all partitions that are possibly mapped.
976 for (const auto& name : {"sys_b", "vnd_b", "prd_b"}) {
977 ASSERT_TRUE(sm->UnmapUpdateSnapshot(name));
978 }
979
980 // Grow all partitions.
981 constexpr uint64_t partition_size = 3788_KiB;
982 SetSize(sys_, partition_size);
983 SetSize(vnd_, partition_size);
984 SetSize(prd_, partition_size);
985
986 AddOperationForPartitions();
987
988 // Execute the update.
989 ASSERT_TRUE(sm->BeginUpdate());
990 ASSERT_TRUE(sm->CreateUpdateSnapshots(manifest_));
991
992 // Test that partitions prioritize using space in super.
993 auto tgt = MetadataBuilder::New(*opener_, "super", 1);
994 ASSERT_NE(tgt, nullptr);
995 ASSERT_NE(nullptr, tgt->FindPartition("sys_b-cow"));
996 ASSERT_NE(nullptr, tgt->FindPartition("vnd_b-cow"));
997 ASSERT_EQ(nullptr, tgt->FindPartition("prd_b-cow"));
998
999 // Write some data to target partitions.
1000 for (const auto& name : {"sys_b", "vnd_b", "prd_b"}) {
1001 ASSERT_TRUE(WriteSnapshotAndHash(name, partition_size));
1002 }
1003
1004 // Assert that source partitions aren't affected.
1005 for (const auto& name : {"sys_a", "vnd_a", "prd_a"}) {
1006 ASSERT_TRUE(IsPartitionUnchanged(name));
1007 }
1008
1009 ASSERT_TRUE(sm->FinishedSnapshotWrites(false));
1010
1011 // Simulate shutting down the device.
1012 ASSERT_TRUE(UnmapAll());
1013
1014 // After reboot, init does first stage mount.
1015 auto init = SnapshotManager::NewForFirstStageMount(new TestDeviceInfo(fake_super, "_b"));
1016 ASSERT_NE(init, nullptr);
1017 ASSERT_TRUE(init->NeedSnapshotsInFirstStageMount());
1018 ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
1019
1020 auto indicator = sm->GetRollbackIndicatorPath();
1021 ASSERT_NE(access(indicator.c_str(), R_OK), 0);
1022
1023 // Check that the target partitions have the same content.
1024 for (const auto& name : {"sys_b", "vnd_b", "prd_b"}) {
1025 ASSERT_TRUE(IsPartitionUnchanged(name));
1026 }
1027
1028 // Initiate the merge and wait for it to be completed.
1029 ASSERT_TRUE(init->InitiateMerge());
1030 ASSERT_EQ(UpdateState::MergeCompleted, init->ProcessUpdateState());
1031
1032 // Check that the target partitions have the same content after the merge.
1033 for (const auto& name : {"sys_b", "vnd_b", "prd_b"}) {
1034 ASSERT_TRUE(IsPartitionUnchanged(name))
1035 << "Content of " << name << " changes after the merge";
1036 }
1037 }
1038
1039 // Test that if new system partitions uses empty space in super, that region is not snapshotted.
TEST_F(SnapshotUpdateTest,DirectWriteEmptySpace)1040 TEST_F(SnapshotUpdateTest, DirectWriteEmptySpace) {
1041 GTEST_SKIP() << "b/141889746";
1042 SetSize(sys_, 4_MiB);
1043 // vnd_b and prd_b are unchanged.
1044 ASSERT_TRUE(sm->CreateUpdateSnapshots(manifest_));
1045 ASSERT_EQ(3_MiB, GetSnapshotSize("sys_b").value_or(0));
1046 }
1047
1048 // Test that if new system partitions uses space of old vendor partition, that region is
1049 // snapshotted.
TEST_F(SnapshotUpdateTest,SnapshotOldPartitions)1050 TEST_F(SnapshotUpdateTest, SnapshotOldPartitions) {
1051 SetSize(sys_, 4_MiB); // grows
1052 SetSize(vnd_, 2_MiB); // shrinks
1053 // prd_b is unchanged
1054 ASSERT_TRUE(sm->CreateUpdateSnapshots(manifest_));
1055 ASSERT_EQ(4_MiB, GetSnapshotSize("sys_b").value_or(0));
1056 }
1057
1058 // Test that even if there seem to be empty space in target metadata, COW partition won't take
1059 // it because they are used by old partitions.
TEST_F(SnapshotUpdateTest,CowPartitionDoNotTakeOldPartitions)1060 TEST_F(SnapshotUpdateTest, CowPartitionDoNotTakeOldPartitions) {
1061 SetSize(sys_, 2_MiB); // shrinks
1062 // vnd_b and prd_b are unchanged.
1063 ASSERT_TRUE(sm->CreateUpdateSnapshots(manifest_));
1064
1065 auto tgt = MetadataBuilder::New(*opener_, "super", 1);
1066 ASSERT_NE(nullptr, tgt);
1067 auto metadata = tgt->Export();
1068 ASSERT_NE(nullptr, metadata);
1069 std::vector<std::string> written;
1070 // Write random data to all COW partitions in super
1071 for (auto p : metadata->partitions) {
1072 if (GetPartitionGroupName(metadata->groups[p.group_index]) != kCowGroupName) {
1073 continue;
1074 }
1075 std::string path;
1076 ASSERT_TRUE(CreateLogicalPartition(
1077 CreateLogicalPartitionParams{
1078 .block_device = fake_super,
1079 .metadata = metadata.get(),
1080 .partition = &p,
1081 .timeout_ms = 1s,
1082 .partition_opener = opener_.get(),
1083 },
1084 &path));
1085 ASSERT_TRUE(WriteRandomData(path));
1086 written.push_back(GetPartitionName(p));
1087 }
1088 ASSERT_FALSE(written.empty())
1089 << "No COW partitions are created even if there are empty space in super partition";
1090
1091 // Make sure source partitions aren't affected.
1092 for (const auto& name : {"sys_a", "vnd_a", "prd_a"}) {
1093 ASSERT_TRUE(IsPartitionUnchanged(name));
1094 }
1095 }
1096
1097 // Test that it crashes after creating snapshot status file but before creating COW image, then
1098 // calling CreateUpdateSnapshots again works.
TEST_F(SnapshotUpdateTest,SnapshotStatusFileWithoutCow)1099 TEST_F(SnapshotUpdateTest, SnapshotStatusFileWithoutCow) {
1100 // Write some trash snapshot files to simulate leftovers from previous runs.
1101 {
1102 ASSERT_TRUE(AcquireLock());
1103 auto local_lock = std::move(lock_);
1104 SnapshotStatus status;
1105 status.set_name("sys_b");
1106 ASSERT_TRUE(sm->WriteSnapshotStatus(local_lock.get(), status));
1107 ASSERT_TRUE(image_manager_->CreateBackingImage("sys_b-cow-img", 1_MiB,
1108 IImageManager::CREATE_IMAGE_DEFAULT));
1109 }
1110
1111 // Redo the update.
1112 ASSERT_TRUE(sm->BeginUpdate());
1113 ASSERT_TRUE(sm->UnmapUpdateSnapshot("sys_b"));
1114
1115 ASSERT_TRUE(sm->CreateUpdateSnapshots(manifest_));
1116
1117 // Check that target partitions can be mapped.
1118 EXPECT_TRUE(MapUpdateSnapshots());
1119 }
1120
1121 // Test that the old partitions are not modified.
TEST_F(SnapshotUpdateTest,TestRollback)1122 TEST_F(SnapshotUpdateTest, TestRollback) {
1123 // Execute the update.
1124 ASSERT_TRUE(sm->BeginUpdate());
1125 ASSERT_TRUE(sm->UnmapUpdateSnapshot("sys_b"));
1126
1127 AddOperationForPartitions();
1128
1129 ASSERT_TRUE(sm->CreateUpdateSnapshots(manifest_));
1130
1131 // Write some data to target partitions.
1132 for (const auto& name : {"sys_b", "vnd_b", "prd_b"}) {
1133 ASSERT_TRUE(WriteSnapshotAndHash(name));
1134 }
1135
1136 // Assert that source partitions aren't affected.
1137 for (const auto& name : {"sys_a", "vnd_a", "prd_a"}) {
1138 ASSERT_TRUE(IsPartitionUnchanged(name));
1139 }
1140
1141 ASSERT_TRUE(sm->FinishedSnapshotWrites(false));
1142
1143 // Simulate shutting down the device.
1144 ASSERT_TRUE(UnmapAll());
1145
1146 // After reboot, init does first stage mount.
1147 auto init = SnapshotManager::NewForFirstStageMount(new TestDeviceInfo(fake_super, "_b"));
1148 ASSERT_NE(init, nullptr);
1149 ASSERT_TRUE(init->NeedSnapshotsInFirstStageMount());
1150 ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
1151
1152 // Check that the target partitions have the same content.
1153 for (const auto& name : {"sys_b", "vnd_b", "prd_b"}) {
1154 ASSERT_TRUE(IsPartitionUnchanged(name));
1155 }
1156
1157 // Simulate shutting down the device again.
1158 ASSERT_TRUE(UnmapAll());
1159 init = SnapshotManager::NewForFirstStageMount(new TestDeviceInfo(fake_super, "_a"));
1160 ASSERT_NE(init, nullptr);
1161 ASSERT_FALSE(init->NeedSnapshotsInFirstStageMount());
1162 ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
1163
1164 // Assert that the source partitions aren't affected.
1165 for (const auto& name : {"sys_a", "vnd_a", "prd_a"}) {
1166 ASSERT_TRUE(IsPartitionUnchanged(name));
1167 }
1168 }
1169
1170 // Test that if an update is applied but not booted into, it can be canceled.
TEST_F(SnapshotUpdateTest,CancelAfterApply)1171 TEST_F(SnapshotUpdateTest, CancelAfterApply) {
1172 ASSERT_TRUE(sm->BeginUpdate());
1173 ASSERT_TRUE(sm->FinishedSnapshotWrites(false));
1174 ASSERT_TRUE(sm->CancelUpdate());
1175 }
1176
ToIntervals(const std::vector<std::unique_ptr<Extent>> & extents)1177 static std::vector<Interval> ToIntervals(const std::vector<std::unique_ptr<Extent>>& extents) {
1178 std::vector<Interval> ret;
1179 std::transform(extents.begin(), extents.end(), std::back_inserter(ret),
1180 [](const auto& extent) { return extent->AsLinearExtent()->AsInterval(); });
1181 return ret;
1182 }
1183
1184 // Test that at the second update, old COW partition spaces are reclaimed.
TEST_F(SnapshotUpdateTest,ReclaimCow)1185 TEST_F(SnapshotUpdateTest, ReclaimCow) {
1186 // Execute the first update.
1187 ASSERT_TRUE(sm->BeginUpdate());
1188 ASSERT_TRUE(sm->CreateUpdateSnapshots(manifest_));
1189 ASSERT_TRUE(MapUpdateSnapshots());
1190 ASSERT_TRUE(sm->FinishedSnapshotWrites(false));
1191
1192 // Simulate shutting down the device.
1193 ASSERT_TRUE(UnmapAll());
1194
1195 // After reboot, init does first stage mount.
1196 auto init = SnapshotManager::NewForFirstStageMount(new TestDeviceInfo(fake_super, "_b"));
1197 ASSERT_NE(init, nullptr);
1198 ASSERT_TRUE(init->NeedSnapshotsInFirstStageMount());
1199 ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
1200 init = nullptr;
1201
1202 // Initiate the merge and wait for it to be completed.
1203 auto new_sm = SnapshotManager::New(new TestDeviceInfo(fake_super, "_b"));
1204 ASSERT_TRUE(new_sm->InitiateMerge());
1205 ASSERT_EQ(UpdateState::MergeCompleted, new_sm->ProcessUpdateState());
1206
1207 // Execute the second update.
1208 ASSERT_TRUE(new_sm->BeginUpdate());
1209 ASSERT_TRUE(new_sm->CreateUpdateSnapshots(manifest_));
1210
1211 // Check that the old COW space is reclaimed and does not occupy space of mapped partitions.
1212 auto src = MetadataBuilder::New(*opener_, "super", 1);
1213 ASSERT_NE(src, nullptr);
1214 auto tgt = MetadataBuilder::New(*opener_, "super", 0);
1215 ASSERT_NE(tgt, nullptr);
1216 for (const auto& cow_part_name : {"sys_a-cow", "vnd_a-cow", "prd_a-cow"}) {
1217 auto* cow_part = tgt->FindPartition(cow_part_name);
1218 ASSERT_NE(nullptr, cow_part) << cow_part_name << " does not exist in target metadata";
1219 auto cow_intervals = ToIntervals(cow_part->extents());
1220 for (const auto& old_part_name : {"sys_b", "vnd_b", "prd_b"}) {
1221 auto* old_part = src->FindPartition(old_part_name);
1222 ASSERT_NE(nullptr, old_part) << old_part_name << " does not exist in source metadata";
1223 auto old_intervals = ToIntervals(old_part->extents());
1224
1225 auto intersect = Interval::Intersect(cow_intervals, old_intervals);
1226 ASSERT_TRUE(intersect.empty()) << "COW uses space of source partitions";
1227 }
1228 }
1229 }
1230
TEST_F(SnapshotUpdateTest,RetrofitAfterRegularAb)1231 TEST_F(SnapshotUpdateTest, RetrofitAfterRegularAb) {
1232 constexpr auto kRetrofitGroupSize = kGroupSize / 2;
1233
1234 // Initialize device-mapper / disk
1235 ASSERT_TRUE(UnmapAll());
1236 FormatFakeSuper();
1237
1238 // Setup source partition metadata to have both _a and _b partitions.
1239 src_ = MetadataBuilder::New(*opener_, "super", 0);
1240 ASSERT_NE(nullptr, src_);
1241 for (const auto& suffix : {"_a"s, "_b"s}) {
1242 ASSERT_TRUE(src_->AddGroup(group_->name() + suffix, kRetrofitGroupSize));
1243 for (const auto& name : {"sys"s, "vnd"s, "prd"s}) {
1244 auto partition = src_->AddPartition(name + suffix, group_->name() + suffix, 0);
1245 ASSERT_NE(nullptr, partition);
1246 ASSERT_TRUE(src_->ResizePartition(partition, 2_MiB));
1247 }
1248 }
1249 auto metadata = src_->Export();
1250 ASSERT_NE(nullptr, metadata);
1251 ASSERT_TRUE(UpdatePartitionTable(*opener_, "super", *metadata.get(), 0));
1252
1253 // Flash source partitions
1254 std::string path;
1255 for (const auto& name : {"sys_a", "vnd_a", "prd_a"}) {
1256 ASSERT_TRUE(CreateLogicalPartition(
1257 CreateLogicalPartitionParams{
1258 .block_device = fake_super,
1259 .metadata_slot = 0,
1260 .partition_name = name,
1261 .timeout_ms = 1s,
1262 .partition_opener = opener_.get(),
1263 },
1264 &path));
1265 ASSERT_TRUE(WriteRandomData(path));
1266 auto hash = GetHash(path);
1267 ASSERT_TRUE(hash.has_value());
1268 hashes_[name] = *hash;
1269 }
1270
1271 // Setup manifest.
1272 group_->set_size(kRetrofitGroupSize);
1273 for (auto* partition : {sys_, vnd_, prd_}) {
1274 SetSize(partition, 2_MiB);
1275 }
1276 AddOperationForPartitions();
1277
1278 ASSERT_TRUE(sm->BeginUpdate());
1279 ASSERT_TRUE(sm->CreateUpdateSnapshots(manifest_));
1280
1281 // Test that COW image should not be created for retrofit devices; super
1282 // should be big enough.
1283 ASSERT_FALSE(image_manager_->BackingImageExists("sys_b-cow-img"));
1284 ASSERT_FALSE(image_manager_->BackingImageExists("vnd_b-cow-img"));
1285 ASSERT_FALSE(image_manager_->BackingImageExists("prd_b-cow-img"));
1286
1287 // Write some data to target partitions.
1288 for (const auto& name : {"sys_b", "vnd_b", "prd_b"}) {
1289 ASSERT_TRUE(WriteSnapshotAndHash(name));
1290 }
1291
1292 // Assert that source partitions aren't affected.
1293 for (const auto& name : {"sys_a", "vnd_a", "prd_a"}) {
1294 ASSERT_TRUE(IsPartitionUnchanged(name));
1295 }
1296
1297 ASSERT_TRUE(sm->FinishedSnapshotWrites(false));
1298 }
1299
TEST_F(SnapshotUpdateTest,MergeCannotRemoveCow)1300 TEST_F(SnapshotUpdateTest, MergeCannotRemoveCow) {
1301 // Make source partitions as big as possible to force COW image to be created.
1302 SetSize(sys_, 5_MiB);
1303 SetSize(vnd_, 5_MiB);
1304 SetSize(prd_, 5_MiB);
1305 src_ = MetadataBuilder::New(*opener_, "super", 0);
1306 ASSERT_NE(src_, nullptr);
1307 src_->RemoveGroupAndPartitions(group_->name() + "_a");
1308 src_->RemoveGroupAndPartitions(group_->name() + "_b");
1309 ASSERT_TRUE(FillFakeMetadata(src_.get(), manifest_, "_a"));
1310 auto metadata = src_->Export();
1311 ASSERT_NE(nullptr, metadata);
1312 ASSERT_TRUE(UpdatePartitionTable(*opener_, "super", *metadata.get(), 0));
1313
1314 // OTA client blindly unmaps all partitions that are possibly mapped.
1315 for (const auto& name : {"sys_b", "vnd_b", "prd_b"}) {
1316 ASSERT_TRUE(sm->UnmapUpdateSnapshot(name));
1317 }
1318
1319 // Add operations for sys. The whole device is written.
1320 AddOperation(sys_);
1321
1322 // Execute the update.
1323 ASSERT_TRUE(sm->BeginUpdate());
1324 ASSERT_TRUE(sm->CreateUpdateSnapshots(manifest_));
1325 ASSERT_TRUE(MapUpdateSnapshots());
1326 ASSERT_TRUE(sm->FinishedSnapshotWrites(false));
1327
1328 // Simulate shutting down the device.
1329 ASSERT_TRUE(UnmapAll());
1330
1331 // After reboot, init does first stage mount.
1332 // Normally we should use NewForFirstStageMount, but if so, "gsid.mapped_image.sys_b-cow-img"
1333 // won't be set.
1334 auto init = SnapshotManager::New(new TestDeviceInfo(fake_super, "_b"));
1335 ASSERT_NE(init, nullptr);
1336 ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
1337
1338 // Keep an open handle to the cow device. This should cause the merge to
1339 // be incomplete.
1340 auto cow_path = android::base::GetProperty("gsid.mapped_image.sys_b-cow-img", "");
1341 unique_fd fd(open(cow_path.c_str(), O_RDONLY | O_CLOEXEC));
1342 ASSERT_GE(fd, 0);
1343
1344 // COW cannot be removed due to open fd, so expect a soft failure.
1345 ASSERT_TRUE(init->InitiateMerge());
1346 ASSERT_EQ(UpdateState::MergeNeedsReboot, init->ProcessUpdateState());
1347
1348 // Simulate shutting down the device.
1349 fd.reset();
1350 ASSERT_TRUE(UnmapAll());
1351
1352 // init does first stage mount again.
1353 ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
1354
1355 // sys_b should be mapped as a dm-linear device directly.
1356 ASSERT_FALSE(sm->IsSnapshotDevice("sys_b", nullptr));
1357
1358 // Merge should be able to complete now.
1359 ASSERT_EQ(UpdateState::MergeCompleted, init->ProcessUpdateState());
1360 }
1361
1362 class MetadataMountedTest : public ::testing::Test {
1363 public:
1364 // This is so main() can instantiate this to invoke Cleanup.
TestBody()1365 virtual void TestBody() override {}
SetUp()1366 void SetUp() override {
1367 SKIP_IF_NON_VIRTUAL_AB();
1368 metadata_dir_ = test_device->GetMetadataDir();
1369 ASSERT_TRUE(ReadDefaultFstab(&fstab_));
1370 }
TearDown()1371 void TearDown() override {
1372 RETURN_IF_NON_VIRTUAL_AB();
1373 SetUp();
1374 // Remount /metadata
1375 test_device->set_recovery(false);
1376 EXPECT_TRUE(android::fs_mgr::EnsurePathMounted(&fstab_, metadata_dir_));
1377 }
IsMetadataMounted()1378 AssertionResult IsMetadataMounted() {
1379 Fstab mounted_fstab;
1380 if (!ReadFstabFromFile("/proc/mounts", &mounted_fstab)) {
1381 ADD_FAILURE() << "Failed to scan mounted volumes";
1382 return AssertionFailure() << "Failed to scan mounted volumes";
1383 }
1384
1385 auto entry = GetEntryForPath(&fstab_, metadata_dir_);
1386 if (entry == nullptr) {
1387 return AssertionFailure() << "No mount point found in fstab for path " << metadata_dir_;
1388 }
1389
1390 auto mv = GetEntryForMountPoint(&mounted_fstab, entry->mount_point);
1391 if (mv == nullptr) {
1392 return AssertionFailure() << metadata_dir_ << " is not mounted";
1393 }
1394 return AssertionSuccess() << metadata_dir_ << " is mounted";
1395 }
1396 std::string metadata_dir_;
1397 Fstab fstab_;
1398 };
1399
MountMetadata()1400 void MountMetadata() {
1401 MetadataMountedTest().TearDown();
1402 }
1403
TEST_F(MetadataMountedTest,Android)1404 TEST_F(MetadataMountedTest, Android) {
1405 auto device = sm->EnsureMetadataMounted();
1406 EXPECT_NE(nullptr, device);
1407 device.reset();
1408
1409 EXPECT_TRUE(IsMetadataMounted());
1410 EXPECT_TRUE(sm->CancelUpdate()) << "Metadata dir should never be unmounted in Android mode";
1411 }
1412
TEST_F(MetadataMountedTest,Recovery)1413 TEST_F(MetadataMountedTest, Recovery) {
1414 test_device->set_recovery(true);
1415 metadata_dir_ = test_device->GetMetadataDir();
1416
1417 EXPECT_TRUE(android::fs_mgr::EnsurePathUnmounted(&fstab_, metadata_dir_));
1418 EXPECT_FALSE(IsMetadataMounted());
1419
1420 auto device = sm->EnsureMetadataMounted();
1421 EXPECT_NE(nullptr, device);
1422 EXPECT_TRUE(IsMetadataMounted());
1423
1424 device.reset();
1425 EXPECT_FALSE(IsMetadataMounted());
1426 }
1427
1428 // Test that during a merge, we can wipe data in recovery.
TEST_F(SnapshotUpdateTest,MergeInRecovery)1429 TEST_F(SnapshotUpdateTest, MergeInRecovery) {
1430 // Execute the first update.
1431 ASSERT_TRUE(sm->BeginUpdate());
1432 ASSERT_TRUE(sm->CreateUpdateSnapshots(manifest_));
1433 ASSERT_TRUE(MapUpdateSnapshots());
1434 ASSERT_TRUE(sm->FinishedSnapshotWrites(false));
1435
1436 // Simulate shutting down the device.
1437 ASSERT_TRUE(UnmapAll());
1438
1439 // After reboot, init does first stage mount.
1440 auto init = SnapshotManager::NewForFirstStageMount(new TestDeviceInfo(fake_super, "_b"));
1441 ASSERT_NE(init, nullptr);
1442 ASSERT_TRUE(init->NeedSnapshotsInFirstStageMount());
1443 ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
1444 init = nullptr;
1445
1446 // Initiate the merge and then immediately stop it to simulate a reboot.
1447 auto new_sm = SnapshotManager::New(new TestDeviceInfo(fake_super, "_b"));
1448 ASSERT_TRUE(new_sm->InitiateMerge());
1449 ASSERT_TRUE(UnmapAll());
1450
1451 // Simulate a reboot into recovery.
1452 auto test_device = std::make_unique<TestDeviceInfo>(fake_super, "_b");
1453 test_device->set_recovery(true);
1454 new_sm = SnapshotManager::NewForFirstStageMount(test_device.release());
1455
1456 ASSERT_TRUE(new_sm->HandleImminentDataWipe());
1457 ASSERT_EQ(new_sm->GetUpdateState(), UpdateState::None);
1458 }
1459
1460 // Test that a merge does not clear the snapshot state in fastboot.
TEST_F(SnapshotUpdateTest,MergeInFastboot)1461 TEST_F(SnapshotUpdateTest, MergeInFastboot) {
1462 // Execute the first update.
1463 ASSERT_TRUE(sm->BeginUpdate());
1464 ASSERT_TRUE(sm->CreateUpdateSnapshots(manifest_));
1465 ASSERT_TRUE(MapUpdateSnapshots());
1466 ASSERT_TRUE(sm->FinishedSnapshotWrites(false));
1467
1468 // Simulate shutting down the device.
1469 ASSERT_TRUE(UnmapAll());
1470
1471 // After reboot, init does first stage mount.
1472 auto init = SnapshotManager::NewForFirstStageMount(new TestDeviceInfo(fake_super, "_b"));
1473 ASSERT_NE(init, nullptr);
1474 ASSERT_TRUE(init->NeedSnapshotsInFirstStageMount());
1475 ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
1476 init = nullptr;
1477
1478 // Initiate the merge and then immediately stop it to simulate a reboot.
1479 auto new_sm = SnapshotManager::New(new TestDeviceInfo(fake_super, "_b"));
1480 ASSERT_TRUE(new_sm->InitiateMerge());
1481 ASSERT_TRUE(UnmapAll());
1482
1483 // Simulate a reboot into recovery.
1484 auto test_device = std::make_unique<TestDeviceInfo>(fake_super, "_b");
1485 test_device->set_recovery(true);
1486 new_sm = SnapshotManager::NewForFirstStageMount(test_device.release());
1487
1488 ASSERT_TRUE(new_sm->FinishMergeInRecovery());
1489
1490 auto mount = new_sm->EnsureMetadataMounted();
1491 ASSERT_TRUE(mount && mount->HasDevice());
1492 ASSERT_EQ(new_sm->ProcessUpdateState(), UpdateState::MergeCompleted);
1493
1494 // Finish the merge in a normal boot.
1495 test_device = std::make_unique<TestDeviceInfo>(fake_super, "_b");
1496 init = SnapshotManager::NewForFirstStageMount(test_device.release());
1497 ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
1498 init = nullptr;
1499
1500 test_device = std::make_unique<TestDeviceInfo>(fake_super, "_b");
1501 new_sm = SnapshotManager::NewForFirstStageMount(test_device.release());
1502 ASSERT_EQ(new_sm->ProcessUpdateState(), UpdateState::MergeCompleted);
1503 ASSERT_EQ(new_sm->ProcessUpdateState(), UpdateState::None);
1504 }
1505
1506 // Test that after an OTA, before a merge, we can wipe data in recovery.
TEST_F(SnapshotUpdateTest,DataWipeRollbackInRecovery)1507 TEST_F(SnapshotUpdateTest, DataWipeRollbackInRecovery) {
1508 // Execute the first update.
1509 ASSERT_TRUE(sm->BeginUpdate());
1510 ASSERT_TRUE(sm->CreateUpdateSnapshots(manifest_));
1511 ASSERT_TRUE(MapUpdateSnapshots());
1512 ASSERT_TRUE(sm->FinishedSnapshotWrites(false));
1513
1514 // Simulate shutting down the device.
1515 ASSERT_TRUE(UnmapAll());
1516
1517 // Simulate a reboot into recovery.
1518 auto test_device = new TestDeviceInfo(fake_super, "_b");
1519 test_device->set_recovery(true);
1520 auto new_sm = SnapshotManager::NewForFirstStageMount(test_device);
1521
1522 ASSERT_TRUE(new_sm->HandleImminentDataWipe());
1523 // Manually mount metadata so that we can call GetUpdateState() below.
1524 MountMetadata();
1525 EXPECT_EQ(new_sm->GetUpdateState(), UpdateState::Unverified);
1526 EXPECT_TRUE(test_device->IsSlotUnbootable(1));
1527 EXPECT_FALSE(test_device->IsSlotUnbootable(0));
1528 }
1529
1530 // Test that after an OTA and a bootloader rollback with no merge, we can wipe
1531 // data in recovery.
TEST_F(SnapshotUpdateTest,DataWipeAfterRollback)1532 TEST_F(SnapshotUpdateTest, DataWipeAfterRollback) {
1533 // Execute the first update.
1534 ASSERT_TRUE(sm->BeginUpdate());
1535 ASSERT_TRUE(sm->CreateUpdateSnapshots(manifest_));
1536 ASSERT_TRUE(MapUpdateSnapshots());
1537 ASSERT_TRUE(sm->FinishedSnapshotWrites(false));
1538
1539 // Simulate shutting down the device.
1540 ASSERT_TRUE(UnmapAll());
1541
1542 // Simulate a rollback, with reboot into recovery.
1543 auto test_device = new TestDeviceInfo(fake_super, "_a");
1544 test_device->set_recovery(true);
1545 auto new_sm = SnapshotManager::NewForFirstStageMount(test_device);
1546
1547 ASSERT_TRUE(new_sm->HandleImminentDataWipe());
1548 EXPECT_EQ(new_sm->GetUpdateState(), UpdateState::None);
1549 EXPECT_FALSE(test_device->IsSlotUnbootable(0));
1550 EXPECT_FALSE(test_device->IsSlotUnbootable(1));
1551 }
1552
1553 // Test update package that requests data wipe.
TEST_F(SnapshotUpdateTest,DataWipeRequiredInPackage)1554 TEST_F(SnapshotUpdateTest, DataWipeRequiredInPackage) {
1555 AddOperationForPartitions();
1556 // Execute the update.
1557 ASSERT_TRUE(sm->BeginUpdate());
1558 ASSERT_TRUE(sm->CreateUpdateSnapshots(manifest_));
1559
1560 // Write some data to target partitions.
1561 for (const auto& name : {"sys_b", "vnd_b", "prd_b"}) {
1562 ASSERT_TRUE(WriteSnapshotAndHash(name)) << name;
1563 }
1564
1565 ASSERT_TRUE(sm->FinishedSnapshotWrites(true /* wipe */));
1566
1567 // Simulate shutting down the device.
1568 ASSERT_TRUE(UnmapAll());
1569
1570 // Simulate a reboot into recovery.
1571 auto test_device = new TestDeviceInfo(fake_super, "_b");
1572 test_device->set_recovery(true);
1573 auto new_sm = SnapshotManager::NewForFirstStageMount(test_device);
1574
1575 ASSERT_TRUE(new_sm->HandleImminentDataWipe());
1576 // Manually mount metadata so that we can call GetUpdateState() below.
1577 MountMetadata();
1578 EXPECT_EQ(new_sm->GetUpdateState(), UpdateState::None);
1579 ASSERT_FALSE(test_device->IsSlotUnbootable(1));
1580 ASSERT_FALSE(test_device->IsSlotUnbootable(0));
1581
1582 // Now reboot into new slot.
1583 test_device = new TestDeviceInfo(fake_super, "_b");
1584 auto init = SnapshotManager::NewForFirstStageMount(test_device);
1585 ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
1586 // Verify that we are on the downgraded build.
1587 for (const auto& name : {"sys_b", "vnd_b", "prd_b"}) {
1588 ASSERT_TRUE(IsPartitionUnchanged(name)) << name;
1589 }
1590 }
1591
TEST_F(SnapshotUpdateTest,Hashtree)1592 TEST_F(SnapshotUpdateTest, Hashtree) {
1593 constexpr auto partition_size = 4_MiB;
1594 constexpr auto data_size = 3_MiB;
1595 constexpr auto hashtree_size = 512_KiB;
1596 constexpr auto fec_size = partition_size - data_size - hashtree_size;
1597
1598 const auto block_size = manifest_.block_size();
1599 SetSize(sys_, partition_size);
1600 AddOperation(sys_, data_size);
1601
1602 // Set hastree extents.
1603 sys_->mutable_hash_tree_data_extent()->set_start_block(0);
1604 sys_->mutable_hash_tree_data_extent()->set_num_blocks(data_size / block_size);
1605
1606 sys_->mutable_hash_tree_extent()->set_start_block(data_size / block_size);
1607 sys_->mutable_hash_tree_extent()->set_num_blocks(hashtree_size / block_size);
1608
1609 // Set FEC extents.
1610 sys_->mutable_fec_data_extent()->set_start_block(0);
1611 sys_->mutable_fec_data_extent()->set_num_blocks((data_size + hashtree_size) / block_size);
1612
1613 sys_->mutable_fec_extent()->set_start_block((data_size + hashtree_size) / block_size);
1614 sys_->mutable_fec_extent()->set_num_blocks(fec_size / block_size);
1615
1616 ASSERT_TRUE(sm->BeginUpdate());
1617 ASSERT_TRUE(sm->CreateUpdateSnapshots(manifest_));
1618
1619 // Map and write some data to target partition.
1620 ASSERT_TRUE(MapUpdateSnapshots({"vnd_b", "prd_b"}));
1621 ASSERT_TRUE(WriteSnapshotAndHash("sys_b", partition_size));
1622
1623 // Finish update.
1624 ASSERT_TRUE(sm->FinishedSnapshotWrites(false));
1625
1626 // Simulate shutting down the device.
1627 ASSERT_TRUE(UnmapAll());
1628
1629 // After reboot, init does first stage mount.
1630 auto init = SnapshotManager::NewForFirstStageMount(new TestDeviceInfo(fake_super, "_b"));
1631 ASSERT_NE(init, nullptr);
1632 ASSERT_TRUE(init->NeedSnapshotsInFirstStageMount());
1633 ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
1634
1635 // Check that the target partition have the same content. Hashtree and FEC extents
1636 // should be accounted for.
1637 ASSERT_TRUE(IsPartitionUnchanged("sys_b"));
1638 }
1639
1640 // Test for overflow bit after update
TEST_F(SnapshotUpdateTest,Overflow)1641 TEST_F(SnapshotUpdateTest, Overflow) {
1642 const auto actual_write_size = GetSize(sys_);
1643 const auto declared_write_size = actual_write_size - 1_MiB;
1644
1645 AddOperation(sys_, declared_write_size);
1646
1647 // Execute the update.
1648 ASSERT_TRUE(sm->BeginUpdate());
1649 ASSERT_TRUE(sm->CreateUpdateSnapshots(manifest_));
1650
1651 // Map and write some data to target partitions.
1652 ASSERT_TRUE(MapUpdateSnapshots({"vnd_b", "prd_b"}));
1653 ASSERT_TRUE(WriteSnapshotAndHash("sys_b", actual_write_size));
1654
1655 std::vector<android::dm::DeviceMapper::TargetInfo> table;
1656 ASSERT_TRUE(DeviceMapper::Instance().GetTableStatus("sys_b", &table));
1657 ASSERT_EQ(1u, table.size());
1658 EXPECT_TRUE(table[0].IsOverflowSnapshot());
1659
1660 ASSERT_FALSE(sm->FinishedSnapshotWrites(false))
1661 << "FinishedSnapshotWrites should detect overflow of CoW device.";
1662 }
1663
TEST_F(SnapshotUpdateTest,LowSpace)1664 TEST_F(SnapshotUpdateTest, LowSpace) {
1665 static constexpr auto kMaxFree = 10_MiB;
1666 auto userdata = std::make_unique<LowSpaceUserdata>();
1667 ASSERT_TRUE(userdata->Init(kMaxFree));
1668
1669 // Grow all partitions to 5_MiB, total 15_MiB. This requires 15 MiB of CoW space. After
1670 // using the empty space in super (< 1 MiB), it uses at least 14 MiB of /userdata space.
1671 constexpr uint64_t partition_size = 5_MiB;
1672 SetSize(sys_, partition_size);
1673 SetSize(vnd_, partition_size);
1674 SetSize(prd_, partition_size);
1675
1676 AddOperationForPartitions();
1677
1678 // Execute the update.
1679 ASSERT_TRUE(sm->BeginUpdate());
1680 auto res = sm->CreateUpdateSnapshots(manifest_);
1681 ASSERT_FALSE(res);
1682 ASSERT_EQ(Return::ErrorCode::NO_SPACE, res.error_code());
1683 ASSERT_GE(res.required_size(), 14_MiB);
1684 ASSERT_LT(res.required_size(), 15_MiB);
1685 }
1686
1687 class FlashAfterUpdateTest : public SnapshotUpdateTest,
1688 public WithParamInterface<std::tuple<uint32_t, bool>> {
1689 public:
InitiateMerge(const std::string & slot_suffix)1690 AssertionResult InitiateMerge(const std::string& slot_suffix) {
1691 auto sm = SnapshotManager::New(new TestDeviceInfo(fake_super, slot_suffix));
1692 if (!sm->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_)) {
1693 return AssertionFailure() << "Cannot CreateLogicalAndSnapshotPartitions";
1694 }
1695 if (!sm->InitiateMerge()) {
1696 return AssertionFailure() << "Cannot initiate merge";
1697 }
1698 return AssertionSuccess();
1699 }
1700 };
1701
TEST_P(FlashAfterUpdateTest,FlashSlotAfterUpdate)1702 TEST_P(FlashAfterUpdateTest, FlashSlotAfterUpdate) {
1703 // OTA client blindly unmaps all partitions that are possibly mapped.
1704 for (const auto& name : {"sys_b", "vnd_b", "prd_b"}) {
1705 ASSERT_TRUE(sm->UnmapUpdateSnapshot(name));
1706 }
1707
1708 // Execute the update.
1709 ASSERT_TRUE(sm->BeginUpdate());
1710 ASSERT_TRUE(sm->CreateUpdateSnapshots(manifest_));
1711 ASSERT_TRUE(MapUpdateSnapshots());
1712 ASSERT_TRUE(sm->FinishedSnapshotWrites(false));
1713
1714 // Simulate shutting down the device.
1715 ASSERT_TRUE(UnmapAll());
1716
1717 bool after_merge = std::get<1>(GetParam());
1718 if (after_merge) {
1719 ASSERT_TRUE(InitiateMerge("_b"));
1720 // Simulate shutting down the device after merge has initiated.
1721 ASSERT_TRUE(UnmapAll());
1722 }
1723
1724 auto flashed_slot = std::get<0>(GetParam());
1725 auto flashed_slot_suffix = SlotSuffixForSlotNumber(flashed_slot);
1726
1727 // Simulate flashing |flashed_slot|. This clears the UPDATED flag.
1728 auto flashed_builder = MetadataBuilder::New(*opener_, "super", flashed_slot);
1729 ASSERT_NE(flashed_builder, nullptr);
1730 flashed_builder->RemoveGroupAndPartitions(group_->name() + flashed_slot_suffix);
1731 flashed_builder->RemoveGroupAndPartitions(kCowGroupName);
1732 ASSERT_TRUE(FillFakeMetadata(flashed_builder.get(), manifest_, flashed_slot_suffix));
1733
1734 // Deliberately remove a partition from this build so that
1735 // InitiateMerge do not switch state to "merging". This is possible in
1736 // practice because the list of dynamic partitions may change.
1737 ASSERT_NE(nullptr, flashed_builder->FindPartition("prd" + flashed_slot_suffix));
1738 flashed_builder->RemovePartition("prd" + flashed_slot_suffix);
1739
1740 // Note that fastbootd always updates the partition table of both slots.
1741 auto flashed_metadata = flashed_builder->Export();
1742 ASSERT_NE(nullptr, flashed_metadata);
1743 ASSERT_TRUE(UpdatePartitionTable(*opener_, "super", *flashed_metadata, 0));
1744 ASSERT_TRUE(UpdatePartitionTable(*opener_, "super", *flashed_metadata, 1));
1745
1746 std::string path;
1747 for (const auto& name : {"sys", "vnd"}) {
1748 ASSERT_TRUE(CreateLogicalPartition(
1749 CreateLogicalPartitionParams{
1750 .block_device = fake_super,
1751 .metadata_slot = flashed_slot,
1752 .partition_name = name + flashed_slot_suffix,
1753 .timeout_ms = 1s,
1754 .partition_opener = opener_.get(),
1755 },
1756 &path));
1757 ASSERT_TRUE(WriteRandomData(path));
1758 auto hash = GetHash(path);
1759 ASSERT_TRUE(hash.has_value());
1760 hashes_[name + flashed_slot_suffix] = *hash;
1761 }
1762
1763 // Simulate shutting down the device after flash.
1764 ASSERT_TRUE(UnmapAll());
1765
1766 // Simulate reboot. After reboot, init does first stage mount.
1767 auto init = SnapshotManager::NewForFirstStageMount(
1768 new TestDeviceInfo(fake_super, flashed_slot_suffix));
1769 ASSERT_NE(init, nullptr);
1770
1771 if (flashed_slot && after_merge) {
1772 ASSERT_TRUE(init->NeedSnapshotsInFirstStageMount());
1773 }
1774 ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
1775
1776 // Check that the target partitions have the same content.
1777 for (const auto& name : {"sys", "vnd"}) {
1778 ASSERT_TRUE(IsPartitionUnchanged(name + flashed_slot_suffix));
1779 }
1780
1781 // There should be no snapshot to merge.
1782 auto new_sm = SnapshotManager::New(new TestDeviceInfo(fake_super, flashed_slot_suffix));
1783 // update_enigne calls ProcessUpdateState first -- should see Cancelled.
1784 ASSERT_EQ(UpdateState::Cancelled, new_sm->ProcessUpdateState());
1785
1786 // Next OTA calls CancelUpdate no matter what.
1787 ASSERT_TRUE(new_sm->CancelUpdate());
1788 }
1789
1790 INSTANTIATE_TEST_SUITE_P(Snapshot, FlashAfterUpdateTest, Combine(Values(0, 1), Bool()),
__anonbc7b12b90502(const TestParamInfo<FlashAfterUpdateTest::ParamType>& info) 1791 [](const TestParamInfo<FlashAfterUpdateTest::ParamType>& info) {
1792 return "Flash"s + (std::get<0>(info.param) ? "New"s : "Old"s) +
1793 "Slot"s + (std::get<1>(info.param) ? "After"s : "Before"s) +
1794 "Merge"s;
1795 });
1796
1797 // Test behavior of ImageManager::Create on low space scenario. These tests assumes image manager
1798 // uses /data as backup device.
1799 class ImageManagerTest : public SnapshotTest, public WithParamInterface<uint64_t> {
1800 protected:
SetUp()1801 void SetUp() override {
1802 SKIP_IF_NON_VIRTUAL_AB();
1803 SnapshotTest::SetUp();
1804 userdata_ = std::make_unique<LowSpaceUserdata>();
1805 ASSERT_TRUE(userdata_->Init(GetParam()));
1806 }
TearDown()1807 void TearDown() override {
1808 RETURN_IF_NON_VIRTUAL_AB();
1809 return; // BUG(149738928)
1810
1811 EXPECT_TRUE(!image_manager_->BackingImageExists(kImageName) ||
1812 image_manager_->DeleteBackingImage(kImageName));
1813 }
1814 static constexpr const char* kImageName = "my_image";
1815 std::unique_ptr<LowSpaceUserdata> userdata_;
1816 };
1817
TEST_P(ImageManagerTest,CreateImageEnoughAvailSpace)1818 TEST_P(ImageManagerTest, CreateImageEnoughAvailSpace) {
1819 if (userdata_->available_space() == 0) {
1820 GTEST_SKIP() << "/data is full (" << userdata_->available_space()
1821 << " bytes available), skipping";
1822 }
1823 ASSERT_TRUE(image_manager_->CreateBackingImage(kImageName, userdata_->available_space(),
1824 IImageManager::CREATE_IMAGE_DEFAULT))
1825 << "Should be able to create image with size = " << userdata_->available_space()
1826 << " bytes";
1827 ASSERT_TRUE(image_manager_->DeleteBackingImage(kImageName))
1828 << "Should be able to delete created image";
1829 }
1830
TEST_P(ImageManagerTest,CreateImageNoSpace)1831 TEST_P(ImageManagerTest, CreateImageNoSpace) {
1832 uint64_t to_allocate = userdata_->free_space() + userdata_->bsize();
1833 auto res = image_manager_->CreateBackingImage(kImageName, to_allocate,
1834 IImageManager::CREATE_IMAGE_DEFAULT);
1835 ASSERT_FALSE(res) << "Should not be able to create image with size = " << to_allocate
1836 << " bytes because only " << userdata_->free_space() << " bytes are free";
1837 ASSERT_EQ(FiemapStatus::ErrorCode::NO_SPACE, res.error_code()) << res.string();
1838 }
1839
ImageManagerTestParams()1840 std::vector<uint64_t> ImageManagerTestParams() {
1841 std::vector<uint64_t> ret;
1842 for (uint64_t size = 1_MiB; size <= 512_MiB; size *= 2) {
1843 ret.push_back(size);
1844 }
1845 return ret;
1846 }
1847
1848 INSTANTIATE_TEST_SUITE_P(ImageManagerTest, ImageManagerTest, ValuesIn(ImageManagerTestParams()));
1849
Mkdir(const std::string & path)1850 bool Mkdir(const std::string& path) {
1851 if (mkdir(path.c_str(), 0700) && errno != EEXIST) {
1852 std::cerr << "Could not mkdir " << path << ": " << strerror(errno) << std::endl;
1853 return false;
1854 }
1855 return true;
1856 }
1857
1858 class SnapshotTestEnvironment : public ::testing::Environment {
1859 public:
~SnapshotTestEnvironment()1860 ~SnapshotTestEnvironment() override {}
1861 void SetUp() override;
1862 void TearDown() override;
1863
1864 private:
1865 std::unique_ptr<IImageManager> super_images_;
1866 };
1867
SetUp()1868 void SnapshotTestEnvironment::SetUp() {
1869 // b/163082876: GTEST_SKIP in Environment will make atest report incorrect results. Until
1870 // that is fixed, don't call GTEST_SKIP here, but instead call GTEST_SKIP in individual test
1871 // suites.
1872 RETURN_IF_NON_VIRTUAL_AB_MSG("Virtual A/B is not enabled, skipping global setup.\n");
1873
1874 std::vector<std::string> paths = {
1875 // clang-format off
1876 "/data/gsi/ota/test",
1877 "/data/gsi/ota/test/super",
1878 "/metadata/gsi/ota/test",
1879 "/metadata/gsi/ota/test/super",
1880 "/metadata/ota/test",
1881 "/metadata/ota/test/snapshots",
1882 // clang-format on
1883 };
1884 for (const auto& path : paths) {
1885 ASSERT_TRUE(Mkdir(path));
1886 }
1887
1888 // Create this once, otherwise, gsid will start/stop between each test.
1889 test_device = new TestDeviceInfo();
1890 sm = SnapshotManager::New(test_device);
1891 ASSERT_NE(nullptr, sm) << "Could not create snapshot manager";
1892
1893 // Clean up previous run.
1894 MetadataMountedTest().TearDown();
1895 SnapshotUpdateTest().Cleanup();
1896 SnapshotTest().Cleanup();
1897
1898 // Use a separate image manager for our fake super partition.
1899 super_images_ = IImageManager::Open("ota/test/super", 10s);
1900 ASSERT_NE(nullptr, super_images_) << "Could not create image manager";
1901
1902 // Clean up any old copy.
1903 DeleteBackingImage(super_images_.get(), "fake-super");
1904
1905 // Create and map the fake super partition.
1906 static constexpr int kImageFlags =
1907 IImageManager::CREATE_IMAGE_DEFAULT | IImageManager::CREATE_IMAGE_ZERO_FILL;
1908 ASSERT_TRUE(super_images_->CreateBackingImage("fake-super", kSuperSize, kImageFlags))
1909 << "Could not create fake super partition";
1910
1911 ASSERT_TRUE(super_images_->MapImageDevice("fake-super", 10s, &fake_super))
1912 << "Could not map fake super partition";
1913 test_device->set_fake_super(fake_super);
1914 }
1915
TearDown()1916 void SnapshotTestEnvironment::TearDown() {
1917 RETURN_IF_NON_VIRTUAL_AB();
1918 if (super_images_ != nullptr) {
1919 DeleteBackingImage(super_images_.get(), "fake-super");
1920 }
1921 }
1922
1923 } // namespace snapshot
1924 } // namespace android
1925
main(int argc,char ** argv)1926 int main(int argc, char** argv) {
1927 ::testing::InitGoogleTest(&argc, argv);
1928 ::testing::AddGlobalTestEnvironment(new ::android::snapshot::SnapshotTestEnvironment());
1929 return RUN_ALL_TESTS();
1930 }
1931