blob: a9bcbf43f65911a59f050d0adcacfe970aa79975 [file] [log] [blame]
Daniel Rosenberg65f99c92018-08-28 01:58:49 -07001/*
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"
Daniel Rosenberg253b44e2019-02-01 19:25:47 -080019#include "VoldUtil.h"
Daniel Rosenberg65f99c92018-08-28 01:58:49 -070020
Paul Lawrence1abb2fe2018-09-21 10:49:57 -070021#include <fstream>
Daniel Rosenberg65f99c92018-08-28 01:58:49 -070022#include <list>
Paul Lawrence20400892018-10-03 14:14:52 -070023#include <memory>
Daniel Rosenberg65f99c92018-08-28 01:58:49 -070024#include <string>
Paul Lawrence1abb2fe2018-09-21 10:49:57 -070025#include <vector>
26
27#include <android-base/file.h>
28#include <android-base/logging.h>
29#include <android-base/parseint.h>
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -080030#include <android-base/properties.h>
Paul Lawrence1abb2fe2018-09-21 10:49:57 -070031#include <android-base/unique_fd.h>
Daniel Rosenbergd3992492018-10-02 17:40:44 -070032#include <android/hardware/boot/1.0/IBootControl.h>
Paul Lawrence1abb2fe2018-09-21 10:49:57 -070033#include <cutils/android_reboot.h>
34#include <fcntl.h>
35#include <fs_mgr.h>
36#include <linux/fs.h>
37#include <mntent.h>
38#include <sys/mount.h>
39#include <sys/stat.h>
Daniel Rosenberg65f99c92018-08-28 01:58:49 -070040
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -080041using android::base::SetProperty;
Daniel Rosenberg73680ec2018-10-10 18:52:04 -070042using android::binder::Status;
Tom Cherry4c5bde22019-01-29 14:34:01 -080043using android::fs_mgr::Fstab;
44using android::fs_mgr::ReadDefaultFstab;
45using android::fs_mgr::ReadFstabFromFile;
Daniel Rosenbergd3992492018-10-02 17:40:44 -070046using android::hardware::hidl_string;
47using android::hardware::boot::V1_0::BoolResult;
48using android::hardware::boot::V1_0::IBootControl;
49using android::hardware::boot::V1_0::Slot;
50
Daniel Rosenberg65f99c92018-08-28 01:58:49 -070051namespace android {
52namespace vold {
53
Paul Lawrence1abb2fe2018-09-21 10:49:57 -070054namespace {
55const std::string kMetadataCPFile = "/metadata/vold/checkpoint";
56
57bool setBowState(std::string const& block_device, std::string const& state) {
58 if (block_device.substr(0, 5) != "/dev/") {
59 LOG(ERROR) << "Expected block device, got " << block_device;
60 return false;
61 }
62
63 std::string state_filename = std::string("/sys/") + block_device.substr(5) + "/bow/state";
64 if (!android::base::WriteStringToFile(state, state_filename)) {
65 PLOG(ERROR) << "Failed to write to file " << state_filename;
66 return false;
67 }
68
69 return true;
70}
71
72} // namespace
Daniel Rosenberg65f99c92018-08-28 01:58:49 -070073
Daniel Rosenberg9b667fb2019-01-22 17:27:25 -080074Status cp_supportsCheckpoint(bool& result) {
75 result = false;
Daniel Rosenberg9b667fb2019-01-22 17:27:25 -080076
Tom Cherry4c5bde22019-01-29 14:34:01 -080077 for (const auto& entry : fstab_default) {
78 if (entry.fs_mgr_flags.checkpoint_blk || entry.fs_mgr_flags.checkpoint_fs) {
Daniel Rosenberg9b667fb2019-01-22 17:27:25 -080079 result = true;
80 return Status::ok();
81 }
82 }
83 return Status::ok();
84}
85
Daniel Rosenberg73680ec2018-10-10 18:52:04 -070086Status cp_startCheckpoint(int retry) {
87 if (retry < -1) return Status::fromExceptionCode(EINVAL, "Retry count must be more than -1");
Daniel Rosenberg80d1ca52018-10-09 19:26:57 -070088 std::string content = std::to_string(retry + 1);
Daniel Rosenbergd3992492018-10-02 17:40:44 -070089 if (retry == -1) {
90 sp<IBootControl> module = IBootControl::getService();
91 if (module) {
92 std::string suffix;
93 auto cb = [&suffix](hidl_string s) { suffix = s; };
94 if (module->getSuffix(module->getCurrentSlot(), cb).isOk()) content += " " + suffix;
95 }
96 }
Daniel Rosenberg73680ec2018-10-10 18:52:04 -070097 if (!android::base::WriteStringToFile(content, kMetadataCPFile))
98 return Status::fromExceptionCode(errno, "Failed to write checkpoint file");
99 return Status::ok();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700100}
101
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800102namespace {
103
104bool isCheckpointing = false;
105}
106
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700107Status cp_commitChanges() {
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800108 if (!isCheckpointing) {
109 return Status::ok();
110 }
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700111 // Must take action for list of mounted checkpointed things here
112 // To do this, we walk the list of mounted file systems.
113 // But we also need to get the matching fstab entries to see
114 // the original flags
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700115 std::string err_str;
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700116
Tom Cherry4c5bde22019-01-29 14:34:01 -0800117 Fstab mounts;
118 if (!ReadFstabFromFile("/proc/mounts", &mounts)) {
119 return Status::fromExceptionCode(EINVAL, "Failed to get /proc/mounts");
120 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700121
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700122 // Walk mounted file systems
Tom Cherry4c5bde22019-01-29 14:34:01 -0800123 for (const auto& mount_rec : mounts) {
124 const auto fstab_rec = GetEntryForMountPoint(&fstab_default, mount_rec.mount_point);
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700125 if (!fstab_rec) continue;
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700126
Tom Cherry4c5bde22019-01-29 14:34:01 -0800127 if (fstab_rec->fs_mgr_flags.checkpoint_fs) {
128 if (fstab_rec->fs_type == "f2fs") {
129 std::string options = mount_rec.fs_options + ",checkpoint=enable";
130 if (mount(mount_rec.blk_device.c_str(), mount_rec.mount_point.c_str(), "none",
Daniel Rosenberg14ca4ac2019-01-24 18:23:18 -0800131 MS_REMOUNT | fstab_rec->flags, options.c_str())) {
Daniel Rosenberg4b86df12018-11-08 22:18:37 -0800132 return Status::fromExceptionCode(EINVAL, "Failed to remount");
133 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700134 }
Tom Cherry4c5bde22019-01-29 14:34:01 -0800135 } else if (fstab_rec->fs_mgr_flags.checkpoint_blk) {
136 if (!setBowState(mount_rec.blk_device, "2"))
Daniel Rosenberg4b86df12018-11-08 22:18:37 -0800137 return Status::fromExceptionCode(EINVAL, "Failed to set bow state");
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700138 }
139 }
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800140 SetProperty("vold.checkpoint_committed", "1");
141 isCheckpointing = false;
Daniel Rosenberg4b86df12018-11-08 22:18:37 -0800142 if (!android::base::RemoveFileIfExists(kMetadataCPFile, &err_str))
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700143 return Status::fromExceptionCode(errno, err_str.c_str());
144 return Status::ok();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700145}
146
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700147Status cp_abortChanges() {
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700148 android_reboot(ANDROID_RB_RESTART2, 0, nullptr);
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700149 return Status::ok();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700150}
151
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700152bool cp_needsRollback() {
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700153 std::string content;
154 bool ret;
155
156 ret = android::base::ReadFileToString(kMetadataCPFile, &content);
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700157 if (ret) {
158 if (content == "0") return true;
159 if (content.substr(0, 3) == "-1 ") {
160 std::string oldSuffix = content.substr(3);
161 sp<IBootControl> module = IBootControl::getService();
162 std::string newSuffix;
163
164 if (module) {
165 auto cb = [&newSuffix](hidl_string s) { newSuffix = s; };
166 module->getSuffix(module->getCurrentSlot(), cb);
167 if (oldSuffix == newSuffix) return true;
168 }
169 }
170 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700171 return false;
172}
173
Daniel Rosenberg80d1ca52018-10-09 19:26:57 -0700174bool cp_needsCheckpoint() {
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700175 bool ret;
176 std::string content;
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700177 sp<IBootControl> module = IBootControl::getService();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700178
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800179 if (module && module->isSlotMarkedSuccessful(module->getCurrentSlot()) == BoolResult::FALSE) {
180 isCheckpointing = true;
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700181 return true;
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800182 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700183 ret = android::base::ReadFileToString(kMetadataCPFile, &content);
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800184 if (ret) {
185 ret = content != "0";
186 isCheckpointing = ret;
187 return ret;
188 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700189 return false;
190}
191
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700192Status cp_prepareCheckpoint() {
Tom Cherry4c5bde22019-01-29 14:34:01 -0800193 Fstab mounts;
194 if (!ReadFstabFromFile("/proc/mounts", &mounts)) {
195 return Status::fromExceptionCode(EINVAL, "Failed to get /proc/mounts");
196 }
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700197
Tom Cherry4c5bde22019-01-29 14:34:01 -0800198 for (const auto& mount_rec : mounts) {
199 const auto fstab_rec = GetEntryForMountPoint(&fstab_default, mount_rec.mount_point);
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700200 if (!fstab_rec) continue;
201
Tom Cherry4c5bde22019-01-29 14:34:01 -0800202 if (fstab_rec->fs_mgr_flags.checkpoint_blk) {
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700203 android::base::unique_fd fd(
Tom Cherry4c5bde22019-01-29 14:34:01 -0800204 TEMP_FAILURE_RETRY(open(mount_rec.mount_point.c_str(), O_RDONLY | O_CLOEXEC)));
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700205 if (!fd) {
Tom Cherry4c5bde22019-01-29 14:34:01 -0800206 PLOG(ERROR) << "Failed to open mount point" << mount_rec.mount_point;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700207 continue;
208 }
209
210 struct fstrim_range range = {};
211 range.len = ULLONG_MAX;
212 if (ioctl(fd, FITRIM, &range)) {
Tom Cherry4c5bde22019-01-29 14:34:01 -0800213 PLOG(ERROR) << "Failed to trim " << mount_rec.mount_point;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700214 continue;
215 }
216
Tom Cherry4c5bde22019-01-29 14:34:01 -0800217 setBowState(mount_rec.blk_device, "1");
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700218 }
219 }
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700220 return Status::ok();
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700221}
222
223namespace {
224const int kBlockSize = 4096;
225const int kSectorSize = 512;
226
227typedef uint64_t sector_t;
228
229struct log_entry {
230 sector_t source;
231 sector_t dest;
232 uint32_t size;
233 uint32_t checksum;
234} __attribute__((packed));
235
236struct log_sector {
237 uint32_t magic;
238 uint32_t count;
239 uint32_t sequence;
Paul Lawrence27691c22018-11-20 14:07:59 -0800240 uint64_t sector0;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700241 struct log_entry entries[];
242} __attribute__((packed));
243
244// MAGIC is BOW in ascii
245const int kMagic = 0x00574f42;
246
247void crc32(const void* data, size_t n_bytes, uint32_t* crc) {
248 static uint32_t table[0x100] = {
249 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535,
250 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD,
251 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D,
252 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
253 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4,
254 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C,
255 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC,
256 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
257 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB,
258 0xB6662D3D,
259
260 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5,
261 0xE8B8D433, 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D,
262 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED,
263 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
264 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, 0x4DB26158, 0x3AB551CE, 0xA3BC0074,
265 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC,
266 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C,
267 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
268 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B,
269 0xC0BA6CAD,
270
271 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615,
272 0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D,
273 0x0A00AE27, 0x7D079EB1, 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D,
274 0x806567CB, 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
275 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4,
276 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, 0xD80D2BDA, 0xAF0A1B4C,
277 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, 0xCB61B38C,
278 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
279 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B,
280 0x5BDEAE1D,
281
282 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785,
283 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D,
284 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD,
285 0xF6B9265B, 0x6FB077E1, 0x18B74777, 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
286 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354,
287 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC,
288 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, 0xBDBDF21C,
289 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
290 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B,
291 0x2D02EF8D};
292
293 for (size_t i = 0; i < n_bytes; ++i) {
294 *crc ^= ((uint8_t*)data)[i];
295 *crc = table[(uint8_t)*crc] ^ *crc >> 8;
296 }
297}
298
299} // namespace
300
Paul Lawrence27691c22018-11-20 14:07:59 -0800301static void read(std::fstream& device, std::vector<log_entry> const& logs, sector_t sector,
302 char* buffer) {
303 for (auto l = logs.rbegin(); l != logs.rend(); l++)
304 if (sector >= l->source && (sector - l->source) * kSectorSize < l->size)
305 sector = sector - l->source + l->dest;
306
307 device.seekg(sector * kSectorSize);
308 device.read(buffer, kBlockSize);
309}
310
311static std::vector<char> read(std::fstream& device, std::vector<log_entry> const& logs,
312 bool validating, sector_t sector, uint32_t size) {
313 if (!validating) {
314 std::vector<char> buffer(size);
315 device.seekg(sector * kSectorSize);
316 device.read(&buffer[0], size);
317 return buffer;
318 }
319
320 // Crude approach at first where we do this sector by sector and just scan
321 // the entire logs for remappings each time
322 std::vector<char> buffer(size);
323
324 for (uint32_t i = 0; i < size; i += kBlockSize, sector += kBlockSize / kSectorSize)
325 read(device, logs, sector, &buffer[i]);
326
327 return buffer;
328}
329
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700330Status cp_restoreCheckpoint(const std::string& blockDevice) {
Paul Lawrence27691c22018-11-20 14:07:59 -0800331 bool validating = true;
332 std::string action = "Validating";
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700333
Paul Lawrence27691c22018-11-20 14:07:59 -0800334 for (;;) {
335 std::vector<log_entry> logs;
336 Status status = Status::ok();
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700337
Paul Lawrence27691c22018-11-20 14:07:59 -0800338 LOG(INFO) << action << " checkpoint on " << blockDevice;
339 std::fstream device(blockDevice, std::ios::binary | std::ios::in | std::ios::out);
340 if (!device) {
341 PLOG(ERROR) << "Cannot open " << blockDevice;
342 return Status::fromExceptionCode(errno, ("Cannot open " + blockDevice).c_str());
343 }
344 auto buffer = read(device, logs, validating, 0, kBlockSize);
345 log_sector& ls = *reinterpret_cast<log_sector*>(&buffer[0]);
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700346 if (ls.magic != kMagic) {
Paul Lawrence27691c22018-11-20 14:07:59 -0800347 LOG(ERROR) << "No magic";
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700348 return Status::fromExceptionCode(EINVAL, "No magic");
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700349 }
350
Paul Lawrence27691c22018-11-20 14:07:59 -0800351 LOG(INFO) << action << " " << ls.sequence << " log sectors";
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700352
Paul Lawrence27691c22018-11-20 14:07:59 -0800353 for (int sequence = ls.sequence; sequence >= 0 && status.isOk(); sequence--) {
354 auto buffer = read(device, logs, validating, 0, kBlockSize);
355 log_sector& ls = *reinterpret_cast<log_sector*>(&buffer[0]);
356 if (ls.magic != kMagic) {
357 LOG(ERROR) << "No magic!";
358 status = Status::fromExceptionCode(EINVAL, "No magic");
359 break;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700360 }
361
Paul Lawrence27691c22018-11-20 14:07:59 -0800362 if ((int)ls.sequence != sequence) {
363 LOG(ERROR) << "Expecting log sector " << sequence << " but got " << ls.sequence;
364 status = Status::fromExceptionCode(
365 EINVAL, ("Expecting log sector " + std::to_string(sequence) + " but got " +
366 std::to_string(ls.sequence))
367 .c_str());
368 break;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700369 }
370
Paul Lawrence27691c22018-11-20 14:07:59 -0800371 LOG(INFO) << action << " from log sector " << ls.sequence;
372
373 for (log_entry* le = &ls.entries[ls.count - 1]; le >= ls.entries; --le) {
374 LOG(INFO) << action << " " << le->size << " bytes from sector " << le->dest
375 << " to " << le->source << " with checksum " << std::hex << le->checksum;
376 auto buffer = read(device, logs, validating, le->dest, le->size);
377 uint32_t checksum = le->source / (kBlockSize / kSectorSize);
378 for (size_t i = 0; i < le->size; i += kBlockSize) {
379 crc32(&buffer[i], kBlockSize, &checksum);
380 }
381
382 if (le->checksum && checksum != le->checksum) {
383 LOG(ERROR) << "Checksums don't match " << std::hex << checksum;
384 status = Status::fromExceptionCode(EINVAL, "Checksums don't match");
385 break;
386 }
387
388 logs.push_back(*le);
389
390 if (!validating) {
391 device.seekg(le->source * kSectorSize);
392 device.write(&buffer[0], le->size);
393 }
394 }
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700395 }
Paul Lawrence27691c22018-11-20 14:07:59 -0800396
397 if (!status.isOk()) {
398 if (!validating) {
399 LOG(ERROR) << "Checkpoint restore failed even though checkpoint validation passed";
400 return status;
401 }
402
403 LOG(WARNING) << "Checkpoint validation failed - attempting to roll forward";
404 auto buffer = read(device, logs, false, ls.sector0, kBlockSize);
405 device.seekg(0);
406 device.write(&buffer[0], kBlockSize);
407 return Status::ok();
408 }
409
410 if (!validating) break;
411
412 validating = false;
413 action = "Restoring";
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700414 }
415
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700416 return Status::ok();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700417}
418
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700419Status cp_markBootAttempt() {
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700420 std::string oldContent, newContent;
421 int retry = 0;
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700422 struct stat st;
423 int result = stat(kMetadataCPFile.c_str(), &st);
424
425 // If the file doesn't exist, we aren't managing a checkpoint retry counter
426 if (result != 0) return Status::ok();
427 if (!android::base::ReadFileToString(kMetadataCPFile, &oldContent)) {
428 PLOG(ERROR) << "Failed to read checkpoint file";
429 return Status::fromExceptionCode(errno, "Failed to read checkpoint file");
430 }
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700431 std::string retryContent = oldContent.substr(0, oldContent.find_first_of(" "));
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700432
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700433 if (!android::base::ParseInt(retryContent, &retry))
434 return Status::fromExceptionCode(EINVAL, "Could not parse retry count");
435 if (retry > 0) {
436 retry--;
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700437
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700438 newContent = std::to_string(retry);
439 if (!android::base::WriteStringToFile(newContent, kMetadataCPFile))
440 return Status::fromExceptionCode(errno, "Could not write checkpoint file");
441 }
442 return Status::ok();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700443}
444
445} // namespace vold
446} // namespace android