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/cow_format.h>
16 #include <libsnapshot/snapshot.h>
17
18 #include <fcntl.h>
19 #include <signal.h>
20 #include <sys/file.h>
21 #include <sys/stat.h>
22 #include <sys/statvfs.h>
23 #include <sys/types.h>
24
25 #include <chrono>
26 #include <deque>
27 #include <future>
28 #include <iostream>
29
30 #include <aidl/android/hardware/boot/MergeStatus.h>
31 #include <android-base/file.h>
32 #include <android-base/logging.h>
33 #include <android-base/properties.h>
34 #include <android-base/strings.h>
35 #include <android-base/unique_fd.h>
36 #include <fs_mgr/file_wait.h>
37 #include <fs_mgr/roots.h>
38 #include <fs_mgr_dm_linear.h>
39 #include <gflags/gflags.h>
40 #include <gtest/gtest.h>
41 #include <libdm/dm.h>
42 #include <libfiemap/image_manager.h>
43 #include <liblp/builder.h>
44 #include <openssl/sha.h>
45 #include <storage_literals/storage_literals.h>
46
47 #include <android/snapshot/snapshot.pb.h>
48 #include <libsnapshot/test_helpers.h>
49 #include "partition_cow_creator.h"
50 #include "utility.h"
51
52 // Mock classes are not used. Header included to ensure mocked class definition aligns with the
53 // class itself.
54 #include <libsnapshot/mock_device_info.h>
55 #include <libsnapshot/mock_snapshot.h>
56
57 #if defined(LIBSNAPSHOT_TEST_VAB_LEGACY)
58 #define DEFAULT_MODE "vab-legacy"
59 #else
60 #define DEFAULT_MODE ""
61 #endif
62
63 DEFINE_string(force_mode, DEFAULT_MODE,
64 "Force testing older modes (vab-legacy) ignoring device config.");
65 DEFINE_string(force_iouring_disable, "",
66 "Force testing mode (iouring_disabled) - disable io_uring");
67 DEFINE_string(compression_method, "gz", "Default compression algorithm.");
68
69 namespace android {
70 namespace snapshot {
71
72 using android::base::unique_fd;
73 using android::dm::DeviceMapper;
74 using android::dm::DmDeviceState;
75 using android::dm::IDeviceMapper;
76 using android::fiemap::FiemapStatus;
77 using android::fiemap::IImageManager;
78 using android::fs_mgr::BlockDeviceInfo;
79 using android::fs_mgr::CreateLogicalPartitionParams;
80 using android::fs_mgr::DestroyLogicalPartition;
81 using android::fs_mgr::EnsurePathMounted;
82 using android::fs_mgr::EnsurePathUnmounted;
83 using android::fs_mgr::Extent;
84 using android::fs_mgr::Fstab;
85 using android::fs_mgr::GetPartitionGroupName;
86 using android::fs_mgr::GetPartitionName;
87 using android::fs_mgr::Interval;
88 using android::fs_mgr::MetadataBuilder;
89 using android::fs_mgr::SlotSuffixForSlotNumber;
90 using chromeos_update_engine::DeltaArchiveManifest;
91 using chromeos_update_engine::DynamicPartitionGroup;
92 using chromeos_update_engine::PartitionUpdate;
93 using namespace ::testing;
94 using namespace android::storage_literals;
95 using namespace std::chrono_literals;
96 using namespace std::string_literals;
97
98 // Global states. See test_helpers.h.
99 std::unique_ptr<SnapshotManager> sm;
100 TestDeviceInfo* test_device = nullptr;
101 std::string fake_super;
102
103 void MountMetadata();
104
105 // @VsrTest = 3.7.6
106 class SnapshotTest : public ::testing::Test {
107 public:
SnapshotTest()108 SnapshotTest() : dm_(DeviceMapper::Instance()) {}
109
110 // This is exposed for main.
Cleanup()111 void Cleanup() {
112 InitializeState();
113 CleanupTestArtifacts();
114 }
115
116 protected:
SetUp()117 void SetUp() override {
118 const testing::TestInfo* const test_info =
119 testing::UnitTest::GetInstance()->current_test_info();
120 test_name_ = test_info->test_suite_name() + "/"s + test_info->name();
121
122 LOG(INFO) << "Starting test: " << test_name_;
123
124 SKIP_IF_NON_VIRTUAL_AB();
125
126 SetupProperties();
127 if (!DeviceSupportsMode()) {
128 GTEST_SKIP() << "Mode not supported on this device";
129 }
130
131 InitializeState();
132 CleanupTestArtifacts();
133 FormatFakeSuper();
134 MountMetadata();
135 ASSERT_TRUE(sm->BeginUpdate());
136 }
137
SetupProperties()138 void SetupProperties() {
139 std::unordered_map<std::string, std::string> properties;
140
141 ASSERT_TRUE(android::base::SetProperty("snapuserd.test.io_uring.force_disable", "0"))
142 << "Failed to set property: snapuserd.test.io_uring.disabled";
143
144 if (FLAGS_force_mode == "vab-legacy") {
145 properties["ro.virtual_ab.compression.enabled"] = "false";
146 properties["ro.virtual_ab.userspace.snapshots.enabled"] = "false";
147 }
148
149 if (FLAGS_force_iouring_disable == "iouring_disabled") {
150 ASSERT_TRUE(android::base::SetProperty("snapuserd.test.io_uring.force_disable", "1"))
151 << "Failed to set property: snapuserd.test.io_uring.disabled";
152 properties["ro.virtual_ab.io_uring.enabled"] = "false";
153 }
154
155 auto fetcher = std::make_unique<SnapshotTestPropertyFetcher>("_a", std::move(properties));
156 IPropertyFetcher::OverrideForTesting(std::move(fetcher));
157
158 if (GetLegacyCompressionEnabledProperty() || CanUseUserspaceSnapshots()) {
159 // If we're asked to test the device's actual configuration, then it
160 // may be misconfigured, so check for kernel support as libsnapshot does.
161 if (FLAGS_force_mode.empty()) {
162 snapuserd_required_ = KernelSupportsCompressedSnapshots();
163 } else {
164 snapuserd_required_ = true;
165 }
166 }
167 }
168
TearDown()169 void TearDown() override {
170 RETURN_IF_NON_VIRTUAL_AB();
171
172 LOG(INFO) << "Tearing down SnapshotTest test: " << test_name_;
173
174 lock_ = nullptr;
175
176 CleanupTestArtifacts();
177 SnapshotTestPropertyFetcher::TearDown();
178
179 LOG(INFO) << "Teardown complete for test: " << test_name_;
180 }
181
DeviceSupportsMode()182 bool DeviceSupportsMode() {
183 if (FLAGS_force_mode.empty()) {
184 return true;
185 }
186 if (snapuserd_required_ && !KernelSupportsCompressedSnapshots()) {
187 return false;
188 }
189 return true;
190 }
191
ShouldSkipLegacyMerging()192 bool ShouldSkipLegacyMerging() {
193 if (!GetLegacyCompressionEnabledProperty() || !snapuserd_required_) {
194 return false;
195 }
196 int api_level = android::base::GetIntProperty("ro.board.api_level", -1);
197 if (api_level == -1) {
198 api_level = android::base::GetIntProperty("ro.product.first_api_level", -1);
199 }
200 return api_level != __ANDROID_API_S__;
201 }
202
InitializeState()203 void InitializeState() {
204 ASSERT_TRUE(sm->EnsureImageManager());
205 image_manager_ = sm->image_manager();
206
207 test_device->set_slot_suffix("_a");
208
209 sm->set_use_first_stage_snapuserd(false);
210 }
211
CleanupTestArtifacts()212 void CleanupTestArtifacts() {
213 // Normally cancelling inside a merge is not allowed. Since these
214 // are tests, we don't care, destroy everything that might exist.
215 // Note we hardcode this list because of an annoying quirk: when
216 // completing a merge, the snapshot stops existing, so we can't
217 // get an accurate list to remove.
218 lock_ = nullptr;
219
220 // If there is no image manager, the test was skipped.
221 if (!image_manager_) {
222 return;
223 }
224
225 std::vector<std::string> snapshots = {"test-snapshot", "test_partition_a",
226 "test_partition_b"};
227 for (const auto& snapshot : snapshots) {
228 CleanupSnapshotArtifacts(snapshot);
229 }
230
231 // Remove stale partitions in fake super.
232 std::vector<std::string> partitions = {
233 "base-device",
234 "test_partition_b",
235 "test_partition_b-base",
236 "test_partition_b-cow",
237 };
238 for (const auto& partition : partitions) {
239 DeleteDevice(partition);
240 }
241
242 if (sm->GetUpdateState() != UpdateState::None) {
243 auto state_file = sm->GetStateFilePath();
244 unlink(state_file.c_str());
245 }
246 }
247
CleanupSnapshotArtifacts(const std::string & snapshot)248 void CleanupSnapshotArtifacts(const std::string& snapshot) {
249 // The device-mapper stack may have been collapsed to dm-linear, so it's
250 // necessary to check what state it's in before attempting a cleanup.
251 // SnapshotManager has no path like this because we'd never remove a
252 // merged snapshot (a live partition).
253 bool is_dm_user = false;
254 DeviceMapper::TargetInfo target;
255 if (sm->IsSnapshotDevice(snapshot, &target)) {
256 is_dm_user = (DeviceMapper::GetTargetType(target.spec) == "user");
257 }
258
259 if (is_dm_user) {
260 ASSERT_TRUE(sm->EnsureSnapuserdConnected());
261 ASSERT_TRUE(AcquireLock());
262
263 auto local_lock = std::move(lock_);
264 ASSERT_TRUE(sm->UnmapUserspaceSnapshotDevice(local_lock.get(), snapshot));
265 }
266
267 ASSERT_TRUE(DeleteSnapshotDevice(snapshot));
268 DeleteBackingImage(image_manager_, snapshot + "-cow-img");
269
270 auto status_file = sm->GetSnapshotStatusFilePath(snapshot);
271 android::base::RemoveFileIfExists(status_file);
272 }
273
AcquireLock()274 bool AcquireLock() {
275 lock_ = sm->LockExclusive();
276 return !!lock_;
277 }
278
279 // This is so main() can instantiate this to invoke Cleanup.
TestBody()280 virtual void TestBody() override {}
281
FormatFakeSuper()282 void FormatFakeSuper() {
283 BlockDeviceInfo super_device("super", kSuperSize, 0, 0, 4096);
284 std::vector<BlockDeviceInfo> devices = {super_device};
285
286 auto builder = MetadataBuilder::New(devices, "super", 65536, 2);
287 ASSERT_NE(builder, nullptr);
288
289 auto metadata = builder->Export();
290 ASSERT_NE(metadata, nullptr);
291
292 TestPartitionOpener opener(fake_super);
293 ASSERT_TRUE(FlashPartitionTable(opener, fake_super, *metadata.get()));
294 }
295
296 // If |path| is non-null, the partition will be mapped after creation.
CreatePartition(const std::string & name,uint64_t size,std::string * path=nullptr,const std::optional<std::string> group={})297 bool CreatePartition(const std::string& name, uint64_t size, std::string* path = nullptr,
298 const std::optional<std::string> group = {}) {
299 TestPartitionOpener opener(fake_super);
300 auto builder = MetadataBuilder::New(opener, "super", 0);
301 if (!builder) return false;
302
303 std::string partition_group = std::string(android::fs_mgr::kDefaultGroup);
304 if (group) {
305 partition_group = *group;
306 }
307 return CreatePartition(builder.get(), name, size, path, partition_group);
308 }
309
CreatePartition(MetadataBuilder * builder,const std::string & name,uint64_t size,std::string * path,const std::string & group)310 bool CreatePartition(MetadataBuilder* builder, const std::string& name, uint64_t size,
311 std::string* path, const std::string& group) {
312 auto partition = builder->AddPartition(name, group, 0);
313 if (!partition) return false;
314 if (!builder->ResizePartition(partition, size)) {
315 return false;
316 }
317
318 // Update the source slot.
319 auto metadata = builder->Export();
320 if (!metadata) return false;
321
322 TestPartitionOpener opener(fake_super);
323 if (!UpdatePartitionTable(opener, "super", *metadata.get(), 0)) {
324 return false;
325 }
326
327 if (!path) return true;
328
329 CreateLogicalPartitionParams params = {
330 .block_device = fake_super,
331 .metadata = metadata.get(),
332 .partition_name = name,
333 .force_writable = true,
334 .timeout_ms = 10s,
335 };
336 return CreateLogicalPartition(params, path);
337 }
338
MapUpdateSnapshot(const std::string & name,std::unique_ptr<ICowWriter> * writer)339 AssertionResult MapUpdateSnapshot(const std::string& name,
340 std::unique_ptr<ICowWriter>* writer) {
341 TestPartitionOpener opener(fake_super);
342 CreateLogicalPartitionParams params{
343 .block_device = fake_super,
344 .metadata_slot = 1,
345 .partition_name = name,
346 .timeout_ms = 10s,
347 .partition_opener = &opener,
348 };
349
350 auto result = sm->OpenSnapshotWriter(params, {});
351 if (!result) {
352 return AssertionFailure() << "Cannot open snapshot for writing: " << name;
353 }
354
355 if (writer) {
356 *writer = std::move(result);
357 }
358 return AssertionSuccess();
359 }
360
MapUpdateSnapshot(const std::string & name,std::string * path)361 AssertionResult MapUpdateSnapshot(const std::string& name, std::string* path) {
362 TestPartitionOpener opener(fake_super);
363 CreateLogicalPartitionParams params{
364 .block_device = fake_super,
365 .metadata_slot = 1,
366 .partition_name = name,
367 .timeout_ms = 10s,
368 .partition_opener = &opener,
369 };
370
371 auto result = sm->MapUpdateSnapshot(params, path);
372 if (!result) {
373 return AssertionFailure() << "Cannot open snapshot for writing: " << name;
374 }
375 return AssertionSuccess();
376 }
377
DeleteSnapshotDevice(const std::string & snapshot)378 AssertionResult DeleteSnapshotDevice(const std::string& snapshot) {
379 AssertionResult res = AssertionSuccess();
380 if (!(res = DeleteDevice(snapshot))) return res;
381 if (!sm->UnmapDmUserDevice(snapshot + "-user-cow")) {
382 return AssertionFailure() << "Cannot delete dm-user device for " << snapshot;
383 }
384 if (!(res = DeleteDevice(snapshot + "-inner"))) return res;
385 if (!(res = DeleteDevice(snapshot + "-cow"))) return res;
386 if (!image_manager_->UnmapImageIfExists(snapshot + "-cow-img")) {
387 return AssertionFailure() << "Cannot unmap image " << snapshot << "-cow-img";
388 }
389 if (!(res = DeleteDevice(snapshot + "-base"))) return res;
390 if (!(res = DeleteDevice(snapshot + "-src"))) return res;
391 return AssertionSuccess();
392 }
393
DeleteDevice(const std::string & device)394 AssertionResult DeleteDevice(const std::string& device) {
395 if (!sm->DeleteDeviceIfExists(device, 1s)) {
396 return AssertionFailure() << "Can't delete " << device;
397 }
398 return AssertionSuccess();
399 }
400
CreateCowImage(const std::string & name)401 AssertionResult CreateCowImage(const std::string& name) {
402 if (!sm->CreateCowImage(lock_.get(), name)) {
403 return AssertionFailure() << "Cannot create COW image " << name;
404 }
405 std::string cow_device;
406 auto map_res = MapCowImage(name, 10s, &cow_device);
407 if (!map_res) {
408 return map_res;
409 }
410 if (!InitializeKernelCow(cow_device)) {
411 return AssertionFailure() << "Cannot zero fill " << cow_device;
412 }
413 if (!sm->UnmapCowImage(name)) {
414 return AssertionFailure() << "Cannot unmap " << name << " after zero filling it";
415 }
416 return AssertionSuccess();
417 }
418
MapCowImage(const std::string & name,const std::chrono::milliseconds & timeout_ms,std::string * path)419 AssertionResult MapCowImage(const std::string& name,
420 const std::chrono::milliseconds& timeout_ms, std::string* path) {
421 auto cow_image_path = sm->MapCowImage(name, timeout_ms);
422 if (!cow_image_path.has_value()) {
423 return AssertionFailure() << "Cannot map cow image " << name;
424 }
425 *path = *cow_image_path;
426 return AssertionSuccess();
427 }
428
429 // Prepare A/B slot for a partition named "test_partition".
PrepareOneSnapshot(uint64_t device_size,std::unique_ptr<ICowWriter> * writer=nullptr)430 AssertionResult PrepareOneSnapshot(uint64_t device_size,
431 std::unique_ptr<ICowWriter>* writer = nullptr) {
432 lock_ = nullptr;
433
434 DeltaArchiveManifest manifest;
435
436 auto dynamic_partition_metadata = manifest.mutable_dynamic_partition_metadata();
437 dynamic_partition_metadata->set_vabc_enabled(snapuserd_required_);
438 dynamic_partition_metadata->set_cow_version(android::snapshot::kCowVersionMajor);
439 if (snapuserd_required_) {
440 dynamic_partition_metadata->set_vabc_compression_param(FLAGS_compression_method);
441 }
442
443 auto group = dynamic_partition_metadata->add_groups();
444 group->set_name("group");
445 group->set_size(device_size * 2);
446 group->add_partition_names("test_partition");
447
448 auto pu = manifest.add_partitions();
449 pu->set_partition_name("test_partition");
450 pu->set_estimate_cow_size(device_size);
451 SetSize(pu, device_size);
452
453 auto extent = pu->add_operations()->add_dst_extents();
454 extent->set_start_block(0);
455 if (device_size) {
456 extent->set_num_blocks(device_size / manifest.block_size());
457 }
458
459 TestPartitionOpener opener(fake_super);
460 auto builder = MetadataBuilder::New(opener, "super", 0);
461 if (!builder) {
462 return AssertionFailure() << "Failed to open MetadataBuilder";
463 }
464 builder->AddGroup("group_a", 16_GiB);
465 builder->AddGroup("group_b", 16_GiB);
466 if (!CreatePartition(builder.get(), "test_partition_a", device_size, nullptr, "group_a")) {
467 return AssertionFailure() << "Failed create test_partition_a";
468 }
469
470 if (!sm->CreateUpdateSnapshots(manifest)) {
471 return AssertionFailure() << "Failed to create update snapshots";
472 }
473
474 if (writer) {
475 auto res = MapUpdateSnapshot("test_partition_b", writer);
476 if (!res) {
477 return res;
478 }
479 } else if (!snapuserd_required_) {
480 std::string ignore;
481 if (!MapUpdateSnapshot("test_partition_b", &ignore)) {
482 return AssertionFailure() << "Failed to map test_partition_b";
483 }
484 }
485 if (!AcquireLock()) {
486 return AssertionFailure() << "Failed to acquire lock";
487 }
488 return AssertionSuccess();
489 }
490
491 // Simulate a reboot into the new slot.
SimulateReboot()492 AssertionResult SimulateReboot() {
493 lock_ = nullptr;
494 if (!sm->FinishedSnapshotWrites(false)) {
495 return AssertionFailure() << "Failed to finish snapshot writes";
496 }
497 if (!sm->UnmapUpdateSnapshot("test_partition_b")) {
498 return AssertionFailure() << "Failed to unmap COW for test_partition_b";
499 }
500 if (!dm_.DeleteDeviceIfExists("test_partition_b")) {
501 return AssertionFailure() << "Failed to delete test_partition_b";
502 }
503 if (!dm_.DeleteDeviceIfExists("test_partition_b-base")) {
504 return AssertionFailure() << "Failed to destroy test_partition_b-base";
505 }
506 return AssertionSuccess();
507 }
508
NewManagerForFirstStageMount(const std::string & slot_suffix="_a")509 std::unique_ptr<SnapshotManager> NewManagerForFirstStageMount(
510 const std::string& slot_suffix = "_a") {
511 auto info = new TestDeviceInfo(fake_super, slot_suffix);
512 return NewManagerForFirstStageMount(info);
513 }
514
NewManagerForFirstStageMount(TestDeviceInfo * info)515 std::unique_ptr<SnapshotManager> NewManagerForFirstStageMount(TestDeviceInfo* info) {
516 info->set_first_stage_init(true);
517 auto init = SnapshotManager::NewForFirstStageMount(info);
518 if (!init) {
519 return nullptr;
520 }
521 init->SetUeventRegenCallback([](const std::string& device) -> bool {
522 return android::fs_mgr::WaitForFile(device, snapshot_timeout_);
523 });
524 return init;
525 }
526
527 static constexpr std::chrono::milliseconds snapshot_timeout_ = 5s;
528 DeviceMapper& dm_;
529 std::unique_ptr<SnapshotManager::LockedFile> lock_;
530 android::fiemap::IImageManager* image_manager_ = nullptr;
531 std::string fake_super_;
532 bool snapuserd_required_ = false;
533 std::string test_name_;
534 };
535
TEST_F(SnapshotTest,CreateSnapshot)536 TEST_F(SnapshotTest, CreateSnapshot) {
537 ASSERT_TRUE(AcquireLock());
538
539 PartitionCowCreator cow_creator;
540 cow_creator.using_snapuserd = snapuserd_required_;
541 if (cow_creator.using_snapuserd) {
542 cow_creator.compression_algorithm = FLAGS_compression_method;
543 } else {
544 cow_creator.compression_algorithm = "none";
545 }
546
547 static const uint64_t kDeviceSize = 1024 * 1024;
548 SnapshotStatus status;
549 status.set_name("test-snapshot");
550 status.set_device_size(kDeviceSize);
551 status.set_snapshot_size(kDeviceSize);
552 status.set_cow_file_size(kDeviceSize);
553 ASSERT_TRUE(sm->CreateSnapshot(lock_.get(), &cow_creator, &status));
554 ASSERT_TRUE(CreateCowImage("test-snapshot"));
555
556 std::vector<std::string> snapshots;
557 ASSERT_TRUE(sm->ListSnapshots(lock_.get(), &snapshots));
558 ASSERT_EQ(snapshots.size(), 1);
559 ASSERT_EQ(snapshots[0], "test-snapshot");
560
561 // Scope so delete can re-acquire the snapshot file lock.
562 {
563 SnapshotStatus status;
564 ASSERT_TRUE(sm->ReadSnapshotStatus(lock_.get(), "test-snapshot", &status));
565 ASSERT_EQ(status.state(), SnapshotState::CREATED);
566 ASSERT_EQ(status.device_size(), kDeviceSize);
567 ASSERT_EQ(status.snapshot_size(), kDeviceSize);
568 ASSERT_EQ(status.using_snapuserd(), cow_creator.using_snapuserd);
569 ASSERT_EQ(status.compression_algorithm(), cow_creator.compression_algorithm);
570 }
571
572 ASSERT_TRUE(sm->UnmapSnapshot(lock_.get(), "test-snapshot"));
573 ASSERT_TRUE(sm->UnmapCowImage("test-snapshot"));
574 ASSERT_TRUE(sm->DeleteSnapshot(lock_.get(), "test-snapshot"));
575 }
576
TEST_F(SnapshotTest,MapSnapshot)577 TEST_F(SnapshotTest, MapSnapshot) {
578 ASSERT_TRUE(AcquireLock());
579
580 PartitionCowCreator cow_creator;
581 cow_creator.using_snapuserd = snapuserd_required_;
582
583 static const uint64_t kDeviceSize = 1024 * 1024;
584 SnapshotStatus status;
585 status.set_name("test-snapshot");
586 status.set_device_size(kDeviceSize);
587 status.set_snapshot_size(kDeviceSize);
588 status.set_cow_file_size(kDeviceSize);
589 ASSERT_TRUE(sm->CreateSnapshot(lock_.get(), &cow_creator, &status));
590 ASSERT_TRUE(CreateCowImage("test-snapshot"));
591
592 std::string base_device;
593 ASSERT_TRUE(CreatePartition("base-device", kDeviceSize, &base_device));
594
595 std::string cow_device;
596 ASSERT_TRUE(MapCowImage("test-snapshot", 10s, &cow_device));
597
598 std::string snap_device;
599 ASSERT_TRUE(sm->MapSnapshot(lock_.get(), "test-snapshot", base_device, cow_device, 10s,
600 &snap_device));
601 ASSERT_TRUE(android::base::StartsWith(snap_device, "/dev/block/dm-"));
602 }
603
TEST_F(SnapshotTest,NoMergeBeforeReboot)604 TEST_F(SnapshotTest, NoMergeBeforeReboot) {
605 ASSERT_TRUE(sm->FinishedSnapshotWrites(false));
606
607 // Merge should fail, since the slot hasn't changed.
608 ASSERT_FALSE(sm->InitiateMerge());
609 }
610
TEST_F(SnapshotTest,CleanFirstStageMount)611 TEST_F(SnapshotTest, CleanFirstStageMount) {
612 // If there's no update in progress, there should be no first-stage mount
613 // needed.
614 auto sm = NewManagerForFirstStageMount();
615 ASSERT_NE(sm, nullptr);
616 ASSERT_FALSE(sm->NeedSnapshotsInFirstStageMount());
617 }
618
TEST_F(SnapshotTest,FirstStageMountAfterRollback)619 TEST_F(SnapshotTest, FirstStageMountAfterRollback) {
620 ASSERT_TRUE(sm->FinishedSnapshotWrites(false));
621
622 // We didn't change the slot, so we shouldn't need snapshots.
623 auto sm = NewManagerForFirstStageMount();
624 ASSERT_NE(sm, nullptr);
625 ASSERT_FALSE(sm->NeedSnapshotsInFirstStageMount());
626
627 auto indicator = sm->GetRollbackIndicatorPath();
628 ASSERT_EQ(access(indicator.c_str(), R_OK), 0);
629 }
630
TEST_F(SnapshotTest,Merge)631 TEST_F(SnapshotTest, Merge) {
632 ASSERT_TRUE(AcquireLock());
633
634 static constexpr uint64_t kDeviceSize = 1024 * 1024;
635 static constexpr uint32_t kBlockSize = 4096;
636
637 std::string test_string = "This is a test string.";
638 test_string.resize(kBlockSize);
639
640 bool userspace_snapshots = false;
641 if (snapuserd_required_) {
642 std::unique_ptr<ICowWriter> writer;
643 ASSERT_TRUE(PrepareOneSnapshot(kDeviceSize, &writer));
644
645 userspace_snapshots = sm->UpdateUsesUserSnapshots(lock_.get());
646
647 // Release the lock.
648 lock_ = nullptr;
649
650 ASSERT_TRUE(writer->AddRawBlocks(0, test_string.data(), test_string.size()));
651 ASSERT_TRUE(writer->Finalize());
652 writer = nullptr;
653 } else {
654 ASSERT_TRUE(PrepareOneSnapshot(kDeviceSize));
655
656 // Release the lock.
657 lock_ = nullptr;
658
659 std::string path;
660 ASSERT_TRUE(dm_.GetDmDevicePathByName("test_partition_b", &path));
661
662 unique_fd fd(open(path.c_str(), O_WRONLY));
663 ASSERT_GE(fd, 0);
664 ASSERT_TRUE(android::base::WriteFully(fd, test_string.data(), test_string.size()));
665 }
666
667 // Done updating.
668 ASSERT_TRUE(sm->FinishedSnapshotWrites(false));
669
670 ASSERT_TRUE(sm->UnmapUpdateSnapshot("test_partition_b"));
671
672 test_device->set_slot_suffix("_b");
673 ASSERT_TRUE(sm->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
674 if (ShouldSkipLegacyMerging()) {
675 LOG(INFO) << "Skipping legacy merge in test";
676 return;
677 }
678 ASSERT_TRUE(sm->InitiateMerge());
679
680 // Create stale files in snapshot directory. Merge should skip these files
681 // as the suffix doesn't match the current slot.
682 auto tmp_path = test_device->GetMetadataDir() + "/snapshots/test_partition_b.tmp";
683 auto other_slot = test_device->GetMetadataDir() + "/snapshots/test_partition_a";
684
685 unique_fd fd(open(tmp_path.c_str(), O_RDWR | O_CLOEXEC | O_CREAT, 0644));
686 ASSERT_GE(fd, 0);
687
688 fd.reset(open(other_slot.c_str(), O_RDWR | O_CLOEXEC | O_CREAT, 0644));
689 ASSERT_GE(fd, 0);
690
691 // The device should have been switched to a snapshot-merge target.
692 DeviceMapper::TargetInfo target;
693 ASSERT_TRUE(sm->IsSnapshotDevice("test_partition_b", &target));
694 if (userspace_snapshots) {
695 ASSERT_EQ(DeviceMapper::GetTargetType(target.spec), "user");
696 } else {
697 ASSERT_EQ(DeviceMapper::GetTargetType(target.spec), "snapshot-merge");
698 }
699
700 // We should not be able to cancel an update now.
701 ASSERT_FALSE(sm->CancelUpdate());
702
703 ASSERT_EQ(sm->ProcessUpdateState(), UpdateState::MergeCompleted);
704 ASSERT_EQ(sm->GetUpdateState(), UpdateState::None);
705
706 // Make sure that snapshot states are cleared and all stale files
707 // are deleted
708 {
709 ASSERT_TRUE(AcquireLock());
710 auto local_lock = std::move(lock_);
711 std::vector<std::string> snapshots;
712 ASSERT_TRUE(sm->ListSnapshots(local_lock.get(), &snapshots));
713 ASSERT_TRUE(snapshots.empty());
714 }
715
716 // The device should no longer be a snapshot or snapshot-merge.
717 ASSERT_FALSE(sm->IsSnapshotDevice("test_partition_b"));
718
719 // Test that we can read back the string we wrote to the snapshot. Note
720 // that the base device is gone now. |snap_device| contains the correct
721 // partition.
722 fd.reset(open("/dev/block/mapper/test_partition_b", O_RDONLY | O_CLOEXEC));
723 ASSERT_GE(fd, 0);
724
725 std::string buffer(test_string.size(), '\0');
726 ASSERT_TRUE(android::base::ReadFully(fd, buffer.data(), buffer.size()));
727 ASSERT_EQ(test_string, buffer);
728 }
729
TEST_F(SnapshotTest,FirstStageMountAndMerge)730 TEST_F(SnapshotTest, FirstStageMountAndMerge) {
731 ASSERT_TRUE(AcquireLock());
732
733 static const uint64_t kDeviceSize = 1024 * 1024;
734 ASSERT_TRUE(PrepareOneSnapshot(kDeviceSize));
735 ASSERT_TRUE(SimulateReboot());
736
737 auto init = NewManagerForFirstStageMount("_b");
738 ASSERT_NE(init, nullptr);
739 ASSERT_TRUE(init->NeedSnapshotsInFirstStageMount());
740 ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
741
742 ASSERT_TRUE(AcquireLock());
743
744 bool userspace_snapshots = init->UpdateUsesUserSnapshots(lock_.get());
745
746 // Validate that we have a snapshot device.
747 SnapshotStatus status;
748 ASSERT_TRUE(init->ReadSnapshotStatus(lock_.get(), "test_partition_b", &status));
749 ASSERT_EQ(status.state(), SnapshotState::CREATED);
750 if (snapuserd_required_) {
751 ASSERT_EQ(status.compression_algorithm(), FLAGS_compression_method);
752 } else {
753 ASSERT_EQ(status.compression_algorithm(), "");
754 }
755
756 DeviceMapper::TargetInfo target;
757 ASSERT_TRUE(init->IsSnapshotDevice("test_partition_b", &target));
758 if (userspace_snapshots) {
759 ASSERT_EQ(DeviceMapper::GetTargetType(target.spec), "user");
760 } else {
761 ASSERT_EQ(DeviceMapper::GetTargetType(target.spec), "snapshot");
762 }
763 }
764
TEST_F(SnapshotTest,FlashSuperDuringUpdate)765 TEST_F(SnapshotTest, FlashSuperDuringUpdate) {
766 ASSERT_TRUE(AcquireLock());
767
768 static const uint64_t kDeviceSize = 1024 * 1024;
769 ASSERT_TRUE(PrepareOneSnapshot(kDeviceSize));
770 ASSERT_TRUE(SimulateReboot());
771
772 // Reflash the super partition.
773 FormatFakeSuper();
774 ASSERT_TRUE(CreatePartition("test_partition_b", kDeviceSize));
775
776 auto init = NewManagerForFirstStageMount("_b");
777 ASSERT_NE(init, nullptr);
778 ASSERT_TRUE(init->NeedSnapshotsInFirstStageMount());
779 ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
780
781 ASSERT_TRUE(AcquireLock());
782
783 SnapshotStatus status;
784 ASSERT_TRUE(init->ReadSnapshotStatus(lock_.get(), "test_partition_b", &status));
785
786 // We should not get a snapshot device now.
787 DeviceMapper::TargetInfo target;
788 ASSERT_FALSE(init->IsSnapshotDevice("test_partition_b", &target));
789
790 // We should see a cancelled update as well.
791 lock_ = nullptr;
792 ASSERT_EQ(sm->ProcessUpdateState(), UpdateState::Cancelled);
793 }
794
TEST_F(SnapshotTest,FlashSuperDuringMerge)795 TEST_F(SnapshotTest, FlashSuperDuringMerge) {
796 ASSERT_TRUE(AcquireLock());
797
798 static const uint64_t kDeviceSize = 1024 * 1024;
799 ASSERT_TRUE(PrepareOneSnapshot(kDeviceSize));
800 ASSERT_TRUE(SimulateReboot());
801
802 auto init = NewManagerForFirstStageMount("_b");
803 ASSERT_NE(init, nullptr);
804 ASSERT_TRUE(init->NeedSnapshotsInFirstStageMount());
805 ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
806 if (ShouldSkipLegacyMerging()) {
807 LOG(INFO) << "Skipping legacy merge in test";
808 return;
809 }
810 ASSERT_TRUE(init->InitiateMerge());
811
812 // Now, reflash super. Note that we haven't called ProcessUpdateState, so the
813 // status is still Merging.
814 ASSERT_TRUE(DeleteSnapshotDevice("test_partition_b"));
815 ASSERT_TRUE(init->image_manager()->UnmapImageIfExists("test_partition_b-cow-img"));
816 FormatFakeSuper();
817 ASSERT_TRUE(CreatePartition("test_partition_b", kDeviceSize));
818 ASSERT_TRUE(init->NeedSnapshotsInFirstStageMount());
819 ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
820
821 // Because the status is Merging, we must call ProcessUpdateState, which should
822 // detect a cancelled update.
823 ASSERT_EQ(init->ProcessUpdateState(), UpdateState::Cancelled);
824 ASSERT_EQ(init->GetUpdateState(), UpdateState::None);
825 }
826
TEST_F(SnapshotTest,UpdateBootControlHal)827 TEST_F(SnapshotTest, UpdateBootControlHal) {
828 ASSERT_TRUE(AcquireLock());
829
830 ASSERT_TRUE(sm->WriteUpdateState(lock_.get(), UpdateState::None));
831 ASSERT_EQ(test_device->merge_status(), MergeStatus::NONE);
832
833 ASSERT_TRUE(sm->WriteUpdateState(lock_.get(), UpdateState::Initiated));
834 ASSERT_EQ(test_device->merge_status(), MergeStatus::NONE);
835
836 ASSERT_TRUE(sm->WriteUpdateState(lock_.get(), UpdateState::Unverified));
837 ASSERT_EQ(test_device->merge_status(), MergeStatus::SNAPSHOTTED);
838
839 ASSERT_TRUE(sm->WriteUpdateState(lock_.get(), UpdateState::Merging));
840 ASSERT_EQ(test_device->merge_status(), MergeStatus::MERGING);
841
842 ASSERT_TRUE(sm->WriteUpdateState(lock_.get(), UpdateState::MergeNeedsReboot));
843 ASSERT_EQ(test_device->merge_status(), MergeStatus::NONE);
844
845 ASSERT_TRUE(sm->WriteUpdateState(lock_.get(), UpdateState::MergeCompleted));
846 ASSERT_EQ(test_device->merge_status(), MergeStatus::NONE);
847
848 ASSERT_TRUE(sm->WriteUpdateState(lock_.get(), UpdateState::MergeFailed));
849 ASSERT_EQ(test_device->merge_status(), MergeStatus::MERGING);
850 }
851
TEST_F(SnapshotTest,MergeFailureCode)852 TEST_F(SnapshotTest, MergeFailureCode) {
853 ASSERT_TRUE(AcquireLock());
854
855 ASSERT_TRUE(sm->WriteUpdateState(lock_.get(), UpdateState::MergeFailed,
856 MergeFailureCode::ListSnapshots));
857 ASSERT_EQ(test_device->merge_status(), MergeStatus::MERGING);
858
859 SnapshotUpdateStatus status = sm->ReadSnapshotUpdateStatus(lock_.get());
860 ASSERT_EQ(status.state(), UpdateState::MergeFailed);
861 ASSERT_EQ(status.merge_failure_code(), MergeFailureCode::ListSnapshots);
862 }
863
864 enum class Request { UNKNOWN, LOCK_SHARED, LOCK_EXCLUSIVE, UNLOCK, EXIT };
operator <<(std::ostream & os,Request request)865 std::ostream& operator<<(std::ostream& os, Request request) {
866 switch (request) {
867 case Request::LOCK_SHARED:
868 return os << "Shared";
869 case Request::LOCK_EXCLUSIVE:
870 return os << "Exclusive";
871 case Request::UNLOCK:
872 return os << "Unlock";
873 case Request::EXIT:
874 return os << "Exit";
875 case Request::UNKNOWN:
876 [[fallthrough]];
877 default:
878 return os << "Unknown";
879 }
880 }
881
882 class LockTestConsumer {
883 public:
MakeRequest(Request new_request)884 AssertionResult MakeRequest(Request new_request) {
885 {
886 std::unique_lock<std::mutex> ulock(mutex_);
887 requests_.push_back(new_request);
888 }
889 cv_.notify_all();
890 return AssertionSuccess() << "Request " << new_request << " successful";
891 }
892
893 template <typename R, typename P>
WaitFulfill(std::chrono::duration<R,P> timeout)894 AssertionResult WaitFulfill(std::chrono::duration<R, P> timeout) {
895 std::unique_lock<std::mutex> ulock(mutex_);
896 if (cv_.wait_for(ulock, timeout, [this] { return requests_.empty(); })) {
897 return AssertionSuccess() << "All requests_ fulfilled.";
898 }
899 return AssertionFailure() << "Timeout waiting for fulfilling " << requests_.size()
900 << " request(s), first one is "
901 << (requests_.empty() ? Request::UNKNOWN : requests_.front());
902 }
903
StartHandleRequestsInBackground()904 void StartHandleRequestsInBackground() {
905 future_ = std::async(std::launch::async, &LockTestConsumer::HandleRequests, this);
906 }
907
908 private:
HandleRequests()909 void HandleRequests() {
910 static constexpr auto consumer_timeout = 3s;
911
912 auto next_request = Request::UNKNOWN;
913 do {
914 // Peek next request.
915 {
916 std::unique_lock<std::mutex> ulock(mutex_);
917 if (cv_.wait_for(ulock, consumer_timeout, [this] { return !requests_.empty(); })) {
918 next_request = requests_.front();
919 } else {
920 next_request = Request::EXIT;
921 }
922 }
923
924 // Handle next request.
925 switch (next_request) {
926 case Request::LOCK_SHARED: {
927 lock_ = sm->LockShared();
928 } break;
929 case Request::LOCK_EXCLUSIVE: {
930 lock_ = sm->LockExclusive();
931 } break;
932 case Request::EXIT:
933 [[fallthrough]];
934 case Request::UNLOCK: {
935 lock_.reset();
936 } break;
937 case Request::UNKNOWN:
938 [[fallthrough]];
939 default:
940 break;
941 }
942
943 // Pop next request. This thread is the only thread that
944 // pops from the front of the requests_ deque.
945 {
946 std::unique_lock<std::mutex> ulock(mutex_);
947 if (next_request == Request::EXIT) {
948 requests_.clear();
949 } else {
950 requests_.pop_front();
951 }
952 }
953 cv_.notify_all();
954 } while (next_request != Request::EXIT);
955 }
956
957 std::mutex mutex_;
958 std::condition_variable cv_;
959 std::deque<Request> requests_;
960 std::unique_ptr<SnapshotManager::LockedFile> lock_;
961 std::future<void> future_;
962 };
963
964 class LockTest : public ::testing::Test {
965 public:
SetUp()966 void SetUp() {
967 SKIP_IF_NON_VIRTUAL_AB();
968 first_consumer.StartHandleRequestsInBackground();
969 second_consumer.StartHandleRequestsInBackground();
970 }
971
TearDown()972 void TearDown() {
973 RETURN_IF_NON_VIRTUAL_AB();
974 EXPECT_TRUE(first_consumer.MakeRequest(Request::EXIT));
975 EXPECT_TRUE(second_consumer.MakeRequest(Request::EXIT));
976 }
977
978 static constexpr auto request_timeout = 500ms;
979 LockTestConsumer first_consumer;
980 LockTestConsumer second_consumer;
981 };
982
TEST_F(LockTest,SharedShared)983 TEST_F(LockTest, SharedShared) {
984 ASSERT_TRUE(first_consumer.MakeRequest(Request::LOCK_SHARED));
985 ASSERT_TRUE(first_consumer.WaitFulfill(request_timeout));
986 ASSERT_TRUE(second_consumer.MakeRequest(Request::LOCK_SHARED));
987 ASSERT_TRUE(second_consumer.WaitFulfill(request_timeout));
988 }
989
990 using LockTestParam = std::pair<Request, Request>;
991 class LockTestP : public LockTest, public ::testing::WithParamInterface<LockTestParam> {};
TEST_P(LockTestP,Test)992 TEST_P(LockTestP, Test) {
993 ASSERT_TRUE(first_consumer.MakeRequest(GetParam().first));
994 ASSERT_TRUE(first_consumer.WaitFulfill(request_timeout));
995 ASSERT_TRUE(second_consumer.MakeRequest(GetParam().second));
996 ASSERT_FALSE(second_consumer.WaitFulfill(request_timeout))
997 << "Should not be able to " << GetParam().second << " while separate thread "
998 << GetParam().first;
999 ASSERT_TRUE(first_consumer.MakeRequest(Request::UNLOCK));
1000 ASSERT_TRUE(second_consumer.WaitFulfill(request_timeout))
1001 << "Should be able to hold lock that is released by separate thread";
1002 }
1003 INSTANTIATE_TEST_SUITE_P(
1004 LockTest, LockTestP,
1005 testing::Values(LockTestParam{Request::LOCK_EXCLUSIVE, Request::LOCK_EXCLUSIVE},
1006 LockTestParam{Request::LOCK_EXCLUSIVE, Request::LOCK_SHARED},
1007 LockTestParam{Request::LOCK_SHARED, Request::LOCK_EXCLUSIVE}),
__anon4de4482e0402(const testing::TestParamInfo<LockTestP::ParamType>& info) 1008 [](const testing::TestParamInfo<LockTestP::ParamType>& info) {
1009 std::stringstream ss;
1010 ss << info.param.first << info.param.second;
1011 return ss.str();
1012 });
1013
1014 class SnapshotUpdateTest : public SnapshotTest {
1015 public:
SetUp()1016 void SetUp() override {
1017 SKIP_IF_NON_VIRTUAL_AB();
1018
1019 SnapshotTest::SetUp();
1020 if (!image_manager_) {
1021 // Test was skipped.
1022 return;
1023 }
1024
1025 Cleanup();
1026
1027 // Cleanup() changes slot suffix, so initialize it again.
1028 test_device->set_slot_suffix("_a");
1029
1030 opener_ = std::make_unique<TestPartitionOpener>(fake_super);
1031
1032 auto dynamic_partition_metadata = manifest_.mutable_dynamic_partition_metadata();
1033 dynamic_partition_metadata->set_vabc_enabled(snapuserd_required_);
1034 dynamic_partition_metadata->set_cow_version(android::snapshot::kCowVersionMajor);
1035 if (snapuserd_required_) {
1036 dynamic_partition_metadata->set_vabc_compression_param(FLAGS_compression_method);
1037 }
1038
1039 // Create a fake update package metadata.
1040 // Not using full name "system", "vendor", "product" because these names collide with the
1041 // mapped partitions on the running device.
1042 // Each test modifies manifest_ slightly to indicate changes to the partition layout.
1043 group_ = dynamic_partition_metadata->add_groups();
1044 group_->set_name("group");
1045 group_->set_size(kGroupSize);
1046 group_->add_partition_names("sys");
1047 group_->add_partition_names("vnd");
1048 group_->add_partition_names("prd");
1049 sys_ = manifest_.add_partitions();
1050 sys_->set_partition_name("sys");
1051 sys_->set_estimate_cow_size(2_MiB);
1052 SetSize(sys_, 3_MiB);
1053 vnd_ = manifest_.add_partitions();
1054 vnd_->set_partition_name("vnd");
1055 vnd_->set_estimate_cow_size(2_MiB);
1056 SetSize(vnd_, 3_MiB);
1057 prd_ = manifest_.add_partitions();
1058 prd_->set_partition_name("prd");
1059 prd_->set_estimate_cow_size(2_MiB);
1060 SetSize(prd_, 3_MiB);
1061
1062 // Initialize source partition metadata using |manifest_|.
1063 src_ = MetadataBuilder::New(*opener_, "super", 0);
1064 ASSERT_NE(src_, nullptr);
1065 ASSERT_TRUE(FillFakeMetadata(src_.get(), manifest_, "_a"));
1066 // Add sys_b which is like system_other.
1067 ASSERT_TRUE(src_->AddGroup("group_b", kGroupSize));
1068 auto partition = src_->AddPartition("sys_b", "group_b", 0);
1069 ASSERT_NE(nullptr, partition);
1070 ASSERT_TRUE(src_->ResizePartition(partition, 1_MiB));
1071 auto metadata = src_->Export();
1072 ASSERT_NE(nullptr, metadata);
1073 ASSERT_TRUE(UpdatePartitionTable(*opener_, "super", *metadata.get(), 0));
1074
1075 // Map source partitions.
1076 std::string path;
1077 for (const auto& name : {"sys_a", "vnd_a", "prd_a"}) {
1078 ASSERT_TRUE(CreateLogicalPartition(
1079 CreateLogicalPartitionParams{
1080 .block_device = fake_super,
1081 .metadata_slot = 0,
1082 .partition_name = name,
1083 .timeout_ms = 1s,
1084 .partition_opener = opener_.get(),
1085 },
1086 &path));
1087 ASSERT_TRUE(WriteRandomData(path));
1088 auto hash = GetHash(path);
1089 ASSERT_TRUE(hash.has_value());
1090 hashes_[name] = *hash;
1091 }
1092
1093 // OTA client blindly unmaps all partitions that are possibly mapped.
1094 for (const auto& name : {"sys_b", "vnd_b", "prd_b"}) {
1095 ASSERT_TRUE(sm->UnmapUpdateSnapshot(name));
1096 }
1097 }
TearDown()1098 void TearDown() override {
1099 RETURN_IF_NON_VIRTUAL_AB();
1100
1101 LOG(INFO) << "Tearing down SnapshotUpdateTest test: " << test_name_;
1102
1103 Cleanup();
1104 SnapshotTest::TearDown();
1105 }
Cleanup()1106 void Cleanup() {
1107 if (!image_manager_) {
1108 InitializeState();
1109 }
1110 MountMetadata();
1111 for (const auto& suffix : {"_a", "_b"}) {
1112 test_device->set_slot_suffix(suffix);
1113
1114 // Cheat our way out of merge failed states.
1115 if (sm->ProcessUpdateState() == UpdateState::MergeFailed) {
1116 ASSERT_TRUE(AcquireLock());
1117 ASSERT_TRUE(sm->WriteUpdateState(lock_.get(), UpdateState::None));
1118 lock_ = {};
1119 }
1120
1121 EXPECT_TRUE(sm->CancelUpdate()) << suffix;
1122 }
1123 EXPECT_TRUE(UnmapAll());
1124 }
1125
IsPartitionUnchanged(const std::string & name)1126 AssertionResult IsPartitionUnchanged(const std::string& name) {
1127 std::string path;
1128 if (!dm_.GetDmDevicePathByName(name, &path)) {
1129 return AssertionFailure() << "Path of " << name << " cannot be determined";
1130 }
1131 auto hash = GetHash(path);
1132 if (!hash.has_value()) {
1133 return AssertionFailure() << "Cannot read partition " << name << ": " << path;
1134 }
1135 auto it = hashes_.find(name);
1136 if (it == hashes_.end()) {
1137 return AssertionFailure() << "No existing hash for " << name << ". Bad test code?";
1138 }
1139 if (it->second != *hash) {
1140 return AssertionFailure() << "Content of " << name << " has changed";
1141 }
1142 return AssertionSuccess();
1143 }
1144
GetSnapshotSize(const std::string & name)1145 std::optional<uint64_t> GetSnapshotSize(const std::string& name) {
1146 if (!AcquireLock()) {
1147 return std::nullopt;
1148 }
1149 auto local_lock = std::move(lock_);
1150
1151 SnapshotStatus status;
1152 if (!sm->ReadSnapshotStatus(local_lock.get(), name, &status)) {
1153 return std::nullopt;
1154 }
1155 return status.snapshot_size();
1156 }
1157
UnmapAll()1158 AssertionResult UnmapAll() {
1159 for (const auto& name : {"sys", "vnd", "prd", "dlkm"}) {
1160 if (!dm_.DeleteDeviceIfExists(name + "_a"s)) {
1161 return AssertionFailure() << "Cannot unmap " << name << "_a";
1162 }
1163 if (!DeleteSnapshotDevice(name + "_b"s)) {
1164 return AssertionFailure() << "Cannot delete snapshot " << name << "_b";
1165 }
1166 }
1167 return AssertionSuccess();
1168 }
1169
MapOneUpdateSnapshot(const std::string & name)1170 AssertionResult MapOneUpdateSnapshot(const std::string& name) {
1171 if (snapuserd_required_) {
1172 std::unique_ptr<ICowWriter> writer;
1173 return MapUpdateSnapshot(name, &writer);
1174 } else {
1175 std::string path;
1176 return MapUpdateSnapshot(name, &path);
1177 }
1178 }
1179
WriteSnapshots()1180 AssertionResult WriteSnapshots() {
1181 for (const auto& partition : {sys_, vnd_, prd_}) {
1182 auto res = WriteSnapshotAndHash(partition);
1183 if (!res) {
1184 return res;
1185 }
1186 }
1187 return AssertionSuccess();
1188 }
1189
WriteSnapshotAndHash(PartitionUpdate * partition)1190 AssertionResult WriteSnapshotAndHash(PartitionUpdate* partition) {
1191 std::string name = partition->partition_name() + "_b";
1192 if (snapuserd_required_) {
1193 std::unique_ptr<ICowWriter> writer;
1194 auto res = MapUpdateSnapshot(name, &writer);
1195 if (!res) {
1196 return res;
1197 }
1198 if (!WriteRandomSnapshotData(writer.get(), &hashes_[name])) {
1199 return AssertionFailure() << "Unable to write random data to snapshot " << name;
1200 }
1201 if (!writer->Finalize()) {
1202 return AssertionFailure() << "Unable to finalize COW for " << name;
1203 }
1204 } else {
1205 std::string path;
1206 auto res = MapUpdateSnapshot(name, &path);
1207 if (!res) {
1208 return res;
1209 }
1210 if (!WriteRandomData(path, std::nullopt, &hashes_[name])) {
1211 return AssertionFailure() << "Unable to write random data to snapshot " << name;
1212 }
1213 }
1214
1215 // Make sure updates to one device are seen by all devices.
1216 sync();
1217
1218 return AssertionSuccess() << "Written random data to snapshot " << name
1219 << ", hash: " << hashes_[name];
1220 }
1221
WriteRandomSnapshotData(ICowWriter * writer,std::string * hash)1222 bool WriteRandomSnapshotData(ICowWriter* writer, std::string* hash) {
1223 unique_fd rand(open("/dev/urandom", O_RDONLY));
1224 if (rand < 0) {
1225 PLOG(ERROR) << "open /dev/urandom";
1226 return false;
1227 }
1228
1229 SHA256_CTX ctx;
1230 SHA256_Init(&ctx);
1231
1232 if (!writer->GetMaxBlocks()) {
1233 LOG(ERROR) << "CowWriter must specify maximum number of blocks";
1234 return false;
1235 }
1236 const auto num_blocks = writer->GetMaxBlocks().value();
1237
1238 const auto block_size = writer->GetBlockSize();
1239 std::string block(block_size, '\0');
1240 for (uint64_t i = 0; i < num_blocks; i++) {
1241 if (!ReadFully(rand, block.data(), block.size())) {
1242 PLOG(ERROR) << "read /dev/urandom";
1243 return false;
1244 }
1245 if (!writer->AddRawBlocks(i, block.data(), block.size())) {
1246 LOG(ERROR) << "Failed to add raw block " << i;
1247 return false;
1248 }
1249 SHA256_Update(&ctx, block.data(), block.size());
1250 }
1251
1252 uint8_t out[32];
1253 SHA256_Final(out, &ctx);
1254 *hash = ToHexString(out, sizeof(out));
1255 return true;
1256 }
1257
1258 // Generate a snapshot that moves all the upper blocks down to the start.
1259 // It doesn't really matter the order, we just want copies that reference
1260 // blocks that won't exist if the partition shrinks.
ShiftAllSnapshotBlocks(const std::string & name,uint64_t old_size)1261 AssertionResult ShiftAllSnapshotBlocks(const std::string& name, uint64_t old_size) {
1262 std::unique_ptr<ICowWriter> writer;
1263 if (auto res = MapUpdateSnapshot(name, &writer); !res) {
1264 return res;
1265 }
1266 if (!writer->GetMaxBlocks() || !*writer->GetMaxBlocks()) {
1267 return AssertionFailure() << "No max blocks set for " << name << " writer";
1268 }
1269
1270 uint64_t src_block = (old_size / writer->GetBlockSize()) - 1;
1271 uint64_t dst_block = 0;
1272 uint64_t max_blocks = *writer->GetMaxBlocks();
1273 while (dst_block < max_blocks && dst_block < src_block) {
1274 if (!writer->AddCopy(dst_block, src_block)) {
1275 return AssertionFailure() << "Unable to add copy for " << name << " for blocks "
1276 << src_block << ", " << dst_block;
1277 }
1278 dst_block++;
1279 src_block--;
1280 }
1281 if (!writer->Finalize()) {
1282 return AssertionFailure() << "Unable to finalize writer for " << name;
1283 }
1284
1285 auto old_partition = "/dev/block/mapper/" + GetOtherPartitionName(name);
1286 auto reader = writer->OpenFileDescriptor(old_partition);
1287 if (!reader) {
1288 return AssertionFailure() << "Could not open file descriptor for " << name;
1289 }
1290
1291 auto hash = HashSnapshot(reader.get());
1292 if (hash.empty()) {
1293 return AssertionFailure() << "Unable to hash snapshot writer for " << name;
1294 }
1295 hashes_[name] = hash;
1296
1297 return AssertionSuccess();
1298 }
1299
MapUpdateSnapshots(const std::vector<std::string> & names={"sys_b", "vnd_b", "prd_b"})1300 AssertionResult MapUpdateSnapshots(const std::vector<std::string>& names = {"sys_b", "vnd_b",
1301 "prd_b"}) {
1302 for (const auto& name : names) {
1303 auto res = MapOneUpdateSnapshot(name);
1304 if (!res) {
1305 return res;
1306 }
1307 }
1308 return AssertionSuccess();
1309 }
1310
1311 // Create fake install operations to grow the COW device size.
AddOperation(PartitionUpdate * partition_update,uint64_t size_bytes=0)1312 void AddOperation(PartitionUpdate* partition_update, uint64_t size_bytes = 0) {
1313 auto e = partition_update->add_operations()->add_dst_extents();
1314 e->set_start_block(0);
1315 if (size_bytes == 0) {
1316 size_bytes = GetSize(partition_update);
1317 }
1318 e->set_num_blocks(size_bytes / manifest_.block_size());
1319 }
1320
AddOperationForPartitions(std::vector<PartitionUpdate * > partitions={})1321 void AddOperationForPartitions(std::vector<PartitionUpdate*> partitions = {}) {
1322 if (partitions.empty()) {
1323 partitions = {sys_, vnd_, prd_};
1324 }
1325 for (auto* partition : partitions) {
1326 AddOperation(partition);
1327 }
1328 }
1329
1330 std::unique_ptr<TestPartitionOpener> opener_;
1331 DeltaArchiveManifest manifest_;
1332 std::unique_ptr<MetadataBuilder> src_;
1333 std::map<std::string, std::string> hashes_;
1334
1335 PartitionUpdate* sys_ = nullptr;
1336 PartitionUpdate* vnd_ = nullptr;
1337 PartitionUpdate* prd_ = nullptr;
1338 DynamicPartitionGroup* group_ = nullptr;
1339 };
1340
1341 // Test full update flow executed by update_engine. Some partitions uses super empty space,
1342 // some uses images, and some uses both.
1343 // Also test UnmapUpdateSnapshot unmaps everything.
1344 // Also test first stage mount and merge after this.
TEST_F(SnapshotUpdateTest,FullUpdateFlow)1345 TEST_F(SnapshotUpdateTest, FullUpdateFlow) {
1346 // Grow all partitions. Set |prd| large enough that |sys| and |vnd|'s COWs
1347 // fit in super, but not |prd|.
1348 constexpr uint64_t partition_size = 3788_KiB;
1349 SetSize(sys_, partition_size);
1350 SetSize(vnd_, partition_size);
1351 SetSize(prd_, 18_MiB);
1352
1353 // Make sure |prd| does not fit in super at all. On VABC, this means we
1354 // fake an extra large COW for |vnd| to fill up super.
1355 vnd_->set_estimate_cow_size(30_MiB);
1356 prd_->set_estimate_cow_size(30_MiB);
1357
1358 AddOperationForPartitions();
1359
1360 // Execute the update.
1361 ASSERT_TRUE(sm->BeginUpdate());
1362 ASSERT_TRUE(sm->CreateUpdateSnapshots(manifest_));
1363
1364 // Test that partitions prioritize using space in super.
1365 auto tgt = MetadataBuilder::New(*opener_, "super", 1);
1366 ASSERT_NE(tgt, nullptr);
1367 ASSERT_NE(nullptr, tgt->FindPartition("sys_b-cow"));
1368 ASSERT_NE(nullptr, tgt->FindPartition("vnd_b-cow"));
1369 ASSERT_EQ(nullptr, tgt->FindPartition("prd_b-cow"));
1370
1371 // Write some data to target partitions.
1372 ASSERT_TRUE(WriteSnapshots());
1373
1374 // Assert that source partitions aren't affected.
1375 for (const auto& name : {"sys_a", "vnd_a", "prd_a"}) {
1376 ASSERT_TRUE(IsPartitionUnchanged(name));
1377 }
1378
1379 ASSERT_TRUE(sm->FinishedSnapshotWrites(false));
1380
1381 // Simulate shutting down the device.
1382 ASSERT_TRUE(UnmapAll());
1383
1384 // After reboot, init does first stage mount.
1385 auto init = NewManagerForFirstStageMount("_b");
1386 ASSERT_NE(init, nullptr);
1387 ASSERT_TRUE(init->NeedSnapshotsInFirstStageMount());
1388 ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
1389
1390 auto indicator = sm->GetRollbackIndicatorPath();
1391 ASSERT_NE(access(indicator.c_str(), R_OK), 0);
1392
1393 // Check that the target partitions have the same content.
1394 for (const auto& name : {"sys_b", "vnd_b", "prd_b"}) {
1395 ASSERT_TRUE(IsPartitionUnchanged(name));
1396 }
1397
1398 // Initiate the merge and wait for it to be completed.
1399 if (ShouldSkipLegacyMerging()) {
1400 LOG(INFO) << "Skipping legacy merge in test";
1401 return;
1402 }
1403 ASSERT_TRUE(init->InitiateMerge());
1404 ASSERT_EQ(init->IsSnapuserdRequired(), snapuserd_required_);
1405 {
1406 // We should have started in SECOND_PHASE since nothing shrinks.
1407 ASSERT_TRUE(AcquireLock());
1408 auto local_lock = std::move(lock_);
1409 auto status = init->ReadSnapshotUpdateStatus(local_lock.get());
1410 ASSERT_EQ(status.merge_phase(), MergePhase::SECOND_PHASE);
1411 }
1412 ASSERT_EQ(UpdateState::MergeCompleted, init->ProcessUpdateState());
1413
1414 // Make sure the second phase ran and deleted snapshots.
1415 {
1416 ASSERT_TRUE(AcquireLock());
1417 auto local_lock = std::move(lock_);
1418 std::vector<std::string> snapshots;
1419 ASSERT_TRUE(init->ListSnapshots(local_lock.get(), &snapshots));
1420 ASSERT_TRUE(snapshots.empty());
1421 }
1422
1423 // Check that the target partitions have the same content after the merge.
1424 for (const auto& name : {"sys_b", "vnd_b", "prd_b"}) {
1425 ASSERT_TRUE(IsPartitionUnchanged(name))
1426 << "Content of " << name << " changes after the merge";
1427 }
1428 }
1429
TEST_F(SnapshotUpdateTest,DuplicateOps)1430 TEST_F(SnapshotUpdateTest, DuplicateOps) {
1431 if (!snapuserd_required_) {
1432 GTEST_SKIP() << "snapuserd-only test";
1433 }
1434
1435 // Execute the update.
1436 ASSERT_TRUE(sm->BeginUpdate());
1437 ASSERT_TRUE(sm->CreateUpdateSnapshots(manifest_));
1438
1439 // Write some data to target partitions.
1440 ASSERT_TRUE(WriteSnapshots());
1441
1442 std::vector<PartitionUpdate*> partitions = {sys_, vnd_, prd_};
1443 for (auto* partition : partitions) {
1444 AddOperation(partition);
1445
1446 std::unique_ptr<ICowWriter> writer;
1447 auto res = MapUpdateSnapshot(partition->partition_name() + "_b", &writer);
1448 ASSERT_TRUE(res);
1449 ASSERT_TRUE(writer->AddZeroBlocks(0, 1));
1450 ASSERT_TRUE(writer->AddZeroBlocks(0, 1));
1451 ASSERT_TRUE(writer->Finalize());
1452 }
1453
1454 ASSERT_TRUE(sm->FinishedSnapshotWrites(false));
1455
1456 // Simulate shutting down the device.
1457 ASSERT_TRUE(UnmapAll());
1458
1459 // After reboot, init does first stage mount.
1460 auto init = NewManagerForFirstStageMount("_b");
1461 ASSERT_NE(init, nullptr);
1462 ASSERT_TRUE(init->NeedSnapshotsInFirstStageMount());
1463 ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
1464
1465 // Initiate the merge and wait for it to be completed.
1466 if (ShouldSkipLegacyMerging()) {
1467 LOG(INFO) << "Skipping legacy merge in test";
1468 return;
1469 }
1470 ASSERT_TRUE(init->InitiateMerge());
1471 ASSERT_EQ(UpdateState::MergeCompleted, init->ProcessUpdateState());
1472 }
1473
1474 // Test that shrinking and growing partitions at the same time is handled
1475 // correctly in VABC.
TEST_F(SnapshotUpdateTest,SpaceSwapUpdate)1476 TEST_F(SnapshotUpdateTest, SpaceSwapUpdate) {
1477 if (!snapuserd_required_) {
1478 // b/179111359
1479 GTEST_SKIP() << "Skipping snapuserd test";
1480 }
1481
1482 auto old_sys_size = GetSize(sys_);
1483 auto old_prd_size = GetSize(prd_);
1484
1485 // Grow |sys| but shrink |prd|.
1486 SetSize(sys_, old_sys_size * 2);
1487 sys_->set_estimate_cow_size(8_MiB);
1488 SetSize(prd_, old_prd_size / 2);
1489 prd_->set_estimate_cow_size(1_MiB);
1490
1491 AddOperationForPartitions();
1492
1493 ASSERT_TRUE(sm->BeginUpdate());
1494 ASSERT_TRUE(sm->CreateUpdateSnapshots(manifest_));
1495
1496 // Check that the old partition sizes were saved correctly.
1497 {
1498 ASSERT_TRUE(AcquireLock());
1499 auto local_lock = std::move(lock_);
1500
1501 SnapshotStatus status;
1502 ASSERT_TRUE(sm->ReadSnapshotStatus(local_lock.get(), "prd_b", &status));
1503 ASSERT_EQ(status.old_partition_size(), 3145728);
1504 ASSERT_TRUE(sm->ReadSnapshotStatus(local_lock.get(), "sys_b", &status));
1505 ASSERT_EQ(status.old_partition_size(), 3145728);
1506 }
1507
1508 ASSERT_TRUE(WriteSnapshotAndHash(sys_));
1509 ASSERT_TRUE(WriteSnapshotAndHash(vnd_));
1510 ASSERT_TRUE(ShiftAllSnapshotBlocks("prd_b", old_prd_size));
1511
1512 sync();
1513
1514 // Assert that source partitions aren't affected.
1515 for (const auto& name : {"sys_a", "vnd_a", "prd_a"}) {
1516 ASSERT_TRUE(IsPartitionUnchanged(name));
1517 }
1518
1519 ASSERT_TRUE(sm->FinishedSnapshotWrites(false));
1520
1521 // Simulate shutting down the device.
1522 ASSERT_TRUE(UnmapAll());
1523
1524 // After reboot, init does first stage mount.
1525 auto init = NewManagerForFirstStageMount("_b");
1526 ASSERT_NE(init, nullptr);
1527 ASSERT_TRUE(init->NeedSnapshotsInFirstStageMount());
1528 ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
1529
1530 auto indicator = sm->GetRollbackIndicatorPath();
1531 ASSERT_NE(access(indicator.c_str(), R_OK), 0);
1532
1533 // Check that the target partitions have the same content.
1534 for (const auto& name : {"sys_b", "vnd_b", "prd_b"}) {
1535 ASSERT_TRUE(IsPartitionUnchanged(name));
1536 }
1537
1538 // Initiate the merge and wait for it to be completed.
1539 if (ShouldSkipLegacyMerging()) {
1540 LOG(INFO) << "Skipping legacy merge in test";
1541 return;
1542 }
1543 ASSERT_TRUE(init->InitiateMerge());
1544 ASSERT_EQ(init->IsSnapuserdRequired(), snapuserd_required_);
1545 {
1546 // Check that the merge phase is FIRST_PHASE until at least one call
1547 // to ProcessUpdateState() occurs.
1548 ASSERT_TRUE(AcquireLock());
1549 auto local_lock = std::move(lock_);
1550 auto status = init->ReadSnapshotUpdateStatus(local_lock.get());
1551 ASSERT_EQ(status.merge_phase(), MergePhase::FIRST_PHASE);
1552 }
1553
1554 // Simulate shutting down the device and creating partitions again.
1555 ASSERT_TRUE(UnmapAll());
1556 ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
1557
1558 // Check that we used the correct types after rebooting mid-merge.
1559 DeviceMapper::TargetInfo target;
1560 ASSERT_TRUE(init->IsSnapshotDevice("prd_b", &target));
1561
1562 bool userspace_snapshots = init->UpdateUsesUserSnapshots();
1563 if (userspace_snapshots) {
1564 ASSERT_EQ(DeviceMapper::GetTargetType(target.spec), "user");
1565 ASSERT_TRUE(init->IsSnapshotDevice("sys_b", &target));
1566 ASSERT_EQ(DeviceMapper::GetTargetType(target.spec), "user");
1567 ASSERT_TRUE(init->IsSnapshotDevice("vnd_b", &target));
1568 ASSERT_EQ(DeviceMapper::GetTargetType(target.spec), "user");
1569 } else {
1570 ASSERT_EQ(DeviceMapper::GetTargetType(target.spec), "snapshot-merge");
1571 ASSERT_TRUE(init->IsSnapshotDevice("sys_b", &target));
1572 ASSERT_EQ(DeviceMapper::GetTargetType(target.spec), "snapshot");
1573 ASSERT_TRUE(init->IsSnapshotDevice("vnd_b", &target));
1574 ASSERT_EQ(DeviceMapper::GetTargetType(target.spec), "snapshot");
1575 }
1576
1577 // Complete the merge.
1578 ASSERT_EQ(UpdateState::MergeCompleted, init->ProcessUpdateState());
1579
1580 // Make sure the second phase ran and deleted snapshots.
1581 {
1582 ASSERT_TRUE(AcquireLock());
1583 auto local_lock = std::move(lock_);
1584 std::vector<std::string> snapshots;
1585 ASSERT_TRUE(init->ListSnapshots(local_lock.get(), &snapshots));
1586 ASSERT_TRUE(snapshots.empty());
1587 }
1588
1589 // Check that the target partitions have the same content after the merge.
1590 for (const auto& name : {"sys_b", "vnd_b", "prd_b"}) {
1591 ASSERT_TRUE(IsPartitionUnchanged(name))
1592 << "Content of " << name << " changes after the merge";
1593 }
1594 }
1595
1596 // Test that if new system partitions uses empty space in super, that region is not snapshotted.
TEST_F(SnapshotUpdateTest,DirectWriteEmptySpace)1597 TEST_F(SnapshotUpdateTest, DirectWriteEmptySpace) {
1598 GTEST_SKIP() << "b/141889746";
1599 SetSize(sys_, 4_MiB);
1600 // vnd_b and prd_b are unchanged.
1601 ASSERT_TRUE(sm->CreateUpdateSnapshots(manifest_));
1602 ASSERT_EQ(3_MiB, GetSnapshotSize("sys_b").value_or(0));
1603 }
1604
1605 // Test that if new system partitions uses space of old vendor partition, that region is
1606 // snapshotted.
TEST_F(SnapshotUpdateTest,SnapshotOldPartitions)1607 TEST_F(SnapshotUpdateTest, SnapshotOldPartitions) {
1608 SetSize(sys_, 4_MiB); // grows
1609 SetSize(vnd_, 2_MiB); // shrinks
1610 // prd_b is unchanged
1611 ASSERT_TRUE(sm->BeginUpdate());
1612 ASSERT_TRUE(sm->CreateUpdateSnapshots(manifest_));
1613 ASSERT_EQ(4_MiB, GetSnapshotSize("sys_b").value_or(0));
1614 }
1615
1616 // Test that even if there seem to be empty space in target metadata, COW partition won't take
1617 // it because they are used by old partitions.
TEST_F(SnapshotUpdateTest,CowPartitionDoNotTakeOldPartitions)1618 TEST_F(SnapshotUpdateTest, CowPartitionDoNotTakeOldPartitions) {
1619 SetSize(sys_, 2_MiB); // shrinks
1620 // vnd_b and prd_b are unchanged.
1621 ASSERT_TRUE(sm->BeginUpdate());
1622 ASSERT_TRUE(sm->CreateUpdateSnapshots(manifest_));
1623
1624 auto tgt = MetadataBuilder::New(*opener_, "super", 1);
1625 ASSERT_NE(nullptr, tgt);
1626 auto metadata = tgt->Export();
1627 ASSERT_NE(nullptr, metadata);
1628 std::vector<std::string> written;
1629 // Write random data to all COW partitions in super
1630 for (auto p : metadata->partitions) {
1631 if (GetPartitionGroupName(metadata->groups[p.group_index]) != kCowGroupName) {
1632 continue;
1633 }
1634 std::string path;
1635 ASSERT_TRUE(CreateLogicalPartition(
1636 CreateLogicalPartitionParams{
1637 .block_device = fake_super,
1638 .metadata = metadata.get(),
1639 .partition = &p,
1640 .timeout_ms = 1s,
1641 .partition_opener = opener_.get(),
1642 },
1643 &path));
1644 ASSERT_TRUE(WriteRandomData(path));
1645 written.push_back(GetPartitionName(p));
1646 }
1647 ASSERT_FALSE(written.empty())
1648 << "No COW partitions are created even if there are empty space in super partition";
1649
1650 // Make sure source partitions aren't affected.
1651 for (const auto& name : {"sys_a", "vnd_a", "prd_a"}) {
1652 ASSERT_TRUE(IsPartitionUnchanged(name));
1653 }
1654 }
1655
1656 // Test that it crashes after creating snapshot status file but before creating COW image, then
1657 // calling CreateUpdateSnapshots again works.
TEST_F(SnapshotUpdateTest,SnapshotStatusFileWithoutCow)1658 TEST_F(SnapshotUpdateTest, SnapshotStatusFileWithoutCow) {
1659 // Write some trash snapshot files to simulate leftovers from previous runs.
1660 {
1661 ASSERT_TRUE(AcquireLock());
1662 auto local_lock = std::move(lock_);
1663 SnapshotStatus status;
1664 status.set_name("sys_b");
1665 ASSERT_TRUE(sm->WriteSnapshotStatus(local_lock.get(), status));
1666 ASSERT_TRUE(image_manager_->CreateBackingImage("sys_b-cow-img", 1_MiB,
1667 IImageManager::CREATE_IMAGE_DEFAULT));
1668 }
1669
1670 // Redo the update.
1671 ASSERT_TRUE(sm->BeginUpdate());
1672 ASSERT_TRUE(sm->UnmapUpdateSnapshot("sys_b"));
1673
1674 ASSERT_TRUE(sm->CreateUpdateSnapshots(manifest_));
1675
1676 // Check that target partitions can be mapped.
1677 EXPECT_TRUE(MapUpdateSnapshots());
1678 }
1679
1680 // Test that the old partitions are not modified.
TEST_F(SnapshotUpdateTest,TestRollback)1681 TEST_F(SnapshotUpdateTest, TestRollback) {
1682 // Execute the update.
1683 ASSERT_TRUE(sm->BeginUpdate());
1684 ASSERT_TRUE(sm->UnmapUpdateSnapshot("sys_b"));
1685
1686 AddOperationForPartitions();
1687
1688 ASSERT_TRUE(sm->CreateUpdateSnapshots(manifest_));
1689
1690 // Write some data to target partitions.
1691 ASSERT_TRUE(WriteSnapshots());
1692
1693 // Assert that source partitions aren't affected.
1694 for (const auto& name : {"sys_a", "vnd_a", "prd_a"}) {
1695 ASSERT_TRUE(IsPartitionUnchanged(name));
1696 }
1697
1698 ASSERT_TRUE(sm->FinishedSnapshotWrites(false));
1699
1700 // Simulate shutting down the device.
1701 ASSERT_TRUE(UnmapAll());
1702
1703 // After reboot, init does first stage mount.
1704 auto init = NewManagerForFirstStageMount("_b");
1705 ASSERT_NE(init, nullptr);
1706 ASSERT_TRUE(init->NeedSnapshotsInFirstStageMount());
1707 ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
1708
1709 // Check that the target partitions have the same content.
1710 for (const auto& name : {"sys_b", "vnd_b", "prd_b"}) {
1711 ASSERT_TRUE(IsPartitionUnchanged(name));
1712 }
1713
1714 // Simulate shutting down the device again.
1715 ASSERT_TRUE(UnmapAll());
1716 init = NewManagerForFirstStageMount("_a");
1717 ASSERT_NE(init, nullptr);
1718 ASSERT_FALSE(init->NeedSnapshotsInFirstStageMount());
1719 ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
1720
1721 // Assert that the source partitions aren't affected.
1722 for (const auto& name : {"sys_a", "vnd_a", "prd_a"}) {
1723 ASSERT_TRUE(IsPartitionUnchanged(name));
1724 }
1725 }
1726
1727 // Test that if an update is applied but not booted into, it can be canceled.
TEST_F(SnapshotUpdateTest,CancelAfterApply)1728 TEST_F(SnapshotUpdateTest, CancelAfterApply) {
1729 ASSERT_TRUE(sm->BeginUpdate());
1730 ASSERT_TRUE(sm->FinishedSnapshotWrites(false));
1731 ASSERT_TRUE(sm->CancelUpdate());
1732 }
1733
ToIntervals(const std::vector<std::unique_ptr<Extent>> & extents)1734 static std::vector<Interval> ToIntervals(const std::vector<std::unique_ptr<Extent>>& extents) {
1735 std::vector<Interval> ret;
1736 std::transform(extents.begin(), extents.end(), std::back_inserter(ret),
1737 [](const auto& extent) { return extent->AsLinearExtent()->AsInterval(); });
1738 return ret;
1739 }
1740
1741 // Test that at the second update, old COW partition spaces are reclaimed.
TEST_F(SnapshotUpdateTest,ReclaimCow)1742 TEST_F(SnapshotUpdateTest, ReclaimCow) {
1743 // Make sure VABC cows are small enough that they fit in fake_super.
1744 sys_->set_estimate_cow_size(64_KiB);
1745 vnd_->set_estimate_cow_size(64_KiB);
1746 prd_->set_estimate_cow_size(64_KiB);
1747
1748 // Execute the first update.
1749 ASSERT_TRUE(sm->BeginUpdate());
1750 ASSERT_TRUE(sm->CreateUpdateSnapshots(manifest_));
1751 ASSERT_TRUE(MapUpdateSnapshots());
1752 ASSERT_TRUE(sm->FinishedSnapshotWrites(false));
1753
1754 // Simulate shutting down the device.
1755 ASSERT_TRUE(UnmapAll());
1756
1757 // After reboot, init does first stage mount.
1758 auto init = NewManagerForFirstStageMount("_b");
1759 ASSERT_NE(init, nullptr);
1760 ASSERT_TRUE(init->NeedSnapshotsInFirstStageMount());
1761 ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
1762 init = nullptr;
1763
1764 // Initiate the merge and wait for it to be completed.
1765 auto new_sm = SnapshotManager::New(new TestDeviceInfo(fake_super, "_b"));
1766 if (ShouldSkipLegacyMerging()) {
1767 LOG(INFO) << "Skipping legacy merge in test";
1768 return;
1769 }
1770 ASSERT_TRUE(new_sm->InitiateMerge());
1771 ASSERT_EQ(UpdateState::MergeCompleted, new_sm->ProcessUpdateState());
1772
1773 // Execute the second update.
1774 ASSERT_TRUE(new_sm->BeginUpdate());
1775 ASSERT_TRUE(new_sm->CreateUpdateSnapshots(manifest_));
1776
1777 // Check that the old COW space is reclaimed and does not occupy space of mapped partitions.
1778 auto src = MetadataBuilder::New(*opener_, "super", 1);
1779 ASSERT_NE(src, nullptr);
1780 auto tgt = MetadataBuilder::New(*opener_, "super", 0);
1781 ASSERT_NE(tgt, nullptr);
1782 for (const auto& cow_part_name : {"sys_a-cow", "vnd_a-cow", "prd_a-cow"}) {
1783 auto* cow_part = tgt->FindPartition(cow_part_name);
1784 ASSERT_NE(nullptr, cow_part) << cow_part_name << " does not exist in target metadata";
1785 auto cow_intervals = ToIntervals(cow_part->extents());
1786 for (const auto& old_part_name : {"sys_b", "vnd_b", "prd_b"}) {
1787 auto* old_part = src->FindPartition(old_part_name);
1788 ASSERT_NE(nullptr, old_part) << old_part_name << " does not exist in source metadata";
1789 auto old_intervals = ToIntervals(old_part->extents());
1790
1791 auto intersect = Interval::Intersect(cow_intervals, old_intervals);
1792 ASSERT_TRUE(intersect.empty()) << "COW uses space of source partitions";
1793 }
1794 }
1795 }
1796
TEST_F(SnapshotUpdateTest,RetrofitAfterRegularAb)1797 TEST_F(SnapshotUpdateTest, RetrofitAfterRegularAb) {
1798 constexpr auto kRetrofitGroupSize = kGroupSize / 2;
1799
1800 // Initialize device-mapper / disk
1801 ASSERT_TRUE(UnmapAll());
1802 FormatFakeSuper();
1803
1804 // Setup source partition metadata to have both _a and _b partitions.
1805 src_ = MetadataBuilder::New(*opener_, "super", 0);
1806 ASSERT_NE(nullptr, src_);
1807 for (const auto& suffix : {"_a"s, "_b"s}) {
1808 ASSERT_TRUE(src_->AddGroup(group_->name() + suffix, kRetrofitGroupSize));
1809 for (const auto& name : {"sys"s, "vnd"s, "prd"s}) {
1810 auto partition = src_->AddPartition(name + suffix, group_->name() + suffix, 0);
1811 ASSERT_NE(nullptr, partition);
1812 ASSERT_TRUE(src_->ResizePartition(partition, 2_MiB));
1813 }
1814 }
1815 auto metadata = src_->Export();
1816 ASSERT_NE(nullptr, metadata);
1817 ASSERT_TRUE(UpdatePartitionTable(*opener_, "super", *metadata.get(), 0));
1818
1819 // Flash source partitions
1820 std::string path;
1821 for (const auto& name : {"sys_a", "vnd_a", "prd_a"}) {
1822 ASSERT_TRUE(CreateLogicalPartition(
1823 CreateLogicalPartitionParams{
1824 .block_device = fake_super,
1825 .metadata_slot = 0,
1826 .partition_name = name,
1827 .timeout_ms = 1s,
1828 .partition_opener = opener_.get(),
1829 },
1830 &path));
1831 ASSERT_TRUE(WriteRandomData(path));
1832 auto hash = GetHash(path);
1833 ASSERT_TRUE(hash.has_value());
1834 hashes_[name] = *hash;
1835 }
1836
1837 // Setup manifest.
1838 group_->set_size(kRetrofitGroupSize);
1839 for (auto* partition : {sys_, vnd_, prd_}) {
1840 SetSize(partition, 2_MiB);
1841 }
1842 AddOperationForPartitions();
1843
1844 ASSERT_TRUE(sm->BeginUpdate());
1845 ASSERT_TRUE(sm->CreateUpdateSnapshots(manifest_));
1846
1847 // Test that COW image should not be created for retrofit devices; super
1848 // should be big enough.
1849 ASSERT_FALSE(image_manager_->BackingImageExists("sys_b-cow-img"));
1850 ASSERT_FALSE(image_manager_->BackingImageExists("vnd_b-cow-img"));
1851 ASSERT_FALSE(image_manager_->BackingImageExists("prd_b-cow-img"));
1852
1853 // Write some data to target partitions.
1854 ASSERT_TRUE(WriteSnapshots());
1855
1856 // Assert that source partitions aren't affected.
1857 for (const auto& name : {"sys_a", "vnd_a", "prd_a"}) {
1858 ASSERT_TRUE(IsPartitionUnchanged(name));
1859 }
1860
1861 ASSERT_TRUE(sm->FinishedSnapshotWrites(false));
1862 }
1863
TEST_F(SnapshotUpdateTest,MergeCannotRemoveCow)1864 TEST_F(SnapshotUpdateTest, MergeCannotRemoveCow) {
1865 // Make source partitions as big as possible to force COW image to be created.
1866 SetSize(sys_, 10_MiB);
1867 SetSize(vnd_, 10_MiB);
1868 SetSize(prd_, 10_MiB);
1869 sys_->set_estimate_cow_size(12_MiB);
1870 vnd_->set_estimate_cow_size(12_MiB);
1871 prd_->set_estimate_cow_size(12_MiB);
1872
1873 src_ = MetadataBuilder::New(*opener_, "super", 0);
1874 ASSERT_NE(src_, nullptr);
1875 src_->RemoveGroupAndPartitions(group_->name() + "_a");
1876 src_->RemoveGroupAndPartitions(group_->name() + "_b");
1877 ASSERT_TRUE(FillFakeMetadata(src_.get(), manifest_, "_a"));
1878 auto metadata = src_->Export();
1879 ASSERT_NE(nullptr, metadata);
1880 ASSERT_TRUE(UpdatePartitionTable(*opener_, "super", *metadata.get(), 0));
1881
1882 // Add operations for sys. The whole device is written.
1883 AddOperation(sys_);
1884
1885 // Execute the update.
1886 ASSERT_TRUE(sm->BeginUpdate());
1887 ASSERT_TRUE(sm->CreateUpdateSnapshots(manifest_));
1888 ASSERT_TRUE(MapUpdateSnapshots());
1889 ASSERT_TRUE(sm->FinishedSnapshotWrites(false));
1890
1891 // Simulate shutting down the device.
1892 ASSERT_TRUE(UnmapAll());
1893
1894 // After reboot, init does first stage mount.
1895 // Normally we should use NewManagerForFirstStageMount, but if so,
1896 // "gsid.mapped_image.sys_b-cow-img" won't be set.
1897 auto init = SnapshotManager::New(new TestDeviceInfo(fake_super, "_b"));
1898 ASSERT_NE(init, nullptr);
1899 ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
1900
1901 // Keep an open handle to the cow device. This should cause the merge to
1902 // be incomplete.
1903 auto cow_path = android::base::GetProperty("gsid.mapped_image.sys_b-cow-img", "");
1904 unique_fd fd(open(cow_path.c_str(), O_RDONLY | O_CLOEXEC));
1905 ASSERT_GE(fd, 0);
1906
1907 // COW cannot be removed due to open fd, so expect a soft failure.
1908 if (ShouldSkipLegacyMerging()) {
1909 LOG(INFO) << "Skipping legacy merge in test";
1910 return;
1911 }
1912 ASSERT_TRUE(init->InitiateMerge());
1913 ASSERT_EQ(UpdateState::MergeNeedsReboot, init->ProcessUpdateState());
1914
1915 // Simulate shutting down the device.
1916 fd.reset();
1917 ASSERT_TRUE(UnmapAll());
1918
1919 // init does first stage mount again.
1920 ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
1921
1922 // sys_b should be mapped as a dm-linear device directly.
1923 ASSERT_FALSE(sm->IsSnapshotDevice("sys_b", nullptr));
1924
1925 // Merge should be able to complete now.
1926 ASSERT_EQ(UpdateState::MergeCompleted, init->ProcessUpdateState());
1927 }
1928
1929 class MetadataMountedTest : public ::testing::Test {
1930 public:
1931 // This is so main() can instantiate this to invoke Cleanup.
TestBody()1932 virtual void TestBody() override {}
SetUp()1933 void SetUp() override {
1934 SKIP_IF_NON_VIRTUAL_AB();
1935 metadata_dir_ = test_device->GetMetadataDir();
1936 ASSERT_TRUE(ReadDefaultFstab(&fstab_));
1937 }
TearDown()1938 void TearDown() override {
1939 RETURN_IF_NON_VIRTUAL_AB();
1940 SetUp();
1941 // Remount /metadata
1942 test_device->set_recovery(false);
1943 EXPECT_TRUE(android::fs_mgr::EnsurePathMounted(&fstab_, metadata_dir_));
1944 }
IsMetadataMounted()1945 AssertionResult IsMetadataMounted() {
1946 Fstab mounted_fstab;
1947 if (!ReadFstabFromFile("/proc/mounts", &mounted_fstab)) {
1948 ADD_FAILURE() << "Failed to scan mounted volumes";
1949 return AssertionFailure() << "Failed to scan mounted volumes";
1950 }
1951
1952 auto entry = GetEntryForPath(&fstab_, metadata_dir_);
1953 if (entry == nullptr) {
1954 return AssertionFailure() << "No mount point found in fstab for path " << metadata_dir_;
1955 }
1956
1957 auto mv = GetEntryForMountPoint(&mounted_fstab, entry->mount_point);
1958 if (mv == nullptr) {
1959 return AssertionFailure() << metadata_dir_ << " is not mounted";
1960 }
1961 return AssertionSuccess() << metadata_dir_ << " is mounted";
1962 }
1963 std::string metadata_dir_;
1964 Fstab fstab_;
1965 };
1966
MountMetadata()1967 void MountMetadata() {
1968 MetadataMountedTest().TearDown();
1969 }
1970
TEST_F(MetadataMountedTest,Android)1971 TEST_F(MetadataMountedTest, Android) {
1972 auto device = sm->EnsureMetadataMounted();
1973 EXPECT_NE(nullptr, device);
1974 device.reset();
1975
1976 EXPECT_TRUE(IsMetadataMounted());
1977 EXPECT_TRUE(sm->CancelUpdate()) << "Metadata dir should never be unmounted in Android mode";
1978 }
1979
TEST_F(MetadataMountedTest,Recovery)1980 TEST_F(MetadataMountedTest, Recovery) {
1981 test_device->set_recovery(true);
1982 metadata_dir_ = test_device->GetMetadataDir();
1983
1984 EXPECT_TRUE(android::fs_mgr::EnsurePathUnmounted(&fstab_, metadata_dir_));
1985 EXPECT_FALSE(IsMetadataMounted());
1986
1987 auto device = sm->EnsureMetadataMounted();
1988 EXPECT_NE(nullptr, device);
1989 EXPECT_TRUE(IsMetadataMounted());
1990
1991 device.reset();
1992 EXPECT_FALSE(IsMetadataMounted());
1993 }
1994
1995 // Test that during a merge, we can wipe data in recovery.
TEST_F(SnapshotUpdateTest,MergeInRecovery)1996 TEST_F(SnapshotUpdateTest, MergeInRecovery) {
1997 // Execute the first update.
1998 ASSERT_TRUE(sm->BeginUpdate());
1999 ASSERT_TRUE(sm->CreateUpdateSnapshots(manifest_));
2000 ASSERT_TRUE(MapUpdateSnapshots());
2001 ASSERT_TRUE(sm->FinishedSnapshotWrites(false));
2002
2003 // Simulate shutting down the device.
2004 ASSERT_TRUE(UnmapAll());
2005
2006 // After reboot, init does first stage mount.
2007 auto init = NewManagerForFirstStageMount("_b");
2008 ASSERT_NE(init, nullptr);
2009 ASSERT_TRUE(init->NeedSnapshotsInFirstStageMount());
2010 ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
2011 init = nullptr;
2012
2013 // Initiate the merge and then immediately stop it to simulate a reboot.
2014 auto new_sm = SnapshotManager::New(new TestDeviceInfo(fake_super, "_b"));
2015 if (ShouldSkipLegacyMerging()) {
2016 LOG(INFO) << "Skipping legacy merge in test";
2017 return;
2018 }
2019 ASSERT_TRUE(new_sm->InitiateMerge());
2020 ASSERT_TRUE(UnmapAll());
2021
2022 // Simulate a reboot into recovery.
2023 auto test_device = std::make_unique<TestDeviceInfo>(fake_super, "_b");
2024 test_device->set_recovery(true);
2025 new_sm = NewManagerForFirstStageMount(test_device.release());
2026
2027 ASSERT_TRUE(new_sm->HandleImminentDataWipe());
2028 ASSERT_EQ(new_sm->GetUpdateState(), UpdateState::None);
2029 }
2030
2031 // Test that a merge does not clear the snapshot state in fastboot.
TEST_F(SnapshotUpdateTest,MergeInFastboot)2032 TEST_F(SnapshotUpdateTest, MergeInFastboot) {
2033 // Execute the first update.
2034 ASSERT_TRUE(sm->BeginUpdate());
2035 ASSERT_TRUE(sm->CreateUpdateSnapshots(manifest_));
2036 ASSERT_TRUE(MapUpdateSnapshots());
2037 ASSERT_TRUE(sm->FinishedSnapshotWrites(false));
2038
2039 // Simulate shutting down the device.
2040 ASSERT_TRUE(UnmapAll());
2041
2042 // After reboot, init does first stage mount.
2043 auto init = NewManagerForFirstStageMount("_b");
2044 ASSERT_NE(init, nullptr);
2045 ASSERT_TRUE(init->NeedSnapshotsInFirstStageMount());
2046 ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
2047 init = nullptr;
2048
2049 // Initiate the merge and then immediately stop it to simulate a reboot.
2050 auto new_sm = SnapshotManager::New(new TestDeviceInfo(fake_super, "_b"));
2051 if (ShouldSkipLegacyMerging()) {
2052 LOG(INFO) << "Skipping legacy merge in test";
2053 return;
2054 }
2055 ASSERT_TRUE(new_sm->InitiateMerge());
2056 ASSERT_TRUE(UnmapAll());
2057
2058 // Simulate a reboot into recovery.
2059 auto test_device = std::make_unique<TestDeviceInfo>(fake_super, "_b");
2060 test_device->set_recovery(true);
2061 new_sm = NewManagerForFirstStageMount(test_device.release());
2062
2063 ASSERT_TRUE(new_sm->FinishMergeInRecovery());
2064
2065 ASSERT_TRUE(UnmapAll());
2066
2067 auto mount = new_sm->EnsureMetadataMounted();
2068 ASSERT_TRUE(mount && mount->HasDevice());
2069 ASSERT_EQ(new_sm->ProcessUpdateState(), UpdateState::MergeCompleted);
2070
2071 // Finish the merge in a normal boot.
2072 test_device = std::make_unique<TestDeviceInfo>(fake_super, "_b");
2073 init = NewManagerForFirstStageMount(test_device.release());
2074 ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
2075 init = nullptr;
2076
2077 test_device = std::make_unique<TestDeviceInfo>(fake_super, "_b");
2078 new_sm = NewManagerForFirstStageMount(test_device.release());
2079 ASSERT_EQ(new_sm->ProcessUpdateState(), UpdateState::MergeCompleted);
2080 ASSERT_EQ(new_sm->ProcessUpdateState(), UpdateState::None);
2081 }
2082
2083 // Test that after an OTA, before a merge, we can wipe data in recovery.
TEST_F(SnapshotUpdateTest,DataWipeRollbackInRecovery)2084 TEST_F(SnapshotUpdateTest, DataWipeRollbackInRecovery) {
2085 // Execute the first update.
2086 ASSERT_TRUE(sm->BeginUpdate());
2087 ASSERT_TRUE(sm->CreateUpdateSnapshots(manifest_));
2088 ASSERT_TRUE(MapUpdateSnapshots());
2089 ASSERT_TRUE(sm->FinishedSnapshotWrites(false));
2090
2091 // Simulate shutting down the device.
2092 ASSERT_TRUE(UnmapAll());
2093
2094 // Simulate a reboot into recovery.
2095 auto test_device = new TestDeviceInfo(fake_super, "_b");
2096 test_device->set_recovery(true);
2097 auto new_sm = NewManagerForFirstStageMount(test_device);
2098
2099 ASSERT_TRUE(new_sm->HandleImminentDataWipe());
2100 // Manually mount metadata so that we can call GetUpdateState() below.
2101 MountMetadata();
2102 EXPECT_EQ(new_sm->GetUpdateState(), UpdateState::None);
2103 EXPECT_TRUE(test_device->IsSlotUnbootable(1));
2104 EXPECT_FALSE(test_device->IsSlotUnbootable(0));
2105 }
2106
2107 // Test that after an OTA and a bootloader rollback with no merge, we can wipe
2108 // data in recovery.
TEST_F(SnapshotUpdateTest,DataWipeAfterRollback)2109 TEST_F(SnapshotUpdateTest, DataWipeAfterRollback) {
2110 // Execute the first update.
2111 ASSERT_TRUE(sm->BeginUpdate());
2112 ASSERT_TRUE(sm->CreateUpdateSnapshots(manifest_));
2113 ASSERT_TRUE(MapUpdateSnapshots());
2114 ASSERT_TRUE(sm->FinishedSnapshotWrites(false));
2115
2116 // Simulate shutting down the device.
2117 ASSERT_TRUE(UnmapAll());
2118
2119 // Simulate a rollback, with reboot into recovery.
2120 auto test_device = new TestDeviceInfo(fake_super, "_a");
2121 test_device->set_recovery(true);
2122 auto new_sm = NewManagerForFirstStageMount(test_device);
2123
2124 ASSERT_TRUE(new_sm->HandleImminentDataWipe());
2125 EXPECT_EQ(new_sm->GetUpdateState(), UpdateState::None);
2126 EXPECT_FALSE(test_device->IsSlotUnbootable(0));
2127 EXPECT_FALSE(test_device->IsSlotUnbootable(1));
2128 }
2129
2130 // Test update package that requests data wipe.
TEST_F(SnapshotUpdateTest,DataWipeRequiredInPackage)2131 TEST_F(SnapshotUpdateTest, DataWipeRequiredInPackage) {
2132 if (ShouldSkipLegacyMerging()) {
2133 GTEST_SKIP() << "Skipping legacy merge in test";
2134 }
2135
2136 AddOperationForPartitions();
2137 // Execute the update.
2138 ASSERT_TRUE(sm->BeginUpdate());
2139 ASSERT_TRUE(sm->CreateUpdateSnapshots(manifest_));
2140
2141 // Write some data to target partitions.
2142 ASSERT_TRUE(WriteSnapshots());
2143
2144 ASSERT_TRUE(sm->FinishedSnapshotWrites(true /* wipe */));
2145
2146 // Simulate shutting down the device.
2147 ASSERT_TRUE(UnmapAll());
2148
2149 // Simulate a reboot into recovery.
2150 auto test_device = new TestDeviceInfo(fake_super, "_b");
2151 test_device->set_recovery(true);
2152 auto new_sm = NewManagerForFirstStageMount(test_device);
2153
2154 ASSERT_TRUE(new_sm->HandleImminentDataWipe());
2155 // Manually mount metadata so that we can call GetUpdateState() below.
2156 MountMetadata();
2157 EXPECT_EQ(new_sm->GetUpdateState(), UpdateState::None);
2158 ASSERT_FALSE(test_device->IsSlotUnbootable(1));
2159 ASSERT_FALSE(test_device->IsSlotUnbootable(0));
2160
2161 ASSERT_TRUE(UnmapAll());
2162
2163 // Now reboot into new slot.
2164 test_device = new TestDeviceInfo(fake_super, "_b");
2165 auto init = NewManagerForFirstStageMount(test_device);
2166 ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
2167 // Verify that we are on the downgraded build.
2168 for (const auto& name : {"sys_b", "vnd_b", "prd_b"}) {
2169 ASSERT_TRUE(IsPartitionUnchanged(name)) << name;
2170 }
2171 }
2172
2173 // Test update package that requests data wipe.
TEST_F(SnapshotUpdateTest,DataWipeWithStaleSnapshots)2174 TEST_F(SnapshotUpdateTest, DataWipeWithStaleSnapshots) {
2175 if (ShouldSkipLegacyMerging()) {
2176 GTEST_SKIP() << "Skipping legacy merge in test";
2177 }
2178
2179 AddOperationForPartitions();
2180
2181 // Execute the update.
2182 ASSERT_TRUE(sm->BeginUpdate());
2183 ASSERT_TRUE(sm->CreateUpdateSnapshots(manifest_));
2184
2185 // Write some data to target partitions.
2186 ASSERT_TRUE(WriteSnapshots());
2187
2188 // Create a stale snapshot that should not exist.
2189 {
2190 ASSERT_TRUE(AcquireLock());
2191
2192 PartitionCowCreator cow_creator = {
2193 .using_snapuserd = snapuserd_required_,
2194 .compression_algorithm = snapuserd_required_ ? FLAGS_compression_method : "",
2195 };
2196 SnapshotStatus status;
2197 status.set_name("sys_a");
2198 status.set_device_size(1_MiB);
2199 status.set_snapshot_size(2_MiB);
2200 status.set_cow_partition_size(2_MiB);
2201
2202 ASSERT_TRUE(sm->CreateSnapshot(lock_.get(), &cow_creator, &status));
2203 lock_ = nullptr;
2204
2205 ASSERT_TRUE(sm->EnsureImageManager());
2206 ASSERT_TRUE(sm->image_manager()->CreateBackingImage("sys_a", 1_MiB, 0));
2207 }
2208
2209 ASSERT_TRUE(sm->FinishedSnapshotWrites(true /* wipe */));
2210
2211 // Simulate shutting down the device.
2212 ASSERT_TRUE(UnmapAll());
2213
2214 // Simulate a reboot into recovery.
2215 auto test_device = new TestDeviceInfo(fake_super, "_b");
2216 test_device->set_recovery(true);
2217 auto new_sm = NewManagerForFirstStageMount(test_device);
2218
2219 ASSERT_TRUE(new_sm->HandleImminentDataWipe());
2220 // Manually mount metadata so that we can call GetUpdateState() below.
2221 MountMetadata();
2222 EXPECT_EQ(new_sm->GetUpdateState(), UpdateState::None);
2223 ASSERT_FALSE(test_device->IsSlotUnbootable(1));
2224 ASSERT_FALSE(test_device->IsSlotUnbootable(0));
2225
2226 ASSERT_TRUE(UnmapAll());
2227
2228 // Now reboot into new slot.
2229 test_device = new TestDeviceInfo(fake_super, "_b");
2230 auto init = NewManagerForFirstStageMount(test_device);
2231 ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
2232 // Verify that we are on the downgraded build.
2233 for (const auto& name : {"sys_b", "vnd_b", "prd_b"}) {
2234 ASSERT_TRUE(IsPartitionUnchanged(name)) << name;
2235 }
2236 }
2237
TEST_F(SnapshotUpdateTest,Hashtree)2238 TEST_F(SnapshotUpdateTest, Hashtree) {
2239 constexpr auto partition_size = 4_MiB;
2240 constexpr auto data_size = 3_MiB;
2241 constexpr auto hashtree_size = 512_KiB;
2242 constexpr auto fec_size = partition_size - data_size - hashtree_size;
2243
2244 const auto block_size = manifest_.block_size();
2245 SetSize(sys_, partition_size);
2246 AddOperation(sys_, data_size);
2247
2248 sys_->set_estimate_cow_size(partition_size + data_size);
2249
2250 // Set hastree extents.
2251 sys_->mutable_hash_tree_data_extent()->set_start_block(0);
2252 sys_->mutable_hash_tree_data_extent()->set_num_blocks(data_size / block_size);
2253
2254 sys_->mutable_hash_tree_extent()->set_start_block(data_size / block_size);
2255 sys_->mutable_hash_tree_extent()->set_num_blocks(hashtree_size / block_size);
2256
2257 // Set FEC extents.
2258 sys_->mutable_fec_data_extent()->set_start_block(0);
2259 sys_->mutable_fec_data_extent()->set_num_blocks((data_size + hashtree_size) / block_size);
2260
2261 sys_->mutable_fec_extent()->set_start_block((data_size + hashtree_size) / block_size);
2262 sys_->mutable_fec_extent()->set_num_blocks(fec_size / block_size);
2263
2264 ASSERT_TRUE(sm->BeginUpdate());
2265 ASSERT_TRUE(sm->CreateUpdateSnapshots(manifest_));
2266
2267 // Map and write some data to target partition.
2268 ASSERT_TRUE(MapUpdateSnapshots({"vnd_b", "prd_b"}));
2269 ASSERT_TRUE(WriteSnapshotAndHash(sys_));
2270
2271 // Finish update.
2272 ASSERT_TRUE(sm->FinishedSnapshotWrites(false));
2273
2274 // Simulate shutting down the device.
2275 ASSERT_TRUE(UnmapAll());
2276
2277 // After reboot, init does first stage mount.
2278 auto init = NewManagerForFirstStageMount("_b");
2279 ASSERT_NE(init, nullptr);
2280 ASSERT_TRUE(init->NeedSnapshotsInFirstStageMount());
2281 ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
2282
2283 // Check that the target partition have the same content. Hashtree and FEC extents
2284 // should be accounted for.
2285 ASSERT_TRUE(IsPartitionUnchanged("sys_b"));
2286 }
2287
2288 // Test for overflow bit after update
TEST_F(SnapshotUpdateTest,Overflow)2289 TEST_F(SnapshotUpdateTest, Overflow) {
2290 if (snapuserd_required_) {
2291 GTEST_SKIP() << "No overflow bit set for snapuserd COWs";
2292 }
2293
2294 const auto actual_write_size = GetSize(sys_);
2295 const auto declared_write_size = actual_write_size - 1_MiB;
2296
2297 AddOperation(sys_, declared_write_size);
2298
2299 // Execute the update.
2300 ASSERT_TRUE(sm->BeginUpdate());
2301 ASSERT_TRUE(sm->CreateUpdateSnapshots(manifest_));
2302
2303 // Map and write some data to target partitions.
2304 ASSERT_TRUE(MapUpdateSnapshots({"vnd_b", "prd_b"}));
2305 ASSERT_TRUE(WriteSnapshotAndHash(sys_));
2306
2307 std::vector<android::dm::DeviceMapper::TargetInfo> table;
2308 ASSERT_TRUE(DeviceMapper::Instance().GetTableStatus("sys_b", &table));
2309 ASSERT_EQ(1u, table.size());
2310 EXPECT_TRUE(table[0].IsOverflowSnapshot());
2311
2312 ASSERT_FALSE(sm->FinishedSnapshotWrites(false))
2313 << "FinishedSnapshotWrites should detect overflow of CoW device.";
2314 }
2315
TEST_F(SnapshotUpdateTest,AddPartition)2316 TEST_F(SnapshotUpdateTest, AddPartition) {
2317 group_->add_partition_names("dlkm");
2318
2319 auto dlkm = manifest_.add_partitions();
2320 dlkm->set_partition_name("dlkm");
2321 dlkm->set_estimate_cow_size(2_MiB);
2322 SetSize(dlkm, 3_MiB);
2323
2324 // Grow all partitions. Set |prd| large enough that |sys| and |vnd|'s COWs
2325 // fit in super, but not |prd|.
2326 constexpr uint64_t partition_size = 3788_KiB;
2327 SetSize(sys_, partition_size);
2328 SetSize(vnd_, partition_size);
2329 SetSize(prd_, partition_size);
2330 SetSize(dlkm, partition_size);
2331
2332 AddOperationForPartitions({sys_, vnd_, prd_, dlkm});
2333
2334 // Execute the update.
2335 ASSERT_TRUE(sm->BeginUpdate());
2336 ASSERT_TRUE(sm->CreateUpdateSnapshots(manifest_));
2337
2338 // Write some data to target partitions.
2339 for (const auto& partition : {sys_, vnd_, prd_, dlkm}) {
2340 ASSERT_TRUE(WriteSnapshotAndHash(partition));
2341 }
2342
2343 // Assert that source partitions aren't affected.
2344 for (const auto& name : {"sys_a", "vnd_a", "prd_a"}) {
2345 ASSERT_TRUE(IsPartitionUnchanged(name));
2346 }
2347
2348 ASSERT_TRUE(sm->FinishedSnapshotWrites(false));
2349
2350 // Simulate shutting down the device.
2351 ASSERT_TRUE(UnmapAll());
2352
2353 // After reboot, init does first stage mount.
2354 auto init = NewManagerForFirstStageMount("_b");
2355 ASSERT_NE(init, nullptr);
2356
2357 if (snapuserd_required_) {
2358 ASSERT_TRUE(init->EnsureSnapuserdConnected());
2359 init->set_use_first_stage_snapuserd(true);
2360 }
2361
2362 ASSERT_TRUE(init->NeedSnapshotsInFirstStageMount());
2363 ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
2364
2365 // Check that the target partitions have the same content.
2366 std::vector<std::string> partitions = {"sys_b", "vnd_b", "prd_b", "dlkm_b"};
2367 for (const auto& name : partitions) {
2368 ASSERT_TRUE(IsPartitionUnchanged(name));
2369 }
2370
2371 if (snapuserd_required_) {
2372 ASSERT_TRUE(init->PerformInitTransition(SnapshotManager::InitTransition::SECOND_STAGE));
2373 for (const auto& name : partitions) {
2374 ASSERT_TRUE(init->snapuserd_client()->WaitForDeviceDelete(name + "-user-cow-init"));
2375 }
2376 }
2377
2378 // Initiate the merge and wait for it to be completed.
2379 if (ShouldSkipLegacyMerging()) {
2380 LOG(INFO) << "Skipping legacy merge in test";
2381 return;
2382 }
2383 ASSERT_TRUE(init->InitiateMerge());
2384 ASSERT_EQ(UpdateState::MergeCompleted, init->ProcessUpdateState());
2385
2386 // Check that the target partitions have the same content after the merge.
2387 for (const auto& name : {"sys_b", "vnd_b", "prd_b", "dlkm_b"}) {
2388 ASSERT_TRUE(IsPartitionUnchanged(name))
2389 << "Content of " << name << " changes after the merge";
2390 }
2391 }
2392
2393 class AutoKill final {
2394 public:
AutoKill(pid_t pid)2395 explicit AutoKill(pid_t pid) : pid_(pid) {}
~AutoKill()2396 ~AutoKill() {
2397 if (pid_ > 0) kill(pid_, SIGKILL);
2398 }
2399
valid() const2400 bool valid() const { return pid_ > 0; }
2401
2402 private:
2403 pid_t pid_;
2404 };
2405
TEST_F(SnapshotUpdateTest,DaemonTransition)2406 TEST_F(SnapshotUpdateTest, DaemonTransition) {
2407 if (!snapuserd_required_) {
2408 GTEST_SKIP() << "Skipping snapuserd test";
2409 }
2410
2411 // Ensure a connection to the second-stage daemon, but use the first-stage
2412 // code paths thereafter.
2413 ASSERT_TRUE(sm->EnsureSnapuserdConnected());
2414 sm->set_use_first_stage_snapuserd(true);
2415
2416 AddOperationForPartitions();
2417 // Execute the update.
2418 ASSERT_TRUE(sm->BeginUpdate());
2419 ASSERT_TRUE(sm->CreateUpdateSnapshots(manifest_));
2420 ASSERT_TRUE(MapUpdateSnapshots());
2421 ASSERT_TRUE(sm->FinishedSnapshotWrites(false));
2422 ASSERT_TRUE(UnmapAll());
2423
2424 auto init = NewManagerForFirstStageMount("_b");
2425 ASSERT_NE(init, nullptr);
2426
2427 ASSERT_TRUE(init->EnsureSnapuserdConnected());
2428 init->set_use_first_stage_snapuserd(true);
2429
2430 ASSERT_TRUE(init->NeedSnapshotsInFirstStageMount());
2431 ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
2432
2433 bool userspace_snapshots = init->UpdateUsesUserSnapshots();
2434
2435 if (userspace_snapshots) {
2436 ASSERT_EQ(access("/dev/dm-user/sys_b-init", F_OK), 0);
2437 ASSERT_EQ(access("/dev/dm-user/sys_b", F_OK), -1);
2438 } else {
2439 ASSERT_EQ(access("/dev/dm-user/sys_b-user-cow-init", F_OK), 0);
2440 ASSERT_EQ(access("/dev/dm-user/sys_b-user-cow", F_OK), -1);
2441 }
2442
2443 ASSERT_TRUE(init->PerformInitTransition(SnapshotManager::InitTransition::SECOND_STAGE));
2444
2445 // :TODO: this is a workaround to ensure the handler list stays empty. We
2446 // should make this test more like actual init, and spawn two copies of
2447 // snapuserd, given how many other tests we now have for normal snapuserd.
2448 if (userspace_snapshots) {
2449 ASSERT_TRUE(init->snapuserd_client()->WaitForDeviceDelete("sys_b-init"));
2450 ASSERT_TRUE(init->snapuserd_client()->WaitForDeviceDelete("vnd_b-init"));
2451 ASSERT_TRUE(init->snapuserd_client()->WaitForDeviceDelete("prd_b-init"));
2452
2453 // The control device should have been renamed.
2454 ASSERT_TRUE(android::fs_mgr::WaitForFileDeleted("/dev/dm-user/sys_b-init", 10s));
2455 ASSERT_EQ(access("/dev/dm-user/sys_b", F_OK), 0);
2456 } else {
2457 ASSERT_TRUE(init->snapuserd_client()->WaitForDeviceDelete("sys_b-user-cow-init"));
2458 ASSERT_TRUE(init->snapuserd_client()->WaitForDeviceDelete("vnd_b-user-cow-init"));
2459 ASSERT_TRUE(init->snapuserd_client()->WaitForDeviceDelete("prd_b-user-cow-init"));
2460
2461 // The control device should have been renamed.
2462 ASSERT_TRUE(android::fs_mgr::WaitForFileDeleted("/dev/dm-user/sys_b-user-cow-init", 10s));
2463 ASSERT_EQ(access("/dev/dm-user/sys_b-user-cow", F_OK), 0);
2464 }
2465 }
2466
TEST_F(SnapshotUpdateTest,MapAllSnapshotsWithoutSlotSwitch)2467 TEST_F(SnapshotUpdateTest, MapAllSnapshotsWithoutSlotSwitch) {
2468 MountMetadata();
2469 AddOperationForPartitions();
2470 // Execute the update.
2471 ASSERT_TRUE(sm->BeginUpdate());
2472 ASSERT_TRUE(sm->CreateUpdateSnapshots(manifest_));
2473
2474 if (!sm->UpdateUsesUserSnapshots()) {
2475 GTEST_SKIP() << "Test does not apply as UserSnapshots aren't enabled.";
2476 }
2477
2478 ASSERT_TRUE(WriteSnapshots());
2479 ASSERT_TRUE(sm->FinishedSnapshotWrites(false));
2480
2481 if (ShouldSkipLegacyMerging()) {
2482 GTEST_SKIP() << "Skipping legacy merge test";
2483 }
2484 // Mark the indicator
2485 ASSERT_TRUE(sm->BootFromSnapshotsWithoutSlotSwitch());
2486
2487 ASSERT_TRUE(sm->EnsureSnapuserdConnected());
2488 sm->set_use_first_stage_snapuserd(true);
2489
2490 ASSERT_TRUE(sm->NeedSnapshotsInFirstStageMount());
2491
2492 // Map snapshots
2493 ASSERT_TRUE(sm->MapAllSnapshots(10s));
2494
2495 // New updates should fail
2496 ASSERT_FALSE(sm->BeginUpdate());
2497
2498 // Snapshots cannot be cancelled
2499 ASSERT_FALSE(sm->CancelUpdate());
2500
2501 // Merge cannot start
2502 ASSERT_FALSE(sm->InitiateMerge());
2503
2504 // Read bytes back and verify they match the cache.
2505 ASSERT_TRUE(IsPartitionUnchanged("sys_b"));
2506
2507 // Remove the indicators
2508 ASSERT_TRUE(sm->PrepareDeviceToBootWithoutSnapshot());
2509
2510 // Ensure snapshots are still mounted
2511 ASSERT_TRUE(sm->IsUserspaceSnapshotUpdateInProgress());
2512
2513 // Cleanup snapshots
2514 ASSERT_TRUE(sm->UnmapAllSnapshots());
2515 }
2516
TEST_F(SnapshotUpdateTest,MapAllSnapshots)2517 TEST_F(SnapshotUpdateTest, MapAllSnapshots) {
2518 AddOperationForPartitions();
2519 // Execute the update.
2520 ASSERT_TRUE(sm->BeginUpdate());
2521 ASSERT_TRUE(sm->CreateUpdateSnapshots(manifest_));
2522 ASSERT_TRUE(WriteSnapshots());
2523 ASSERT_TRUE(sm->FinishedSnapshotWrites(false));
2524 ASSERT_TRUE(sm->MapAllSnapshots(10s));
2525
2526 // Read bytes back and verify they match the cache.
2527 ASSERT_TRUE(IsPartitionUnchanged("sys_b"));
2528
2529 ASSERT_TRUE(sm->UnmapAllSnapshots());
2530 }
2531
TEST_F(SnapshotUpdateTest,CancelOnTargetSlot)2532 TEST_F(SnapshotUpdateTest, CancelOnTargetSlot) {
2533 AddOperationForPartitions();
2534
2535 ASSERT_TRUE(UnmapAll());
2536
2537 // Execute the update from B->A.
2538 test_device->set_slot_suffix("_b");
2539 ASSERT_TRUE(sm->BeginUpdate());
2540 ASSERT_TRUE(sm->CreateUpdateSnapshots(manifest_));
2541
2542 std::string path;
2543 ASSERT_TRUE(CreateLogicalPartition(
2544 CreateLogicalPartitionParams{
2545 .block_device = fake_super,
2546 .metadata_slot = 0,
2547 .partition_name = "sys_a",
2548 .timeout_ms = 1s,
2549 .partition_opener = opener_.get(),
2550 },
2551 &path));
2552
2553 bool userspace_snapshots = sm->UpdateUsesUserSnapshots();
2554
2555 unique_fd fd;
2556 if (!userspace_snapshots) {
2557 // Hold sys_a open so it can't be unmapped.
2558 fd.reset(open(path.c_str(), O_RDONLY));
2559 }
2560
2561 // Switch back to "A", make sure we can cancel. Instead of unmapping sys_a
2562 // we should simply delete the old snapshots.
2563 test_device->set_slot_suffix("_a");
2564 ASSERT_TRUE(sm->BeginUpdate());
2565 }
2566
TEST_F(SnapshotUpdateTest,QueryStatusError)2567 TEST_F(SnapshotUpdateTest, QueryStatusError) {
2568 // Grow all partitions. Set |prd| large enough that |sys| and |vnd|'s COWs
2569 // fit in super, but not |prd|.
2570 constexpr uint64_t partition_size = 3788_KiB;
2571 SetSize(sys_, partition_size);
2572
2573 AddOperationForPartitions();
2574
2575 // Execute the update.
2576 ASSERT_TRUE(sm->BeginUpdate());
2577 ASSERT_TRUE(sm->CreateUpdateSnapshots(manifest_));
2578
2579 if (sm->UpdateUsesUserSnapshots()) {
2580 GTEST_SKIP() << "Test does not apply to userspace snapshots";
2581 }
2582
2583 ASSERT_TRUE(WriteSnapshots());
2584 ASSERT_TRUE(sm->FinishedSnapshotWrites(false));
2585
2586 ASSERT_TRUE(UnmapAll());
2587
2588 class DmStatusFailure final : public DeviceMapperWrapper {
2589 public:
2590 bool GetTableStatus(const std::string& name, std::vector<TargetInfo>* table) override {
2591 if (!DeviceMapperWrapper::GetTableStatus(name, table)) {
2592 return false;
2593 }
2594 if (name == "sys_b" && !table->empty()) {
2595 auto& info = table->at(0);
2596 if (DeviceMapper::GetTargetType(info.spec) == "snapshot-merge") {
2597 info.data = "Merge failed";
2598 }
2599 }
2600 return true;
2601 }
2602 };
2603 DmStatusFailure wrapper;
2604
2605 // After reboot, init does first stage mount.
2606 auto info = new TestDeviceInfo(fake_super, "_b");
2607 info->set_dm(&wrapper);
2608
2609 auto init = NewManagerForFirstStageMount(info);
2610 ASSERT_NE(init, nullptr);
2611
2612 ASSERT_TRUE(init->NeedSnapshotsInFirstStageMount());
2613 ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
2614
2615 // Initiate the merge and wait for it to be completed.
2616 ASSERT_TRUE(init->InitiateMerge());
2617 ASSERT_EQ(UpdateState::MergeFailed, init->ProcessUpdateState());
2618
2619 if (ShouldSkipLegacyMerging()) {
2620 LOG(INFO) << "Skipping legacy merge in test";
2621 return;
2622 }
2623
2624 // Simulate a reboot that tries the merge again, with the non-failing dm.
2625 ASSERT_TRUE(UnmapAll());
2626 init = NewManagerForFirstStageMount("_b");
2627 ASSERT_NE(init, nullptr);
2628 ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
2629 ASSERT_EQ(UpdateState::MergeCompleted, init->ProcessUpdateState());
2630 }
2631
TEST_F(SnapshotUpdateTest,BadCowVersion)2632 TEST_F(SnapshotUpdateTest, BadCowVersion) {
2633 if (!snapuserd_required_) {
2634 GTEST_SKIP() << "VABC only";
2635 }
2636
2637 ASSERT_TRUE(sm->BeginUpdate());
2638
2639 auto dynamic_partition_metadata = manifest_.mutable_dynamic_partition_metadata();
2640 dynamic_partition_metadata->set_cow_version(kMinCowVersion - 1);
2641 ASSERT_FALSE(sm->CreateUpdateSnapshots(manifest_));
2642
2643 dynamic_partition_metadata->set_cow_version(kMaxCowVersion + 1);
2644 ASSERT_FALSE(sm->CreateUpdateSnapshots(manifest_));
2645
2646 dynamic_partition_metadata->set_cow_version(kMaxCowVersion);
2647 ASSERT_TRUE(sm->CreateUpdateSnapshots(manifest_));
2648 }
2649
TEST_F(SnapshotTest,FlagCheck)2650 TEST_F(SnapshotTest, FlagCheck) {
2651 if (!snapuserd_required_) {
2652 GTEST_SKIP() << "Skipping snapuserd test";
2653 }
2654 ASSERT_TRUE(AcquireLock());
2655
2656 SnapshotUpdateStatus status = sm->ReadSnapshotUpdateStatus(lock_.get());
2657
2658 // Set flags in proto
2659 status.set_o_direct(true);
2660 status.set_io_uring_enabled(true);
2661 status.set_userspace_snapshots(true);
2662
2663 sm->WriteSnapshotUpdateStatus(lock_.get(), status);
2664 // Ensure a connection to the second-stage daemon, but use the first-stage
2665 // code paths thereafter.
2666 ASSERT_TRUE(sm->EnsureSnapuserdConnected());
2667 sm->set_use_first_stage_snapuserd(true);
2668
2669 auto init = NewManagerForFirstStageMount("_b");
2670 ASSERT_NE(init, nullptr);
2671
2672 lock_ = nullptr;
2673
2674 std::vector<std::string> snapuserd_argv;
2675 ASSERT_TRUE(init->PerformInitTransition(SnapshotManager::InitTransition::SELINUX_DETACH,
2676 &snapuserd_argv));
2677 ASSERT_TRUE(std::find(snapuserd_argv.begin(), snapuserd_argv.end(), "-o_direct") !=
2678 snapuserd_argv.end());
2679 ASSERT_TRUE(std::find(snapuserd_argv.begin(), snapuserd_argv.end(), "-io_uring") !=
2680 snapuserd_argv.end());
2681 ASSERT_TRUE(std::find(snapuserd_argv.begin(), snapuserd_argv.end(), "-user_snapshot") !=
2682 snapuserd_argv.end());
2683 }
2684
2685 class FlashAfterUpdateTest : public SnapshotUpdateTest,
2686 public WithParamInterface<std::tuple<uint32_t, bool>> {
2687 public:
InitiateMerge(const std::string & slot_suffix)2688 AssertionResult InitiateMerge(const std::string& slot_suffix) {
2689 auto sm = SnapshotManager::New(new TestDeviceInfo(fake_super, slot_suffix));
2690 if (!sm->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_)) {
2691 return AssertionFailure() << "Cannot CreateLogicalAndSnapshotPartitions";
2692 }
2693 if (!sm->InitiateMerge()) {
2694 return AssertionFailure() << "Cannot initiate merge";
2695 }
2696 return AssertionSuccess();
2697 }
2698 };
2699
TEST_P(FlashAfterUpdateTest,FlashSlotAfterUpdate)2700 TEST_P(FlashAfterUpdateTest, FlashSlotAfterUpdate) {
2701 // Execute the update.
2702 ASSERT_TRUE(sm->BeginUpdate());
2703 ASSERT_TRUE(sm->CreateUpdateSnapshots(manifest_));
2704 ASSERT_TRUE(MapUpdateSnapshots());
2705 ASSERT_TRUE(sm->FinishedSnapshotWrites(false));
2706
2707 // Simulate shutting down the device.
2708 ASSERT_TRUE(UnmapAll());
2709
2710 bool after_merge = std::get<1>(GetParam());
2711 if (after_merge) {
2712 ASSERT_TRUE(InitiateMerge("_b"));
2713 // Simulate shutting down the device after merge has initiated.
2714 ASSERT_TRUE(UnmapAll());
2715 }
2716
2717 auto flashed_slot = std::get<0>(GetParam());
2718 auto flashed_slot_suffix = SlotSuffixForSlotNumber(flashed_slot);
2719
2720 // Simulate flashing |flashed_slot|. This clears the UPDATED flag.
2721 auto flashed_builder = MetadataBuilder::New(*opener_, "super", flashed_slot);
2722 ASSERT_NE(flashed_builder, nullptr);
2723 flashed_builder->RemoveGroupAndPartitions(group_->name() + flashed_slot_suffix);
2724 flashed_builder->RemoveGroupAndPartitions(kCowGroupName);
2725 ASSERT_TRUE(FillFakeMetadata(flashed_builder.get(), manifest_, flashed_slot_suffix));
2726
2727 // Deliberately remove a partition from this build so that
2728 // InitiateMerge do not switch state to "merging". This is possible in
2729 // practice because the list of dynamic partitions may change.
2730 ASSERT_NE(nullptr, flashed_builder->FindPartition("prd" + flashed_slot_suffix));
2731 flashed_builder->RemovePartition("prd" + flashed_slot_suffix);
2732
2733 // Note that fastbootd always updates the partition table of both slots.
2734 auto flashed_metadata = flashed_builder->Export();
2735 ASSERT_NE(nullptr, flashed_metadata);
2736 ASSERT_TRUE(UpdatePartitionTable(*opener_, "super", *flashed_metadata, 0));
2737 ASSERT_TRUE(UpdatePartitionTable(*opener_, "super", *flashed_metadata, 1));
2738
2739 std::string path;
2740 for (const auto& name : {"sys", "vnd"}) {
2741 ASSERT_TRUE(CreateLogicalPartition(
2742 CreateLogicalPartitionParams{
2743 .block_device = fake_super,
2744 .metadata_slot = flashed_slot,
2745 .partition_name = name + flashed_slot_suffix,
2746 .timeout_ms = 1s,
2747 .partition_opener = opener_.get(),
2748 },
2749 &path));
2750 ASSERT_TRUE(WriteRandomData(path));
2751 auto hash = GetHash(path);
2752 ASSERT_TRUE(hash.has_value());
2753 hashes_[name + flashed_slot_suffix] = *hash;
2754 }
2755
2756 // Simulate shutting down the device after flash.
2757 ASSERT_TRUE(UnmapAll());
2758
2759 // Simulate reboot. After reboot, init does first stage mount.
2760 auto init = NewManagerForFirstStageMount(flashed_slot_suffix);
2761 ASSERT_NE(init, nullptr);
2762
2763 if (flashed_slot && after_merge) {
2764 ASSERT_TRUE(init->NeedSnapshotsInFirstStageMount());
2765 }
2766 ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
2767
2768 // Check that the target partitions have the same content.
2769 for (const auto& name : {"sys", "vnd"}) {
2770 ASSERT_TRUE(IsPartitionUnchanged(name + flashed_slot_suffix));
2771 }
2772
2773 // There should be no snapshot to merge.
2774 auto new_sm = SnapshotManager::New(new TestDeviceInfo(fake_super, flashed_slot_suffix));
2775 if (flashed_slot == 0 && after_merge) {
2776 ASSERT_EQ(UpdateState::MergeCompleted, new_sm->ProcessUpdateState());
2777 } else {
2778 // update_engine calls ProcessUpdateState first -- should see Cancelled.
2779 ASSERT_EQ(UpdateState::Cancelled, new_sm->ProcessUpdateState());
2780 }
2781
2782 // Next OTA calls CancelUpdate no matter what.
2783 ASSERT_TRUE(new_sm->CancelUpdate());
2784 }
2785
2786 INSTANTIATE_TEST_SUITE_P(Snapshot, FlashAfterUpdateTest, Combine(Values(0, 1), Bool()),
__anon4de4482e0602(const TestParamInfo<FlashAfterUpdateTest::ParamType>& info) 2787 [](const TestParamInfo<FlashAfterUpdateTest::ParamType>& info) {
2788 return "Flash"s + (std::get<0>(info.param) ? "New"s : "Old"s) +
2789 "Slot"s + (std::get<1>(info.param) ? "After"s : "Before"s) +
2790 "Merge"s;
2791 });
2792
Mkdir(const std::string & path)2793 bool Mkdir(const std::string& path) {
2794 if (mkdir(path.c_str(), 0700) && errno != EEXIST) {
2795 std::cerr << "Could not mkdir " << path << ": " << strerror(errno) << std::endl;
2796 return false;
2797 }
2798 return true;
2799 }
2800
2801 class SnapshotTestEnvironment : public ::testing::Environment {
2802 public:
~SnapshotTestEnvironment()2803 ~SnapshotTestEnvironment() override {}
2804 void SetUp() override;
2805 void TearDown() override;
2806
2807 private:
2808 bool CreateFakeSuper();
2809
2810 std::unique_ptr<IImageManager> super_images_;
2811 };
2812
CreateFakeSuper()2813 bool SnapshotTestEnvironment::CreateFakeSuper() {
2814 // Create and map the fake super partition.
2815 static constexpr int kImageFlags =
2816 IImageManager::CREATE_IMAGE_DEFAULT | IImageManager::CREATE_IMAGE_ZERO_FILL;
2817 if (!super_images_->CreateBackingImage("fake-super", kSuperSize, kImageFlags)) {
2818 LOG(ERROR) << "Could not create fake super partition";
2819 return false;
2820 }
2821 if (!super_images_->MapImageDevice("fake-super", 10s, &fake_super)) {
2822 LOG(ERROR) << "Could not map fake super partition";
2823 return false;
2824 }
2825 test_device->set_fake_super(fake_super);
2826 return true;
2827 }
2828
SetUp()2829 void SnapshotTestEnvironment::SetUp() {
2830 // b/163082876: GTEST_SKIP in Environment will make atest report incorrect results. Until
2831 // that is fixed, don't call GTEST_SKIP here, but instead call GTEST_SKIP in individual test
2832 // suites.
2833 RETURN_IF_NON_VIRTUAL_AB_MSG("Virtual A/B is not enabled, skipping global setup.\n");
2834
2835 std::vector<std::string> paths = {
2836 // clang-format off
2837 "/data/gsi/ota/test",
2838 "/data/gsi/ota/test/super",
2839 "/metadata/gsi/ota/test",
2840 "/metadata/gsi/ota/test/super",
2841 "/metadata/ota/test",
2842 "/metadata/ota/test/snapshots",
2843 // clang-format on
2844 };
2845 for (const auto& path : paths) {
2846 ASSERT_TRUE(Mkdir(path));
2847 }
2848
2849 // Create this once, otherwise, gsid will start/stop between each test.
2850 test_device = new TestDeviceInfo();
2851 sm = SnapshotManager::New(test_device);
2852 ASSERT_NE(nullptr, sm) << "Could not create snapshot manager";
2853
2854 // Use a separate image manager for our fake super partition.
2855 super_images_ = IImageManager::Open("ota/test/super", 10s);
2856 ASSERT_NE(nullptr, super_images_) << "Could not create image manager";
2857
2858 // Map the old image if one exists so we can safely unmap everything that
2859 // depends on it.
2860 bool recreate_fake_super;
2861 if (super_images_->BackingImageExists("fake-super")) {
2862 if (super_images_->IsImageMapped("fake-super")) {
2863 ASSERT_TRUE(super_images_->GetMappedImageDevice("fake-super", &fake_super));
2864 } else {
2865 ASSERT_TRUE(super_images_->MapImageDevice("fake-super", 10s, &fake_super));
2866 }
2867 test_device->set_fake_super(fake_super);
2868 recreate_fake_super = true;
2869 } else {
2870 ASSERT_TRUE(CreateFakeSuper());
2871 recreate_fake_super = false;
2872 }
2873
2874 // Clean up previous run.
2875 MetadataMountedTest().TearDown();
2876 SnapshotUpdateTest().Cleanup();
2877 SnapshotTest().Cleanup();
2878
2879 if (recreate_fake_super) {
2880 // Clean up any old copy.
2881 DeleteBackingImage(super_images_.get(), "fake-super");
2882 ASSERT_TRUE(CreateFakeSuper());
2883 }
2884 }
2885
TearDown()2886 void SnapshotTestEnvironment::TearDown() {
2887 RETURN_IF_NON_VIRTUAL_AB();
2888 if (super_images_ != nullptr) {
2889 DeleteBackingImage(super_images_.get(), "fake-super");
2890 }
2891 }
2892
KillSnapuserd()2893 void KillSnapuserd() {
2894 // Detach the daemon if it's alive
2895 auto snapuserd_client = SnapuserdClient::TryConnect(kSnapuserdSocket, 5s);
2896 if (snapuserd_client) {
2897 snapuserd_client->DetachSnapuserd();
2898 }
2899
2900 // Now stop the service - Init will send a SIGKILL to the daemon. However,
2901 // process state will move from "running" to "stopping". Only after the
2902 // process is reaped by init, the service state is moved to "stopped".
2903 //
2904 // Since the tests involve starting the daemon immediately, wait for the
2905 // process to completely stop (aka. wait until init reaps the terminated
2906 // process).
2907 android::base::SetProperty("ctl.stop", "snapuserd");
2908 if (!android::base::WaitForProperty("init.svc.snapuserd", "stopped", 10s)) {
2909 LOG(ERROR) << "Timed out waiting for snapuserd to stop.";
2910 }
2911 }
2912
2913 } // namespace snapshot
2914 } // namespace android
2915
main(int argc,char ** argv)2916 int main(int argc, char** argv) {
2917 ::testing::InitGoogleTest(&argc, argv);
2918 ::testing::AddGlobalTestEnvironment(new ::android::snapshot::SnapshotTestEnvironment());
2919 gflags::ParseCommandLineFlags(&argc, &argv, false);
2920
2921 bool vab_legacy = false;
2922 if (FLAGS_force_mode == "vab-legacy") {
2923 vab_legacy = true;
2924 }
2925
2926 if (!vab_legacy) {
2927 // This is necessary if the configuration we're testing doesn't match the device.
2928 android::base::SetProperty("ctl.stop", "snapuserd");
2929 android::snapshot::KillSnapuserd();
2930 }
2931
2932 std::unordered_set<std::string> modes = {"", "vab-legacy"};
2933 if (modes.count(FLAGS_force_mode) == 0) {
2934 std::cerr << "Unexpected force_config argument\n";
2935 return 1;
2936 }
2937
2938 int ret = RUN_ALL_TESTS();
2939
2940 android::base::SetProperty("snapuserd.test.io_uring.force_disable", "0");
2941
2942 if (!vab_legacy) {
2943 android::snapshot::KillSnapuserd();
2944 }
2945 return ret;
2946 }
2947