blob: c33d934288e8abbfef6705b09bf383b480823e68 [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() {
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 {
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700236const int kSectorSize = 512;
237
238typedef uint64_t sector_t;
239
240struct log_entry {
241 sector_t source;
242 sector_t dest;
243 uint32_t size;
244 uint32_t checksum;
245} __attribute__((packed));
246
Paul Lawrencef5077682019-01-18 10:28:34 -0800247struct log_sector_v1_0 {
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700248 uint32_t magic;
Paul Lawrencef5077682019-01-18 10:28:34 -0800249 uint16_t header_version;
250 uint16_t header_size;
Paul Lawrence4f13a902019-01-10 13:06:07 -0800251 uint32_t block_size;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700252 uint32_t count;
253 uint32_t sequence;
Paul Lawrence27691c22018-11-20 14:07:59 -0800254 uint64_t sector0;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700255} __attribute__((packed));
256
257// MAGIC is BOW in ascii
258const int kMagic = 0x00574f42;
259
260void crc32(const void* data, size_t n_bytes, uint32_t* crc) {
261 static uint32_t table[0x100] = {
262 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535,
263 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD,
264 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D,
265 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
266 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4,
267 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C,
268 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC,
269 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
270 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB,
271 0xB6662D3D,
272
273 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5,
274 0xE8B8D433, 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D,
275 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED,
276 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
277 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, 0x4DB26158, 0x3AB551CE, 0xA3BC0074,
278 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC,
279 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C,
280 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
281 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B,
282 0xC0BA6CAD,
283
284 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615,
285 0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D,
286 0x0A00AE27, 0x7D079EB1, 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D,
287 0x806567CB, 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
288 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4,
289 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, 0xD80D2BDA, 0xAF0A1B4C,
290 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, 0xCB61B38C,
291 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
292 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B,
293 0x5BDEAE1D,
294
295 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785,
296 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D,
297 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD,
298 0xF6B9265B, 0x6FB077E1, 0x18B74777, 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
299 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354,
300 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC,
301 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, 0xBDBDF21C,
302 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
303 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B,
304 0x2D02EF8D};
305
306 for (size_t i = 0; i < n_bytes; ++i) {
307 *crc ^= ((uint8_t*)data)[i];
308 *crc = table[(uint8_t)*crc] ^ *crc >> 8;
309 }
310}
311
Paul Lawrence4f13a902019-01-10 13:06:07 -0800312void read(std::fstream& device, std::vector<log_entry> const& logs, sector_t sector, char* buffer,
313 uint32_t block_size) {
314 // Crude approach at first where we do this sector by sector and just scan
315 // the entire logs for remappings each time
Paul Lawrence27691c22018-11-20 14:07:59 -0800316 for (auto l = logs.rbegin(); l != logs.rend(); l++)
317 if (sector >= l->source && (sector - l->source) * kSectorSize < l->size)
318 sector = sector - l->source + l->dest;
319
320 device.seekg(sector * kSectorSize);
Paul Lawrence4f13a902019-01-10 13:06:07 -0800321 device.read(buffer, block_size);
Paul Lawrence27691c22018-11-20 14:07:59 -0800322}
323
Paul Lawrence4f13a902019-01-10 13:06:07 -0800324// Read from the device as though we were restoring, even if we are validating
325std::vector<char> read(std::fstream& device, std::vector<log_entry> const& logs, bool validating,
326 sector_t sector, uint32_t size, uint32_t block_size) {
Paul Lawrence27691c22018-11-20 14:07:59 -0800327 if (!validating) {
328 std::vector<char> buffer(size);
329 device.seekg(sector * kSectorSize);
330 device.read(&buffer[0], size);
331 return buffer;
332 }
333
Paul Lawrence27691c22018-11-20 14:07:59 -0800334 std::vector<char> buffer(size);
Paul Lawrence4f13a902019-01-10 13:06:07 -0800335 for (uint32_t i = 0; i < size; i += block_size, sector += block_size / kSectorSize)
336 read(device, logs, sector, &buffer[i], block_size);
Paul Lawrence27691c22018-11-20 14:07:59 -0800337
338 return buffer;
339}
340
Paul Lawrence4f13a902019-01-10 13:06:07 -0800341} // namespace
342
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700343Status cp_restoreCheckpoint(const std::string& blockDevice) {
Paul Lawrence27691c22018-11-20 14:07:59 -0800344 bool validating = true;
345 std::string action = "Validating";
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700346
Paul Lawrence27691c22018-11-20 14:07:59 -0800347 for (;;) {
348 std::vector<log_entry> logs;
349 Status status = Status::ok();
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700350
Paul Lawrence27691c22018-11-20 14:07:59 -0800351 LOG(INFO) << action << " checkpoint on " << blockDevice;
352 std::fstream device(blockDevice, std::ios::binary | std::ios::in | std::ios::out);
353 if (!device) {
354 PLOG(ERROR) << "Cannot open " << blockDevice;
355 return Status::fromExceptionCode(errno, ("Cannot open " + blockDevice).c_str());
356 }
Paul Lawrence4f13a902019-01-10 13:06:07 -0800357
Paul Lawrencef5077682019-01-18 10:28:34 -0800358 log_sector_v1_0 original_ls;
Paul Lawrence4f13a902019-01-10 13:06:07 -0800359 device.read(reinterpret_cast<char*>(&original_ls), sizeof(original_ls));
360 if (original_ls.magic != kMagic) {
Paul Lawrence27691c22018-11-20 14:07:59 -0800361 LOG(ERROR) << "No magic";
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700362 return Status::fromExceptionCode(EINVAL, "No magic");
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700363 }
364
Paul Lawrence4f13a902019-01-10 13:06:07 -0800365 LOG(INFO) << action << " " << original_ls.sequence << " log sectors";
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700366
Paul Lawrence4f13a902019-01-10 13:06:07 -0800367 for (int sequence = original_ls.sequence; sequence >= 0 && status.isOk(); sequence--) {
368 auto buffer =
369 read(device, logs, validating, 0, original_ls.block_size, original_ls.block_size);
Paul Lawrencef5077682019-01-18 10:28:34 -0800370 log_sector_v1_0 const& ls = *reinterpret_cast<log_sector_v1_0*>(&buffer[0]);
Paul Lawrence27691c22018-11-20 14:07:59 -0800371 if (ls.magic != kMagic) {
372 LOG(ERROR) << "No magic!";
373 status = Status::fromExceptionCode(EINVAL, "No magic");
374 break;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700375 }
376
Paul Lawrence4f13a902019-01-10 13:06:07 -0800377 if (ls.block_size != original_ls.block_size) {
378 LOG(ERROR) << "Block size mismatch!";
379 status = Status::fromExceptionCode(EINVAL, "Block size mismatch");
380 break;
381 }
382
Paul Lawrence27691c22018-11-20 14:07:59 -0800383 if ((int)ls.sequence != sequence) {
384 LOG(ERROR) << "Expecting log sector " << sequence << " but got " << ls.sequence;
385 status = Status::fromExceptionCode(
386 EINVAL, ("Expecting log sector " + std::to_string(sequence) + " but got " +
387 std::to_string(ls.sequence))
388 .c_str());
389 break;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700390 }
391
Paul Lawrence27691c22018-11-20 14:07:59 -0800392 LOG(INFO) << action << " from log sector " << ls.sequence;
393
Paul Lawrencef5077682019-01-18 10:28:34 -0800394 for (log_entry* le =
395 reinterpret_cast<log_entry*>(&buffer[ls.header_size]) + ls.count - 1;
396 le >= reinterpret_cast<log_entry*>(&buffer[ls.header_size]); --le) {
397 // This is very noisy - limit to DEBUG only
398 LOG(DEBUG) << action << " " << le->size << " bytes from sector " << le->dest
399 << " to " << le->source << " with checksum " << std::hex << le->checksum;
400
Paul Lawrence4f13a902019-01-10 13:06:07 -0800401 auto buffer = read(device, logs, validating, le->dest, le->size, ls.block_size);
402 uint32_t checksum = le->source / (ls.block_size / kSectorSize);
403 for (size_t i = 0; i < le->size; i += ls.block_size) {
404 crc32(&buffer[i], ls.block_size, &checksum);
Paul Lawrence27691c22018-11-20 14:07:59 -0800405 }
406
407 if (le->checksum && checksum != le->checksum) {
408 LOG(ERROR) << "Checksums don't match " << std::hex << checksum;
409 status = Status::fromExceptionCode(EINVAL, "Checksums don't match");
410 break;
411 }
412
413 logs.push_back(*le);
414
415 if (!validating) {
416 device.seekg(le->source * kSectorSize);
417 device.write(&buffer[0], le->size);
418 }
419 }
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700420 }
Paul Lawrence27691c22018-11-20 14:07:59 -0800421
422 if (!status.isOk()) {
423 if (!validating) {
424 LOG(ERROR) << "Checkpoint restore failed even though checkpoint validation passed";
425 return status;
426 }
427
428 LOG(WARNING) << "Checkpoint validation failed - attempting to roll forward";
Paul Lawrence4f13a902019-01-10 13:06:07 -0800429 auto buffer = read(device, logs, false, original_ls.sector0, original_ls.block_size,
430 original_ls.block_size);
Paul Lawrence27691c22018-11-20 14:07:59 -0800431 device.seekg(0);
Paul Lawrence4f13a902019-01-10 13:06:07 -0800432 device.write(&buffer[0], original_ls.block_size);
Paul Lawrence27691c22018-11-20 14:07:59 -0800433 return Status::ok();
434 }
435
436 if (!validating) break;
437
438 validating = false;
439 action = "Restoring";
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700440 }
441
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700442 return Status::ok();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700443}
444
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700445Status cp_markBootAttempt() {
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700446 std::string oldContent, newContent;
447 int retry = 0;
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700448 struct stat st;
449 int result = stat(kMetadataCPFile.c_str(), &st);
450
451 // If the file doesn't exist, we aren't managing a checkpoint retry counter
452 if (result != 0) return Status::ok();
453 if (!android::base::ReadFileToString(kMetadataCPFile, &oldContent)) {
454 PLOG(ERROR) << "Failed to read checkpoint file";
455 return Status::fromExceptionCode(errno, "Failed to read checkpoint file");
456 }
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700457 std::string retryContent = oldContent.substr(0, oldContent.find_first_of(" "));
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700458
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700459 if (!android::base::ParseInt(retryContent, &retry))
460 return Status::fromExceptionCode(EINVAL, "Could not parse retry count");
461 if (retry > 0) {
462 retry--;
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700463
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700464 newContent = std::to_string(retry);
465 if (!android::base::WriteStringToFile(newContent, kMetadataCPFile))
466 return Status::fromExceptionCode(errno, "Could not write checkpoint file");
467 }
468 return Status::ok();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700469}
470
471} // namespace vold
472} // namespace android