blob: 948231d4f6af98a271fbe35f7717d59c5097143f [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"
Sandeep Patilf8da61f2019-04-15 08:45:27 -070020#include "VolumeManager.h"
Daniel Rosenberg65f99c92018-08-28 01:58:49 -070021
Paul Lawrence1abb2fe2018-09-21 10:49:57 -070022#include <fstream>
Daniel Rosenberg65f99c92018-08-28 01:58:49 -070023#include <list>
Paul Lawrence20400892018-10-03 14:14:52 -070024#include <memory>
Daniel Rosenberg65f99c92018-08-28 01:58:49 -070025#include <string>
Daniel Rosenberg8daeec02018-11-20 19:03:11 -080026#include <thread>
Paul Lawrence1abb2fe2018-09-21 10:49:57 -070027#include <vector>
28
Kelvin Zhangdec03ab2022-06-21 14:31:01 -070029#include <BootControlClient.h>
Paul Lawrence1abb2fe2018-09-21 10:49:57 -070030#include <android-base/file.h>
31#include <android-base/logging.h>
32#include <android-base/parseint.h>
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -080033#include <android-base/properties.h>
Paul Lawrence1abb2fe2018-09-21 10:49:57 -070034#include <android-base/unique_fd.h>
35#include <cutils/android_reboot.h>
36#include <fcntl.h>
37#include <fs_mgr.h>
38#include <linux/fs.h>
39#include <mntent.h>
40#include <sys/mount.h>
41#include <sys/stat.h>
Daniel Rosenberg8daeec02018-11-20 19:03:11 -080042#include <sys/statvfs.h>
43#include <unistd.h>
Daniel Rosenberg65f99c92018-08-28 01:58:49 -070044
Daniel Rosenberg8daeec02018-11-20 19:03:11 -080045using android::base::GetBoolProperty;
46using android::base::GetUintProperty;
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -080047using android::base::SetProperty;
Daniel Rosenberg73680ec2018-10-10 18:52:04 -070048using android::binder::Status;
Tom Cherry4c5bde22019-01-29 14:34:01 -080049using android::fs_mgr::Fstab;
Tom Cherry4c5bde22019-01-29 14:34:01 -080050using android::fs_mgr::ReadFstabFromFile;
Kelvin Zhangdec03ab2022-06-21 14:31:01 -070051using android::hal::BootControlClient;
Daniel Rosenbergd3992492018-10-02 17:40:44 -070052
Daniel Rosenberg65f99c92018-08-28 01:58:49 -070053namespace android {
54namespace vold {
55
Paul Lawrence1abb2fe2018-09-21 10:49:57 -070056namespace {
57const std::string kMetadataCPFile = "/metadata/vold/checkpoint";
58
Paul Lawrence82b35052019-04-19 14:26:39 -070059binder::Status error(const std::string& msg) {
60 PLOG(ERROR) << msg;
61 return binder::Status::fromServiceSpecificError(errno, String8(msg.c_str()));
62}
63
64binder::Status error(int error, const std::string& msg) {
65 LOG(ERROR) << msg;
66 return binder::Status::fromServiceSpecificError(error, String8(msg.c_str()));
67}
68
Paul Lawrence1abb2fe2018-09-21 10:49:57 -070069bool setBowState(std::string const& block_device, std::string const& state) {
Paul Lawrence236e5e82019-06-25 14:44:33 -070070 std::string bow_device = fs_mgr_find_bow_device(block_device);
71 if (bow_device.empty()) return false;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -070072
Paul Lawrence236e5e82019-06-25 14:44:33 -070073 if (!android::base::WriteStringToFile(state, bow_device + "/bow/state")) {
74 PLOG(ERROR) << "Failed to write to file " << bow_device + "/bow/state";
Paul Lawrence1abb2fe2018-09-21 10:49:57 -070075 return false;
76 }
77
78 return true;
79}
80
81} // namespace
Daniel Rosenberg65f99c92018-08-28 01:58:49 -070082
Daniel Rosenberg9b667fb2019-01-22 17:27:25 -080083Status cp_supportsCheckpoint(bool& result) {
84 result = false;
Daniel Rosenberg9b667fb2019-01-22 17:27:25 -080085
Tom Cherry4c5bde22019-01-29 14:34:01 -080086 for (const auto& entry : fstab_default) {
87 if (entry.fs_mgr_flags.checkpoint_blk || entry.fs_mgr_flags.checkpoint_fs) {
Daniel Rosenberg9b667fb2019-01-22 17:27:25 -080088 result = true;
89 return Status::ok();
90 }
91 }
92 return Status::ok();
93}
94
Paul Lawrencec5c79c52019-03-18 13:36:40 -070095Status cp_supportsBlockCheckpoint(bool& result) {
96 result = false;
97
98 for (const auto& entry : fstab_default) {
99 if (entry.fs_mgr_flags.checkpoint_blk) {
100 result = true;
101 return Status::ok();
102 }
103 }
104 return Status::ok();
105}
106
107Status cp_supportsFileCheckpoint(bool& result) {
108 result = false;
109
110 for (const auto& entry : fstab_default) {
111 if (entry.fs_mgr_flags.checkpoint_fs) {
112 result = true;
113 return Status::ok();
114 }
115 }
116 return Status::ok();
117}
118
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700119Status cp_startCheckpoint(int retry) {
Paul Lawrencec2a145f2019-05-15 09:42:04 -0700120 bool result;
121 if (!cp_supportsCheckpoint(result).isOk() || !result)
122 return error(ENOTSUP, "Checkpoints not supported");
123
Paul Lawrence82b35052019-04-19 14:26:39 -0700124 if (retry < -1) return error(EINVAL, "Retry count must be more than -1");
Daniel Rosenberg80d1ca52018-10-09 19:26:57 -0700125 std::string content = std::to_string(retry + 1);
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700126 if (retry == -1) {
Kelvin Zhangdec03ab2022-06-21 14:31:01 -0700127 auto module = BootControlClient::WaitForService();
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700128 if (module) {
Kelvin Zhangdec03ab2022-06-21 14:31:01 -0700129 std::string suffix = module->GetSuffix(module->GetCurrentSlot());
130 if (!suffix.empty()) content += " " + suffix;
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700131 }
132 }
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700133 if (!android::base::WriteStringToFile(content, kMetadataCPFile))
Paul Lawrence82b35052019-04-19 14:26:39 -0700134 return error("Failed to write checkpoint file");
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700135 return Status::ok();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700136}
137
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800138namespace {
139
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800140volatile bool isCheckpointing = false;
Paul Lawrence1d57f682019-08-22 09:51:18 -0700141
Nikita Ioffea5798fc2019-10-11 16:38:21 +0100142volatile bool needsCheckpointWasCalled = false;
143
144// Protects isCheckpointing, needsCheckpointWasCalled and code that makes decisions based on status
145// of isCheckpointing
Paul Lawrence1d57f682019-08-22 09:51:18 -0700146std::mutex isCheckpointingLock;
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800147}
148
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700149Status cp_commitChanges() {
Paul Lawrence1d57f682019-08-22 09:51:18 -0700150 std::lock_guard<std::mutex> lock(isCheckpointingLock);
151
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800152 if (!isCheckpointing) {
153 return Status::ok();
154 }
Paul Lawrencea7972dc2019-06-12 12:03:01 -0700155 if (android::base::GetProperty("persist.vold.dont_commit_checkpoint", "0") == "1") {
156 LOG(WARNING)
157 << "NOT COMMITTING CHECKPOINT BECAUSE persist.vold.dont_commit_checkpoint IS 1";
158 return Status::ok();
159 }
Kelvin Zhangdec03ab2022-06-21 14:31:01 -0700160 auto module = BootControlClient::WaitForService();
Daniel Rosenberg886915b2019-01-23 15:16:04 -0800161 if (module) {
Kelvin Zhangdec03ab2022-06-21 14:31:01 -0700162 auto cr = module->MarkBootSuccessful();
Paul Lawrence82b35052019-04-19 14:26:39 -0700163 if (!cr.success)
164 return error(EINVAL, "Error marking booted successfully: " + std::string(cr.errMsg));
Daniel Rosenberg886915b2019-01-23 15:16:04 -0800165 LOG(INFO) << "Marked slot as booted successfully.";
Tianjie Xu09de0ff2019-11-15 14:05:29 -0800166 // Clears the warm reset flag for next reboot.
167 if (!SetProperty("ota.warm_reset", "0")) {
168 LOG(WARNING) << "Failed to reset the warm reset flag";
169 }
Kelvin Zhangdec03ab2022-06-21 14:31:01 -0700170 } else {
171 LOG(ERROR) << "Failed to get BootControl HAL, not marking slot as successful.";
Daniel Rosenberg886915b2019-01-23 15:16:04 -0800172 }
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700173 // Must take action for list of mounted checkpointed things here
174 // To do this, we walk the list of mounted file systems.
175 // But we also need to get the matching fstab entries to see
176 // the original flags
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700177 std::string err_str;
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700178
Tom Cherry4c5bde22019-01-29 14:34:01 -0800179 Fstab mounts;
180 if (!ReadFstabFromFile("/proc/mounts", &mounts)) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700181 return error(EINVAL, "Failed to get /proc/mounts");
Tom Cherry4c5bde22019-01-29 14:34:01 -0800182 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700183
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700184 // Walk mounted file systems
Tom Cherry4c5bde22019-01-29 14:34:01 -0800185 for (const auto& mount_rec : mounts) {
186 const auto fstab_rec = GetEntryForMountPoint(&fstab_default, mount_rec.mount_point);
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700187 if (!fstab_rec) continue;
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700188
Tom Cherry4c5bde22019-01-29 14:34:01 -0800189 if (fstab_rec->fs_mgr_flags.checkpoint_fs) {
190 if (fstab_rec->fs_type == "f2fs") {
191 std::string options = mount_rec.fs_options + ",checkpoint=enable";
192 if (mount(mount_rec.blk_device.c_str(), mount_rec.mount_point.c_str(), "none",
Daniel Rosenberg14ca4ac2019-01-24 18:23:18 -0800193 MS_REMOUNT | fstab_rec->flags, options.c_str())) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700194 return error(EINVAL, "Failed to remount");
Daniel Rosenberg4b86df12018-11-08 22:18:37 -0800195 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700196 }
Tom Cherry4c5bde22019-01-29 14:34:01 -0800197 } else if (fstab_rec->fs_mgr_flags.checkpoint_blk) {
198 if (!setBowState(mount_rec.blk_device, "2"))
Paul Lawrence82b35052019-04-19 14:26:39 -0700199 return error(EINVAL, "Failed to set bow state");
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700200 }
201 }
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800202 SetProperty("vold.checkpoint_committed", "1");
Daniel Rosenberg886915b2019-01-23 15:16:04 -0800203 LOG(INFO) << "Checkpoint has been committed.";
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800204 isCheckpointing = false;
Daniel Rosenberg4b86df12018-11-08 22:18:37 -0800205 if (!android::base::RemoveFileIfExists(kMetadataCPFile, &err_str))
Paul Lawrence82b35052019-04-19 14:26:39 -0700206 return error(err_str.c_str());
207
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700208 return Status::ok();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700209}
210
Daniel Rosenberga59e4392019-03-20 17:02:47 -0700211namespace {
212void abort_metadata_file() {
213 std::string oldContent, newContent;
214 int retry = 0;
215 struct stat st;
216 int result = stat(kMetadataCPFile.c_str(), &st);
217
218 // If the file doesn't exist, we aren't managing a checkpoint retry counter
219 if (result != 0) return;
220 if (!android::base::ReadFileToString(kMetadataCPFile, &oldContent)) {
221 PLOG(ERROR) << "Failed to read checkpoint file";
222 return;
223 }
224 std::string retryContent = oldContent.substr(0, oldContent.find_first_of(" "));
225
226 if (!android::base::ParseInt(retryContent, &retry)) {
227 PLOG(ERROR) << "Could not parse retry count";
228 return;
229 }
230 if (retry > 0) {
231 newContent = "0";
232 if (!android::base::WriteStringToFile(newContent, kMetadataCPFile))
233 PLOG(ERROR) << "Could not write checkpoint file";
234 }
235}
236} // namespace
237
238void cp_abortChanges(const std::string& message, bool retry) {
239 if (!cp_needsCheckpoint()) return;
240 if (!retry) abort_metadata_file();
241 android_reboot(ANDROID_RB_RESTART2, 0, message.c_str());
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700242}
243
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700244bool cp_needsRollback() {
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700245 std::string content;
246 bool ret;
247
248 ret = android::base::ReadFileToString(kMetadataCPFile, &content);
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700249 if (ret) {
250 if (content == "0") return true;
251 if (content.substr(0, 3) == "-1 ") {
252 std::string oldSuffix = content.substr(3);
Kelvin Zhangdec03ab2022-06-21 14:31:01 -0700253 auto module = BootControlClient::WaitForService();
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700254 std::string newSuffix;
255
256 if (module) {
Kelvin Zhangdec03ab2022-06-21 14:31:01 -0700257 newSuffix = module->GetSuffix(module->GetCurrentSlot());
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700258 if (oldSuffix == newSuffix) return true;
259 }
260 }
261 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700262 return false;
263}
264
Daniel Rosenberg80d1ca52018-10-09 19:26:57 -0700265bool cp_needsCheckpoint() {
Nikita Ioffea5798fc2019-10-11 16:38:21 +0100266 std::lock_guard<std::mutex> lock(isCheckpointingLock);
267
Paul Lawrence9a6d1f72019-08-26 15:09:41 -0700268 // Make sure we only return true during boot. See b/138952436 for discussion
Nikita Ioffea5798fc2019-10-11 16:38:21 +0100269 if (needsCheckpointWasCalled) return isCheckpointing;
270 needsCheckpointWasCalled = true;
Paul Lawrence9a6d1f72019-08-26 15:09:41 -0700271
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700272 bool ret;
273 std::string content;
Kelvin Zhangdec03ab2022-06-21 14:31:01 -0700274 auto module = BootControlClient::WaitForService();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700275
Daniel Rosenberg84203c12019-03-19 14:02:59 -0700276 if (isCheckpointing) return isCheckpointing;
Kelvin Zhangdec03ab2022-06-21 14:31:01 -0700277 // In case of INVALID slot or other failures, we do not perform checkpoint.
278 if (module && !module->IsSlotMarkedSuccessful(module->GetCurrentSlot()).value_or(true)) {
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800279 isCheckpointing = true;
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700280 return true;
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800281 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700282 ret = android::base::ReadFileToString(kMetadataCPFile, &content);
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800283 if (ret) {
284 ret = content != "0";
285 isCheckpointing = ret;
286 return ret;
287 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700288 return false;
289}
290
David Anderson23850d32020-06-10 23:51:17 -0700291bool cp_isCheckpointing() {
292 return isCheckpointing;
293}
294
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800295namespace {
Daniel Rosenbergb7dddd02019-03-26 14:42:14 -0700296const std::string kSleepTimeProp = "ro.sys.cp_msleeptime";
297const uint32_t msleeptime_default = 1000; // 1 s
298const uint32_t max_msleeptime = 3600000; // 1 h
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800299
300const std::string kMinFreeBytesProp = "ro.sys.cp_min_free_bytes";
301const uint64_t min_free_bytes_default = 100 * (1 << 20); // 100 MiB
302
303const std::string kCommitOnFullProp = "ro.sys.cp_commit_on_full";
304const bool commit_on_full_default = true;
305
306static void cp_healthDaemon(std::string mnt_pnt, std::string blk_device, bool is_fs_cp) {
307 struct statvfs data;
Daniel Rosenbergb7dddd02019-03-26 14:42:14 -0700308 uint32_t msleeptime = GetUintProperty(kSleepTimeProp, msleeptime_default, max_msleeptime);
Satoshi Futenma18d10d42019-03-25 23:13:36 +0900309 uint64_t min_free_bytes =
310 GetUintProperty(kMinFreeBytesProp, min_free_bytes_default, (uint64_t)-1);
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800311 bool commit_on_full = GetBoolProperty(kCommitOnFullProp, commit_on_full_default);
312
Daniel Rosenbergb7dddd02019-03-26 14:42:14 -0700313 struct timespec req;
314 req.tv_sec = msleeptime / 1000;
315 msleeptime %= 1000;
316 req.tv_nsec = msleeptime * 1000000;
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800317 while (isCheckpointing) {
Paul Lawrence236e5e82019-06-25 14:44:33 -0700318 uint64_t free_bytes = 0;
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800319 if (is_fs_cp) {
320 statvfs(mnt_pnt.c_str(), &data);
Qilin Tan5d0aaaf2020-01-02 19:07:47 +0800321 free_bytes = ((uint64_t) data.f_bavail) * data.f_frsize;
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800322 } else {
Paul Lawrence236e5e82019-06-25 14:44:33 -0700323 std::string bow_device = fs_mgr_find_bow_device(blk_device);
324 if (!bow_device.empty()) {
325 std::string content;
326 if (android::base::ReadFileToString(bow_device + "/bow/free", &content)) {
Qilin Tan5d0aaaf2020-01-02 19:07:47 +0800327 free_bytes = std::strtoull(content.c_str(), NULL, 10);
Paul Lawrence236e5e82019-06-25 14:44:33 -0700328 }
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800329 }
330 }
331 if (free_bytes < min_free_bytes) {
332 if (commit_on_full) {
333 LOG(INFO) << "Low space for checkpointing. Commiting changes";
334 cp_commitChanges();
335 break;
336 } else {
337 LOG(INFO) << "Low space for checkpointing. Rebooting";
338 cp_abortChanges("checkpoint,low_space", false);
339 break;
340 }
341 }
Daniel Rosenbergb7dddd02019-03-26 14:42:14 -0700342 nanosleep(&req, NULL);
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800343 }
344}
345
346} // namespace
347
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700348Status cp_prepareCheckpoint() {
Paul Lawrence4c757fb2019-10-23 09:36:18 -0700349 // Log to notify CTS - see b/137924328 for context
350 LOG(INFO) << "cp_prepareCheckpoint called";
Paul Lawrence1d57f682019-08-22 09:51:18 -0700351 std::lock_guard<std::mutex> lock(isCheckpointingLock);
Paul Lawrencedb086942019-02-19 14:18:54 -0800352 if (!isCheckpointing) {
353 return Status::ok();
354 }
355
Tom Cherry4c5bde22019-01-29 14:34:01 -0800356 Fstab mounts;
357 if (!ReadFstabFromFile("/proc/mounts", &mounts)) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700358 return error(EINVAL, "Failed to get /proc/mounts");
Tom Cherry4c5bde22019-01-29 14:34:01 -0800359 }
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700360
Tom Cherry4c5bde22019-01-29 14:34:01 -0800361 for (const auto& mount_rec : mounts) {
362 const auto fstab_rec = GetEntryForMountPoint(&fstab_default, mount_rec.mount_point);
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700363 if (!fstab_rec) continue;
364
Tom Cherry4c5bde22019-01-29 14:34:01 -0800365 if (fstab_rec->fs_mgr_flags.checkpoint_blk) {
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700366 android::base::unique_fd fd(
Tom Cherry4c5bde22019-01-29 14:34:01 -0800367 TEMP_FAILURE_RETRY(open(mount_rec.mount_point.c_str(), O_RDONLY | O_CLOEXEC)));
Bernie Innocentiebe293a2019-03-28 15:24:30 +0900368 if (fd == -1) {
Tom Cherry4c5bde22019-01-29 14:34:01 -0800369 PLOG(ERROR) << "Failed to open mount point" << mount_rec.mount_point;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700370 continue;
371 }
372
373 struct fstrim_range range = {};
374 range.len = ULLONG_MAX;
Sandeep Patilf8da61f2019-04-15 08:45:27 -0700375 nsecs_t start = systemTime(SYSTEM_TIME_BOOTTIME);
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700376 if (ioctl(fd, FITRIM, &range)) {
Tom Cherry4c5bde22019-01-29 14:34:01 -0800377 PLOG(ERROR) << "Failed to trim " << mount_rec.mount_point;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700378 continue;
379 }
Sandeep Patilf8da61f2019-04-15 08:45:27 -0700380 nsecs_t time = systemTime(SYSTEM_TIME_BOOTTIME) - start;
381 LOG(INFO) << "Trimmed " << range.len << " bytes on " << mount_rec.mount_point << " in "
382 << nanoseconds_to_milliseconds(time) << "ms for checkpoint";
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700383
Tom Cherry4c5bde22019-01-29 14:34:01 -0800384 setBowState(mount_rec.blk_device, "1");
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700385 }
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800386 if (fstab_rec->fs_mgr_flags.checkpoint_blk || fstab_rec->fs_mgr_flags.checkpoint_fs) {
387 std::thread(cp_healthDaemon, std::string(mount_rec.mount_point),
Paul Lawrencee81f4c12019-03-29 13:06:34 -0700388 std::string(mount_rec.blk_device),
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800389 fstab_rec->fs_mgr_flags.checkpoint_fs == 1)
390 .detach();
391 }
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700392 }
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700393 return Status::ok();
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700394}
395
396namespace {
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700397const int kSectorSize = 512;
398
399typedef uint64_t sector_t;
400
401struct log_entry {
Paul Lawrenced41a9392019-01-22 14:31:43 -0800402 sector_t source; // in sectors of size kSectorSize
403 sector_t dest; // in sectors of size kSectorSize
404 uint32_t size; // in bytes
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700405 uint32_t checksum;
406} __attribute__((packed));
407
Paul Lawrencef5077682019-01-18 10:28:34 -0800408struct log_sector_v1_0 {
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700409 uint32_t magic;
Paul Lawrencef5077682019-01-18 10:28:34 -0800410 uint16_t header_version;
411 uint16_t header_size;
Paul Lawrence4f13a902019-01-10 13:06:07 -0800412 uint32_t block_size;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700413 uint32_t count;
414 uint32_t sequence;
Paul Lawrence27691c22018-11-20 14:07:59 -0800415 uint64_t sector0;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700416} __attribute__((packed));
417
418// MAGIC is BOW in ascii
419const int kMagic = 0x00574f42;
Daniel Rosenberg52985932019-03-01 22:01:22 -0800420// Partially restored MAGIC is WOB in ascii
421const int kPartialRestoreMagic = 0x00424f57;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700422
423void crc32(const void* data, size_t n_bytes, uint32_t* crc) {
424 static uint32_t table[0x100] = {
425 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535,
426 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD,
427 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D,
428 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
429 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4,
430 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C,
431 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC,
432 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
433 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB,
434 0xB6662D3D,
435
436 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5,
437 0xE8B8D433, 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D,
438 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED,
439 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
440 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, 0x4DB26158, 0x3AB551CE, 0xA3BC0074,
441 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC,
442 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C,
443 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
444 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B,
445 0xC0BA6CAD,
446
447 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615,
448 0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D,
449 0x0A00AE27, 0x7D079EB1, 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D,
450 0x806567CB, 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
451 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4,
452 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, 0xD80D2BDA, 0xAF0A1B4C,
453 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, 0xCB61B38C,
454 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
455 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B,
456 0x5BDEAE1D,
457
458 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785,
459 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D,
460 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD,
461 0xF6B9265B, 0x6FB077E1, 0x18B74777, 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
462 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354,
463 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC,
464 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, 0xBDBDF21C,
465 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
466 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B,
467 0x2D02EF8D};
468
469 for (size_t i = 0; i < n_bytes; ++i) {
470 *crc ^= ((uint8_t*)data)[i];
471 *crc = table[(uint8_t)*crc] ^ *crc >> 8;
472 }
473}
474
Paul Lawrenced41a9392019-01-22 14:31:43 -0800475// A map of relocations.
476// The map must be initialized so that relocations[0] = 0
477// During restore, we replay the log records in reverse, copying from dest to
478// source
479// To validate, we must be able to read the 'dest' sectors as though they had
480// been copied but without actually copying. This map represents how the sectors
481// would have been moved. To read a sector s, find the index <= s and read
482// relocations[index] + s - index
483typedef std::map<sector_t, sector_t> Relocations;
Paul Lawrence27691c22018-11-20 14:07:59 -0800484
Paul Lawrenced41a9392019-01-22 14:31:43 -0800485void relocate(Relocations& relocations, sector_t dest, sector_t source, int count) {
486 // Find first one we're equal to or greater than
487 auto s = --relocations.upper_bound(source);
488
489 // Take slice
490 Relocations slice;
491 slice[dest] = source - s->first + s->second;
492 ++s;
493
494 // Add rest of elements
495 for (; s != relocations.end() && s->first < source + count; ++s)
496 slice[dest - source + s->first] = s->second;
497
498 // Split range at end of dest
499 auto dest_end = --relocations.upper_bound(dest + count);
500 relocations[dest + count] = dest + count - dest_end->first + dest_end->second;
501
502 // Remove all elements in [dest, dest + count)
503 relocations.erase(relocations.lower_bound(dest), relocations.lower_bound(dest + count));
504
505 // Add new elements
506 relocations.insert(slice.begin(), slice.end());
Paul Lawrence27691c22018-11-20 14:07:59 -0800507}
508
Daniel Rosenberg52985932019-03-01 22:01:22 -0800509// A map of sectors that have been written to.
510// The final entry must always be False.
511// When we restart the restore after an interruption, we must take care that
512// when we copy from dest to source, that the block we copy to was not
513// previously copied from.
514// i e. A->B C->A; If we replay this sequence, we end up copying C->B
515// We must save our partial result whenever we finish a page, or when we copy
516// to a location that was copied from earlier (our source is an earlier dest)
517typedef std::map<sector_t, bool> Used_Sectors;
518
519bool checkCollision(Used_Sectors& used_sectors, sector_t start, sector_t end) {
520 auto second_overlap = used_sectors.upper_bound(start);
521 auto first_overlap = --second_overlap;
522
523 if (first_overlap->second) {
524 return true;
525 } else if (second_overlap != used_sectors.end() && second_overlap->first < end) {
526 return true;
527 }
528 return false;
529}
530
531void markUsed(Used_Sectors& used_sectors, sector_t start, sector_t end) {
532 auto start_pos = used_sectors.insert_or_assign(start, true).first;
533 auto end_pos = used_sectors.insert_or_assign(end, false).first;
534
535 if (start_pos == used_sectors.begin() || !std::prev(start_pos)->second) {
536 start_pos++;
537 }
538 if (std::next(end_pos) != used_sectors.end() && !std::next(end_pos)->second) {
539 end_pos++;
540 }
541 if (start_pos->first < end_pos->first) {
542 used_sectors.erase(start_pos, end_pos);
543 }
544}
545
546// Restores the given log_entry's data from dest -> source
547// If that entry is a log sector, set the magic to kPartialRestoreMagic and flush.
548void restoreSector(int device_fd, Used_Sectors& used_sectors, std::vector<char>& ls_buffer,
549 log_entry* le, std::vector<char>& buffer) {
550 log_sector_v1_0& ls = *reinterpret_cast<log_sector_v1_0*>(&ls_buffer[0]);
551 uint32_t index = le - ((log_entry*)&ls_buffer[ls.header_size]);
552 int count = (le->size - 1) / kSectorSize + 1;
553
554 if (checkCollision(used_sectors, le->source, le->source + count)) {
555 fsync(device_fd);
556 lseek64(device_fd, 0, SEEK_SET);
557 ls.count = index + 1;
558 ls.magic = kPartialRestoreMagic;
559 write(device_fd, &ls_buffer[0], ls.block_size);
560 fsync(device_fd);
561 used_sectors.clear();
562 used_sectors[0] = false;
563 }
564
565 markUsed(used_sectors, le->dest, le->dest + count);
566
567 if (index == 0 && ls.sequence != 0) {
568 log_sector_v1_0* next = reinterpret_cast<log_sector_v1_0*>(&buffer[0]);
569 if (next->magic == kMagic) {
570 next->magic = kPartialRestoreMagic;
571 }
572 }
573
574 lseek64(device_fd, le->source * kSectorSize, SEEK_SET);
575 write(device_fd, &buffer[0], le->size);
576
577 if (index == 0) {
578 fsync(device_fd);
579 }
580}
581
Paul Lawrenced41a9392019-01-22 14:31:43 -0800582// Read from the device
583// If we are validating, the read occurs as though the relocations had happened
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800584std::vector<char> relocatedRead(int device_fd, Relocations const& relocations, bool validating,
585 sector_t sector, uint32_t size, uint32_t block_size) {
Paul Lawrence27691c22018-11-20 14:07:59 -0800586 if (!validating) {
587 std::vector<char> buffer(size);
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800588 lseek64(device_fd, sector * kSectorSize, SEEK_SET);
589 read(device_fd, &buffer[0], size);
Paul Lawrence27691c22018-11-20 14:07:59 -0800590 return buffer;
591 }
592
Paul Lawrence27691c22018-11-20 14:07:59 -0800593 std::vector<char> buffer(size);
Paul Lawrenced41a9392019-01-22 14:31:43 -0800594 for (uint32_t i = 0; i < size; i += block_size, sector += block_size / kSectorSize) {
595 auto relocation = --relocations.upper_bound(sector);
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800596 lseek64(device_fd, (sector + relocation->second - relocation->first) * kSectorSize,
597 SEEK_SET);
598 read(device_fd, &buffer[i], block_size);
Paul Lawrenced41a9392019-01-22 14:31:43 -0800599 }
Paul Lawrence27691c22018-11-20 14:07:59 -0800600
601 return buffer;
602}
603
Paul Lawrence4f13a902019-01-10 13:06:07 -0800604} // namespace
605
Daniel Rosenbergdda59812019-03-06 17:45:17 -0800606Status cp_restoreCheckpoint(const std::string& blockDevice, int restore_limit) {
Paul Lawrence27691c22018-11-20 14:07:59 -0800607 bool validating = true;
608 std::string action = "Validating";
Daniel Rosenbergdda59812019-03-06 17:45:17 -0800609 int restore_count = 0;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700610
Paul Lawrence27691c22018-11-20 14:07:59 -0800611 for (;;) {
Paul Lawrenced41a9392019-01-22 14:31:43 -0800612 Relocations relocations;
613 relocations[0] = 0;
Paul Lawrence27691c22018-11-20 14:07:59 -0800614 Status status = Status::ok();
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700615
Paul Lawrence27691c22018-11-20 14:07:59 -0800616 LOG(INFO) << action << " checkpoint on " << blockDevice;
Nick Kraleviche7e89ac2019-03-29 16:03:51 -0700617 base::unique_fd device_fd(open(blockDevice.c_str(), O_RDWR | O_CLOEXEC));
Paul Lawrence82b35052019-04-19 14:26:39 -0700618 if (device_fd < 0) return error("Cannot open " + blockDevice);
Paul Lawrence4f13a902019-01-10 13:06:07 -0800619
Paul Lawrencef5077682019-01-18 10:28:34 -0800620 log_sector_v1_0 original_ls;
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800621 read(device_fd, reinterpret_cast<char*>(&original_ls), sizeof(original_ls));
Daniel Rosenberg52985932019-03-01 22:01:22 -0800622 if (original_ls.magic == kPartialRestoreMagic) {
623 validating = false;
624 action = "Restoring";
625 } else if (original_ls.magic != kMagic) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700626 return error(EINVAL, "No magic");
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700627 }
628
Paul Lawrence4f13a902019-01-10 13:06:07 -0800629 LOG(INFO) << action << " " << original_ls.sequence << " log sectors";
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700630
Paul Lawrence4f13a902019-01-10 13:06:07 -0800631 for (int sequence = original_ls.sequence; sequence >= 0 && status.isOk(); sequence--) {
Daniel Rosenberg52985932019-03-01 22:01:22 -0800632 auto ls_buffer = relocatedRead(device_fd, relocations, validating, 0,
633 original_ls.block_size, original_ls.block_size);
634 log_sector_v1_0& ls = *reinterpret_cast<log_sector_v1_0*>(&ls_buffer[0]);
635
636 Used_Sectors used_sectors;
637 used_sectors[0] = false;
638
639 if (ls.magic != kMagic && (ls.magic != kPartialRestoreMagic || validating)) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700640 status = error(EINVAL, "No magic");
Paul Lawrence27691c22018-11-20 14:07:59 -0800641 break;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700642 }
643
Paul Lawrence4f13a902019-01-10 13:06:07 -0800644 if (ls.block_size != original_ls.block_size) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700645 status = error(EINVAL, "Block size mismatch");
Paul Lawrence4f13a902019-01-10 13:06:07 -0800646 break;
647 }
648
Paul Lawrence27691c22018-11-20 14:07:59 -0800649 if ((int)ls.sequence != sequence) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700650 status = error(EINVAL, "Expecting log sector " + std::to_string(sequence) +
651 " but got " + std::to_string(ls.sequence));
Paul Lawrence27691c22018-11-20 14:07:59 -0800652 break;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700653 }
654
Paul Lawrence27691c22018-11-20 14:07:59 -0800655 LOG(INFO) << action << " from log sector " << ls.sequence;
Paul Lawrencef5077682019-01-18 10:28:34 -0800656 for (log_entry* le =
Daniel Rosenberg52985932019-03-01 22:01:22 -0800657 reinterpret_cast<log_entry*>(&ls_buffer[ls.header_size]) + ls.count - 1;
658 le >= reinterpret_cast<log_entry*>(&ls_buffer[ls.header_size]); --le) {
Paul Lawrencef5077682019-01-18 10:28:34 -0800659 // This is very noisy - limit to DEBUG only
Paul Lawrenced41a9392019-01-22 14:31:43 -0800660 LOG(VERBOSE) << action << " " << le->size << " bytes from sector " << le->dest
661 << " to " << le->source << " with checksum " << std::hex
662 << le->checksum;
Paul Lawrencef5077682019-01-18 10:28:34 -0800663
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800664 auto buffer = relocatedRead(device_fd, relocations, validating, le->dest, le->size,
Paul Lawrenced41a9392019-01-22 14:31:43 -0800665 ls.block_size);
Paul Lawrence4f13a902019-01-10 13:06:07 -0800666 uint32_t checksum = le->source / (ls.block_size / kSectorSize);
667 for (size_t i = 0; i < le->size; i += ls.block_size) {
668 crc32(&buffer[i], ls.block_size, &checksum);
Paul Lawrence27691c22018-11-20 14:07:59 -0800669 }
670
671 if (le->checksum && checksum != le->checksum) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700672 status = error(EINVAL, "Checksums don't match");
Paul Lawrence27691c22018-11-20 14:07:59 -0800673 break;
674 }
675
Paul Lawrenced41a9392019-01-22 14:31:43 -0800676 if (validating) {
Daniel Rosenberg52985932019-03-01 22:01:22 -0800677 relocate(relocations, le->source, le->dest, (le->size - 1) / kSectorSize + 1);
Paul Lawrenced41a9392019-01-22 14:31:43 -0800678 } else {
Daniel Rosenberg52985932019-03-01 22:01:22 -0800679 restoreSector(device_fd, used_sectors, ls_buffer, le, buffer);
Daniel Rosenbergdda59812019-03-06 17:45:17 -0800680 restore_count++;
681 if (restore_limit && restore_count >= restore_limit) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700682 status = error(EAGAIN, "Hit the test limit");
Daniel Rosenbergdda59812019-03-06 17:45:17 -0800683 break;
684 }
Paul Lawrence27691c22018-11-20 14:07:59 -0800685 }
686 }
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700687 }
Paul Lawrence27691c22018-11-20 14:07:59 -0800688
689 if (!status.isOk()) {
690 if (!validating) {
691 LOG(ERROR) << "Checkpoint restore failed even though checkpoint validation passed";
692 return status;
693 }
694
695 LOG(WARNING) << "Checkpoint validation failed - attempting to roll forward";
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800696 auto buffer = relocatedRead(device_fd, relocations, false, original_ls.sector0,
Paul Lawrenced41a9392019-01-22 14:31:43 -0800697 original_ls.block_size, original_ls.block_size);
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800698 lseek64(device_fd, 0, SEEK_SET);
699 write(device_fd, &buffer[0], original_ls.block_size);
Paul Lawrence27691c22018-11-20 14:07:59 -0800700 return Status::ok();
701 }
702
703 if (!validating) break;
704
705 validating = false;
706 action = "Restoring";
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700707 }
708
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700709 return Status::ok();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700710}
711
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700712Status cp_markBootAttempt() {
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700713 std::string oldContent, newContent;
714 int retry = 0;
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700715 struct stat st;
716 int result = stat(kMetadataCPFile.c_str(), &st);
717
718 // If the file doesn't exist, we aren't managing a checkpoint retry counter
719 if (result != 0) return Status::ok();
Paul Lawrence82b35052019-04-19 14:26:39 -0700720 if (!android::base::ReadFileToString(kMetadataCPFile, &oldContent))
721 return error("Failed to read checkpoint file");
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700722 std::string retryContent = oldContent.substr(0, oldContent.find_first_of(" "));
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700723
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700724 if (!android::base::ParseInt(retryContent, &retry))
Paul Lawrence82b35052019-04-19 14:26:39 -0700725 return error(EINVAL, "Could not parse retry count");
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700726 if (retry > 0) {
727 retry--;
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700728
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700729 newContent = std::to_string(retry);
730 if (!android::base::WriteStringToFile(newContent, kMetadataCPFile))
Paul Lawrence82b35052019-04-19 14:26:39 -0700731 return error("Could not write checkpoint file");
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700732 }
733 return Status::ok();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700734}
735
Nikita Ioffea5798fc2019-10-11 16:38:21 +0100736void cp_resetCheckpoint() {
737 std::lock_guard<std::mutex> lock(isCheckpointingLock);
738 needsCheckpointWasCalled = false;
739}
740
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700741} // namespace vold
742} // namespace android