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