xref: /aosp_15_r20/system/core/fs_mgr/libsnapshot/snapshotctl.cpp (revision 00c7fec1bb09f3284aad6a6f96d2f63dfc3650ad)
1 //
2 // Copyright (C) 2019 The Android Open Source Project
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //      http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 //
16 
17 #include <sysexits.h>
18 #include <unistd.h>
19 #include <chrono>
20 #include <filesystem>
21 #include <fstream>
22 #include <future>
23 #include <iostream>
24 #include <map>
25 #include <sstream>
26 #include <thread>
27 
28 #include <android-base/file.h>
29 #include <android-base/logging.h>
30 #include <android-base/unique_fd.h>
31 
32 #include <android-base/chrono_utils.h>
33 #include <android-base/parseint.h>
34 #include <android-base/properties.h>
35 #include <android-base/scopeguard.h>
36 #include <android-base/stringprintf.h>
37 #include <android-base/strings.h>
38 
39 #include <fs_mgr.h>
40 #include <fs_mgr_dm_linear.h>
41 #include <fstab/fstab.h>
42 #include <liblp/builder.h>
43 #include <libsnapshot/cow_format.h>
44 #include <libsnapshot/snapshot.h>
45 #include <storage_literals/storage_literals.h>
46 
47 #include "partition_cow_creator.h"
48 #include "scratch_super.h"
49 
50 #ifdef SNAPSHOTCTL_USERDEBUG_OR_ENG
51 #include <BootControlClient.h>
52 #endif
53 
54 using namespace std::chrono_literals;
55 using namespace std::string_literals;
56 using namespace android::storage_literals;
57 using android::base::LogdLogger;
58 using android::base::StderrLogger;
59 using android::base::TeeLogger;
60 using namespace android::dm;
61 using namespace android::fs_mgr;
62 using android::fs_mgr::CreateLogicalPartitionParams;
63 using android::fs_mgr::FindPartition;
64 using android::fs_mgr::GetPartitionSize;
65 using android::fs_mgr::PartitionOpener;
66 using android::fs_mgr::ReadMetadata;
67 using android::fs_mgr::SlotNumberForSlotSuffix;
68 
Usage()69 int Usage() {
70     std::cerr << "snapshotctl: Control snapshots.\n"
71                  "Usage: snapshotctl [action] [flags]\n"
72                  "Actions:\n"
73                  "  dump\n"
74                  "    Print snapshot states.\n"
75                  "  merge\n"
76                  "    Deprecated.\n"
77                  "  map\n"
78                  "    Map all partitions at /dev/block/mapper\n"
79                  "  map-snapshots <directory where snapshot patches are present>\n"
80                  "    Map all snapshots based on patches present in the directory\n"
81                  "  unmap-snapshots\n"
82                  "    Unmap all pre-created snapshots\n"
83                  "  delete-snapshots\n"
84                  "    Delete all pre-created snapshots\n"
85                  "  revert-snapshots\n"
86                  "    Prepares devices to boot without snapshots on next boot.\n"
87                  "    This does not delete the snapshot. It only removes the indicators\n"
88                  "    so that first stage init will not mount from snapshots.\n"
89                  "  apply-update\n"
90                  "    Apply the incremental OTA update wherein the snapshots are\n"
91                  "    directly written to COW block device. This will bypass update-engine\n"
92                  "    and the device will be ready to boot from the target build.\n";
93     return EX_USAGE;
94 }
95 
96 namespace android {
97 namespace snapshot {
98 
99 #ifdef SNAPSHOTCTL_USERDEBUG_OR_ENG
100 class MapSnapshots {
101   public:
102     MapSnapshots(std::string path = "", bool metadata_super = false);
103     bool CreateSnapshotDevice(std::string& partition_name, std::string& patch);
104     bool InitiateThreadedSnapshotWrite(std::string& pname, std::string& snapshot_patch);
105     bool FinishSnapshotWrites();
106     bool UnmapCowImagePath(std::string& name);
107     bool DeleteSnapshots();
108     bool CleanupSnapshot();
109     bool BeginUpdate();
110     bool ApplyUpdate();
111 
112   private:
113     std::optional<std::string> GetCowImagePath(std::string& name);
114     bool PrepareUpdate();
115     bool GetCowDevicePath(std::string partition_name, std::string* cow_path);
116     bool WriteSnapshotPatch(std::string cow_device, std::string patch);
117     std::string GetGroupName(const android::fs_mgr::LpMetadata& pt,
118                              const std::string& partiton_name);
119     std::unique_ptr<SnapshotManager::LockedFile> lock_;
120     std::unique_ptr<SnapshotManager> sm_;
121     std::vector<std::future<bool>> threads_;
122     std::string snapshot_dir_path_;
123     std::unordered_map<std::string, chromeos_update_engine::DynamicPartitionGroup*> group_map_;
124 
125     std::vector<std::string> patchfiles_;
126     chromeos_update_engine::DeltaArchiveManifest manifest_;
127     bool metadata_super_ = false;
128 };
129 
MapSnapshots(std::string path,bool metadata_super)130 MapSnapshots::MapSnapshots(std::string path, bool metadata_super) {
131     snapshot_dir_path_ = path + "/";
132     metadata_super_ = metadata_super;
133 }
134 
GetGroupName(const android::fs_mgr::LpMetadata & pt,const std::string & partition_name)135 std::string MapSnapshots::GetGroupName(const android::fs_mgr::LpMetadata& pt,
136                                        const std::string& partition_name) {
137     std::string group_name;
138     for (const auto& partition : pt.partitions) {
139         std::string name = android::fs_mgr::GetPartitionName(partition);
140         auto suffix = android::fs_mgr::GetPartitionSlotSuffix(name);
141         std::string pname = name.substr(0, name.size() - suffix.size());
142         if (pname == partition_name) {
143             std::string group_name =
144                     android::fs_mgr::GetPartitionGroupName(pt.groups[partition.group_index]);
145             return group_name.substr(0, group_name.size() - suffix.size());
146         }
147     }
148     return "";
149 }
150 
PrepareUpdate()151 bool MapSnapshots::PrepareUpdate() {
152     if (metadata_super_ && !CreateScratchOtaMetadataOnSuper()) {
153         LOG(ERROR) << "Failed to create OTA metadata on super";
154         return false;
155     }
156     sm_ = SnapshotManager::New();
157 
158     auto source_slot = fs_mgr_get_slot_suffix();
159     auto source_slot_number = SlotNumberForSlotSuffix(source_slot);
160     auto super_source = fs_mgr_get_super_partition_name(source_slot_number);
161 
162     // Get current partition information.
163     PartitionOpener opener;
164     auto source_metadata = ReadMetadata(opener, super_source, source_slot_number);
165     if (!source_metadata) {
166         LOG(ERROR) << "Could not read source partition metadata.\n";
167         return false;
168     }
169 
170     auto dap = manifest_.mutable_dynamic_partition_metadata();
171     dap->set_snapshot_enabled(true);
172     dap->set_vabc_enabled(true);
173     dap->set_vabc_compression_param("lz4");
174     dap->set_cow_version(3);
175 
176     for (const auto& entry : std::filesystem::directory_iterator(snapshot_dir_path_)) {
177         if (android::base::EndsWith(entry.path().generic_string(), ".patch")) {
178             patchfiles_.push_back(android::base::Basename(entry.path().generic_string()));
179         }
180     }
181 
182     for (auto& patchfile : patchfiles_) {
183         std::string parsing_file = snapshot_dir_path_ + patchfile;
184         android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(parsing_file.c_str(), O_RDONLY)));
185         if (fd < 0) {
186             LOG(ERROR) << "Failed to open file: " << parsing_file;
187             return false;
188         }
189         uint64_t dev_sz = lseek(fd.get(), 0, SEEK_END);
190         if (!dev_sz) {
191             LOG(ERROR) << "Could not determine block device size: " << parsing_file;
192             return false;
193         }
194 
195         const int block_sz = 4_KiB;
196         dev_sz += block_sz - 1;
197         dev_sz &= ~(block_sz - 1);
198 
199         auto npos = patchfile.rfind(".patch");
200         auto partition_name = patchfile.substr(0, npos);
201 
202         chromeos_update_engine::DynamicPartitionGroup* group = nullptr;
203         std::string group_name = GetGroupName(*source_metadata.get(), partition_name);
204         if (group_map_.find(group_name) != group_map_.end()) {
205             group = group_map_[group_name];
206         } else {
207             group = dap->add_groups();
208             group->set_name(group_name);
209             group_map_[group_name] = group;
210         }
211         group->add_partition_names(partition_name);
212 
213         auto pu = manifest_.mutable_partitions()->Add();
214         pu->set_partition_name(partition_name);
215         pu->set_estimate_cow_size(dev_sz);
216 
217         CowReader reader;
218         if (!reader.Parse(fd)) {
219             LOG(ERROR) << "COW reader parse failed";
220             return false;
221         }
222 
223         uint64_t new_device_size = 0;
224         const auto& header = reader.GetHeader();
225         if (header.prefix.major_version == 2) {
226             size_t num_ops = reader.get_num_total_data_ops();
227             new_device_size = (num_ops * header.block_size);
228         } else {
229             const auto& v3_header = reader.header_v3();
230             new_device_size = v3_header.op_count_max * v3_header.block_size;
231         }
232 
233         LOG(INFO) << "Partition: " << partition_name << " Group_name: " << group_name
234                   << " size: " << new_device_size << " COW-size: " << dev_sz;
235         pu->mutable_new_partition_info()->set_size(new_device_size);
236     }
237     return true;
238 }
239 
GetCowDevicePath(std::string partition_name,std::string * cow_path)240 bool MapSnapshots::GetCowDevicePath(std::string partition_name, std::string* cow_path) {
241     auto& dm = android::dm::DeviceMapper::Instance();
242 
243     std::string cow_device = partition_name + "-cow-img";
244     if (metadata_super_) {
245         // If COW device exists on /data, then data wipe cannot be done.
246         if (dm.GetDmDevicePathByName(cow_device, cow_path)) {
247             LOG(ERROR) << "COW device exists on /data: " << *cow_path;
248             return false;
249         }
250     }
251 
252     cow_device = partition_name + "-cow";
253     if (dm.GetDmDevicePathByName(cow_device, cow_path)) {
254         return true;
255     }
256 
257     LOG(INFO) << "Failed to find cow path: " << cow_device << " Checking the device for -img path";
258     // If the COW device exists only on /data
259     cow_device = partition_name + "-cow-img";
260     if (!dm.GetDmDevicePathByName(cow_device, cow_path)) {
261         LOG(ERROR) << "Failed to cow path: " << cow_device;
262         return false;
263     }
264     return true;
265 }
266 
ApplyUpdate()267 bool MapSnapshots::ApplyUpdate() {
268     if (!PrepareUpdate()) {
269         LOG(ERROR) << "PrepareUpdate failed";
270         return false;
271     }
272     if (!sm_->BeginUpdate()) {
273         LOG(ERROR) << "BeginUpdate failed";
274         return false;
275     }
276     if (!sm_->CreateUpdateSnapshots(manifest_)) {
277         LOG(ERROR) << "Could not apply snapshots";
278         return false;
279     }
280 
281     LOG(INFO) << "CreateUpdateSnapshots success";
282     if (!sm_->MapAllSnapshots(10s)) {
283         LOG(ERROR) << "MapAllSnapshots failed";
284         return false;
285     }
286 
287     LOG(INFO) << "MapAllSnapshots success";
288 
289     auto target_slot = fs_mgr_get_other_slot_suffix();
290     for (auto& patchfile : patchfiles_) {
291         auto npos = patchfile.rfind(".patch");
292         auto partition_name = patchfile.substr(0, npos) + target_slot;
293         std::string cow_path;
294         if (!GetCowDevicePath(partition_name, &cow_path)) {
295             LOG(ERROR) << "Failed to find cow path";
296             return false;
297         }
298         threads_.emplace_back(std::async(std::launch::async, &MapSnapshots::WriteSnapshotPatch,
299                                          this, cow_path, patchfile));
300     }
301 
302     bool ret = true;
303     for (auto& t : threads_) {
304         ret = t.get() && ret;
305     }
306     if (!ret) {
307         LOG(ERROR) << "Snapshot writes failed";
308         return false;
309     }
310     if (!sm_->UnmapAllSnapshots()) {
311         LOG(ERROR) << "UnmapAllSnapshots failed";
312         return false;
313     }
314 
315     LOG(INFO) << "Pre-created snapshots successfully copied";
316     // All snapshots have been written.
317     if (!sm_->FinishedSnapshotWrites(false /* wipe */)) {
318         LOG(ERROR) << "Could not finalize snapshot writes.\n";
319         return false;
320     }
321 
322     auto hal = hal::BootControlClient::WaitForService();
323     if (!hal) {
324         LOG(ERROR) << "Could not find IBootControl HAL.\n";
325         return false;
326     }
327     auto target_slot_number = SlotNumberForSlotSuffix(target_slot);
328     auto cr = hal->SetActiveBootSlot(target_slot_number);
329     if (!cr.IsOk()) {
330         LOG(ERROR) << "Could not set active boot slot: " << cr.errMsg;
331         return false;
332     }
333 
334     LOG(INFO) << "ApplyUpdate success";
335     return true;
336 }
337 
BeginUpdate()338 bool MapSnapshots::BeginUpdate() {
339     if (metadata_super_ && !CreateScratchOtaMetadataOnSuper()) {
340         LOG(ERROR) << "Failed to create OTA metadata on super";
341         return false;
342     }
343     sm_ = SnapshotManager::New();
344 
345     lock_ = sm_->LockExclusive();
346     std::vector<std::string> snapshots;
347     sm_->ListSnapshots(lock_.get(), &snapshots);
348     if (!snapshots.empty()) {
349         // Snapshots are already present.
350         return true;
351     }
352 
353     lock_ = nullptr;
354     if (!sm_->BeginUpdate()) {
355         LOG(ERROR) << "BeginUpdate failed";
356         return false;
357     }
358     lock_ = sm_->LockExclusive();
359     return true;
360 }
361 
CreateSnapshotDevice(std::string & partition_name,std::string & patchfile)362 bool MapSnapshots::CreateSnapshotDevice(std::string& partition_name, std::string& patchfile) {
363     std::string parsing_file = snapshot_dir_path_ + patchfile;
364 
365     android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(parsing_file.c_str(), O_RDONLY)));
366     if (fd < 0) {
367         LOG(ERROR) << "Failed to open file: " << parsing_file;
368         return false;
369     }
370 
371     uint64_t dev_sz = lseek(fd.get(), 0, SEEK_END);
372     if (!dev_sz) {
373         LOG(ERROR) << "Could not determine block device size: " << parsing_file;
374         return false;
375     }
376 
377     const int block_sz = 4_KiB;
378     dev_sz += block_sz - 1;
379     dev_sz &= ~(block_sz - 1);
380 
381     SnapshotStatus status;
382     status.set_state(SnapshotState::CREATED);
383     status.set_using_snapuserd(true);
384     status.set_old_partition_size(0);
385     status.set_name(partition_name);
386     status.set_cow_file_size(dev_sz);
387     status.set_cow_partition_size(0);
388 
389     PartitionCowCreator cow_creator;
390     cow_creator.using_snapuserd = true;
391 
392     if (!sm_->CreateSnapshot(lock_.get(), &cow_creator, &status)) {
393         LOG(ERROR) << "CreateSnapshot failed";
394         return false;
395     }
396 
397     if (!sm_->CreateCowImage(lock_.get(), partition_name)) {
398         LOG(ERROR) << "CreateCowImage failed";
399         return false;
400     }
401 
402     return true;
403 }
404 
GetCowImagePath(std::string & name)405 std::optional<std::string> MapSnapshots::GetCowImagePath(std::string& name) {
406     auto cow_dev = sm_->MapCowImage(name, 5s);
407     if (!cow_dev.has_value()) {
408         LOG(ERROR) << "Failed to get COW device path";
409         return std::nullopt;
410     }
411 
412     LOG(INFO) << "COW Device path: " << cow_dev.value();
413     return cow_dev;
414 }
415 
WriteSnapshotPatch(std::string cow_device,std::string patch)416 bool MapSnapshots::WriteSnapshotPatch(std::string cow_device, std::string patch) {
417     std::string patch_file = snapshot_dir_path_ + patch;
418 
419     android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(patch_file.c_str(), O_RDONLY)));
420     if (fd < 0) {
421         LOG(ERROR) << "Failed to open file: " << patch_file;
422         return false;
423     }
424 
425     uint64_t dev_sz = lseek(fd.get(), 0, SEEK_END);
426     if (!dev_sz) {
427         std::cout << "Could not determine block device size: " << patch_file;
428         return false;
429     }
430 
431     android::base::unique_fd cfd(TEMP_FAILURE_RETRY(open(cow_device.c_str(), O_RDWR)));
432     if (cfd < 0) {
433         LOG(ERROR) << "Failed to open file: " << cow_device;
434         return false;
435     }
436 
437     const uint64_t read_sz = 1_MiB;
438     std::unique_ptr<uint8_t[]> buffer = std::make_unique<uint8_t[]>(read_sz);
439     off_t file_offset = 0;
440 
441     while (true) {
442         size_t to_read = std::min((dev_sz - file_offset), read_sz);
443         if (!android::base::ReadFullyAtOffset(fd.get(), buffer.get(), to_read, file_offset)) {
444             PLOG(ERROR) << "ReadFullyAtOffset failed";
445             return false;
446         }
447 
448         if (!android::base::WriteFullyAtOffset(cfd, buffer.get(), to_read, file_offset)) {
449             PLOG(ERROR) << "WriteFullyAtOffset failed";
450             return false;
451         }
452         file_offset += to_read;
453         if (file_offset >= dev_sz) {
454             break;
455         }
456     }
457     if (fsync(cfd.get()) < 0) {
458         PLOG(ERROR) << "Fsync failed";
459         return false;
460     }
461     return true;
462 }
463 
InitiateThreadedSnapshotWrite(std::string & pname,std::string & snapshot_patch)464 bool MapSnapshots::InitiateThreadedSnapshotWrite(std::string& pname, std::string& snapshot_patch) {
465     auto path = GetCowImagePath(pname);
466     if (!path.has_value()) {
467         return false;
468     }
469     threads_.emplace_back(std::async(std::launch::async, &MapSnapshots::WriteSnapshotPatch, this,
470                                      path.value(), snapshot_patch));
471     return true;
472 }
473 
FinishSnapshotWrites()474 bool MapSnapshots::FinishSnapshotWrites() {
475     bool ret = true;
476     for (auto& t : threads_) {
477         ret = t.get() && ret;
478     }
479 
480     lock_ = nullptr;
481     if (ret) {
482         LOG(INFO) << "Pre-created snapshots successfully copied";
483         if (!sm_->FinishedSnapshotWrites(false)) {
484             return false;
485         }
486         return sm_->BootFromSnapshotsWithoutSlotSwitch();
487     }
488 
489     LOG(ERROR) << "Snapshot copy failed";
490     return false;
491 }
492 
UnmapCowImagePath(std::string & name)493 bool MapSnapshots::UnmapCowImagePath(std::string& name) {
494     sm_ = SnapshotManager::New();
495     return sm_->UnmapCowImage(name);
496 }
497 
CleanupSnapshot()498 bool MapSnapshots::CleanupSnapshot() {
499     sm_ = SnapshotManager::New();
500     return sm_->PrepareDeviceToBootWithoutSnapshot();
501 }
502 
DeleteSnapshots()503 bool MapSnapshots::DeleteSnapshots() {
504     sm_ = SnapshotManager::New();
505     lock_ = sm_->LockExclusive();
506     if (!sm_->RemoveAllUpdateState(lock_.get())) {
507         LOG(ERROR) << "Remove All Update State failed";
508         return false;
509     }
510     return true;
511 }
512 #endif
513 
DumpCmdHandler(int,char ** argv)514 bool DumpCmdHandler(int /*argc*/, char** argv) {
515     android::base::InitLogging(argv, TeeLogger(LogdLogger(), &StderrLogger));
516     return SnapshotManager::New()->Dump(std::cout);
517 }
518 
MapCmdHandler(int,char ** argv)519 bool MapCmdHandler(int, char** argv) {
520     android::base::InitLogging(argv, TeeLogger(LogdLogger(), &StderrLogger));
521     using namespace std::chrono_literals;
522     return SnapshotManager::New()->MapAllSnapshots(5000ms);
523 }
524 
UnmapCmdHandler(int,char ** argv)525 bool UnmapCmdHandler(int, char** argv) {
526     android::base::InitLogging(argv, TeeLogger(LogdLogger(), &StderrLogger));
527     return SnapshotManager::New()->UnmapAllSnapshots();
528 }
529 
MergeCmdHandler(int,char ** argv)530 bool MergeCmdHandler(int /*argc*/, char** argv) {
531     android::base::InitLogging(argv, TeeLogger(LogdLogger(), &StderrLogger));
532     LOG(WARNING) << "Deprecated. Call update_engine_client --merge instead.";
533     return false;
534 }
535 
536 #ifdef SNAPSHOTCTL_USERDEBUG_OR_ENG
GetVerityPartitions(std::vector<std::string> & partitions)537 bool GetVerityPartitions(std::vector<std::string>& partitions) {
538     auto& dm = android::dm::DeviceMapper::Instance();
539     auto dm_block_devices = dm.FindDmPartitions();
540     if (dm_block_devices.empty()) {
541         LOG(ERROR) << "No dm-enabled block device is found.";
542         return false;
543     }
544 
545     for (auto& block_device : dm_block_devices) {
546         std::string dm_block_name = block_device.first;
547         std::string slot_suffix = fs_mgr_get_slot_suffix();
548         std::string partition = dm_block_name + slot_suffix;
549         partitions.push_back(partition);
550     }
551     return true;
552 }
553 
UnMapPrecreatedSnapshots(int,char ** argv)554 bool UnMapPrecreatedSnapshots(int, char** argv) {
555     android::base::InitLogging(argv, &android::base::KernelLogger);
556     // Make sure we are root.
557     if (::getuid() != 0) {
558         LOG(ERROR) << "Not running as root. Try \"adb root\" first.";
559         return EXIT_FAILURE;
560     }
561 
562     std::vector<std::string> partitions;
563     if (!GetVerityPartitions(partitions)) {
564         return false;
565     }
566 
567     MapSnapshots snapshot;
568     for (auto partition : partitions) {
569         if (!snapshot.UnmapCowImagePath(partition)) {
570             LOG(ERROR) << "UnmapCowImagePath failed: " << partition;
571         }
572     }
573     return true;
574 }
575 
RemovePrecreatedSnapshots(int,char ** argv)576 bool RemovePrecreatedSnapshots(int, char** argv) {
577     android::base::InitLogging(argv, &android::base::KernelLogger);
578     // Make sure we are root.
579     if (::getuid() != 0) {
580         LOG(ERROR) << "Not running as root. Try \"adb root\" first.";
581         return false;
582     }
583 
584     MapSnapshots snapshot;
585     if (!snapshot.CleanupSnapshot()) {
586         LOG(ERROR) << "CleanupSnapshot failed";
587         return false;
588     }
589     return true;
590 }
591 
DeletePrecreatedSnapshots(int,char ** argv)592 bool DeletePrecreatedSnapshots(int, char** argv) {
593     android::base::InitLogging(argv, &android::base::KernelLogger);
594     // Make sure we are root.
595     if (::getuid() != 0) {
596         LOG(ERROR) << "Not running as root. Try \"adb root\" first.";
597         return EXIT_FAILURE;
598     }
599 
600     MapSnapshots snapshot;
601     return snapshot.DeleteSnapshots();
602 }
603 
ApplyUpdate(int argc,char ** argv)604 bool ApplyUpdate(int argc, char** argv) {
605     android::base::InitLogging(argv, &android::base::KernelLogger);
606 
607     // Make sure we are root.
608     if (::getuid() != 0) {
609         LOG(ERROR) << "Not running as root. Try \"adb root\" first.";
610         return EXIT_FAILURE;
611     }
612 
613     if (argc < 3) {
614         std::cerr << " apply-update <directory location where snapshot patches are present> {-w}"
615                      "    Apply the snapshots to the COW block device\n";
616         return false;
617     }
618 
619     std::string path = std::string(argv[2]);
620     bool metadata_on_super = false;
621     if (argc == 4) {
622         if (std::string(argv[3]) == "-w") {
623             metadata_on_super = true;
624         }
625     }
626     MapSnapshots cow(path, metadata_on_super);
627     if (!cow.ApplyUpdate()) {
628         return false;
629     }
630     LOG(INFO) << "Apply update success. Please reboot the device";
631     return true;
632 }
633 
MapPrecreatedSnapshots(int argc,char ** argv)634 bool MapPrecreatedSnapshots(int argc, char** argv) {
635     android::base::InitLogging(argv, &android::base::KernelLogger);
636 
637     // Make sure we are root.
638     if (::getuid() != 0) {
639         LOG(ERROR) << "Not running as root. Try \"adb root\" first.";
640         return EXIT_FAILURE;
641     }
642 
643     if (argc < 3) {
644         std::cerr << " map-snapshots <directory location where snapshot patches are present> {-w}"
645                      "    Map all snapshots based on patches present in the directory\n";
646         return false;
647     }
648 
649     std::string path = std::string(argv[2]);
650     std::vector<std::string> patchfiles;
651 
652     for (const auto& entry : std::filesystem::directory_iterator(path)) {
653         if (android::base::EndsWith(entry.path().generic_string(), ".patch")) {
654             patchfiles.push_back(android::base::Basename(entry.path().generic_string()));
655         }
656     }
657     auto& dm = android::dm::DeviceMapper::Instance();
658     auto dm_block_devices = dm.FindDmPartitions();
659     if (dm_block_devices.empty()) {
660         LOG(ERROR) << "No dm-enabled block device is found.";
661         return false;
662     }
663 
664     std::vector<std::pair<std::string, std::string>> partitions;
665     for (auto& patchfile : patchfiles) {
666         auto npos = patchfile.rfind(".patch");
667         auto dm_block_name = patchfile.substr(0, npos);
668         if (dm_block_devices.find(dm_block_name) != dm_block_devices.end()) {
669             std::string slot_suffix = fs_mgr_get_slot_suffix();
670             std::string partition = dm_block_name + slot_suffix;
671             partitions.push_back(std::make_pair(partition, patchfile));
672         }
673     }
674 
675     bool metadata_on_super = false;
676     if (argc == 4) {
677         if (std::string(argv[3]) == "-w") {
678             metadata_on_super = true;
679         }
680     }
681 
682     MapSnapshots cow(path, metadata_on_super);
683     if (!cow.BeginUpdate()) {
684         LOG(ERROR) << "BeginUpdate failed";
685         return false;
686     }
687 
688     for (auto& pair : partitions) {
689         if (!cow.CreateSnapshotDevice(pair.first, pair.second)) {
690             LOG(ERROR) << "CreateSnapshotDevice failed for: " << pair.first;
691             return false;
692         }
693         if (!cow.InitiateThreadedSnapshotWrite(pair.first, pair.second)) {
694             LOG(ERROR) << "InitiateThreadedSnapshotWrite failed for: " << pair.first;
695             return false;
696         }
697     }
698 
699     return cow.FinishSnapshotWrites();
700 }
701 
CreateTestUpdate(SnapshotManager * sm)702 bool CreateTestUpdate(SnapshotManager* sm) {
703     chromeos_update_engine::DeltaArchiveManifest manifest;
704 
705     // We only copy system, to simplify things.
706     manifest.set_partial_update(true);
707 
708     auto dap = manifest.mutable_dynamic_partition_metadata();
709     dap->set_snapshot_enabled(true);
710     dap->set_vabc_enabled(true);
711     dap->set_vabc_compression_param("none");
712     dap->set_cow_version(kCowVersionMajor);
713 
714     auto source_slot = fs_mgr_get_slot_suffix();
715     auto source_slot_number = SlotNumberForSlotSuffix(source_slot);
716     auto target_slot = fs_mgr_get_other_slot_suffix();
717     auto target_slot_number = SlotNumberForSlotSuffix(target_slot);
718     auto super_source = fs_mgr_get_super_partition_name(source_slot_number);
719 
720     // Get current partition information.
721     PartitionOpener opener;
722     auto source_metadata = ReadMetadata(opener, super_source, source_slot_number);
723     if (!source_metadata) {
724         std::cerr << "Could not read source partition metadata.\n";
725         return false;
726     }
727 
728     auto system_source_name = "system" + source_slot;
729     auto system_source = FindPartition(*source_metadata.get(), system_source_name);
730     if (!system_source) {
731         std::cerr << "Could not find system partition: " << system_source_name << ".\n";
732         return false;
733     }
734     auto system_source_size = GetPartitionSize(*source_metadata.get(), *system_source);
735 
736     // Since we only add copy operations, 64MB should be enough.
737     auto system_update = manifest.mutable_partitions()->Add();
738     system_update->set_partition_name("system");
739     system_update->set_estimate_cow_size(64_MiB);
740     system_update->mutable_new_partition_info()->set_size(system_source_size);
741 
742     if (!sm->CreateUpdateSnapshots(manifest)) {
743         std::cerr << "Could not create update snapshots.\n";
744         return false;
745     }
746 
747     // Write the "new" system partition.
748     auto system_target_name = "system" + target_slot;
749     CreateLogicalPartitionParams clpp = {
750             .block_device = fs_mgr_get_super_partition_name(target_slot_number),
751             .metadata_slot = {target_slot_number},
752             .partition_name = system_target_name,
753             .timeout_ms = 10s,
754             .partition_opener = &opener,
755     };
756     auto writer = sm->OpenSnapshotWriter(clpp, std::nullopt);
757     if (!writer) {
758         std::cerr << "Could not open snapshot writer.\n";
759         return false;
760     }
761 
762     for (uint64_t block = 0; block < system_source_size / 4096; block++) {
763         if (!writer->AddCopy(block, block)) {
764             std::cerr << "Unable to add copy operation for block " << block << ".\n";
765             return false;
766         }
767     }
768     if (!writer->Finalize()) {
769         std::cerr << "Could not finalize COW for " << system_target_name << ".\n";
770         return false;
771     }
772     writer = nullptr;
773 
774     // Finished writing this partition, unmap.
775     if (!sm->UnmapUpdateSnapshot(system_target_name)) {
776         std::cerr << "Could not unmap snapshot for " << system_target_name << ".\n";
777         return false;
778     }
779 
780     // All snapshots have been written.
781     if (!sm->FinishedSnapshotWrites(false /* wipe */)) {
782         std::cerr << "Could not finalize snapshot writes.\n";
783         return false;
784     }
785 
786     auto hal = hal::BootControlClient::WaitForService();
787     if (!hal) {
788         std::cerr << "Could not find IBootControl HAL.\n";
789         return false;
790     }
791     auto cr = hal->SetActiveBootSlot(target_slot_number);
792     if (!cr.IsOk()) {
793         std::cerr << "Could not set active boot slot: " << cr.errMsg;
794         return false;
795     }
796 
797     std::cerr << "It is now safe to reboot your device. If using a physical device, make\n"
798               << "sure that all physical partitions are flashed to both A and B slots.\n";
799     return true;
800 }
801 
TestOtaHandler(int,char **)802 bool TestOtaHandler(int /* argc */, char** /* argv */) {
803     auto sm = SnapshotManager::New();
804 
805     if (!sm->BeginUpdate()) {
806         std::cerr << "Error starting update.\n";
807         return false;
808     }
809 
810     if (!CreateTestUpdate(sm.get())) {
811         sm->CancelUpdate();
812         return false;
813     }
814     return true;
815 }
816 #endif
817 
818 static std::map<std::string, std::function<bool(int, char**)>> kCmdMap = {
819         // clang-format off
820         {"dump", DumpCmdHandler},
821         {"merge", MergeCmdHandler},
822         {"map", MapCmdHandler},
823 #ifdef SNAPSHOTCTL_USERDEBUG_OR_ENG
824         {"test-blank-ota", TestOtaHandler},
825         {"apply-update", ApplyUpdate},
826         {"map-snapshots", MapPrecreatedSnapshots},
827         {"unmap-snapshots", UnMapPrecreatedSnapshots},
828         {"delete-snapshots", DeletePrecreatedSnapshots},
829         {"revert-snapshots", RemovePrecreatedSnapshots},
830 #endif
831         {"unmap", UnmapCmdHandler},
832         // clang-format on
833 };
834 
835 }  // namespace snapshot
836 }  // namespace android
837 
main(int argc,char ** argv)838 int main(int argc, char** argv) {
839     using namespace android::snapshot;
840     if (argc < 2) {
841         return Usage();
842     }
843 
844     for (const auto& cmd : kCmdMap) {
845         if (cmd.first == argv[1]) {
846             return cmd.second(argc, argv) ? EX_OK : EX_SOFTWARE;
847         }
848     }
849 
850     return Usage();
851 }
852