2 * Copyright (C) 2018 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #define LOG_TAG "Checkpoint"
18 #include "Checkpoint.h"
28 #include <android-base/file.h>
29 #include <android-base/logging.h>
30 #include <android-base/parseint.h>
31 #include <android-base/properties.h>
32 #include <android-base/unique_fd.h>
33 #include <android/hardware/boot/1.0/IBootControl.h>
34 #include <cutils/android_reboot.h>
39 #include <sys/mount.h>
41 #include <sys/statvfs.h>
44 using android::base::GetBoolProperty;
45 using android::base::GetUintProperty;
46 using android::base::SetProperty;
47 using android::binder::Status;
48 using android::fs_mgr::Fstab;
49 using android::fs_mgr::ReadDefaultFstab;
50 using android::fs_mgr::ReadFstabFromFile;
51 using android::hardware::hidl_string;
52 using android::hardware::boot::V1_0::BoolResult;
53 using android::hardware::boot::V1_0::CommandResult;
54 using android::hardware::boot::V1_0::IBootControl;
55 using android::hardware::boot::V1_0::Slot;
61 const std::string kMetadataCPFile = "/metadata/vold/checkpoint";
63 bool setBowState(std::string const& block_device, std::string const& state) {
64 if (block_device.substr(0, 5) != "/dev/") {
65 LOG(ERROR) << "Expected block device, got " << block_device;
69 std::string state_filename = std::string("/sys/") + block_device.substr(5) + "/bow/state";
70 if (!android::base::WriteStringToFile(state, state_filename)) {
71 PLOG(ERROR) << "Failed to write to file " << state_filename;
80 Status cp_supportsCheckpoint(bool& result) {
83 for (const auto& entry : fstab_default) {
84 if (entry.fs_mgr_flags.checkpoint_blk || entry.fs_mgr_flags.checkpoint_fs) {
92 Status cp_supportsBlockCheckpoint(bool& result) {
95 for (const auto& entry : fstab_default) {
96 if (entry.fs_mgr_flags.checkpoint_blk) {
104 Status cp_supportsFileCheckpoint(bool& result) {
107 for (const auto& entry : fstab_default) {
108 if (entry.fs_mgr_flags.checkpoint_fs) {
116 Status cp_startCheckpoint(int retry) {
117 if (retry < -1) return Status::fromExceptionCode(EINVAL, "Retry count must be more than -1");
118 std::string content = std::to_string(retry + 1);
120 sp<IBootControl> module = IBootControl::getService();
123 auto cb = [&suffix](hidl_string s) { suffix = s; };
124 if (module->getSuffix(module->getCurrentSlot(), cb).isOk()) content += " " + suffix;
127 if (!android::base::WriteStringToFile(content, kMetadataCPFile))
128 return Status::fromExceptionCode(errno, "Failed to write checkpoint file");
134 volatile bool isCheckpointing = false;
137 Status cp_commitChanges() {
138 if (!isCheckpointing) {
141 sp<IBootControl> module = IBootControl::getService();
144 module->markBootSuccessful([&cr](CommandResult result) { cr = result; });
146 std::string msg = "Error marking booted successfully: " + std::string(cr.errMsg);
147 return Status::fromExceptionCode(EINVAL, String8(msg.c_str()));
149 LOG(INFO) << "Marked slot as booted successfully.";
151 // Must take action for list of mounted checkpointed things here
152 // To do this, we walk the list of mounted file systems.
153 // But we also need to get the matching fstab entries to see
154 // the original flags
158 if (!ReadFstabFromFile("/proc/mounts", &mounts)) {
159 return Status::fromExceptionCode(EINVAL, "Failed to get /proc/mounts");
162 // Walk mounted file systems
163 for (const auto& mount_rec : mounts) {
164 const auto fstab_rec = GetEntryForMountPoint(&fstab_default, mount_rec.mount_point);
165 if (!fstab_rec) continue;
167 if (fstab_rec->fs_mgr_flags.checkpoint_fs) {
168 if (fstab_rec->fs_type == "f2fs") {
169 std::string options = mount_rec.fs_options + ",checkpoint=enable";
170 if (mount(mount_rec.blk_device.c_str(), mount_rec.mount_point.c_str(), "none",
171 MS_REMOUNT | fstab_rec->flags, options.c_str())) {
172 return Status::fromExceptionCode(EINVAL, "Failed to remount");
175 } else if (fstab_rec->fs_mgr_flags.checkpoint_blk) {
176 if (!setBowState(mount_rec.blk_device, "2"))
177 return Status::fromExceptionCode(EINVAL, "Failed to set bow state");
180 SetProperty("vold.checkpoint_committed", "1");
181 LOG(INFO) << "Checkpoint has been committed.";
182 isCheckpointing = false;
183 if (!android::base::RemoveFileIfExists(kMetadataCPFile, &err_str))
184 return Status::fromExceptionCode(errno, err_str.c_str());
189 void abort_metadata_file() {
190 std::string oldContent, newContent;
193 int result = stat(kMetadataCPFile.c_str(), &st);
195 // If the file doesn't exist, we aren't managing a checkpoint retry counter
196 if (result != 0) return;
197 if (!android::base::ReadFileToString(kMetadataCPFile, &oldContent)) {
198 PLOG(ERROR) << "Failed to read checkpoint file";
201 std::string retryContent = oldContent.substr(0, oldContent.find_first_of(" "));
203 if (!android::base::ParseInt(retryContent, &retry)) {
204 PLOG(ERROR) << "Could not parse retry count";
209 if (!android::base::WriteStringToFile(newContent, kMetadataCPFile))
210 PLOG(ERROR) << "Could not write checkpoint file";
215 void cp_abortChanges(const std::string& message, bool retry) {
216 if (!cp_needsCheckpoint()) return;
217 if (!retry) abort_metadata_file();
218 android_reboot(ANDROID_RB_RESTART2, 0, message.c_str());
221 bool cp_needsRollback() {
225 ret = android::base::ReadFileToString(kMetadataCPFile, &content);
227 if (content == "0") return true;
228 if (content.substr(0, 3) == "-1 ") {
229 std::string oldSuffix = content.substr(3);
230 sp<IBootControl> module = IBootControl::getService();
231 std::string newSuffix;
234 auto cb = [&newSuffix](hidl_string s) { newSuffix = s; };
235 module->getSuffix(module->getCurrentSlot(), cb);
236 if (oldSuffix == newSuffix) return true;
243 bool cp_needsCheckpoint() {
246 sp<IBootControl> module = IBootControl::getService();
248 if (isCheckpointing) return isCheckpointing;
250 if (module && module->isSlotMarkedSuccessful(module->getCurrentSlot()) == BoolResult::FALSE) {
251 isCheckpointing = true;
254 ret = android::base::ReadFileToString(kMetadataCPFile, &content);
256 ret = content != "0";
257 isCheckpointing = ret;
264 const std::string kSleepTimeProp = "ro.sys.cp_msleeptime";
265 const uint32_t msleeptime_default = 1000; // 1 s
266 const uint32_t max_msleeptime = 3600000; // 1 h
268 const std::string kMinFreeBytesProp = "ro.sys.cp_min_free_bytes";
269 const uint64_t min_free_bytes_default = 100 * (1 << 20); // 100 MiB
271 const std::string kCommitOnFullProp = "ro.sys.cp_commit_on_full";
272 const bool commit_on_full_default = true;
274 static void cp_healthDaemon(std::string mnt_pnt, std::string blk_device, bool is_fs_cp) {
276 uint64_t free_bytes = 0;
277 uint32_t msleeptime = GetUintProperty(kSleepTimeProp, msleeptime_default, max_msleeptime);
278 uint64_t min_free_bytes =
279 GetUintProperty(kMinFreeBytesProp, min_free_bytes_default, (uint64_t)-1);
280 bool commit_on_full = GetBoolProperty(kCommitOnFullProp, commit_on_full_default);
283 req.tv_sec = msleeptime / 1000;
285 req.tv_nsec = msleeptime * 1000000;
286 while (isCheckpointing) {
288 statvfs(mnt_pnt.c_str(), &data);
289 free_bytes = data.f_bavail * data.f_frsize;
292 std::string size_filename = std::string("/sys/") + blk_device.substr(5) + "/bow/free";
294 ret = android::base::ReadFileToString(kMetadataCPFile, &content);
296 free_bytes = std::strtoul(content.c_str(), NULL, 10);
299 if (free_bytes < min_free_bytes) {
300 if (commit_on_full) {
301 LOG(INFO) << "Low space for checkpointing. Commiting changes";
305 LOG(INFO) << "Low space for checkpointing. Rebooting";
306 cp_abortChanges("checkpoint,low_space", false);
310 nanosleep(&req, NULL);
316 Status cp_prepareCheckpoint() {
317 if (!isCheckpointing) {
322 if (!ReadFstabFromFile("/proc/mounts", &mounts)) {
323 return Status::fromExceptionCode(EINVAL, "Failed to get /proc/mounts");
326 for (const auto& mount_rec : mounts) {
327 const auto fstab_rec = GetEntryForMountPoint(&fstab_default, mount_rec.mount_point);
328 if (!fstab_rec) continue;
330 if (fstab_rec->fs_mgr_flags.checkpoint_blk) {
331 android::base::unique_fd fd(
332 TEMP_FAILURE_RETRY(open(mount_rec.mount_point.c_str(), O_RDONLY | O_CLOEXEC)));
334 PLOG(ERROR) << "Failed to open mount point" << mount_rec.mount_point;
338 struct fstrim_range range = {};
339 range.len = ULLONG_MAX;
340 if (ioctl(fd, FITRIM, &range)) {
341 PLOG(ERROR) << "Failed to trim " << mount_rec.mount_point;
345 setBowState(mount_rec.blk_device, "1");
347 if (fstab_rec->fs_mgr_flags.checkpoint_blk || fstab_rec->fs_mgr_flags.checkpoint_fs) {
348 std::thread(cp_healthDaemon, std::string(mount_rec.mount_point),
349 std::string(mount_rec.mount_point),
350 fstab_rec->fs_mgr_flags.checkpoint_fs == 1)
358 const int kSectorSize = 512;
360 typedef uint64_t sector_t;
363 sector_t source; // in sectors of size kSectorSize
364 sector_t dest; // in sectors of size kSectorSize
365 uint32_t size; // in bytes
367 } __attribute__((packed));
369 struct log_sector_v1_0 {
371 uint16_t header_version;
372 uint16_t header_size;
377 } __attribute__((packed));
379 // MAGIC is BOW in ascii
380 const int kMagic = 0x00574f42;
381 // Partially restored MAGIC is WOB in ascii
382 const int kPartialRestoreMagic = 0x00424f57;
384 void crc32(const void* data, size_t n_bytes, uint32_t* crc) {
385 static uint32_t table[0x100] = {
386 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535,
387 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD,
388 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D,
389 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
390 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4,
391 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C,
392 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC,
393 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
394 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB,
397 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5,
398 0xE8B8D433, 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D,
399 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED,
400 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
401 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, 0x4DB26158, 0x3AB551CE, 0xA3BC0074,
402 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC,
403 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C,
404 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
405 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B,
408 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615,
409 0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D,
410 0x0A00AE27, 0x7D079EB1, 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D,
411 0x806567CB, 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
412 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4,
413 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, 0xD80D2BDA, 0xAF0A1B4C,
414 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, 0xCB61B38C,
415 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
416 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B,
419 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785,
420 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D,
421 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD,
422 0xF6B9265B, 0x6FB077E1, 0x18B74777, 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
423 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354,
424 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC,
425 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, 0xBDBDF21C,
426 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
427 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B,
430 for (size_t i = 0; i < n_bytes; ++i) {
431 *crc ^= ((uint8_t*)data)[i];
432 *crc = table[(uint8_t)*crc] ^ *crc >> 8;
436 // A map of relocations.
437 // The map must be initialized so that relocations[0] = 0
438 // During restore, we replay the log records in reverse, copying from dest to
440 // To validate, we must be able to read the 'dest' sectors as though they had
441 // been copied but without actually copying. This map represents how the sectors
442 // would have been moved. To read a sector s, find the index <= s and read
443 // relocations[index] + s - index
444 typedef std::map<sector_t, sector_t> Relocations;
446 void relocate(Relocations& relocations, sector_t dest, sector_t source, int count) {
447 // Find first one we're equal to or greater than
448 auto s = --relocations.upper_bound(source);
452 slice[dest] = source - s->first + s->second;
455 // Add rest of elements
456 for (; s != relocations.end() && s->first < source + count; ++s)
457 slice[dest - source + s->first] = s->second;
459 // Split range at end of dest
460 auto dest_end = --relocations.upper_bound(dest + count);
461 relocations[dest + count] = dest + count - dest_end->first + dest_end->second;
463 // Remove all elements in [dest, dest + count)
464 relocations.erase(relocations.lower_bound(dest), relocations.lower_bound(dest + count));
467 relocations.insert(slice.begin(), slice.end());
470 // A map of sectors that have been written to.
471 // The final entry must always be False.
472 // When we restart the restore after an interruption, we must take care that
473 // when we copy from dest to source, that the block we copy to was not
474 // previously copied from.
475 // i e. A->B C->A; If we replay this sequence, we end up copying C->B
476 // We must save our partial result whenever we finish a page, or when we copy
477 // to a location that was copied from earlier (our source is an earlier dest)
478 typedef std::map<sector_t, bool> Used_Sectors;
480 bool checkCollision(Used_Sectors& used_sectors, sector_t start, sector_t end) {
481 auto second_overlap = used_sectors.upper_bound(start);
482 auto first_overlap = --second_overlap;
484 if (first_overlap->second) {
486 } else if (second_overlap != used_sectors.end() && second_overlap->first < end) {
492 void markUsed(Used_Sectors& used_sectors, sector_t start, sector_t end) {
493 auto start_pos = used_sectors.insert_or_assign(start, true).first;
494 auto end_pos = used_sectors.insert_or_assign(end, false).first;
496 if (start_pos == used_sectors.begin() || !std::prev(start_pos)->second) {
499 if (std::next(end_pos) != used_sectors.end() && !std::next(end_pos)->second) {
502 if (start_pos->first < end_pos->first) {
503 used_sectors.erase(start_pos, end_pos);
507 // Restores the given log_entry's data from dest -> source
508 // If that entry is a log sector, set the magic to kPartialRestoreMagic and flush.
509 void restoreSector(int device_fd, Used_Sectors& used_sectors, std::vector<char>& ls_buffer,
510 log_entry* le, std::vector<char>& buffer) {
511 log_sector_v1_0& ls = *reinterpret_cast<log_sector_v1_0*>(&ls_buffer[0]);
512 uint32_t index = le - ((log_entry*)&ls_buffer[ls.header_size]);
513 int count = (le->size - 1) / kSectorSize + 1;
515 if (checkCollision(used_sectors, le->source, le->source + count)) {
517 lseek64(device_fd, 0, SEEK_SET);
518 ls.count = index + 1;
519 ls.magic = kPartialRestoreMagic;
520 write(device_fd, &ls_buffer[0], ls.block_size);
522 used_sectors.clear();
523 used_sectors[0] = false;
526 markUsed(used_sectors, le->dest, le->dest + count);
528 if (index == 0 && ls.sequence != 0) {
529 log_sector_v1_0* next = reinterpret_cast<log_sector_v1_0*>(&buffer[0]);
530 if (next->magic == kMagic) {
531 next->magic = kPartialRestoreMagic;
535 lseek64(device_fd, le->source * kSectorSize, SEEK_SET);
536 write(device_fd, &buffer[0], le->size);
543 // Read from the device
544 // If we are validating, the read occurs as though the relocations had happened
545 std::vector<char> relocatedRead(int device_fd, Relocations const& relocations, bool validating,
546 sector_t sector, uint32_t size, uint32_t block_size) {
548 std::vector<char> buffer(size);
549 lseek64(device_fd, sector * kSectorSize, SEEK_SET);
550 read(device_fd, &buffer[0], size);
554 std::vector<char> buffer(size);
555 for (uint32_t i = 0; i < size; i += block_size, sector += block_size / kSectorSize) {
556 auto relocation = --relocations.upper_bound(sector);
557 lseek64(device_fd, (sector + relocation->second - relocation->first) * kSectorSize,
559 read(device_fd, &buffer[i], block_size);
567 Status cp_restoreCheckpoint(const std::string& blockDevice, int restore_limit) {
568 bool validating = true;
569 std::string action = "Validating";
570 int restore_count = 0;
573 Relocations relocations;
575 Status status = Status::ok();
577 LOG(INFO) << action << " checkpoint on " << blockDevice;
578 base::unique_fd device_fd(open(blockDevice.c_str(), O_RDWR));
580 PLOG(ERROR) << "Cannot open " << blockDevice;
581 return Status::fromExceptionCode(errno, ("Cannot open " + blockDevice).c_str());
584 log_sector_v1_0 original_ls;
585 read(device_fd, reinterpret_cast<char*>(&original_ls), sizeof(original_ls));
586 if (original_ls.magic == kPartialRestoreMagic) {
588 action = "Restoring";
589 } else if (original_ls.magic != kMagic) {
590 LOG(ERROR) << "No magic";
591 return Status::fromExceptionCode(EINVAL, "No magic");
594 LOG(INFO) << action << " " << original_ls.sequence << " log sectors";
596 for (int sequence = original_ls.sequence; sequence >= 0 && status.isOk(); sequence--) {
597 auto ls_buffer = relocatedRead(device_fd, relocations, validating, 0,
598 original_ls.block_size, original_ls.block_size);
599 log_sector_v1_0& ls = *reinterpret_cast<log_sector_v1_0*>(&ls_buffer[0]);
601 Used_Sectors used_sectors;
602 used_sectors[0] = false;
604 if (ls.magic != kMagic && (ls.magic != kPartialRestoreMagic || validating)) {
605 LOG(ERROR) << "No magic!";
606 status = Status::fromExceptionCode(EINVAL, "No magic");
610 if (ls.block_size != original_ls.block_size) {
611 LOG(ERROR) << "Block size mismatch!";
612 status = Status::fromExceptionCode(EINVAL, "Block size mismatch");
616 if ((int)ls.sequence != sequence) {
617 LOG(ERROR) << "Expecting log sector " << sequence << " but got " << ls.sequence;
618 status = Status::fromExceptionCode(
619 EINVAL, ("Expecting log sector " + std::to_string(sequence) + " but got " +
620 std::to_string(ls.sequence))
625 LOG(INFO) << action << " from log sector " << ls.sequence;
627 reinterpret_cast<log_entry*>(&ls_buffer[ls.header_size]) + ls.count - 1;
628 le >= reinterpret_cast<log_entry*>(&ls_buffer[ls.header_size]); --le) {
629 // This is very noisy - limit to DEBUG only
630 LOG(VERBOSE) << action << " " << le->size << " bytes from sector " << le->dest
631 << " to " << le->source << " with checksum " << std::hex
634 auto buffer = relocatedRead(device_fd, relocations, validating, le->dest, le->size,
636 uint32_t checksum = le->source / (ls.block_size / kSectorSize);
637 for (size_t i = 0; i < le->size; i += ls.block_size) {
638 crc32(&buffer[i], ls.block_size, &checksum);
641 if (le->checksum && checksum != le->checksum) {
642 LOG(ERROR) << "Checksums don't match " << std::hex << checksum;
643 status = Status::fromExceptionCode(EINVAL, "Checksums don't match");
648 relocate(relocations, le->source, le->dest, (le->size - 1) / kSectorSize + 1);
650 restoreSector(device_fd, used_sectors, ls_buffer, le, buffer);
652 if (restore_limit && restore_count >= restore_limit) {
653 LOG(WARNING) << "Hit the test limit";
654 status = Status::fromExceptionCode(EAGAIN, "Hit the test limit");
661 if (!status.isOk()) {
663 LOG(ERROR) << "Checkpoint restore failed even though checkpoint validation passed";
667 LOG(WARNING) << "Checkpoint validation failed - attempting to roll forward";
668 auto buffer = relocatedRead(device_fd, relocations, false, original_ls.sector0,
669 original_ls.block_size, original_ls.block_size);
670 lseek64(device_fd, 0, SEEK_SET);
671 write(device_fd, &buffer[0], original_ls.block_size);
675 if (!validating) break;
678 action = "Restoring";
684 Status cp_markBootAttempt() {
685 std::string oldContent, newContent;
688 int result = stat(kMetadataCPFile.c_str(), &st);
690 // If the file doesn't exist, we aren't managing a checkpoint retry counter
691 if (result != 0) return Status::ok();
692 if (!android::base::ReadFileToString(kMetadataCPFile, &oldContent)) {
693 PLOG(ERROR) << "Failed to read checkpoint file";
694 return Status::fromExceptionCode(errno, "Failed to read checkpoint file");
696 std::string retryContent = oldContent.substr(0, oldContent.find_first_of(" "));
698 if (!android::base::ParseInt(retryContent, &retry))
699 return Status::fromExceptionCode(EINVAL, "Could not parse retry count");
703 newContent = std::to_string(retry);
704 if (!android::base::WriteStringToFile(newContent, kMetadataCPFile))
705 return Status::fromExceptionCode(errno, "Could not write checkpoint file");
711 } // namespace android