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