blob: cdfc8aa80004cf72918d08abf799deeb0a298a3f [file] [log] [blame]
bigbiffa957f072021-03-07 18:20:29 -05001/*
2 * Copyright (C) 2018 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#define LOG_TAG "Checkpoint"
18#include "Checkpoint.h"
19#include "VoldUtil.h"
20#include "VolumeManager.h"
21
22#include <fstream>
23#include <list>
24#include <memory>
25#include <string>
26#include <thread>
27#include <vector>
28
29#include <android-base/file.h>
30#include <android-base/logging.h>
31#include <android-base/parseint.h>
32#include <android-base/properties.h>
33#include <android-base/unique_fd.h>
34#include <android/hardware/boot/1.0/IBootControl.h>
35#include <cutils/android_reboot.h>
36#include <fcntl.h>
37#include <fs_mgr.h>
38#include <linux/fs.h>
39#include <mntent.h>
40#include <sys/mount.h>
41#include <sys/stat.h>
42#include <sys/statvfs.h>
43#include <unistd.h>
44
45using android::base::GetBoolProperty;
46using android::base::GetUintProperty;
47using android::base::SetProperty;
48using android::binder::Status;
49using android::fs_mgr::Fstab;
50using android::fs_mgr::ReadDefaultFstab;
51using android::fs_mgr::ReadFstabFromFile;
52using android::hardware::hidl_string;
53using android::hardware::boot::V1_0::BoolResult;
54using android::hardware::boot::V1_0::CommandResult;
55using android::hardware::boot::V1_0::IBootControl;
56using android::hardware::boot::V1_0::Slot;
57
58
59namespace {
60const std::string kMetadataCPFile = "/metadata/vold/checkpoint";
61
62android::binder::Status error(const std::string& msg) {
63 PLOG(ERROR) << msg;
64 return android::binder::Status::fromServiceSpecificError(errno, android::String8(msg.c_str()));
65}
66
67android::binder::Status error(int error, const std::string& msg) {
68 LOG(ERROR) << msg;
69 return android::binder::Status::fromServiceSpecificError(error, android::String8(msg.c_str()));
70}
71
72bool setBowState(std::string const& block_device, std::string const& state) {
73 std::string bow_device = fs_mgr_find_bow_device(block_device);
74 if (bow_device.empty()) return false;
75
76 if (!android::base::WriteStringToFile(state, bow_device + "/bow/state")) {
77 PLOG(ERROR) << "Failed to write to file " << bow_device + "/bow/state";
78 return false;
79 }
80
81 return true;
82}
83
84} // namespace
85
86Status cp_supportsCheckpoint(bool& result) {
87 result = false;
88
89 for (const auto& entry : fstab_default) {
90 if (entry.fs_mgr_flags.checkpoint_blk || entry.fs_mgr_flags.checkpoint_fs) {
91 result = true;
92 return Status::ok();
93 }
94 }
95 return Status::ok();
96}
97
98Status cp_supportsBlockCheckpoint(bool& result) {
99 result = false;
100
101 for (const auto& entry : fstab_default) {
102 if (entry.fs_mgr_flags.checkpoint_blk) {
103 result = true;
104 return Status::ok();
105 }
106 }
107 return Status::ok();
108}
109
110Status cp_supportsFileCheckpoint(bool& result) {
111 result = false;
112
113 for (const auto& entry : fstab_default) {
114 if (entry.fs_mgr_flags.checkpoint_fs) {
115 result = true;
116 return Status::ok();
117 }
118 }
119 return Status::ok();
120}
121
122Status cp_startCheckpoint(int retry) {
123 bool result;
124 if (!cp_supportsCheckpoint(result).isOk() || !result)
125 return error(ENOTSUP, "Checkpoints not supported");
126
127 if (retry < -1) return error(EINVAL, "Retry count must be more than -1");
128 std::string content = std::to_string(retry + 1);
129 if (retry == -1) {
130 android::sp<IBootControl> module = IBootControl::getService();
131 if (module) {
132 std::string suffix;
133 auto cb = [&suffix](hidl_string s) { suffix = s; };
134 if (module->getSuffix(module->getCurrentSlot(), cb).isOk()) content += " " + suffix;
135 }
136 }
137 if (!android::base::WriteStringToFile(content, kMetadataCPFile))
138 return error("Failed to write checkpoint file");
139 return Status::ok();
140}
141
142namespace {
143
144volatile bool isCheckpointing = false;
145
146volatile bool needsCheckpointWasCalled = false;
147
148// Protects isCheckpointing, needsCheckpointWasCalled and code that makes decisions based on status
149// of isCheckpointing
150std::mutex isCheckpointingLock;
151}
152
153Status cp_commitChanges() {
154 std::lock_guard<std::mutex> lock(isCheckpointingLock);
155
156 if (!isCheckpointing) {
157 return Status::ok();
158 }
159 if (android::base::GetProperty("persist.vold.dont_commit_checkpoint", "0") == "1") {
160 LOG(WARNING)
161 << "NOT COMMITTING CHECKPOINT BECAUSE persist.vold.dont_commit_checkpoint IS 1";
162 return Status::ok();
163 }
164 android::sp<IBootControl> module = IBootControl::getService();
165 if (module) {
166 CommandResult cr;
167 module->markBootSuccessful([&cr](CommandResult result) { cr = result; });
168 if (!cr.success)
169 return error(EINVAL, "Error marking booted successfully: " + std::string(cr.errMsg));
170 LOG(INFO) << "Marked slot as booted successfully.";
171 // Clears the warm reset flag for next reboot.
172 if (!SetProperty("ota.warm_reset", "0")) {
173 LOG(WARNING) << "Failed to reset the warm reset flag";
174 }
175 }
176 // Must take action for list of mounted checkpointed things here
177 // To do this, we walk the list of mounted file systems.
178 // But we also need to get the matching fstab entries to see
179 // the original flags
180 std::string err_str;
181
182 Fstab mounts;
183 if (!ReadFstabFromFile("/proc/mounts", &mounts)) {
184 return error(EINVAL, "Failed to get /proc/mounts");
185 }
186
187 // Walk mounted file systems
188 for (const auto& mount_rec : mounts) {
189 const auto fstab_rec = GetEntryForMountPoint(&fstab_default, mount_rec.mount_point);
190 if (!fstab_rec) continue;
191
192 if (fstab_rec->fs_mgr_flags.checkpoint_fs) {
193 if (fstab_rec->fs_type == "f2fs") {
194 std::string options = mount_rec.fs_options + ",checkpoint=enable";
195 if (mount(mount_rec.blk_device.c_str(), mount_rec.mount_point.c_str(), "none",
196 MS_REMOUNT | fstab_rec->flags, options.c_str())) {
197 return error(EINVAL, "Failed to remount");
198 }
199 }
200 } else if (fstab_rec->fs_mgr_flags.checkpoint_blk) {
201 if (!setBowState(mount_rec.blk_device, "2"))
202 return error(EINVAL, "Failed to set bow state");
203 }
204 }
205 SetProperty("vold.checkpoint_committed", "1");
206 LOG(INFO) << "Checkpoint has been committed.";
207 isCheckpointing = false;
208 if (!android::base::RemoveFileIfExists(kMetadataCPFile, &err_str))
209 return error(err_str.c_str());
210
211 return Status::ok();
212}
213
214namespace {
215void abort_metadata_file() {
216 std::string oldContent, newContent;
217 int retry = 0;
218 struct stat st;
219 int result = stat(kMetadataCPFile.c_str(), &st);
220
221 // If the file doesn't exist, we aren't managing a checkpoint retry counter
222 if (result != 0) return;
223 if (!android::base::ReadFileToString(kMetadataCPFile, &oldContent)) {
224 PLOG(ERROR) << "Failed to read checkpoint file";
225 return;
226 }
227 std::string retryContent = oldContent.substr(0, oldContent.find_first_of(" "));
228
229 if (!android::base::ParseInt(retryContent, &retry)) {
230 PLOG(ERROR) << "Could not parse retry count";
231 return;
232 }
233 if (retry > 0) {
234 newContent = "0";
235 if (!android::base::WriteStringToFile(newContent, kMetadataCPFile))
236 PLOG(ERROR) << "Could not write checkpoint file";
237 }
238}
239} // namespace
240
241void cp_abortChanges(const std::string& message, bool retry) {
242 if (!cp_needsCheckpoint()) return;
243 if (!retry) abort_metadata_file();
244 android_reboot(ANDROID_RB_RESTART2, 0, message.c_str());
245}
246
247bool cp_needsRollback() {
248 std::string content;
249 bool ret;
250
251 ret = android::base::ReadFileToString(kMetadataCPFile, &content);
252 if (ret) {
253 if (content == "0") return true;
254 if (content.substr(0, 3) == "-1 ") {
255 std::string oldSuffix = content.substr(3);
256 android::sp<IBootControl> module = IBootControl::getService();
257 std::string newSuffix;
258
259 if (module) {
260 auto cb = [&newSuffix](hidl_string s) { newSuffix = s; };
261 module->getSuffix(module->getCurrentSlot(), cb);
262 if (oldSuffix == newSuffix) return true;
263 }
264 }
265 }
266 return false;
267}
268
269bool cp_needsCheckpoint() {
270 std::lock_guard<std::mutex> lock(isCheckpointingLock);
271
272 // Make sure we only return true during boot. See b/138952436 for discussion
273 if (needsCheckpointWasCalled) return isCheckpointing;
274 needsCheckpointWasCalled = true;
275
276 bool ret;
277 std::string content;
278 android::sp<IBootControl> module = IBootControl::getService();
279
280 if (isCheckpointing) return isCheckpointing;
281
282 if (module && module->isSlotMarkedSuccessful(module->getCurrentSlot()) == BoolResult::FALSE) {
283 isCheckpointing = true;
284 return true;
285 }
286 ret = android::base::ReadFileToString(kMetadataCPFile, &content);
287 if (ret) {
288 ret = content != "0";
289 isCheckpointing = ret;
290 return ret;
291 }
292 return false;
293}
294
295bool cp_isCheckpointing() {
296 return isCheckpointing;
297}
298
299namespace {
300const std::string kSleepTimeProp = "ro.sys.cp_msleeptime";
301const uint32_t msleeptime_default = 1000; // 1 s
302const uint32_t max_msleeptime = 3600000; // 1 h
303
304const std::string kMinFreeBytesProp = "ro.sys.cp_min_free_bytes";
305const uint64_t min_free_bytes_default = 100 * (1 << 20); // 100 MiB
306
307const std::string kCommitOnFullProp = "ro.sys.cp_commit_on_full";
308const bool commit_on_full_default = true;
309
310static void cp_healthDaemon(std::string mnt_pnt, std::string blk_device, bool is_fs_cp) {
311 struct statvfs data;
312 uint32_t msleeptime = GetUintProperty(kSleepTimeProp, msleeptime_default, max_msleeptime);
313 uint64_t min_free_bytes =
314 GetUintProperty(kMinFreeBytesProp, min_free_bytes_default, (uint64_t)-1);
315 bool commit_on_full = GetBoolProperty(kCommitOnFullProp, commit_on_full_default);
316
317 struct timespec req;
318 req.tv_sec = msleeptime / 1000;
319 msleeptime %= 1000;
320 req.tv_nsec = msleeptime * 1000000;
321 while (isCheckpointing) {
322 uint64_t free_bytes = 0;
323 if (is_fs_cp) {
324 statvfs(mnt_pnt.c_str(), &data);
325 free_bytes = ((uint64_t) data.f_bavail) * data.f_frsize;
326 } else {
327 std::string bow_device = fs_mgr_find_bow_device(blk_device);
328 if (!bow_device.empty()) {
329 std::string content;
330 if (android::base::ReadFileToString(bow_device + "/bow/free", &content)) {
331 free_bytes = std::strtoull(content.c_str(), NULL, 10);
332 }
333 }
334 }
335 if (free_bytes < min_free_bytes) {
336 if (commit_on_full) {
337 LOG(INFO) << "Low space for checkpointing. Commiting changes";
338 cp_commitChanges();
339 break;
340 } else {
341 LOG(INFO) << "Low space for checkpointing. Rebooting";
342 cp_abortChanges("checkpoint,low_space", false);
343 break;
344 }
345 }
346 nanosleep(&req, NULL);
347 }
348}
349
350} // namespace
351
352Status cp_prepareCheckpoint() {
353 // Log to notify CTS - see b/137924328 for context
354 LOG(INFO) << "cp_prepareCheckpoint called";
355 std::lock_guard<std::mutex> lock(isCheckpointingLock);
356 if (!isCheckpointing) {
357 return Status::ok();
358 }
359
360 Fstab mounts;
361 if (!ReadFstabFromFile("/proc/mounts", &mounts)) {
362 return error(EINVAL, "Failed to get /proc/mounts");
363 }
364
365 for (const auto& mount_rec : mounts) {
366 const auto fstab_rec = GetEntryForMountPoint(&fstab_default, mount_rec.mount_point);
367 if (!fstab_rec) continue;
368
369 if (fstab_rec->fs_mgr_flags.checkpoint_blk) {
370 android::base::unique_fd fd(
371 TEMP_FAILURE_RETRY(open(mount_rec.mount_point.c_str(), O_RDONLY | O_CLOEXEC)));
372 if (fd == -1) {
373 PLOG(ERROR) << "Failed to open mount point" << mount_rec.mount_point;
374 continue;
375 }
376
377 struct fstrim_range range = {};
378 range.len = ULLONG_MAX;
379 nsecs_t start = systemTime(SYSTEM_TIME_BOOTTIME);
380 if (ioctl(fd, FITRIM, &range)) {
381 PLOG(ERROR) << "Failed to trim " << mount_rec.mount_point;
382 continue;
383 }
384 nsecs_t time = systemTime(SYSTEM_TIME_BOOTTIME) - start;
385 LOG(INFO) << "Trimmed " << range.len << " bytes on " << mount_rec.mount_point << " in "
386 << nanoseconds_to_milliseconds(time) << "ms for checkpoint";
387
388 setBowState(mount_rec.blk_device, "1");
389 }
390 if (fstab_rec->fs_mgr_flags.checkpoint_blk || fstab_rec->fs_mgr_flags.checkpoint_fs) {
391 std::thread(cp_healthDaemon, std::string(mount_rec.mount_point),
392 std::string(mount_rec.blk_device),
393 fstab_rec->fs_mgr_flags.checkpoint_fs == 1)
394 .detach();
395 }
396 }
397 return Status::ok();
398}
399
400namespace {
401const int kSectorSize = 512;
402
403typedef uint64_t sector_t;
404
405struct log_entry {
406 sector_t source; // in sectors of size kSectorSize
407 sector_t dest; // in sectors of size kSectorSize
408 uint32_t size; // in bytes
409 uint32_t checksum;
410} __attribute__((packed));
411
412struct log_sector_v1_0 {
413 uint32_t magic;
414 uint16_t header_version;
415 uint16_t header_size;
416 uint32_t block_size;
417 uint32_t count;
418 uint32_t sequence;
419 uint64_t sector0;
420} __attribute__((packed));
421
422// MAGIC is BOW in ascii
423const int kMagic = 0x00574f42;
424// Partially restored MAGIC is WOB in ascii
425const int kPartialRestoreMagic = 0x00424f57;
426
427void crc32(const void* data, size_t n_bytes, uint32_t* crc) {
428 static uint32_t table[0x100] = {
429 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535,
430 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD,
431 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D,
432 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
433 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4,
434 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C,
435 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC,
436 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
437 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB,
438 0xB6662D3D,
439
440 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5,
441 0xE8B8D433, 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D,
442 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED,
443 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
444 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, 0x4DB26158, 0x3AB551CE, 0xA3BC0074,
445 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC,
446 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C,
447 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
448 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B,
449 0xC0BA6CAD,
450
451 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615,
452 0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D,
453 0x0A00AE27, 0x7D079EB1, 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D,
454 0x806567CB, 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
455 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4,
456 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, 0xD80D2BDA, 0xAF0A1B4C,
457 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, 0xCB61B38C,
458 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
459 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B,
460 0x5BDEAE1D,
461
462 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785,
463 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D,
464 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD,
465 0xF6B9265B, 0x6FB077E1, 0x18B74777, 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
466 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354,
467 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC,
468 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, 0xBDBDF21C,
469 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
470 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B,
471 0x2D02EF8D};
472
473 for (size_t i = 0; i < n_bytes; ++i) {
474 *crc ^= ((uint8_t*)data)[i];
475 *crc = table[(uint8_t)*crc] ^ *crc >> 8;
476 }
477}
478
479// A map of relocations.
480// The map must be initialized so that relocations[0] = 0
481// During restore, we replay the log records in reverse, copying from dest to
482// source
483// To validate, we must be able to read the 'dest' sectors as though they had
484// been copied but without actually copying. This map represents how the sectors
485// would have been moved. To read a sector s, find the index <= s and read
486// relocations[index] + s - index
487typedef std::map<sector_t, sector_t> Relocations;
488
489void relocate(Relocations& relocations, sector_t dest, sector_t source, int count) {
490 // Find first one we're equal to or greater than
491 auto s = --relocations.upper_bound(source);
492
493 // Take slice
494 Relocations slice;
495 slice[dest] = source - s->first + s->second;
496 ++s;
497
498 // Add rest of elements
499 for (; s != relocations.end() && s->first < source + count; ++s)
500 slice[dest - source + s->first] = s->second;
501
502 // Split range at end of dest
503 auto dest_end = --relocations.upper_bound(dest + count);
504 relocations[dest + count] = dest + count - dest_end->first + dest_end->second;
505
506 // Remove all elements in [dest, dest + count)
507 relocations.erase(relocations.lower_bound(dest), relocations.lower_bound(dest + count));
508
509 // Add new elements
510 relocations.insert(slice.begin(), slice.end());
511}
512
513// A map of sectors that have been written to.
514// The final entry must always be False.
515// When we restart the restore after an interruption, we must take care that
516// when we copy from dest to source, that the block we copy to was not
517// previously copied from.
518// i e. A->B C->A; If we replay this sequence, we end up copying C->B
519// We must save our partial result whenever we finish a page, or when we copy
520// to a location that was copied from earlier (our source is an earlier dest)
521typedef std::map<sector_t, bool> Used_Sectors;
522
523bool checkCollision(Used_Sectors& used_sectors, sector_t start, sector_t end) {
524 auto second_overlap = used_sectors.upper_bound(start);
525 auto first_overlap = --second_overlap;
526
527 if (first_overlap->second) {
528 return true;
529 } else if (second_overlap != used_sectors.end() && second_overlap->first < end) {
530 return true;
531 }
532 return false;
533}
534
535void markUsed(Used_Sectors& used_sectors, sector_t start, sector_t end) {
536 auto start_pos = used_sectors.insert_or_assign(start, true).first;
537 auto end_pos = used_sectors.insert_or_assign(end, false).first;
538
539 if (start_pos == used_sectors.begin() || !std::prev(start_pos)->second) {
540 start_pos++;
541 }
542 if (std::next(end_pos) != used_sectors.end() && !std::next(end_pos)->second) {
543 end_pos++;
544 }
545 if (start_pos->first < end_pos->first) {
546 used_sectors.erase(start_pos, end_pos);
547 }
548}
549
550// Restores the given log_entry's data from dest -> source
551// If that entry is a log sector, set the magic to kPartialRestoreMagic and flush.
552void restoreSector(int device_fd, Used_Sectors& used_sectors, std::vector<char>& ls_buffer,
553 log_entry* le, std::vector<char>& buffer) {
554 log_sector_v1_0& ls = *reinterpret_cast<log_sector_v1_0*>(&ls_buffer[0]);
555 uint32_t index = le - ((log_entry*)&ls_buffer[ls.header_size]);
556 int count = (le->size - 1) / kSectorSize + 1;
557
558 if (checkCollision(used_sectors, le->source, le->source + count)) {
559 fsync(device_fd);
560 lseek64(device_fd, 0, SEEK_SET);
561 ls.count = index + 1;
562 ls.magic = kPartialRestoreMagic;
563 write(device_fd, &ls_buffer[0], ls.block_size);
564 fsync(device_fd);
565 used_sectors.clear();
566 used_sectors[0] = false;
567 }
568
569 markUsed(used_sectors, le->dest, le->dest + count);
570
571 if (index == 0 && ls.sequence != 0) {
572 log_sector_v1_0* next = reinterpret_cast<log_sector_v1_0*>(&buffer[0]);
573 if (next->magic == kMagic) {
574 next->magic = kPartialRestoreMagic;
575 }
576 }
577
578 lseek64(device_fd, le->source * kSectorSize, SEEK_SET);
579 write(device_fd, &buffer[0], le->size);
580
581 if (index == 0) {
582 fsync(device_fd);
583 }
584}
585
586// Read from the device
587// If we are validating, the read occurs as though the relocations had happened
588std::vector<char> relocatedRead(int device_fd, Relocations const& relocations, bool validating,
589 sector_t sector, uint32_t size, uint32_t block_size) {
590 if (!validating) {
591 std::vector<char> buffer(size);
592 lseek64(device_fd, sector * kSectorSize, SEEK_SET);
593 read(device_fd, &buffer[0], size);
594 return buffer;
595 }
596
597 std::vector<char> buffer(size);
598 for (uint32_t i = 0; i < size; i += block_size, sector += block_size / kSectorSize) {
599 auto relocation = --relocations.upper_bound(sector);
600 lseek64(device_fd, (sector + relocation->second - relocation->first) * kSectorSize,
601 SEEK_SET);
602 read(device_fd, &buffer[i], block_size);
603 }
604
605 return buffer;
606}
607
608} // namespace
609
610Status cp_restoreCheckpoint(const std::string& blockDevice, int restore_limit) {
611 bool validating = true;
612 std::string action = "Validating";
613 int restore_count = 0;
614
615 for (;;) {
616 Relocations relocations;
617 relocations[0] = 0;
618 Status status = Status::ok();
619
620 LOG(INFO) << action << " checkpoint on " << blockDevice;
621 android::base::unique_fd device_fd(open(blockDevice.c_str(), O_RDWR | O_CLOEXEC));
622 if (device_fd < 0) return error("Cannot open " + blockDevice);
623
624 log_sector_v1_0 original_ls;
625 read(device_fd, reinterpret_cast<char*>(&original_ls), sizeof(original_ls));
626 if (original_ls.magic == kPartialRestoreMagic) {
627 validating = false;
628 action = "Restoring";
629 } else if (original_ls.magic != kMagic) {
630 return error(EINVAL, "No magic");
631 }
632
633 LOG(INFO) << action << " " << original_ls.sequence << " log sectors";
634
635 for (int sequence = original_ls.sequence; sequence >= 0 && status.isOk(); sequence--) {
636 auto ls_buffer = relocatedRead(device_fd, relocations, validating, 0,
637 original_ls.block_size, original_ls.block_size);
638 log_sector_v1_0& ls = *reinterpret_cast<log_sector_v1_0*>(&ls_buffer[0]);
639
640 Used_Sectors used_sectors;
641 used_sectors[0] = false;
642
643 if (ls.magic != kMagic && (ls.magic != kPartialRestoreMagic || validating)) {
644 status = error(EINVAL, "No magic");
645 break;
646 }
647
648 if (ls.block_size != original_ls.block_size) {
649 status = error(EINVAL, "Block size mismatch");
650 break;
651 }
652
653 if ((int)ls.sequence != sequence) {
654 status = error(EINVAL, "Expecting log sector " + std::to_string(sequence) +
655 " but got " + std::to_string(ls.sequence));
656 break;
657 }
658
659 LOG(INFO) << action << " from log sector " << ls.sequence;
660 for (log_entry* le =
661 reinterpret_cast<log_entry*>(&ls_buffer[ls.header_size]) + ls.count - 1;
662 le >= reinterpret_cast<log_entry*>(&ls_buffer[ls.header_size]); --le) {
663 // This is very noisy - limit to DEBUG only
664 LOG(VERBOSE) << action << " " << le->size << " bytes from sector " << le->dest
665 << " to " << le->source << " with checksum " << std::hex
666 << le->checksum;
667
668 auto buffer = relocatedRead(device_fd, relocations, validating, le->dest, le->size,
669 ls.block_size);
670 uint32_t checksum = le->source / (ls.block_size / kSectorSize);
671 for (size_t i = 0; i < le->size; i += ls.block_size) {
672 crc32(&buffer[i], ls.block_size, &checksum);
673 }
674
675 if (le->checksum && checksum != le->checksum) {
676 status = error(EINVAL, "Checksums don't match");
677 break;
678 }
679
680 if (validating) {
681 relocate(relocations, le->source, le->dest, (le->size - 1) / kSectorSize + 1);
682 } else {
683 restoreSector(device_fd, used_sectors, ls_buffer, le, buffer);
684 restore_count++;
685 if (restore_limit && restore_count >= restore_limit) {
686 status = error(EAGAIN, "Hit the test limit");
687 break;
688 }
689 }
690 }
691 }
692
693 if (!status.isOk()) {
694 if (!validating) {
695 LOG(ERROR) << "Checkpoint restore failed even though checkpoint validation passed";
696 return status;
697 }
698
699 LOG(WARNING) << "Checkpoint validation failed - attempting to roll forward";
700 auto buffer = relocatedRead(device_fd, relocations, false, original_ls.sector0,
701 original_ls.block_size, original_ls.block_size);
702 lseek64(device_fd, 0, SEEK_SET);
703 write(device_fd, &buffer[0], original_ls.block_size);
704 return Status::ok();
705 }
706
707 if (!validating) break;
708
709 validating = false;
710 action = "Restoring";
711 }
712
713 return Status::ok();
714}
715
716Status cp_markBootAttempt() {
717 std::string oldContent, newContent;
718 int retry = 0;
719 struct stat st;
720 int result = stat(kMetadataCPFile.c_str(), &st);
721
722 // If the file doesn't exist, we aren't managing a checkpoint retry counter
723 if (result != 0) return Status::ok();
724 if (!android::base::ReadFileToString(kMetadataCPFile, &oldContent))
725 return error("Failed to read checkpoint file");
726 std::string retryContent = oldContent.substr(0, oldContent.find_first_of(" "));
727
728 if (!android::base::ParseInt(retryContent, &retry))
729 return error(EINVAL, "Could not parse retry count");
730 if (retry > 0) {
731 retry--;
732
733 newContent = std::to_string(retry);
734 if (!android::base::WriteStringToFile(newContent, kMetadataCPFile))
735 return error("Could not write checkpoint file");
736 }
737 return Status::ok();
738}
739
740void cp_resetCheckpoint() {
741 std::lock_guard<std::mutex> lock(isCheckpointingLock);
742 needsCheckpointWasCalled = false;
743}