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