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