blob: 633bd1f724421cb0711b418eff23985112798f3a [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"
19
Paul Lawrence1abb2fe2018-09-21 10:49:57 -070020#include <fstream>
Daniel Rosenberg65f99c92018-08-28 01:58:49 -070021#include <list>
Paul Lawrence20400892018-10-03 14:14:52 -070022#include <memory>
Daniel Rosenberg65f99c92018-08-28 01:58:49 -070023#include <string>
Paul Lawrence1abb2fe2018-09-21 10:49:57 -070024#include <vector>
25
26#include <android-base/file.h>
27#include <android-base/logging.h>
28#include <android-base/parseint.h>
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -080029#include <android-base/properties.h>
Paul Lawrence1abb2fe2018-09-21 10:49:57 -070030#include <android-base/unique_fd.h>
Daniel Rosenbergd3992492018-10-02 17:40:44 -070031#include <android/hardware/boot/1.0/IBootControl.h>
Paul Lawrence1abb2fe2018-09-21 10:49:57 -070032#include <cutils/android_reboot.h>
33#include <fcntl.h>
34#include <fs_mgr.h>
35#include <linux/fs.h>
36#include <mntent.h>
37#include <sys/mount.h>
38#include <sys/stat.h>
Daniel Rosenberg65f99c92018-08-28 01:58:49 -070039
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -080040using android::base::SetProperty;
Daniel Rosenberg73680ec2018-10-10 18:52:04 -070041using android::binder::Status;
Tom Cherry4c5bde22019-01-29 14:34:01 -080042using android::fs_mgr::Fstab;
43using android::fs_mgr::ReadDefaultFstab;
44using android::fs_mgr::ReadFstabFromFile;
Daniel Rosenbergd3992492018-10-02 17:40:44 -070045using android::hardware::hidl_string;
46using android::hardware::boot::V1_0::BoolResult;
47using android::hardware::boot::V1_0::IBootControl;
48using android::hardware::boot::V1_0::Slot;
49
Daniel Rosenberg65f99c92018-08-28 01:58:49 -070050namespace android {
51namespace vold {
52
Paul Lawrence1abb2fe2018-09-21 10:49:57 -070053namespace {
54const std::string kMetadataCPFile = "/metadata/vold/checkpoint";
55
56bool setBowState(std::string const& block_device, std::string const& state) {
57 if (block_device.substr(0, 5) != "/dev/") {
58 LOG(ERROR) << "Expected block device, got " << block_device;
59 return false;
60 }
61
62 std::string state_filename = std::string("/sys/") + block_device.substr(5) + "/bow/state";
63 if (!android::base::WriteStringToFile(state, state_filename)) {
64 PLOG(ERROR) << "Failed to write to file " << state_filename;
65 return false;
66 }
67
68 return true;
69}
70
71} // namespace
Daniel Rosenberg65f99c92018-08-28 01:58:49 -070072
Daniel Rosenberg9b667fb2019-01-22 17:27:25 -080073Status cp_supportsCheckpoint(bool& result) {
74 result = false;
Tom Cherry4c5bde22019-01-29 14:34:01 -080075 Fstab fstab_default;
76 if (!ReadDefaultFstab(&fstab_default)) {
77 return Status::fromExceptionCode(EINVAL, "Failed to get fstab");
78 }
Daniel Rosenberg9b667fb2019-01-22 17:27:25 -080079
Tom Cherry4c5bde22019-01-29 14:34:01 -080080 for (const auto& entry : fstab_default) {
81 if (entry.fs_mgr_flags.checkpoint_blk || entry.fs_mgr_flags.checkpoint_fs) {
Daniel Rosenberg9b667fb2019-01-22 17:27:25 -080082 result = true;
83 return Status::ok();
84 }
85 }
86 return Status::ok();
87}
88
Daniel Rosenberg73680ec2018-10-10 18:52:04 -070089Status cp_startCheckpoint(int retry) {
90 if (retry < -1) return Status::fromExceptionCode(EINVAL, "Retry count must be more than -1");
Daniel Rosenberg80d1ca52018-10-09 19:26:57 -070091 std::string content = std::to_string(retry + 1);
Daniel Rosenbergd3992492018-10-02 17:40:44 -070092 if (retry == -1) {
93 sp<IBootControl> module = IBootControl::getService();
94 if (module) {
95 std::string suffix;
96 auto cb = [&suffix](hidl_string s) { suffix = s; };
97 if (module->getSuffix(module->getCurrentSlot(), cb).isOk()) content += " " + suffix;
98 }
99 }
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700100 if (!android::base::WriteStringToFile(content, kMetadataCPFile))
101 return Status::fromExceptionCode(errno, "Failed to write checkpoint file");
102 return Status::ok();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700103}
104
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800105namespace {
106
107bool isCheckpointing = false;
108}
109
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700110Status cp_commitChanges() {
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800111 if (!isCheckpointing) {
112 return Status::ok();
113 }
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700114 // Must take action for list of mounted checkpointed things here
115 // To do this, we walk the list of mounted file systems.
116 // But we also need to get the matching fstab entries to see
117 // the original flags
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700118 std::string err_str;
Tom Cherry4c5bde22019-01-29 14:34:01 -0800119 Fstab fstab_default;
120 if (!ReadDefaultFstab(&fstab_default)) {
121 return Status::fromExceptionCode(EINVAL, "Failed to get fstab");
122 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700123
Tom Cherry4c5bde22019-01-29 14:34:01 -0800124 Fstab mounts;
125 if (!ReadFstabFromFile("/proc/mounts", &mounts)) {
126 return Status::fromExceptionCode(EINVAL, "Failed to get /proc/mounts");
127 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700128
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700129 // Walk mounted file systems
Tom Cherry4c5bde22019-01-29 14:34:01 -0800130 for (const auto& mount_rec : mounts) {
131 const auto fstab_rec = GetEntryForMountPoint(&fstab_default, mount_rec.mount_point);
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700132 if (!fstab_rec) continue;
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700133
Tom Cherry4c5bde22019-01-29 14:34:01 -0800134 if (fstab_rec->fs_mgr_flags.checkpoint_fs) {
135 if (fstab_rec->fs_type == "f2fs") {
136 std::string options = mount_rec.fs_options + ",checkpoint=enable";
137 if (mount(mount_rec.blk_device.c_str(), mount_rec.mount_point.c_str(), "none",
Daniel Rosenberg14ca4ac2019-01-24 18:23:18 -0800138 MS_REMOUNT | fstab_rec->flags, options.c_str())) {
Daniel Rosenberg4b86df12018-11-08 22:18:37 -0800139 return Status::fromExceptionCode(EINVAL, "Failed to remount");
140 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700141 }
Tom Cherry4c5bde22019-01-29 14:34:01 -0800142 } else if (fstab_rec->fs_mgr_flags.checkpoint_blk) {
143 if (!setBowState(mount_rec.blk_device, "2"))
Daniel Rosenberg4b86df12018-11-08 22:18:37 -0800144 return Status::fromExceptionCode(EINVAL, "Failed to set bow state");
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700145 }
146 }
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800147 SetProperty("vold.checkpoint_committed", "1");
148 isCheckpointing = false;
Daniel Rosenberg4b86df12018-11-08 22:18:37 -0800149 if (!android::base::RemoveFileIfExists(kMetadataCPFile, &err_str))
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700150 return Status::fromExceptionCode(errno, err_str.c_str());
151 return Status::ok();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700152}
153
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700154Status cp_abortChanges() {
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700155 android_reboot(ANDROID_RB_RESTART2, 0, nullptr);
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700156 return Status::ok();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700157}
158
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700159bool cp_needsRollback() {
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700160 std::string content;
161 bool ret;
162
163 ret = android::base::ReadFileToString(kMetadataCPFile, &content);
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700164 if (ret) {
165 if (content == "0") return true;
166 if (content.substr(0, 3) == "-1 ") {
167 std::string oldSuffix = content.substr(3);
168 sp<IBootControl> module = IBootControl::getService();
169 std::string newSuffix;
170
171 if (module) {
172 auto cb = [&newSuffix](hidl_string s) { newSuffix = s; };
173 module->getSuffix(module->getCurrentSlot(), cb);
174 if (oldSuffix == newSuffix) return true;
175 }
176 }
177 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700178 return false;
179}
180
Daniel Rosenberg80d1ca52018-10-09 19:26:57 -0700181bool cp_needsCheckpoint() {
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700182 bool ret;
183 std::string content;
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700184 sp<IBootControl> module = IBootControl::getService();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700185
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800186 if (module && module->isSlotMarkedSuccessful(module->getCurrentSlot()) == BoolResult::FALSE) {
187 isCheckpointing = true;
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700188 return true;
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800189 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700190 ret = android::base::ReadFileToString(kMetadataCPFile, &content);
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800191 if (ret) {
192 ret = content != "0";
193 isCheckpointing = ret;
194 return ret;
195 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700196 return false;
197}
198
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700199Status cp_prepareCheckpoint() {
Tom Cherry4c5bde22019-01-29 14:34:01 -0800200 Fstab fstab_default;
201 if (!ReadDefaultFstab(&fstab_default)) {
202 return Status::fromExceptionCode(EINVAL, "Failed to get fstab");
203 }
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700204
Tom Cherry4c5bde22019-01-29 14:34:01 -0800205 Fstab mounts;
206 if (!ReadFstabFromFile("/proc/mounts", &mounts)) {
207 return Status::fromExceptionCode(EINVAL, "Failed to get /proc/mounts");
208 }
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700209
Tom Cherry4c5bde22019-01-29 14:34:01 -0800210 for (const auto& mount_rec : mounts) {
211 const auto fstab_rec = GetEntryForMountPoint(&fstab_default, mount_rec.mount_point);
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700212 if (!fstab_rec) continue;
213
Tom Cherry4c5bde22019-01-29 14:34:01 -0800214 if (fstab_rec->fs_mgr_flags.checkpoint_blk) {
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700215 android::base::unique_fd fd(
Tom Cherry4c5bde22019-01-29 14:34:01 -0800216 TEMP_FAILURE_RETRY(open(mount_rec.mount_point.c_str(), O_RDONLY | O_CLOEXEC)));
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700217 if (!fd) {
Tom Cherry4c5bde22019-01-29 14:34:01 -0800218 PLOG(ERROR) << "Failed to open mount point" << mount_rec.mount_point;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700219 continue;
220 }
221
222 struct fstrim_range range = {};
223 range.len = ULLONG_MAX;
224 if (ioctl(fd, FITRIM, &range)) {
Tom Cherry4c5bde22019-01-29 14:34:01 -0800225 PLOG(ERROR) << "Failed to trim " << mount_rec.mount_point;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700226 continue;
227 }
228
Tom Cherry4c5bde22019-01-29 14:34:01 -0800229 setBowState(mount_rec.blk_device, "1");
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700230 }
231 }
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700232 return Status::ok();
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700233}
234
235namespace {
236const int kBlockSize = 4096;
237const int kSectorSize = 512;
238
239typedef uint64_t sector_t;
240
241struct log_entry {
242 sector_t source;
243 sector_t dest;
244 uint32_t size;
245 uint32_t checksum;
246} __attribute__((packed));
247
248struct log_sector {
249 uint32_t magic;
250 uint32_t count;
251 uint32_t sequence;
Paul Lawrence27691c22018-11-20 14:07:59 -0800252 uint64_t sector0;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700253 struct log_entry entries[];
254} __attribute__((packed));
255
256// MAGIC is BOW in ascii
257const int kMagic = 0x00574f42;
258
259void crc32(const void* data, size_t n_bytes, uint32_t* crc) {
260 static uint32_t table[0x100] = {
261 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535,
262 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD,
263 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D,
264 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
265 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4,
266 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C,
267 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC,
268 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
269 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB,
270 0xB6662D3D,
271
272 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5,
273 0xE8B8D433, 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D,
274 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED,
275 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
276 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, 0x4DB26158, 0x3AB551CE, 0xA3BC0074,
277 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC,
278 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C,
279 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
280 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B,
281 0xC0BA6CAD,
282
283 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615,
284 0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D,
285 0x0A00AE27, 0x7D079EB1, 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D,
286 0x806567CB, 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
287 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4,
288 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, 0xD80D2BDA, 0xAF0A1B4C,
289 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, 0xCB61B38C,
290 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
291 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B,
292 0x5BDEAE1D,
293
294 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785,
295 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D,
296 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD,
297 0xF6B9265B, 0x6FB077E1, 0x18B74777, 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
298 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354,
299 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC,
300 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, 0xBDBDF21C,
301 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
302 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B,
303 0x2D02EF8D};
304
305 for (size_t i = 0; i < n_bytes; ++i) {
306 *crc ^= ((uint8_t*)data)[i];
307 *crc = table[(uint8_t)*crc] ^ *crc >> 8;
308 }
309}
310
311} // namespace
312
Paul Lawrence27691c22018-11-20 14:07:59 -0800313static void read(std::fstream& device, std::vector<log_entry> const& logs, sector_t sector,
314 char* buffer) {
315 for (auto l = logs.rbegin(); l != logs.rend(); l++)
316 if (sector >= l->source && (sector - l->source) * kSectorSize < l->size)
317 sector = sector - l->source + l->dest;
318
319 device.seekg(sector * kSectorSize);
320 device.read(buffer, kBlockSize);
321}
322
323static std::vector<char> read(std::fstream& device, std::vector<log_entry> const& logs,
324 bool validating, sector_t sector, uint32_t size) {
325 if (!validating) {
326 std::vector<char> buffer(size);
327 device.seekg(sector * kSectorSize);
328 device.read(&buffer[0], size);
329 return buffer;
330 }
331
332 // Crude approach at first where we do this sector by sector and just scan
333 // the entire logs for remappings each time
334 std::vector<char> buffer(size);
335
336 for (uint32_t i = 0; i < size; i += kBlockSize, sector += kBlockSize / kSectorSize)
337 read(device, logs, sector, &buffer[i]);
338
339 return buffer;
340}
341
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700342Status cp_restoreCheckpoint(const std::string& blockDevice) {
Paul Lawrence27691c22018-11-20 14:07:59 -0800343 bool validating = true;
344 std::string action = "Validating";
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700345
Paul Lawrence27691c22018-11-20 14:07:59 -0800346 for (;;) {
347 std::vector<log_entry> logs;
348 Status status = Status::ok();
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700349
Paul Lawrence27691c22018-11-20 14:07:59 -0800350 LOG(INFO) << action << " checkpoint on " << blockDevice;
351 std::fstream device(blockDevice, std::ios::binary | std::ios::in | std::ios::out);
352 if (!device) {
353 PLOG(ERROR) << "Cannot open " << blockDevice;
354 return Status::fromExceptionCode(errno, ("Cannot open " + blockDevice).c_str());
355 }
356 auto buffer = read(device, logs, validating, 0, kBlockSize);
357 log_sector& ls = *reinterpret_cast<log_sector*>(&buffer[0]);
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700358 if (ls.magic != kMagic) {
Paul Lawrence27691c22018-11-20 14:07:59 -0800359 LOG(ERROR) << "No magic";
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700360 return Status::fromExceptionCode(EINVAL, "No magic");
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700361 }
362
Paul Lawrence27691c22018-11-20 14:07:59 -0800363 LOG(INFO) << action << " " << ls.sequence << " log sectors";
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700364
Paul Lawrence27691c22018-11-20 14:07:59 -0800365 for (int sequence = ls.sequence; sequence >= 0 && status.isOk(); sequence--) {
366 auto buffer = read(device, logs, validating, 0, kBlockSize);
367 log_sector& ls = *reinterpret_cast<log_sector*>(&buffer[0]);
368 if (ls.magic != kMagic) {
369 LOG(ERROR) << "No magic!";
370 status = Status::fromExceptionCode(EINVAL, "No magic");
371 break;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700372 }
373
Paul Lawrence27691c22018-11-20 14:07:59 -0800374 if ((int)ls.sequence != sequence) {
375 LOG(ERROR) << "Expecting log sector " << sequence << " but got " << ls.sequence;
376 status = Status::fromExceptionCode(
377 EINVAL, ("Expecting log sector " + std::to_string(sequence) + " but got " +
378 std::to_string(ls.sequence))
379 .c_str());
380 break;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700381 }
382
Paul Lawrence27691c22018-11-20 14:07:59 -0800383 LOG(INFO) << action << " from log sector " << ls.sequence;
384
385 for (log_entry* le = &ls.entries[ls.count - 1]; le >= ls.entries; --le) {
386 LOG(INFO) << action << " " << le->size << " bytes from sector " << le->dest
387 << " to " << le->source << " with checksum " << std::hex << le->checksum;
388 auto buffer = read(device, logs, validating, le->dest, le->size);
389 uint32_t checksum = le->source / (kBlockSize / kSectorSize);
390 for (size_t i = 0; i < le->size; i += kBlockSize) {
391 crc32(&buffer[i], kBlockSize, &checksum);
392 }
393
394 if (le->checksum && checksum != le->checksum) {
395 LOG(ERROR) << "Checksums don't match " << std::hex << checksum;
396 status = Status::fromExceptionCode(EINVAL, "Checksums don't match");
397 break;
398 }
399
400 logs.push_back(*le);
401
402 if (!validating) {
403 device.seekg(le->source * kSectorSize);
404 device.write(&buffer[0], le->size);
405 }
406 }
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700407 }
Paul Lawrence27691c22018-11-20 14:07:59 -0800408
409 if (!status.isOk()) {
410 if (!validating) {
411 LOG(ERROR) << "Checkpoint restore failed even though checkpoint validation passed";
412 return status;
413 }
414
415 LOG(WARNING) << "Checkpoint validation failed - attempting to roll forward";
416 auto buffer = read(device, logs, false, ls.sector0, kBlockSize);
417 device.seekg(0);
418 device.write(&buffer[0], kBlockSize);
419 return Status::ok();
420 }
421
422 if (!validating) break;
423
424 validating = false;
425 action = "Restoring";
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700426 }
427
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700428 return Status::ok();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700429}
430
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700431Status cp_markBootAttempt() {
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700432 std::string oldContent, newContent;
433 int retry = 0;
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700434 struct stat st;
435 int result = stat(kMetadataCPFile.c_str(), &st);
436
437 // If the file doesn't exist, we aren't managing a checkpoint retry counter
438 if (result != 0) return Status::ok();
439 if (!android::base::ReadFileToString(kMetadataCPFile, &oldContent)) {
440 PLOG(ERROR) << "Failed to read checkpoint file";
441 return Status::fromExceptionCode(errno, "Failed to read checkpoint file");
442 }
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700443 std::string retryContent = oldContent.substr(0, oldContent.find_first_of(" "));
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700444
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700445 if (!android::base::ParseInt(retryContent, &retry))
446 return Status::fromExceptionCode(EINVAL, "Could not parse retry count");
447 if (retry > 0) {
448 retry--;
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700449
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700450 newContent = std::to_string(retry);
451 if (!android::base::WriteStringToFile(newContent, kMetadataCPFile))
452 return Status::fromExceptionCode(errno, "Could not write checkpoint file");
453 }
454 return Status::ok();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700455}
456
457} // namespace vold
458} // namespace android