blob: 0f6edcfa48c6b547dfa8a1acd550df95c87ffe9b [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;
Daniel Rosenberg886915b2019-01-23 15:16:04 -080048using android::hardware::boot::V1_0::CommandResult;
Daniel Rosenbergd3992492018-10-02 17:40:44 -070049using android::hardware::boot::V1_0::IBootControl;
50using android::hardware::boot::V1_0::Slot;
51
Daniel Rosenberg65f99c92018-08-28 01:58:49 -070052namespace android {
53namespace vold {
54
Paul Lawrence1abb2fe2018-09-21 10:49:57 -070055namespace {
56const std::string kMetadataCPFile = "/metadata/vold/checkpoint";
57
58bool setBowState(std::string const& block_device, std::string const& state) {
59 if (block_device.substr(0, 5) != "/dev/") {
60 LOG(ERROR) << "Expected block device, got " << block_device;
61 return false;
62 }
63
64 std::string state_filename = std::string("/sys/") + block_device.substr(5) + "/bow/state";
65 if (!android::base::WriteStringToFile(state, state_filename)) {
66 PLOG(ERROR) << "Failed to write to file " << state_filename;
67 return false;
68 }
69
70 return true;
71}
72
73} // namespace
Daniel Rosenberg65f99c92018-08-28 01:58:49 -070074
Daniel Rosenberg9b667fb2019-01-22 17:27:25 -080075Status cp_supportsCheckpoint(bool& result) {
76 result = false;
Daniel Rosenberg9b667fb2019-01-22 17:27:25 -080077
Tom Cherry4c5bde22019-01-29 14:34:01 -080078 for (const auto& entry : fstab_default) {
79 if (entry.fs_mgr_flags.checkpoint_blk || entry.fs_mgr_flags.checkpoint_fs) {
Daniel Rosenberg9b667fb2019-01-22 17:27:25 -080080 result = true;
81 return Status::ok();
82 }
83 }
84 return Status::ok();
85}
86
Daniel Rosenberg73680ec2018-10-10 18:52:04 -070087Status cp_startCheckpoint(int retry) {
88 if (retry < -1) return Status::fromExceptionCode(EINVAL, "Retry count must be more than -1");
Daniel Rosenberg80d1ca52018-10-09 19:26:57 -070089 std::string content = std::to_string(retry + 1);
Daniel Rosenbergd3992492018-10-02 17:40:44 -070090 if (retry == -1) {
91 sp<IBootControl> module = IBootControl::getService();
92 if (module) {
93 std::string suffix;
94 auto cb = [&suffix](hidl_string s) { suffix = s; };
95 if (module->getSuffix(module->getCurrentSlot(), cb).isOk()) content += " " + suffix;
96 }
97 }
Daniel Rosenberg73680ec2018-10-10 18:52:04 -070098 if (!android::base::WriteStringToFile(content, kMetadataCPFile))
99 return Status::fromExceptionCode(errno, "Failed to write checkpoint file");
100 return Status::ok();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700101}
102
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800103namespace {
104
105bool isCheckpointing = false;
106}
107
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700108Status cp_commitChanges() {
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800109 if (!isCheckpointing) {
110 return Status::ok();
111 }
Daniel Rosenberg886915b2019-01-23 15:16:04 -0800112 sp<IBootControl> module = IBootControl::getService();
113 if (module) {
114 CommandResult cr;
115 module->markBootSuccessful([&cr](CommandResult result) { cr = result; });
116 if (!cr.success) {
117 std::string msg = "Error marking booted successfully: " + std::string(cr.errMsg);
118 return Status::fromExceptionCode(EINVAL, String8(msg.c_str()));
119 }
120 LOG(INFO) << "Marked slot as booted successfully.";
121 }
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700122 // Must take action for list of mounted checkpointed things here
123 // To do this, we walk the list of mounted file systems.
124 // But we also need to get the matching fstab entries to see
125 // the original flags
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700126 std::string err_str;
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700127
Tom Cherry4c5bde22019-01-29 14:34:01 -0800128 Fstab mounts;
129 if (!ReadFstabFromFile("/proc/mounts", &mounts)) {
130 return Status::fromExceptionCode(EINVAL, "Failed to get /proc/mounts");
131 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700132
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700133 // Walk mounted file systems
Tom Cherry4c5bde22019-01-29 14:34:01 -0800134 for (const auto& mount_rec : mounts) {
135 const auto fstab_rec = GetEntryForMountPoint(&fstab_default, mount_rec.mount_point);
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700136 if (!fstab_rec) continue;
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700137
Tom Cherry4c5bde22019-01-29 14:34:01 -0800138 if (fstab_rec->fs_mgr_flags.checkpoint_fs) {
139 if (fstab_rec->fs_type == "f2fs") {
140 std::string options = mount_rec.fs_options + ",checkpoint=enable";
141 if (mount(mount_rec.blk_device.c_str(), mount_rec.mount_point.c_str(), "none",
Daniel Rosenberg14ca4ac2019-01-24 18:23:18 -0800142 MS_REMOUNT | fstab_rec->flags, options.c_str())) {
Daniel Rosenberg4b86df12018-11-08 22:18:37 -0800143 return Status::fromExceptionCode(EINVAL, "Failed to remount");
144 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700145 }
Tom Cherry4c5bde22019-01-29 14:34:01 -0800146 } else if (fstab_rec->fs_mgr_flags.checkpoint_blk) {
147 if (!setBowState(mount_rec.blk_device, "2"))
Daniel Rosenberg4b86df12018-11-08 22:18:37 -0800148 return Status::fromExceptionCode(EINVAL, "Failed to set bow state");
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700149 }
150 }
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800151 SetProperty("vold.checkpoint_committed", "1");
Daniel Rosenberg886915b2019-01-23 15:16:04 -0800152 LOG(INFO) << "Checkpoint has been committed.";
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800153 isCheckpointing = false;
Daniel Rosenberg4b86df12018-11-08 22:18:37 -0800154 if (!android::base::RemoveFileIfExists(kMetadataCPFile, &err_str))
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700155 return Status::fromExceptionCode(errno, err_str.c_str());
156 return Status::ok();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700157}
158
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700159Status cp_abortChanges() {
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700160 android_reboot(ANDROID_RB_RESTART2, 0, nullptr);
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700161 return Status::ok();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700162}
163
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700164bool cp_needsRollback() {
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700165 std::string content;
166 bool ret;
167
168 ret = android::base::ReadFileToString(kMetadataCPFile, &content);
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700169 if (ret) {
170 if (content == "0") return true;
171 if (content.substr(0, 3) == "-1 ") {
172 std::string oldSuffix = content.substr(3);
173 sp<IBootControl> module = IBootControl::getService();
174 std::string newSuffix;
175
176 if (module) {
177 auto cb = [&newSuffix](hidl_string s) { newSuffix = s; };
178 module->getSuffix(module->getCurrentSlot(), cb);
179 if (oldSuffix == newSuffix) return true;
180 }
181 }
182 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700183 return false;
184}
185
Daniel Rosenberg80d1ca52018-10-09 19:26:57 -0700186bool cp_needsCheckpoint() {
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700187 bool ret;
188 std::string content;
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700189 sp<IBootControl> module = IBootControl::getService();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700190
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800191 if (module && module->isSlotMarkedSuccessful(module->getCurrentSlot()) == BoolResult::FALSE) {
192 isCheckpointing = true;
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700193 return true;
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800194 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700195 ret = android::base::ReadFileToString(kMetadataCPFile, &content);
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800196 if (ret) {
197 ret = content != "0";
198 isCheckpointing = ret;
199 return ret;
200 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700201 return false;
202}
203
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700204Status cp_prepareCheckpoint() {
Paul Lawrencedb086942019-02-19 14:18:54 -0800205 if (!isCheckpointing) {
206 return Status::ok();
207 }
208
Tom Cherry4c5bde22019-01-29 14:34:01 -0800209 Fstab mounts;
210 if (!ReadFstabFromFile("/proc/mounts", &mounts)) {
211 return Status::fromExceptionCode(EINVAL, "Failed to get /proc/mounts");
212 }
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700213
Tom Cherry4c5bde22019-01-29 14:34:01 -0800214 for (const auto& mount_rec : mounts) {
215 const auto fstab_rec = GetEntryForMountPoint(&fstab_default, mount_rec.mount_point);
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700216 if (!fstab_rec) continue;
217
Tom Cherry4c5bde22019-01-29 14:34:01 -0800218 if (fstab_rec->fs_mgr_flags.checkpoint_blk) {
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700219 android::base::unique_fd fd(
Tom Cherry4c5bde22019-01-29 14:34:01 -0800220 TEMP_FAILURE_RETRY(open(mount_rec.mount_point.c_str(), O_RDONLY | O_CLOEXEC)));
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700221 if (!fd) {
Tom Cherry4c5bde22019-01-29 14:34:01 -0800222 PLOG(ERROR) << "Failed to open mount point" << mount_rec.mount_point;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700223 continue;
224 }
225
226 struct fstrim_range range = {};
227 range.len = ULLONG_MAX;
228 if (ioctl(fd, FITRIM, &range)) {
Tom Cherry4c5bde22019-01-29 14:34:01 -0800229 PLOG(ERROR) << "Failed to trim " << mount_rec.mount_point;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700230 continue;
231 }
232
Tom Cherry4c5bde22019-01-29 14:34:01 -0800233 setBowState(mount_rec.blk_device, "1");
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700234 }
235 }
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700236 return Status::ok();
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700237}
238
239namespace {
240const int kBlockSize = 4096;
241const int kSectorSize = 512;
242
243typedef uint64_t sector_t;
244
245struct log_entry {
246 sector_t source;
247 sector_t dest;
248 uint32_t size;
249 uint32_t checksum;
250} __attribute__((packed));
251
252struct log_sector {
253 uint32_t magic;
254 uint32_t count;
255 uint32_t sequence;
Paul Lawrence27691c22018-11-20 14:07:59 -0800256 uint64_t sector0;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700257 struct log_entry entries[];
258} __attribute__((packed));
259
260// MAGIC is BOW in ascii
261const int kMagic = 0x00574f42;
262
263void crc32(const void* data, size_t n_bytes, uint32_t* crc) {
264 static uint32_t table[0x100] = {
265 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535,
266 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD,
267 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D,
268 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
269 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4,
270 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C,
271 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC,
272 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
273 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB,
274 0xB6662D3D,
275
276 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5,
277 0xE8B8D433, 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D,
278 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED,
279 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
280 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, 0x4DB26158, 0x3AB551CE, 0xA3BC0074,
281 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC,
282 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C,
283 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
284 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B,
285 0xC0BA6CAD,
286
287 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615,
288 0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D,
289 0x0A00AE27, 0x7D079EB1, 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D,
290 0x806567CB, 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
291 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4,
292 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, 0xD80D2BDA, 0xAF0A1B4C,
293 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, 0xCB61B38C,
294 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
295 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B,
296 0x5BDEAE1D,
297
298 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785,
299 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D,
300 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD,
301 0xF6B9265B, 0x6FB077E1, 0x18B74777, 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
302 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354,
303 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC,
304 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, 0xBDBDF21C,
305 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
306 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B,
307 0x2D02EF8D};
308
309 for (size_t i = 0; i < n_bytes; ++i) {
310 *crc ^= ((uint8_t*)data)[i];
311 *crc = table[(uint8_t)*crc] ^ *crc >> 8;
312 }
313}
314
315} // namespace
316
Paul Lawrence27691c22018-11-20 14:07:59 -0800317static void read(std::fstream& device, std::vector<log_entry> const& logs, sector_t sector,
318 char* buffer) {
319 for (auto l = logs.rbegin(); l != logs.rend(); l++)
320 if (sector >= l->source && (sector - l->source) * kSectorSize < l->size)
321 sector = sector - l->source + l->dest;
322
323 device.seekg(sector * kSectorSize);
324 device.read(buffer, kBlockSize);
325}
326
327static std::vector<char> read(std::fstream& device, std::vector<log_entry> const& logs,
328 bool validating, sector_t sector, uint32_t size) {
329 if (!validating) {
330 std::vector<char> buffer(size);
331 device.seekg(sector * kSectorSize);
332 device.read(&buffer[0], size);
333 return buffer;
334 }
335
336 // Crude approach at first where we do this sector by sector and just scan
337 // the entire logs for remappings each time
338 std::vector<char> buffer(size);
339
340 for (uint32_t i = 0; i < size; i += kBlockSize, sector += kBlockSize / kSectorSize)
341 read(device, logs, sector, &buffer[i]);
342
343 return buffer;
344}
345
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700346Status cp_restoreCheckpoint(const std::string& blockDevice) {
Paul Lawrence27691c22018-11-20 14:07:59 -0800347 bool validating = true;
348 std::string action = "Validating";
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700349
Paul Lawrence27691c22018-11-20 14:07:59 -0800350 for (;;) {
351 std::vector<log_entry> logs;
352 Status status = Status::ok();
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700353
Paul Lawrence27691c22018-11-20 14:07:59 -0800354 LOG(INFO) << action << " checkpoint on " << blockDevice;
355 std::fstream device(blockDevice, std::ios::binary | std::ios::in | std::ios::out);
356 if (!device) {
357 PLOG(ERROR) << "Cannot open " << blockDevice;
358 return Status::fromExceptionCode(errno, ("Cannot open " + blockDevice).c_str());
359 }
360 auto buffer = read(device, logs, validating, 0, kBlockSize);
361 log_sector& ls = *reinterpret_cast<log_sector*>(&buffer[0]);
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700362 if (ls.magic != kMagic) {
Paul Lawrence27691c22018-11-20 14:07:59 -0800363 LOG(ERROR) << "No magic";
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700364 return Status::fromExceptionCode(EINVAL, "No magic");
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700365 }
366
Paul Lawrence27691c22018-11-20 14:07:59 -0800367 LOG(INFO) << action << " " << ls.sequence << " log sectors";
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700368
Paul Lawrence27691c22018-11-20 14:07:59 -0800369 for (int sequence = ls.sequence; sequence >= 0 && status.isOk(); sequence--) {
370 auto buffer = read(device, logs, validating, 0, kBlockSize);
371 log_sector& ls = *reinterpret_cast<log_sector*>(&buffer[0]);
372 if (ls.magic != kMagic) {
373 LOG(ERROR) << "No magic!";
374 status = Status::fromExceptionCode(EINVAL, "No magic");
375 break;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700376 }
377
Paul Lawrence27691c22018-11-20 14:07:59 -0800378 if ((int)ls.sequence != sequence) {
379 LOG(ERROR) << "Expecting log sector " << sequence << " but got " << ls.sequence;
380 status = Status::fromExceptionCode(
381 EINVAL, ("Expecting log sector " + std::to_string(sequence) + " but got " +
382 std::to_string(ls.sequence))
383 .c_str());
384 break;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700385 }
386
Paul Lawrence27691c22018-11-20 14:07:59 -0800387 LOG(INFO) << action << " from log sector " << ls.sequence;
388
389 for (log_entry* le = &ls.entries[ls.count - 1]; le >= ls.entries; --le) {
390 LOG(INFO) << action << " " << le->size << " bytes from sector " << le->dest
391 << " to " << le->source << " with checksum " << std::hex << le->checksum;
392 auto buffer = read(device, logs, validating, le->dest, le->size);
393 uint32_t checksum = le->source / (kBlockSize / kSectorSize);
394 for (size_t i = 0; i < le->size; i += kBlockSize) {
395 crc32(&buffer[i], kBlockSize, &checksum);
396 }
397
398 if (le->checksum && checksum != le->checksum) {
399 LOG(ERROR) << "Checksums don't match " << std::hex << checksum;
400 status = Status::fromExceptionCode(EINVAL, "Checksums don't match");
401 break;
402 }
403
404 logs.push_back(*le);
405
406 if (!validating) {
407 device.seekg(le->source * kSectorSize);
408 device.write(&buffer[0], le->size);
409 }
410 }
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700411 }
Paul Lawrence27691c22018-11-20 14:07:59 -0800412
413 if (!status.isOk()) {
414 if (!validating) {
415 LOG(ERROR) << "Checkpoint restore failed even though checkpoint validation passed";
416 return status;
417 }
418
419 LOG(WARNING) << "Checkpoint validation failed - attempting to roll forward";
420 auto buffer = read(device, logs, false, ls.sector0, kBlockSize);
421 device.seekg(0);
422 device.write(&buffer[0], kBlockSize);
423 return Status::ok();
424 }
425
426 if (!validating) break;
427
428 validating = false;
429 action = "Restoring";
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700430 }
431
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700432 return Status::ok();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700433}
434
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700435Status cp_markBootAttempt() {
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700436 std::string oldContent, newContent;
437 int retry = 0;
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700438 struct stat st;
439 int result = stat(kMetadataCPFile.c_str(), &st);
440
441 // If the file doesn't exist, we aren't managing a checkpoint retry counter
442 if (result != 0) return Status::ok();
443 if (!android::base::ReadFileToString(kMetadataCPFile, &oldContent)) {
444 PLOG(ERROR) << "Failed to read checkpoint file";
445 return Status::fromExceptionCode(errno, "Failed to read checkpoint file");
446 }
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700447 std::string retryContent = oldContent.substr(0, oldContent.find_first_of(" "));
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700448
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700449 if (!android::base::ParseInt(retryContent, &retry))
450 return Status::fromExceptionCode(EINVAL, "Could not parse retry count");
451 if (retry > 0) {
452 retry--;
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700453
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700454 newContent = std::to_string(retry);
455 if (!android::base::WriteStringToFile(newContent, kMetadataCPFile))
456 return Status::fromExceptionCode(errno, "Could not write checkpoint file");
457 }
458 return Status::ok();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700459}
460
461} // namespace vold
462} // namespace android