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