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