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 <android-base/strings.h>
16 #include <gflags/gflags.h>
17 
18 #include <fcntl.h>
19 #include <linux/fs.h>
20 #include <linux/memfd.h>
21 #include <sys/ioctl.h>
22 #include <sys/stat.h>
23 #include <sys/syscall.h>
24 #include <sys/types.h>
25 #include <unistd.h>
26 
27 #include <chrono>
28 #include <iostream>
29 #include <memory>
30 #include <string_view>
31 
32 #include <android-base/file.h>
33 #include <android-base/properties.h>
34 #include <android-base/unique_fd.h>
35 #include <fs_mgr/file_wait.h>
36 #include <gtest/gtest.h>
37 #include <libdm/dm.h>
38 #include <libdm/loop_control.h>
39 #include <libsnapshot/cow_writer.h>
40 #include <snapuserd/snapuserd_client.h>
41 #include <storage_literals/storage_literals.h>
42 
43 #include "snapuserd_core.h"
44 
45 DEFINE_string(force_config, "", "Force testing mode with iouring disabled");
46 
47 namespace android {
48 namespace snapshot {
49 
50 using namespace android::storage_literals;
51 using android::base::unique_fd;
52 using LoopDevice = android::dm::LoopDevice;
53 using namespace std::chrono_literals;
54 using namespace android::dm;
55 using namespace std;
56 
57 static constexpr char kSnapuserdSocketTest[] = "snapuserdTest";
58 
59 class Tempdevice {
60   public:
Tempdevice(const std::string & name,const DmTable & table)61     Tempdevice(const std::string& name, const DmTable& table)
62         : dm_(DeviceMapper::Instance()), name_(name), valid_(false) {
63         valid_ = dm_.CreateDevice(name, table, &path_, std::chrono::seconds(5));
64     }
Tempdevice(Tempdevice && other)65     Tempdevice(Tempdevice&& other) noexcept
66         : dm_(other.dm_), name_(other.name_), path_(other.path_), valid_(other.valid_) {
67         other.valid_ = false;
68     }
~Tempdevice()69     ~Tempdevice() {
70         if (valid_) {
71             dm_.DeleteDevice(name_);
72         }
73     }
Destroy()74     bool Destroy() {
75         if (!valid_) {
76             return false;
77         }
78         valid_ = false;
79         return dm_.DeleteDevice(name_);
80     }
path() const81     const std::string& path() const { return path_; }
name() const82     const std::string& name() const { return name_; }
valid() const83     bool valid() const { return valid_; }
84 
85     Tempdevice(const Tempdevice&) = delete;
86     Tempdevice& operator=(const Tempdevice&) = delete;
87 
operator =(Tempdevice && other)88     Tempdevice& operator=(Tempdevice&& other) noexcept {
89         name_ = other.name_;
90         valid_ = other.valid_;
91         other.valid_ = false;
92         return *this;
93     }
94 
95   private:
96     DeviceMapper& dm_;
97     std::string name_;
98     std::string path_;
99     bool valid_;
100 };
101 
102 class SnapuserdTest : public ::testing::Test {
103   public:
104     bool SetupDefault();
105     bool SetupOrderedOps();
106     bool SetupOrderedOpsInverted();
107     bool SetupCopyOverlap_1();
108     bool SetupCopyOverlap_2();
109     bool Merge();
110     void ValidateMerge();
111     void ReadSnapshotDeviceAndValidate();
112     void Shutdown();
113     void MergeInterrupt();
114     void MergeInterruptFixed(int duration);
115     void MergeInterruptRandomly(int max_duration);
116     void StartMerge();
117     void CheckMergeCompletion();
118 
119     static const uint64_t kSectorSize = 512;
120 
121   protected:
SetUp()122     void SetUp() override {}
TearDown()123     void TearDown() override { Shutdown(); }
124 
125   private:
126     void SetupImpl();
127 
128     void SimulateDaemonRestart();
129 
130     void CreateCowDevice();
131     void CreateCowDeviceOrderedOps();
132     void CreateCowDeviceOrderedOpsInverted();
133     void CreateCowDeviceWithCopyOverlap_1();
134     void CreateCowDeviceWithCopyOverlap_2();
135     bool SetupDaemon();
136     void CreateBaseDevice();
137     void InitCowDevice();
138     void SetDeviceControlName();
139     void InitDaemon();
140     void CreateDmUserDevice();
141     void StartSnapuserdDaemon();
142 
143     unique_ptr<LoopDevice> base_loop_;
144     unique_ptr<Tempdevice> dmuser_dev_;
145 
146     std::string system_device_ctrl_name_;
147     std::string system_device_name_;
148 
149     unique_fd base_fd_;
150     std::unique_ptr<TemporaryFile> cow_system_;
151     std::unique_ptr<SnapuserdClient> client_;
152     std::unique_ptr<uint8_t[]> orig_buffer_;
153     std::unique_ptr<uint8_t[]> merged_buffer_;
154     bool setup_ok_ = false;
155     bool merge_ok_ = false;
156     size_t size_ = 100_MiB;
157     int cow_num_sectors_;
158     int total_base_size_;
159 };
160 
CreateTempFile(const std::string & name,size_t size)161 static unique_fd CreateTempFile(const std::string& name, size_t size) {
162     unique_fd fd(syscall(__NR_memfd_create, name.c_str(), MFD_ALLOW_SEALING));
163     if (fd < 0) {
164         return {};
165     }
166     if (size) {
167         if (ftruncate(fd, size) < 0) {
168             perror("ftruncate");
169             return {};
170         }
171         if (fcntl(fd, F_ADD_SEALS, F_SEAL_GROW | F_SEAL_SHRINK) < 0) {
172             perror("fcntl");
173             return {};
174         }
175     }
176     return fd;
177 }
178 
Shutdown()179 void SnapuserdTest::Shutdown() {
180     ASSERT_TRUE(dmuser_dev_->Destroy());
181 
182     auto misc_device = "/dev/dm-user/" + system_device_ctrl_name_;
183     ASSERT_TRUE(client_->WaitForDeviceDelete(system_device_ctrl_name_));
184     ASSERT_TRUE(android::fs_mgr::WaitForFileDeleted(misc_device, 10s));
185     ASSERT_TRUE(client_->DetachSnapuserd());
186 }
187 
SetupDefault()188 bool SnapuserdTest::SetupDefault() {
189     SetupImpl();
190     return setup_ok_;
191 }
192 
SetupOrderedOps()193 bool SnapuserdTest::SetupOrderedOps() {
194     CreateBaseDevice();
195     CreateCowDeviceOrderedOps();
196     return SetupDaemon();
197 }
198 
SetupOrderedOpsInverted()199 bool SnapuserdTest::SetupOrderedOpsInverted() {
200     CreateBaseDevice();
201     CreateCowDeviceOrderedOpsInverted();
202     return SetupDaemon();
203 }
204 
SetupCopyOverlap_1()205 bool SnapuserdTest::SetupCopyOverlap_1() {
206     CreateBaseDevice();
207     CreateCowDeviceWithCopyOverlap_1();
208     return SetupDaemon();
209 }
210 
SetupCopyOverlap_2()211 bool SnapuserdTest::SetupCopyOverlap_2() {
212     CreateBaseDevice();
213     CreateCowDeviceWithCopyOverlap_2();
214     return SetupDaemon();
215 }
216 
SetupDaemon()217 bool SnapuserdTest::SetupDaemon() {
218     SetDeviceControlName();
219 
220     StartSnapuserdDaemon();
221 
222     CreateDmUserDevice();
223     InitCowDevice();
224     InitDaemon();
225 
226     setup_ok_ = true;
227 
228     return setup_ok_;
229 }
230 
StartSnapuserdDaemon()231 void SnapuserdTest::StartSnapuserdDaemon() {
232     pid_t pid = fork();
233     ASSERT_GE(pid, 0);
234     if (pid == 0) {
235         std::string arg0 = "/system/bin/snapuserd";
236         std::string arg1 = "-socket="s + kSnapuserdSocketTest;
237         char* const argv[] = {arg0.data(), arg1.data(), nullptr};
238         ASSERT_GE(execv(arg0.c_str(), argv), 0);
239     } else {
240         client_ = SnapuserdClient::Connect(kSnapuserdSocketTest, 10s);
241         ASSERT_NE(client_, nullptr);
242     }
243 }
244 
CreateBaseDevice()245 void SnapuserdTest::CreateBaseDevice() {
246     unique_fd rnd_fd;
247 
248     total_base_size_ = (size_ * 5);
249     base_fd_ = CreateTempFile("base_device", total_base_size_);
250     ASSERT_GE(base_fd_, 0);
251 
252     rnd_fd.reset(open("/dev/random", O_RDONLY));
253     ASSERT_TRUE(rnd_fd > 0);
254 
255     std::unique_ptr<uint8_t[]> random_buffer = std::make_unique<uint8_t[]>(1_MiB);
256 
257     for (size_t j = 0; j < ((total_base_size_) / 1_MiB); j++) {
258         ASSERT_EQ(ReadFullyAtOffset(rnd_fd, (char*)random_buffer.get(), 1_MiB, 0), true);
259         ASSERT_EQ(android::base::WriteFully(base_fd_, random_buffer.get(), 1_MiB), true);
260     }
261 
262     ASSERT_EQ(lseek(base_fd_, 0, SEEK_SET), 0);
263 
264     base_loop_ = std::make_unique<LoopDevice>(base_fd_, 10s);
265     ASSERT_TRUE(base_loop_->valid());
266 }
267 
ReadSnapshotDeviceAndValidate()268 void SnapuserdTest::ReadSnapshotDeviceAndValidate() {
269     unique_fd fd(open(dmuser_dev_->path().c_str(), O_RDONLY));
270     ASSERT_GE(fd, 0);
271     std::unique_ptr<uint8_t[]> snapuserd_buffer = std::make_unique<uint8_t[]>(size_);
272 
273     // COPY
274     loff_t offset = 0;
275     ASSERT_EQ(ReadFullyAtOffset(fd, snapuserd_buffer.get(), size_, offset), true);
276     ASSERT_EQ(memcmp(snapuserd_buffer.get(), orig_buffer_.get(), size_), 0);
277 
278     // REPLACE
279     offset += size_;
280     ASSERT_EQ(ReadFullyAtOffset(fd, snapuserd_buffer.get(), size_, offset), true);
281     ASSERT_EQ(memcmp(snapuserd_buffer.get(), (char*)orig_buffer_.get() + size_, size_), 0);
282 
283     // ZERO
284     offset += size_;
285     ASSERT_EQ(ReadFullyAtOffset(fd, snapuserd_buffer.get(), size_, offset), true);
286     ASSERT_EQ(memcmp(snapuserd_buffer.get(), (char*)orig_buffer_.get() + (size_ * 2), size_), 0);
287 
288     // REPLACE
289     offset += size_;
290     ASSERT_EQ(ReadFullyAtOffset(fd, snapuserd_buffer.get(), size_, offset), true);
291     ASSERT_EQ(memcmp(snapuserd_buffer.get(), (char*)orig_buffer_.get() + (size_ * 3), size_), 0);
292 
293     // XOR
294     offset += size_;
295     ASSERT_EQ(ReadFullyAtOffset(fd, snapuserd_buffer.get(), size_, offset), true);
296     ASSERT_EQ(memcmp(snapuserd_buffer.get(), (char*)orig_buffer_.get() + (size_ * 4), size_), 0);
297 }
298 
CreateCowDeviceWithCopyOverlap_2()299 void SnapuserdTest::CreateCowDeviceWithCopyOverlap_2() {
300     std::string path = android::base::GetExecutableDirectory();
301     cow_system_ = std::make_unique<TemporaryFile>(path);
302 
303     CowOptions options;
304     options.compression = "gz";
305     CowWriter writer(options);
306 
307     ASSERT_TRUE(writer.Initialize(cow_system_->fd));
308 
309     size_t num_blocks = size_ / options.block_size;
310     size_t x = num_blocks;
311     size_t blk_src_copy = 0;
312 
313     // Create overlapping copy operations
314     while (1) {
315         ASSERT_TRUE(writer.AddCopy(blk_src_copy, blk_src_copy + 1));
316         x -= 1;
317         if (x == 1) {
318             break;
319         }
320         blk_src_copy += 1;
321     }
322 
323     // Flush operations
324     ASSERT_TRUE(writer.Finalize());
325 
326     // Construct the buffer required for validation
327     orig_buffer_ = std::make_unique<uint8_t[]>(total_base_size_);
328 
329     // Read the entire base device
330     ASSERT_EQ(android::base::ReadFullyAtOffset(base_fd_, orig_buffer_.get(), total_base_size_, 0),
331               true);
332 
333     // Merged operations required for validation
334     int block_size = 4096;
335     x = num_blocks;
336     loff_t src_offset = block_size;
337     loff_t dest_offset = 0;
338 
339     while (1) {
340         memmove((char*)orig_buffer_.get() + dest_offset, (char*)orig_buffer_.get() + src_offset,
341                 block_size);
342         x -= 1;
343         if (x == 1) {
344             break;
345         }
346         src_offset += block_size;
347         dest_offset += block_size;
348     }
349 }
350 
CreateCowDeviceWithCopyOverlap_1()351 void SnapuserdTest::CreateCowDeviceWithCopyOverlap_1() {
352     std::string path = android::base::GetExecutableDirectory();
353     cow_system_ = std::make_unique<TemporaryFile>(path);
354 
355     CowOptions options;
356     options.compression = "gz";
357     CowWriter writer(options);
358 
359     ASSERT_TRUE(writer.Initialize(cow_system_->fd));
360 
361     size_t num_blocks = size_ / options.block_size;
362     size_t x = num_blocks;
363     size_t blk_src_copy = num_blocks - 1;
364 
365     // Create overlapping copy operations
366     while (1) {
367         ASSERT_TRUE(writer.AddCopy(blk_src_copy + 1, blk_src_copy));
368         x -= 1;
369         if (x == 0) {
370             ASSERT_EQ(blk_src_copy, 0);
371             break;
372         }
373         blk_src_copy -= 1;
374     }
375 
376     // Flush operations
377     ASSERT_TRUE(writer.Finalize());
378 
379     // Construct the buffer required for validation
380     orig_buffer_ = std::make_unique<uint8_t[]>(total_base_size_);
381 
382     // Read the entire base device
383     ASSERT_EQ(android::base::ReadFullyAtOffset(base_fd_, orig_buffer_.get(), total_base_size_, 0),
384               true);
385 
386     // Merged operations
387     ASSERT_EQ(android::base::ReadFullyAtOffset(base_fd_, orig_buffer_.get(), options.block_size, 0),
388               true);
389     ASSERT_EQ(android::base::ReadFullyAtOffset(
390                       base_fd_, (char*)orig_buffer_.get() + options.block_size, size_, 0),
391               true);
392 }
393 
CreateCowDeviceOrderedOpsInverted()394 void SnapuserdTest::CreateCowDeviceOrderedOpsInverted() {
395     unique_fd rnd_fd;
396     loff_t offset = 0;
397 
398     std::string path = android::base::GetExecutableDirectory();
399     cow_system_ = std::make_unique<TemporaryFile>(path);
400 
401     rnd_fd.reset(open("/dev/random", O_RDONLY));
402     ASSERT_TRUE(rnd_fd > 0);
403 
404     std::unique_ptr<uint8_t[]> random_buffer_1_ = std::make_unique<uint8_t[]>(size_);
405 
406     // Fill random data
407     for (size_t j = 0; j < (size_ / 1_MiB); j++) {
408         ASSERT_EQ(ReadFullyAtOffset(rnd_fd, (char*)random_buffer_1_.get() + offset, 1_MiB, 0),
409                   true);
410 
411         offset += 1_MiB;
412     }
413 
414     CowOptions options;
415     options.compression = "gz";
416     CowWriter writer(options);
417 
418     ASSERT_TRUE(writer.Initialize(cow_system_->fd));
419 
420     size_t num_blocks = size_ / options.block_size;
421     size_t blk_end_copy = num_blocks * 3;
422     size_t source_blk = num_blocks - 1;
423     size_t blk_src_copy = blk_end_copy - 1;
424     uint16_t xor_offset = 5;
425 
426     size_t x = num_blocks;
427     while (1) {
428         ASSERT_TRUE(writer.AddCopy(source_blk, blk_src_copy));
429         x -= 1;
430         if (x == 0) {
431             break;
432         }
433         source_blk -= 1;
434         blk_src_copy -= 1;
435     }
436 
437     for (size_t i = num_blocks; i > 0; i--) {
438         ASSERT_TRUE(writer.AddXorBlocks(num_blocks + i - 1,
439                                         &random_buffer_1_.get()[options.block_size * (i - 1)],
440                                         options.block_size, 2 * num_blocks + i - 1, xor_offset));
441     }
442     // Flush operations
443     ASSERT_TRUE(writer.Finalize());
444     // Construct the buffer required for validation
445     orig_buffer_ = std::make_unique<uint8_t[]>(total_base_size_);
446     // Read the entire base device
447     ASSERT_EQ(android::base::ReadFullyAtOffset(base_fd_, orig_buffer_.get(), total_base_size_, 0),
448               true);
449     // Merged Buffer
450     memmove(orig_buffer_.get(), (char*)orig_buffer_.get() + 2 * size_, size_);
451     memmove(orig_buffer_.get() + size_, (char*)orig_buffer_.get() + 2 * size_ + xor_offset, size_);
452     for (int i = 0; i < size_; i++) {
453         orig_buffer_.get()[size_ + i] ^= random_buffer_1_.get()[i];
454     }
455 }
456 
CreateCowDeviceOrderedOps()457 void SnapuserdTest::CreateCowDeviceOrderedOps() {
458     unique_fd rnd_fd;
459     loff_t offset = 0;
460 
461     std::string path = android::base::GetExecutableDirectory();
462     cow_system_ = std::make_unique<TemporaryFile>(path);
463 
464     rnd_fd.reset(open("/dev/random", O_RDONLY));
465     ASSERT_TRUE(rnd_fd > 0);
466 
467     std::unique_ptr<uint8_t[]> random_buffer_1_ = std::make_unique<uint8_t[]>(size_);
468 
469     // Fill random data
470     for (size_t j = 0; j < (size_ / 1_MiB); j++) {
471         ASSERT_EQ(ReadFullyAtOffset(rnd_fd, (char*)random_buffer_1_.get() + offset, 1_MiB, 0),
472                   true);
473 
474         offset += 1_MiB;
475     }
476     memset(random_buffer_1_.get(), 0, size_);
477 
478     CowOptions options;
479     options.compression = "gz";
480     CowWriter writer(options);
481 
482     ASSERT_TRUE(writer.Initialize(cow_system_->fd));
483 
484     size_t num_blocks = size_ / options.block_size;
485     size_t x = num_blocks;
486     size_t source_blk = 0;
487     size_t blk_src_copy = 2 * num_blocks;
488     uint16_t xor_offset = 5;
489 
490     while (1) {
491         ASSERT_TRUE(writer.AddCopy(source_blk, blk_src_copy));
492 
493         x -= 1;
494         if (x == 0) {
495             break;
496         }
497         source_blk += 1;
498         blk_src_copy += 1;
499     }
500 
501     ASSERT_TRUE(writer.AddXorBlocks(num_blocks, random_buffer_1_.get(), size_, 2 * num_blocks,
502                                     xor_offset));
503     // Flush operations
504     ASSERT_TRUE(writer.Finalize());
505     // Construct the buffer required for validation
506     orig_buffer_ = std::make_unique<uint8_t[]>(total_base_size_);
507     // Read the entire base device
508     ASSERT_EQ(android::base::ReadFullyAtOffset(base_fd_, orig_buffer_.get(), total_base_size_, 0),
509               true);
510     // Merged Buffer
511     memmove(orig_buffer_.get(), (char*)orig_buffer_.get() + 2 * size_, size_);
512     memmove(orig_buffer_.get() + size_, (char*)orig_buffer_.get() + 2 * size_ + xor_offset, size_);
513     for (int i = 0; i < size_; i++) {
514         orig_buffer_.get()[size_ + i] ^= random_buffer_1_.get()[i];
515     }
516 }
517 
CreateCowDevice()518 void SnapuserdTest::CreateCowDevice() {
519     unique_fd rnd_fd;
520     loff_t offset = 0;
521 
522     std::string path = android::base::GetExecutableDirectory();
523     cow_system_ = std::make_unique<TemporaryFile>(path);
524 
525     rnd_fd.reset(open("/dev/random", O_RDONLY));
526     ASSERT_TRUE(rnd_fd > 0);
527 
528     std::unique_ptr<uint8_t[]> random_buffer_1_ = std::make_unique<uint8_t[]>(size_);
529 
530     // Fill random data
531     for (size_t j = 0; j < (size_ / 1_MiB); j++) {
532         ASSERT_EQ(ReadFullyAtOffset(rnd_fd, (char*)random_buffer_1_.get() + offset, 1_MiB, 0),
533                   true);
534 
535         offset += 1_MiB;
536     }
537 
538     CowOptions options;
539     options.compression = "gz";
540     CowWriter writer(options);
541 
542     ASSERT_TRUE(writer.Initialize(cow_system_->fd));
543 
544     size_t num_blocks = size_ / options.block_size;
545     size_t blk_end_copy = num_blocks * 2;
546     size_t source_blk = num_blocks - 1;
547     size_t blk_src_copy = blk_end_copy - 1;
548 
549     uint32_t sequence[num_blocks * 2];
550     // Sequence for Copy ops
551     for (int i = 0; i < num_blocks; i++) {
552         sequence[i] = num_blocks - 1 - i;
553     }
554     // Sequence for Xor ops
555     for (int i = 0; i < num_blocks; i++) {
556         sequence[num_blocks + i] = 5 * num_blocks - 1 - i;
557     }
558     ASSERT_TRUE(writer.AddSequenceData(2 * num_blocks, sequence));
559 
560     size_t x = num_blocks;
561     while (1) {
562         ASSERT_TRUE(writer.AddCopy(source_blk, blk_src_copy));
563         x -= 1;
564         if (x == 0) {
565             break;
566         }
567         source_blk -= 1;
568         blk_src_copy -= 1;
569     }
570 
571     source_blk = num_blocks;
572     blk_src_copy = blk_end_copy;
573 
574     ASSERT_TRUE(writer.AddRawBlocks(source_blk, random_buffer_1_.get(), size_));
575 
576     size_t blk_zero_copy_start = source_blk + num_blocks;
577     size_t blk_zero_copy_end = blk_zero_copy_start + num_blocks;
578 
579     ASSERT_TRUE(writer.AddZeroBlocks(blk_zero_copy_start, num_blocks));
580 
581     size_t blk_random2_replace_start = blk_zero_copy_end;
582 
583     ASSERT_TRUE(writer.AddRawBlocks(blk_random2_replace_start, random_buffer_1_.get(), size_));
584 
585     size_t blk_xor_start = blk_random2_replace_start + num_blocks;
586     size_t xor_offset = BLOCK_SZ / 2;
587     ASSERT_TRUE(writer.AddXorBlocks(blk_xor_start, random_buffer_1_.get(), size_, num_blocks,
588                                     xor_offset));
589 
590     // Flush operations
591     ASSERT_TRUE(writer.Finalize());
592     // Construct the buffer required for validation
593     orig_buffer_ = std::make_unique<uint8_t[]>(total_base_size_);
594     std::string zero_buffer(size_, 0);
595     ASSERT_EQ(android::base::ReadFullyAtOffset(base_fd_, orig_buffer_.get(), size_, size_), true);
596     memcpy((char*)orig_buffer_.get() + size_, random_buffer_1_.get(), size_);
597     memcpy((char*)orig_buffer_.get() + (size_ * 2), (void*)zero_buffer.c_str(), size_);
598     memcpy((char*)orig_buffer_.get() + (size_ * 3), random_buffer_1_.get(), size_);
599     ASSERT_EQ(android::base::ReadFullyAtOffset(base_fd_, &orig_buffer_.get()[size_ * 4], size_,
600                                                size_ + xor_offset),
601               true);
602     for (int i = 0; i < size_; i++) {
603         orig_buffer_.get()[(size_ * 4) + i] =
604                 (uint8_t)(orig_buffer_.get()[(size_ * 4) + i] ^ random_buffer_1_.get()[i]);
605     }
606 }
607 
InitCowDevice()608 void SnapuserdTest::InitCowDevice() {
609     uint64_t num_sectors = client_->InitDmUserCow(system_device_ctrl_name_, cow_system_->path,
610                                                   base_loop_->device(), base_loop_->device());
611     ASSERT_NE(num_sectors, 0);
612 }
613 
SetDeviceControlName()614 void SnapuserdTest::SetDeviceControlName() {
615     system_device_name_.clear();
616     system_device_ctrl_name_.clear();
617 
618     std::string str(cow_system_->path);
619     std::size_t found = str.find_last_of("/\\");
620     ASSERT_NE(found, std::string::npos);
621     system_device_name_ = str.substr(found + 1);
622 
623     system_device_ctrl_name_ = system_device_name_ + "-ctrl";
624 }
625 
CreateDmUserDevice()626 void SnapuserdTest::CreateDmUserDevice() {
627     unique_fd fd(TEMP_FAILURE_RETRY(open(base_loop_->device().c_str(), O_RDONLY | O_CLOEXEC)));
628     ASSERT_TRUE(fd > 0);
629 
630     uint64_t dev_sz = get_block_device_size(fd.get());
631     ASSERT_TRUE(dev_sz > 0);
632 
633     cow_num_sectors_ = dev_sz >> 9;
634 
635     DmTable dmuser_table;
636     ASSERT_TRUE(dmuser_table.AddTarget(
637             std::make_unique<DmTargetUser>(0, cow_num_sectors_, system_device_ctrl_name_)));
638     ASSERT_TRUE(dmuser_table.valid());
639 
640     dmuser_dev_ = std::make_unique<Tempdevice>(system_device_name_, dmuser_table);
641     ASSERT_TRUE(dmuser_dev_->valid());
642     ASSERT_FALSE(dmuser_dev_->path().empty());
643 
644     auto misc_device = "/dev/dm-user/" + system_device_ctrl_name_;
645     ASSERT_TRUE(android::fs_mgr::WaitForFile(misc_device, 10s));
646 }
647 
InitDaemon()648 void SnapuserdTest::InitDaemon() {
649     bool ok = client_->AttachDmUser(system_device_ctrl_name_);
650     ASSERT_TRUE(ok);
651 }
652 
CheckMergeCompletion()653 void SnapuserdTest::CheckMergeCompletion() {
654     while (true) {
655         double percentage = client_->GetMergePercent();
656         if ((int)percentage == 100) {
657             break;
658         }
659 
660         std::this_thread::sleep_for(1s);
661     }
662 }
663 
SetupImpl()664 void SnapuserdTest::SetupImpl() {
665     CreateBaseDevice();
666     CreateCowDevice();
667 
668     SetDeviceControlName();
669 
670     StartSnapuserdDaemon();
671 
672     CreateDmUserDevice();
673     InitCowDevice();
674     InitDaemon();
675 
676     setup_ok_ = true;
677 }
678 
Merge()679 bool SnapuserdTest::Merge() {
680     StartMerge();
681     CheckMergeCompletion();
682     merge_ok_ = true;
683     return merge_ok_;
684 }
685 
StartMerge()686 void SnapuserdTest::StartMerge() {
687     bool ok = client_->InitiateMerge(system_device_ctrl_name_);
688     ASSERT_TRUE(ok);
689 }
690 
ValidateMerge()691 void SnapuserdTest::ValidateMerge() {
692     merged_buffer_ = std::make_unique<uint8_t[]>(total_base_size_);
693     ASSERT_EQ(android::base::ReadFullyAtOffset(base_fd_, merged_buffer_.get(), total_base_size_, 0),
694               true);
695     ASSERT_EQ(memcmp(merged_buffer_.get(), orig_buffer_.get(), total_base_size_), 0);
696 }
697 
SimulateDaemonRestart()698 void SnapuserdTest::SimulateDaemonRestart() {
699     Shutdown();
700     std::this_thread::sleep_for(500ms);
701     SetDeviceControlName();
702     StartSnapuserdDaemon();
703     CreateDmUserDevice();
704     InitCowDevice();
705     InitDaemon();
706 }
707 
MergeInterruptRandomly(int max_duration)708 void SnapuserdTest::MergeInterruptRandomly(int max_duration) {
709     std::srand(std::time(nullptr));
710     StartMerge();
711 
712     for (int i = 0; i < 20; i++) {
713         int duration = std::rand() % max_duration;
714         std::this_thread::sleep_for(std::chrono::milliseconds(duration));
715         SimulateDaemonRestart();
716         StartMerge();
717     }
718 
719     SimulateDaemonRestart();
720     ASSERT_TRUE(Merge());
721 }
722 
MergeInterruptFixed(int duration)723 void SnapuserdTest::MergeInterruptFixed(int duration) {
724     StartMerge();
725 
726     for (int i = 0; i < 25; i++) {
727         std::this_thread::sleep_for(std::chrono::milliseconds(duration));
728         SimulateDaemonRestart();
729         StartMerge();
730     }
731 
732     SimulateDaemonRestart();
733     ASSERT_TRUE(Merge());
734 }
735 
MergeInterrupt()736 void SnapuserdTest::MergeInterrupt() {
737     // Interrupt merge at various intervals
738     StartMerge();
739     std::this_thread::sleep_for(250ms);
740     SimulateDaemonRestart();
741 
742     StartMerge();
743     std::this_thread::sleep_for(250ms);
744     SimulateDaemonRestart();
745 
746     StartMerge();
747     std::this_thread::sleep_for(150ms);
748     SimulateDaemonRestart();
749 
750     StartMerge();
751     std::this_thread::sleep_for(100ms);
752     SimulateDaemonRestart();
753 
754     StartMerge();
755     std::this_thread::sleep_for(800ms);
756     SimulateDaemonRestart();
757 
758     StartMerge();
759     std::this_thread::sleep_for(600ms);
760     SimulateDaemonRestart();
761 
762     ASSERT_TRUE(Merge());
763 }
764 
TEST_F(SnapuserdTest,Snapshot_IO_TEST)765 TEST_F(SnapuserdTest, Snapshot_IO_TEST) {
766     ASSERT_TRUE(SetupDefault());
767     // I/O before merge
768     ReadSnapshotDeviceAndValidate();
769     ASSERT_TRUE(Merge());
770     ValidateMerge();
771     // I/O after merge - daemon should read directly
772     // from base device
773     ReadSnapshotDeviceAndValidate();
774     Shutdown();
775 }
776 
TEST_F(SnapuserdTest,Snapshot_MERGE_IO_TEST)777 TEST_F(SnapuserdTest, Snapshot_MERGE_IO_TEST) {
778     ASSERT_TRUE(SetupDefault());
779     // Issue I/O before merge begins
780     std::async(std::launch::async, &SnapuserdTest::ReadSnapshotDeviceAndValidate, this);
781     // Start the merge
782     ASSERT_TRUE(Merge());
783     ValidateMerge();
784     Shutdown();
785 }
786 
TEST_F(SnapuserdTest,Snapshot_MERGE_IO_TEST_1)787 TEST_F(SnapuserdTest, Snapshot_MERGE_IO_TEST_1) {
788     ASSERT_TRUE(SetupDefault());
789     // Start the merge
790     StartMerge();
791     // Issue I/O in parallel when merge is in-progress
792     std::async(std::launch::async, &SnapuserdTest::ReadSnapshotDeviceAndValidate, this);
793     CheckMergeCompletion();
794     ValidateMerge();
795     Shutdown();
796 }
797 
TEST_F(SnapuserdTest,Snapshot_Merge_Resume)798 TEST_F(SnapuserdTest, Snapshot_Merge_Resume) {
799     ASSERT_TRUE(SetupDefault());
800     MergeInterrupt();
801     ValidateMerge();
802     Shutdown();
803 }
804 
TEST_F(SnapuserdTest,Snapshot_COPY_Overlap_TEST_1)805 TEST_F(SnapuserdTest, Snapshot_COPY_Overlap_TEST_1) {
806     ASSERT_TRUE(SetupCopyOverlap_1());
807     ASSERT_TRUE(Merge());
808     ValidateMerge();
809     Shutdown();
810 }
811 
TEST_F(SnapuserdTest,Snapshot_COPY_Overlap_TEST_2)812 TEST_F(SnapuserdTest, Snapshot_COPY_Overlap_TEST_2) {
813     ASSERT_TRUE(SetupCopyOverlap_2());
814     ASSERT_TRUE(Merge());
815     ValidateMerge();
816     Shutdown();
817 }
818 
TEST_F(SnapuserdTest,Snapshot_COPY_Overlap_Merge_Resume_TEST)819 TEST_F(SnapuserdTest, Snapshot_COPY_Overlap_Merge_Resume_TEST) {
820     ASSERT_TRUE(SetupCopyOverlap_1());
821     MergeInterrupt();
822     ValidateMerge();
823     Shutdown();
824 }
825 
TEST_F(SnapuserdTest,Snapshot_Merge_Crash_Fixed_Ordered)826 TEST_F(SnapuserdTest, Snapshot_Merge_Crash_Fixed_Ordered) {
827     ASSERT_TRUE(SetupOrderedOps());
828     MergeInterruptFixed(300);
829     ValidateMerge();
830     Shutdown();
831 }
832 
TEST_F(SnapuserdTest,Snapshot_Merge_Crash_Random_Ordered)833 TEST_F(SnapuserdTest, Snapshot_Merge_Crash_Random_Ordered) {
834     ASSERT_TRUE(SetupOrderedOps());
835     MergeInterruptRandomly(500);
836     ValidateMerge();
837     Shutdown();
838 }
839 
TEST_F(SnapuserdTest,Snapshot_Merge_Crash_Fixed_Inverted)840 TEST_F(SnapuserdTest, Snapshot_Merge_Crash_Fixed_Inverted) {
841     ASSERT_TRUE(SetupOrderedOpsInverted());
842     MergeInterruptFixed(50);
843     ValidateMerge();
844     Shutdown();
845 }
846 
TEST_F(SnapuserdTest,Snapshot_Merge_Crash_Random_Inverted)847 TEST_F(SnapuserdTest, Snapshot_Merge_Crash_Random_Inverted) {
848     ASSERT_TRUE(SetupOrderedOpsInverted());
849     MergeInterruptRandomly(50);
850     ValidateMerge();
851     Shutdown();
852 }
853 
854 }  // namespace snapshot
855 }  // namespace android
856 
main(int argc,char ** argv)857 int main(int argc, char** argv) {
858     ::testing::InitGoogleTest(&argc, argv);
859 
860     gflags::ParseCommandLineFlags(&argc, &argv, false);
861 
862     android::base::SetProperty("ctl.stop", "snapuserd");
863 
864     if (FLAGS_force_config == "iouring_disabled") {
865         if (!android::base::SetProperty("snapuserd.test.io_uring.force_disable", "1")) {
866             return testing::AssertionFailure()
867                    << "Failed to disable property: snapuserd.test.io_uring.disabled";
868         }
869     }
870 
871     int ret = RUN_ALL_TESTS();
872 
873     if (FLAGS_force_config == "iouring_disabled") {
874         android::base::SetProperty("snapuserd.test.io_uring.force_disable", "0");
875     }
876 
877     return ret;
878 }
879