blob: 195a13728862c8870b80cc0546763299248792b8 [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"
Eric Biggersb615f3b2022-11-09 05:48:45 +000019#include "FsCrypt.h"
20#include "KeyStorage.h"
Daniel Rosenberg253b44e2019-02-01 19:25:47 -080021#include "VoldUtil.h"
Sandeep Patilf8da61f2019-04-15 08:45:27 -070022#include "VolumeManager.h"
Daniel Rosenberg65f99c92018-08-28 01:58:49 -070023
Paul Lawrence1abb2fe2018-09-21 10:49:57 -070024#include <fstream>
Daniel Rosenberg65f99c92018-08-28 01:58:49 -070025#include <list>
Paul Lawrence20400892018-10-03 14:14:52 -070026#include <memory>
Daniel Rosenberg65f99c92018-08-28 01:58:49 -070027#include <string>
Daniel Rosenberg8daeec02018-11-20 19:03:11 -080028#include <thread>
Paul Lawrence1abb2fe2018-09-21 10:49:57 -070029#include <vector>
30
Kelvin Zhangdec03ab2022-06-21 14:31:01 -070031#include <BootControlClient.h>
Paul Lawrence1abb2fe2018-09-21 10:49:57 -070032#include <android-base/file.h>
33#include <android-base/logging.h>
34#include <android-base/parseint.h>
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -080035#include <android-base/properties.h>
Paul Lawrence1abb2fe2018-09-21 10:49:57 -070036#include <android-base/unique_fd.h>
37#include <cutils/android_reboot.h>
38#include <fcntl.h>
39#include <fs_mgr.h>
40#include <linux/fs.h>
41#include <mntent.h>
42#include <sys/mount.h>
43#include <sys/stat.h>
Daniel Rosenberg8daeec02018-11-20 19:03:11 -080044#include <sys/statvfs.h>
45#include <unistd.h>
Daniel Rosenberg65f99c92018-08-28 01:58:49 -070046
Daniel Rosenberg8daeec02018-11-20 19:03:11 -080047using android::base::GetBoolProperty;
48using android::base::GetUintProperty;
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -080049using android::base::SetProperty;
Daniel Rosenberg73680ec2018-10-10 18:52:04 -070050using android::binder::Status;
Tom Cherry4c5bde22019-01-29 14:34:01 -080051using android::fs_mgr::Fstab;
Tom Cherry4c5bde22019-01-29 14:34:01 -080052using android::fs_mgr::ReadFstabFromFile;
Kelvin Zhangdec03ab2022-06-21 14:31:01 -070053using android::hal::BootControlClient;
Daniel Rosenbergd3992492018-10-02 17:40:44 -070054
Daniel Rosenberg65f99c92018-08-28 01:58:49 -070055namespace android {
56namespace vold {
57
Paul Lawrence1abb2fe2018-09-21 10:49:57 -070058namespace {
59const std::string kMetadataCPFile = "/metadata/vold/checkpoint";
60
Paul Lawrence82b35052019-04-19 14:26:39 -070061binder::Status error(const std::string& msg) {
62 PLOG(ERROR) << msg;
63 return binder::Status::fromServiceSpecificError(errno, String8(msg.c_str()));
64}
65
66binder::Status error(int error, const std::string& msg) {
67 LOG(ERROR) << msg;
68 return binder::Status::fromServiceSpecificError(error, String8(msg.c_str()));
69}
70
Paul Lawrence1abb2fe2018-09-21 10:49:57 -070071bool setBowState(std::string const& block_device, std::string const& state) {
Paul Lawrence236e5e82019-06-25 14:44:33 -070072 std::string bow_device = fs_mgr_find_bow_device(block_device);
73 if (bow_device.empty()) return false;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -070074
Paul Lawrence236e5e82019-06-25 14:44:33 -070075 if (!android::base::WriteStringToFile(state, bow_device + "/bow/state")) {
76 PLOG(ERROR) << "Failed to write to file " << bow_device + "/bow/state";
Paul Lawrence1abb2fe2018-09-21 10:49:57 -070077 return false;
78 }
79
80 return true;
81}
82
Eric Biggersb615f3b2022-11-09 05:48:45 +000083// Do any work that was deferred until the userdata filesystem checkpoint was
84// committed. This work involves the deletion of resources that aren't covered
85// by the userdata filesystem checkpoint, e.g. Keystore keys.
86void DoCheckpointCommittedWork() {
87 // Take the crypt lock to provide synchronization with the Binder calls that
88 // operate on key directories.
89 std::lock_guard<std::mutex> lock(VolumeManager::Instance()->getCryptLock());
90
91 DeferredCommitKeystoreKeys();
92 fscrypt_deferred_fixate_ce_keys();
93}
94
Paul Lawrence1abb2fe2018-09-21 10:49:57 -070095} // namespace
Daniel Rosenberg65f99c92018-08-28 01:58:49 -070096
Daniel Rosenberg9b667fb2019-01-22 17:27:25 -080097Status cp_supportsCheckpoint(bool& result) {
98 result = false;
Daniel Rosenberg9b667fb2019-01-22 17:27:25 -080099
Tom Cherry4c5bde22019-01-29 14:34:01 -0800100 for (const auto& entry : fstab_default) {
101 if (entry.fs_mgr_flags.checkpoint_blk || entry.fs_mgr_flags.checkpoint_fs) {
Daniel Rosenberg9b667fb2019-01-22 17:27:25 -0800102 result = true;
103 return Status::ok();
104 }
105 }
106 return Status::ok();
107}
108
Paul Lawrencec5c79c52019-03-18 13:36:40 -0700109Status cp_supportsBlockCheckpoint(bool& result) {
110 result = false;
111
112 for (const auto& entry : fstab_default) {
113 if (entry.fs_mgr_flags.checkpoint_blk) {
114 result = true;
115 return Status::ok();
116 }
117 }
118 return Status::ok();
119}
120
121Status cp_supportsFileCheckpoint(bool& result) {
122 result = false;
123
124 for (const auto& entry : fstab_default) {
125 if (entry.fs_mgr_flags.checkpoint_fs) {
126 result = true;
127 return Status::ok();
128 }
129 }
130 return Status::ok();
131}
132
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700133Status cp_startCheckpoint(int retry) {
Paul Lawrencec2a145f2019-05-15 09:42:04 -0700134 bool result;
135 if (!cp_supportsCheckpoint(result).isOk() || !result)
136 return error(ENOTSUP, "Checkpoints not supported");
137
Paul Lawrence82b35052019-04-19 14:26:39 -0700138 if (retry < -1) return error(EINVAL, "Retry count must be more than -1");
Weston Carvalho582fca72025-03-06 13:24:03 -0600139 std::string content;
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700140 if (retry == -1) {
Weston Carvalho582fca72025-03-06 13:24:03 -0600141 content = std::to_string(-1);
Kelvin Zhangdec03ab2022-06-21 14:31:01 -0700142 auto module = BootControlClient::WaitForService();
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700143 if (module) {
Kelvin Zhangdec03ab2022-06-21 14:31:01 -0700144 std::string suffix = module->GetSuffix(module->GetCurrentSlot());
145 if (!suffix.empty()) content += " " + suffix;
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700146 }
Weston Carvalho582fca72025-03-06 13:24:03 -0600147 } else {
148 content = std::to_string(retry + 1);
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700149 }
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700150 if (!android::base::WriteStringToFile(content, kMetadataCPFile))
Paul Lawrence82b35052019-04-19 14:26:39 -0700151 return error("Failed to write checkpoint file");
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700152 return Status::ok();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700153}
154
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800155namespace {
156
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800157volatile bool isCheckpointing = false;
faqiang.zhudd20dc32021-07-19 12:27:37 +0800158volatile bool isBow = true;
Paul Lawrence1d57f682019-08-22 09:51:18 -0700159
Nikita Ioffea5798fc2019-10-11 16:38:21 +0100160volatile bool needsCheckpointWasCalled = false;
161
162// Protects isCheckpointing, needsCheckpointWasCalled and code that makes decisions based on status
163// of isCheckpointing
Paul Lawrence1d57f682019-08-22 09:51:18 -0700164std::mutex isCheckpointingLock;
Weston Carvalho6ab20652024-12-03 15:21:45 -0600165
166std::mutex listenersLock;
167std::vector<android::sp<android::system::vold::IVoldCheckpointListener>> listeners;
168} // namespace
169
170void notifyCheckpointListeners() {
171 std::lock_guard<std::mutex> lock(listenersLock);
172
173 for (auto& listener : listeners) {
174 listener->onCheckpointingComplete();
175 listener = nullptr;
176 }
177
178 // Reclaim vector memory; we likely won't need it again.
179 listeners = std::vector<android::sp<android::system::vold::IVoldCheckpointListener>>();
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800180}
181
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700182Status cp_commitChanges() {
Paul Lawrence1d57f682019-08-22 09:51:18 -0700183 std::lock_guard<std::mutex> lock(isCheckpointingLock);
184
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800185 if (!isCheckpointing) {
186 return Status::ok();
187 }
Paul Lawrencea7972dc2019-06-12 12:03:01 -0700188 if (android::base::GetProperty("persist.vold.dont_commit_checkpoint", "0") == "1") {
189 LOG(WARNING)
190 << "NOT COMMITTING CHECKPOINT BECAUSE persist.vold.dont_commit_checkpoint IS 1";
191 return Status::ok();
192 }
Kelvin Zhangdec03ab2022-06-21 14:31:01 -0700193 auto module = BootControlClient::WaitForService();
Daniel Rosenberg886915b2019-01-23 15:16:04 -0800194 if (module) {
Kelvin Zhangdec03ab2022-06-21 14:31:01 -0700195 auto cr = module->MarkBootSuccessful();
Paul Lawrence82b35052019-04-19 14:26:39 -0700196 if (!cr.success)
197 return error(EINVAL, "Error marking booted successfully: " + std::string(cr.errMsg));
Daniel Rosenberg886915b2019-01-23 15:16:04 -0800198 LOG(INFO) << "Marked slot as booted successfully.";
Tianjie Xu09de0ff2019-11-15 14:05:29 -0800199 // Clears the warm reset flag for next reboot.
200 if (!SetProperty("ota.warm_reset", "0")) {
201 LOG(WARNING) << "Failed to reset the warm reset flag";
202 }
Kelvin Zhangdec03ab2022-06-21 14:31:01 -0700203 } else {
204 LOG(ERROR) << "Failed to get BootControl HAL, not marking slot as successful.";
Daniel Rosenberg886915b2019-01-23 15:16:04 -0800205 }
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700206 // Must take action for list of mounted checkpointed things here
207 // To do this, we walk the list of mounted file systems.
208 // But we also need to get the matching fstab entries to see
209 // the original flags
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700210 std::string err_str;
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700211
Tom Cherry4c5bde22019-01-29 14:34:01 -0800212 Fstab mounts;
213 if (!ReadFstabFromFile("/proc/mounts", &mounts)) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700214 return error(EINVAL, "Failed to get /proc/mounts");
Tom Cherry4c5bde22019-01-29 14:34:01 -0800215 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700216
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700217 // Walk mounted file systems
Tom Cherry4c5bde22019-01-29 14:34:01 -0800218 for (const auto& mount_rec : mounts) {
Kelvin Zhangfd5eb262024-04-24 14:15:06 -0700219 const auto fstab_rec =
220 GetEntryForMountPoint(&fstab_default, mount_rec.mount_point, mount_rec.fs_type);
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700221 if (!fstab_rec) continue;
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700222
Tom Cherry4c5bde22019-01-29 14:34:01 -0800223 if (fstab_rec->fs_mgr_flags.checkpoint_fs) {
224 if (fstab_rec->fs_type == "f2fs") {
225 std::string options = mount_rec.fs_options + ",checkpoint=enable";
226 if (mount(mount_rec.blk_device.c_str(), mount_rec.mount_point.c_str(), "none",
Daniel Rosenberg14ca4ac2019-01-24 18:23:18 -0800227 MS_REMOUNT | fstab_rec->flags, options.c_str())) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700228 return error(EINVAL, "Failed to remount");
Daniel Rosenberg4b86df12018-11-08 22:18:37 -0800229 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700230 }
faqiang.zhudd20dc32021-07-19 12:27:37 +0800231 } else if (fstab_rec->fs_mgr_flags.checkpoint_blk && isBow) {
Tom Cherry4c5bde22019-01-29 14:34:01 -0800232 if (!setBowState(mount_rec.blk_device, "2"))
Paul Lawrence82b35052019-04-19 14:26:39 -0700233 return error(EINVAL, "Failed to set bow state");
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700234 }
235 }
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800236 SetProperty("vold.checkpoint_committed", "1");
Daniel Rosenberg886915b2019-01-23 15:16:04 -0800237 LOG(INFO) << "Checkpoint has been committed.";
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800238 isCheckpointing = false;
Daniel Rosenberg4b86df12018-11-08 22:18:37 -0800239 if (!android::base::RemoveFileIfExists(kMetadataCPFile, &err_str))
Paul Lawrence82b35052019-04-19 14:26:39 -0700240 return error(err_str.c_str());
241
Weston Carvalho6ab20652024-12-03 15:21:45 -0600242 notifyCheckpointListeners();
243
Eric Biggersb615f3b2022-11-09 05:48:45 +0000244 std::thread(DoCheckpointCommittedWork).detach();
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700245 return Status::ok();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700246}
247
Daniel Rosenberga59e4392019-03-20 17:02:47 -0700248namespace {
249void abort_metadata_file() {
250 std::string oldContent, newContent;
251 int retry = 0;
252 struct stat st;
253 int result = stat(kMetadataCPFile.c_str(), &st);
254
255 // If the file doesn't exist, we aren't managing a checkpoint retry counter
256 if (result != 0) return;
257 if (!android::base::ReadFileToString(kMetadataCPFile, &oldContent)) {
258 PLOG(ERROR) << "Failed to read checkpoint file";
259 return;
260 }
261 std::string retryContent = oldContent.substr(0, oldContent.find_first_of(" "));
262
263 if (!android::base::ParseInt(retryContent, &retry)) {
264 PLOG(ERROR) << "Could not parse retry count";
265 return;
266 }
267 if (retry > 0) {
268 newContent = "0";
269 if (!android::base::WriteStringToFile(newContent, kMetadataCPFile))
270 PLOG(ERROR) << "Could not write checkpoint file";
271 }
272}
273} // namespace
274
275void cp_abortChanges(const std::string& message, bool retry) {
276 if (!cp_needsCheckpoint()) return;
277 if (!retry) abort_metadata_file();
278 android_reboot(ANDROID_RB_RESTART2, 0, message.c_str());
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700279}
280
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700281bool cp_needsRollback() {
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700282 std::string content;
283 bool ret;
284
285 ret = android::base::ReadFileToString(kMetadataCPFile, &content);
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700286 if (ret) {
287 if (content == "0") return true;
288 if (content.substr(0, 3) == "-1 ") {
289 std::string oldSuffix = content.substr(3);
Kelvin Zhangdec03ab2022-06-21 14:31:01 -0700290 auto module = BootControlClient::WaitForService();
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700291 std::string newSuffix;
292
293 if (module) {
Kelvin Zhangdec03ab2022-06-21 14:31:01 -0700294 newSuffix = module->GetSuffix(module->GetCurrentSlot());
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700295 if (oldSuffix == newSuffix) return true;
296 }
297 }
298 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700299 return false;
300}
301
Daniel Rosenberg80d1ca52018-10-09 19:26:57 -0700302bool cp_needsCheckpoint() {
Nikita Ioffea5798fc2019-10-11 16:38:21 +0100303 std::lock_guard<std::mutex> lock(isCheckpointingLock);
304
Paul Lawrence9a6d1f72019-08-26 15:09:41 -0700305 // Make sure we only return true during boot. See b/138952436 for discussion
Nikita Ioffea5798fc2019-10-11 16:38:21 +0100306 if (needsCheckpointWasCalled) return isCheckpointing;
307 needsCheckpointWasCalled = true;
Paul Lawrence9a6d1f72019-08-26 15:09:41 -0700308
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700309 bool ret;
310 std::string content;
Kelvin Zhangdec03ab2022-06-21 14:31:01 -0700311 auto module = BootControlClient::WaitForService();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700312
Weston Carvalhoa2db7fe2025-02-11 14:26:13 -0600313 if (isCheckpointing) return true;
314
Kelvin Zhangdec03ab2022-06-21 14:31:01 -0700315 // In case of INVALID slot or other failures, we do not perform checkpoint.
316 if (module && !module->IsSlotMarkedSuccessful(module->GetCurrentSlot()).value_or(true)) {
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800317 isCheckpointing = true;
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700318 return true;
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800319 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700320 ret = android::base::ReadFileToString(kMetadataCPFile, &content);
Weston Carvalhoa2db7fe2025-02-11 14:26:13 -0600321 if (ret && content != "0") {
322 isCheckpointing = true;
323 return true;
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800324 }
Weston Carvalhoa2db7fe2025-02-11 14:26:13 -0600325
326 // Leave isCheckpointing false and notify listeners now that we know we don't need one
327 notifyCheckpointListeners();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700328 return false;
329}
330
David Anderson23850d32020-06-10 23:51:17 -0700331bool cp_isCheckpointing() {
332 return isCheckpointing;
333}
334
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800335namespace {
Daniel Rosenbergb7dddd02019-03-26 14:42:14 -0700336const std::string kSleepTimeProp = "ro.sys.cp_msleeptime";
337const uint32_t msleeptime_default = 1000; // 1 s
338const uint32_t max_msleeptime = 3600000; // 1 h
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800339
340const std::string kMinFreeBytesProp = "ro.sys.cp_min_free_bytes";
341const uint64_t min_free_bytes_default = 100 * (1 << 20); // 100 MiB
342
343const std::string kCommitOnFullProp = "ro.sys.cp_commit_on_full";
344const bool commit_on_full_default = true;
345
346static void cp_healthDaemon(std::string mnt_pnt, std::string blk_device, bool is_fs_cp) {
347 struct statvfs data;
Daniel Rosenbergb7dddd02019-03-26 14:42:14 -0700348 uint32_t msleeptime = GetUintProperty(kSleepTimeProp, msleeptime_default, max_msleeptime);
Satoshi Futenma18d10d42019-03-25 23:13:36 +0900349 uint64_t min_free_bytes =
350 GetUintProperty(kMinFreeBytesProp, min_free_bytes_default, (uint64_t)-1);
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800351 bool commit_on_full = GetBoolProperty(kCommitOnFullProp, commit_on_full_default);
352
Daniel Rosenbergb7dddd02019-03-26 14:42:14 -0700353 struct timespec req;
354 req.tv_sec = msleeptime / 1000;
355 msleeptime %= 1000;
356 req.tv_nsec = msleeptime * 1000000;
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800357 while (isCheckpointing) {
Paul Lawrence236e5e82019-06-25 14:44:33 -0700358 uint64_t free_bytes = 0;
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800359 if (is_fs_cp) {
360 statvfs(mnt_pnt.c_str(), &data);
Qilin Tan5d0aaaf2020-01-02 19:07:47 +0800361 free_bytes = ((uint64_t) data.f_bavail) * data.f_frsize;
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800362 } else {
Paul Lawrence236e5e82019-06-25 14:44:33 -0700363 std::string bow_device = fs_mgr_find_bow_device(blk_device);
364 if (!bow_device.empty()) {
365 std::string content;
366 if (android::base::ReadFileToString(bow_device + "/bow/free", &content)) {
Qilin Tan5d0aaaf2020-01-02 19:07:47 +0800367 free_bytes = std::strtoull(content.c_str(), NULL, 10);
Paul Lawrence236e5e82019-06-25 14:44:33 -0700368 }
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800369 }
370 }
371 if (free_bytes < min_free_bytes) {
372 if (commit_on_full) {
373 LOG(INFO) << "Low space for checkpointing. Commiting changes";
374 cp_commitChanges();
375 break;
376 } else {
377 LOG(INFO) << "Low space for checkpointing. Rebooting";
378 cp_abortChanges("checkpoint,low_space", false);
379 break;
380 }
381 }
Daniel Rosenbergb7dddd02019-03-26 14:42:14 -0700382 nanosleep(&req, NULL);
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800383 }
384}
385
386} // namespace
387
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700388Status cp_prepareCheckpoint() {
Paul Lawrence4c757fb2019-10-23 09:36:18 -0700389 // Log to notify CTS - see b/137924328 for context
390 LOG(INFO) << "cp_prepareCheckpoint called";
Paul Lawrence1d57f682019-08-22 09:51:18 -0700391 std::lock_guard<std::mutex> lock(isCheckpointingLock);
Paul Lawrencedb086942019-02-19 14:18:54 -0800392 if (!isCheckpointing) {
393 return Status::ok();
394 }
395
Tom Cherry4c5bde22019-01-29 14:34:01 -0800396 Fstab mounts;
397 if (!ReadFstabFromFile("/proc/mounts", &mounts)) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700398 return error(EINVAL, "Failed to get /proc/mounts");
Tom Cherry4c5bde22019-01-29 14:34:01 -0800399 }
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700400
Tom Cherry4c5bde22019-01-29 14:34:01 -0800401 for (const auto& mount_rec : mounts) {
402 const auto fstab_rec = GetEntryForMountPoint(&fstab_default, mount_rec.mount_point);
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700403 if (!fstab_rec) continue;
404
Tom Cherry4c5bde22019-01-29 14:34:01 -0800405 if (fstab_rec->fs_mgr_flags.checkpoint_blk) {
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700406 android::base::unique_fd fd(
Tom Cherry4c5bde22019-01-29 14:34:01 -0800407 TEMP_FAILURE_RETRY(open(mount_rec.mount_point.c_str(), O_RDONLY | O_CLOEXEC)));
Bernie Innocentiebe293a2019-03-28 15:24:30 +0900408 if (fd == -1) {
Tom Cherry4c5bde22019-01-29 14:34:01 -0800409 PLOG(ERROR) << "Failed to open mount point" << mount_rec.mount_point;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700410 continue;
411 }
412
413 struct fstrim_range range = {};
414 range.len = ULLONG_MAX;
Sandeep Patilf8da61f2019-04-15 08:45:27 -0700415 nsecs_t start = systemTime(SYSTEM_TIME_BOOTTIME);
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700416 if (ioctl(fd, FITRIM, &range)) {
Tom Cherry4c5bde22019-01-29 14:34:01 -0800417 PLOG(ERROR) << "Failed to trim " << mount_rec.mount_point;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700418 continue;
419 }
Sandeep Patilf8da61f2019-04-15 08:45:27 -0700420 nsecs_t time = systemTime(SYSTEM_TIME_BOOTTIME) - start;
421 LOG(INFO) << "Trimmed " << range.len << " bytes on " << mount_rec.mount_point << " in "
422 << nanoseconds_to_milliseconds(time) << "ms for checkpoint";
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700423
faqiang.zhudd20dc32021-07-19 12:27:37 +0800424 isBow &= setBowState(mount_rec.blk_device, "1");
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700425 }
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800426 if (fstab_rec->fs_mgr_flags.checkpoint_blk || fstab_rec->fs_mgr_flags.checkpoint_fs) {
427 std::thread(cp_healthDaemon, std::string(mount_rec.mount_point),
Paul Lawrencee81f4c12019-03-29 13:06:34 -0700428 std::string(mount_rec.blk_device),
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800429 fstab_rec->fs_mgr_flags.checkpoint_fs == 1)
430 .detach();
431 }
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700432 }
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700433 return Status::ok();
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700434}
435
436namespace {
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700437const int kSectorSize = 512;
438
439typedef uint64_t sector_t;
440
441struct log_entry {
Paul Lawrenced41a9392019-01-22 14:31:43 -0800442 sector_t source; // in sectors of size kSectorSize
443 sector_t dest; // in sectors of size kSectorSize
444 uint32_t size; // in bytes
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700445 uint32_t checksum;
446} __attribute__((packed));
447
Paul Lawrencef5077682019-01-18 10:28:34 -0800448struct log_sector_v1_0 {
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700449 uint32_t magic;
Paul Lawrencef5077682019-01-18 10:28:34 -0800450 uint16_t header_version;
451 uint16_t header_size;
Paul Lawrence4f13a902019-01-10 13:06:07 -0800452 uint32_t block_size;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700453 uint32_t count;
454 uint32_t sequence;
Paul Lawrence27691c22018-11-20 14:07:59 -0800455 uint64_t sector0;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700456} __attribute__((packed));
457
458// MAGIC is BOW in ascii
459const int kMagic = 0x00574f42;
Daniel Rosenberg52985932019-03-01 22:01:22 -0800460// Partially restored MAGIC is WOB in ascii
461const int kPartialRestoreMagic = 0x00424f57;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700462
463void crc32(const void* data, size_t n_bytes, uint32_t* crc) {
464 static uint32_t table[0x100] = {
465 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535,
466 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD,
467 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D,
468 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
469 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4,
470 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C,
471 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC,
472 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
473 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB,
474 0xB6662D3D,
475
476 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5,
477 0xE8B8D433, 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D,
478 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED,
479 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
480 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, 0x4DB26158, 0x3AB551CE, 0xA3BC0074,
481 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC,
482 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C,
483 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
484 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B,
485 0xC0BA6CAD,
486
487 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615,
488 0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D,
489 0x0A00AE27, 0x7D079EB1, 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D,
490 0x806567CB, 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
491 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4,
492 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, 0xD80D2BDA, 0xAF0A1B4C,
493 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, 0xCB61B38C,
494 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
495 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B,
496 0x5BDEAE1D,
497
498 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785,
499 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D,
500 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD,
501 0xF6B9265B, 0x6FB077E1, 0x18B74777, 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
502 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354,
503 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC,
504 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, 0xBDBDF21C,
505 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
506 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B,
507 0x2D02EF8D};
508
509 for (size_t i = 0; i < n_bytes; ++i) {
510 *crc ^= ((uint8_t*)data)[i];
511 *crc = table[(uint8_t)*crc] ^ *crc >> 8;
512 }
513}
514
Paul Lawrenced41a9392019-01-22 14:31:43 -0800515// A map of relocations.
516// The map must be initialized so that relocations[0] = 0
517// During restore, we replay the log records in reverse, copying from dest to
518// source
519// To validate, we must be able to read the 'dest' sectors as though they had
520// been copied but without actually copying. This map represents how the sectors
521// would have been moved. To read a sector s, find the index <= s and read
522// relocations[index] + s - index
523typedef std::map<sector_t, sector_t> Relocations;
Paul Lawrence27691c22018-11-20 14:07:59 -0800524
Paul Lawrenced41a9392019-01-22 14:31:43 -0800525void relocate(Relocations& relocations, sector_t dest, sector_t source, int count) {
526 // Find first one we're equal to or greater than
527 auto s = --relocations.upper_bound(source);
528
529 // Take slice
530 Relocations slice;
531 slice[dest] = source - s->first + s->second;
532 ++s;
533
534 // Add rest of elements
535 for (; s != relocations.end() && s->first < source + count; ++s)
536 slice[dest - source + s->first] = s->second;
537
538 // Split range at end of dest
539 auto dest_end = --relocations.upper_bound(dest + count);
540 relocations[dest + count] = dest + count - dest_end->first + dest_end->second;
541
542 // Remove all elements in [dest, dest + count)
543 relocations.erase(relocations.lower_bound(dest), relocations.lower_bound(dest + count));
544
545 // Add new elements
546 relocations.insert(slice.begin(), slice.end());
Paul Lawrence27691c22018-11-20 14:07:59 -0800547}
548
Daniel Rosenberg52985932019-03-01 22:01:22 -0800549// A map of sectors that have been written to.
550// The final entry must always be False.
551// When we restart the restore after an interruption, we must take care that
552// when we copy from dest to source, that the block we copy to was not
553// previously copied from.
554// i e. A->B C->A; If we replay this sequence, we end up copying C->B
555// We must save our partial result whenever we finish a page, or when we copy
556// to a location that was copied from earlier (our source is an earlier dest)
557typedef std::map<sector_t, bool> Used_Sectors;
558
559bool checkCollision(Used_Sectors& used_sectors, sector_t start, sector_t end) {
560 auto second_overlap = used_sectors.upper_bound(start);
561 auto first_overlap = --second_overlap;
562
563 if (first_overlap->second) {
564 return true;
565 } else if (second_overlap != used_sectors.end() && second_overlap->first < end) {
566 return true;
567 }
568 return false;
569}
570
571void markUsed(Used_Sectors& used_sectors, sector_t start, sector_t end) {
572 auto start_pos = used_sectors.insert_or_assign(start, true).first;
573 auto end_pos = used_sectors.insert_or_assign(end, false).first;
574
575 if (start_pos == used_sectors.begin() || !std::prev(start_pos)->second) {
576 start_pos++;
577 }
578 if (std::next(end_pos) != used_sectors.end() && !std::next(end_pos)->second) {
579 end_pos++;
580 }
581 if (start_pos->first < end_pos->first) {
582 used_sectors.erase(start_pos, end_pos);
583 }
584}
585
586// Restores the given log_entry's data from dest -> source
587// If that entry is a log sector, set the magic to kPartialRestoreMagic and flush.
588void restoreSector(int device_fd, Used_Sectors& used_sectors, std::vector<char>& ls_buffer,
589 log_entry* le, std::vector<char>& buffer) {
590 log_sector_v1_0& ls = *reinterpret_cast<log_sector_v1_0*>(&ls_buffer[0]);
591 uint32_t index = le - ((log_entry*)&ls_buffer[ls.header_size]);
592 int count = (le->size - 1) / kSectorSize + 1;
593
594 if (checkCollision(used_sectors, le->source, le->source + count)) {
595 fsync(device_fd);
596 lseek64(device_fd, 0, SEEK_SET);
597 ls.count = index + 1;
598 ls.magic = kPartialRestoreMagic;
599 write(device_fd, &ls_buffer[0], ls.block_size);
600 fsync(device_fd);
601 used_sectors.clear();
602 used_sectors[0] = false;
603 }
604
605 markUsed(used_sectors, le->dest, le->dest + count);
606
607 if (index == 0 && ls.sequence != 0) {
608 log_sector_v1_0* next = reinterpret_cast<log_sector_v1_0*>(&buffer[0]);
609 if (next->magic == kMagic) {
610 next->magic = kPartialRestoreMagic;
611 }
612 }
613
614 lseek64(device_fd, le->source * kSectorSize, SEEK_SET);
615 write(device_fd, &buffer[0], le->size);
616
617 if (index == 0) {
618 fsync(device_fd);
619 }
620}
621
Paul Lawrenced41a9392019-01-22 14:31:43 -0800622// Read from the device
623// If we are validating, the read occurs as though the relocations had happened
Paul Lawrencea3594a62023-01-31 13:42:09 -0800624// returns the amount asked for or an empty buffer on error. Partial reads are considered a failure
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800625std::vector<char> relocatedRead(int device_fd, Relocations const& relocations, bool validating,
626 sector_t sector, uint32_t size, uint32_t block_size) {
Paul Lawrence27691c22018-11-20 14:07:59 -0800627 if (!validating) {
628 std::vector<char> buffer(size);
Paul Lawrencea3594a62023-01-31 13:42:09 -0800629 off64_t offset = sector * kSectorSize;
630 if (lseek64(device_fd, offset, SEEK_SET) != offset) {
631 return std::vector<char>();
632 }
633 if (read(device_fd, &buffer[0], size) != static_cast<ssize_t>(size)) {
634 return std::vector<char>();
635 }
Paul Lawrence27691c22018-11-20 14:07:59 -0800636 return buffer;
637 }
638
Paul Lawrence27691c22018-11-20 14:07:59 -0800639 std::vector<char> buffer(size);
Paul Lawrenced41a9392019-01-22 14:31:43 -0800640 for (uint32_t i = 0; i < size; i += block_size, sector += block_size / kSectorSize) {
641 auto relocation = --relocations.upper_bound(sector);
Paul Lawrencea3594a62023-01-31 13:42:09 -0800642 off64_t offset = (sector + relocation->second - relocation->first) * kSectorSize;
643 if (lseek64(device_fd, offset, SEEK_SET) != offset) {
644 return std::vector<char>();
645 }
646 if (read(device_fd, &buffer[i], block_size) != static_cast<ssize_t>(block_size)) {
647 return std::vector<char>();
648 }
Paul Lawrenced41a9392019-01-22 14:31:43 -0800649 }
Paul Lawrence27691c22018-11-20 14:07:59 -0800650
651 return buffer;
652}
653
Paul Lawrence4f13a902019-01-10 13:06:07 -0800654} // namespace
655
Daniel Rosenbergdda59812019-03-06 17:45:17 -0800656Status cp_restoreCheckpoint(const std::string& blockDevice, int restore_limit) {
Paul Lawrence27691c22018-11-20 14:07:59 -0800657 bool validating = true;
658 std::string action = "Validating";
Daniel Rosenbergdda59812019-03-06 17:45:17 -0800659 int restore_count = 0;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700660
Paul Lawrence27691c22018-11-20 14:07:59 -0800661 for (;;) {
Paul Lawrenced41a9392019-01-22 14:31:43 -0800662 Relocations relocations;
663 relocations[0] = 0;
Paul Lawrence27691c22018-11-20 14:07:59 -0800664 Status status = Status::ok();
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700665
Paul Lawrence27691c22018-11-20 14:07:59 -0800666 LOG(INFO) << action << " checkpoint on " << blockDevice;
Nick Kraleviche7e89ac2019-03-29 16:03:51 -0700667 base::unique_fd device_fd(open(blockDevice.c_str(), O_RDWR | O_CLOEXEC));
Paul Lawrence82b35052019-04-19 14:26:39 -0700668 if (device_fd < 0) return error("Cannot open " + blockDevice);
Paul Lawrence4f13a902019-01-10 13:06:07 -0800669
Paul Lawrencef5077682019-01-18 10:28:34 -0800670 log_sector_v1_0 original_ls;
Paul Lawrencea3594a62023-01-31 13:42:09 -0800671 if (read(device_fd, reinterpret_cast<char*>(&original_ls), sizeof(original_ls)) !=
672 sizeof(original_ls)) {
673 return error(EINVAL, "Cannot read sector");
674 }
Daniel Rosenberg52985932019-03-01 22:01:22 -0800675 if (original_ls.magic == kPartialRestoreMagic) {
676 validating = false;
677 action = "Restoring";
678 } else if (original_ls.magic != kMagic) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700679 return error(EINVAL, "No magic");
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700680 }
681
Paul Lawrencea3594a62023-01-31 13:42:09 -0800682 if (original_ls.block_size < sizeof(log_sector_v1_0)) {
683 return error(EINVAL, "Block size is invalid");
684 }
685
Paul Lawrence4f13a902019-01-10 13:06:07 -0800686 LOG(INFO) << action << " " << original_ls.sequence << " log sectors";
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700687
Paul Lawrence4f13a902019-01-10 13:06:07 -0800688 for (int sequence = original_ls.sequence; sequence >= 0 && status.isOk(); sequence--) {
Daniel Rosenberg52985932019-03-01 22:01:22 -0800689 auto ls_buffer = relocatedRead(device_fd, relocations, validating, 0,
690 original_ls.block_size, original_ls.block_size);
Paul Lawrencea3594a62023-01-31 13:42:09 -0800691 if (ls_buffer.size() != original_ls.block_size) {
692 status = error(EINVAL, "Failed to read log sector");
693 break;
694 }
Daniel Rosenberg52985932019-03-01 22:01:22 -0800695 log_sector_v1_0& ls = *reinterpret_cast<log_sector_v1_0*>(&ls_buffer[0]);
696
697 Used_Sectors used_sectors;
698 used_sectors[0] = false;
699
700 if (ls.magic != kMagic && (ls.magic != kPartialRestoreMagic || validating)) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700701 status = error(EINVAL, "No magic");
Paul Lawrence27691c22018-11-20 14:07:59 -0800702 break;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700703 }
704
Paul Lawrence4f13a902019-01-10 13:06:07 -0800705 if (ls.block_size != original_ls.block_size) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700706 status = error(EINVAL, "Block size mismatch");
Paul Lawrence4f13a902019-01-10 13:06:07 -0800707 break;
708 }
709
Paul Lawrence27691c22018-11-20 14:07:59 -0800710 if ((int)ls.sequence != sequence) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700711 status = error(EINVAL, "Expecting log sector " + std::to_string(sequence) +
712 " but got " + std::to_string(ls.sequence));
Paul Lawrence27691c22018-11-20 14:07:59 -0800713 break;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700714 }
715
Paul Lawrencea3594a62023-01-31 13:42:09 -0800716 if (ls.header_size < sizeof(log_sector_v1_0) || ls.header_size > ls.block_size) {
717 status = error(EINVAL, "Log sector header size is invalid");
718 break;
719 }
720 if (ls.count < 1 || ls.count > (ls.block_size - ls.header_size) / sizeof(log_entry)) {
721 status = error(EINVAL, "Log sector count is invalid");
722 break;
723 }
Paul Lawrence27691c22018-11-20 14:07:59 -0800724 LOG(INFO) << action << " from log sector " << ls.sequence;
Paul Lawrencef5077682019-01-18 10:28:34 -0800725 for (log_entry* le =
Daniel Rosenberg52985932019-03-01 22:01:22 -0800726 reinterpret_cast<log_entry*>(&ls_buffer[ls.header_size]) + ls.count - 1;
727 le >= reinterpret_cast<log_entry*>(&ls_buffer[ls.header_size]); --le) {
Paul Lawrencef5077682019-01-18 10:28:34 -0800728 // This is very noisy - limit to DEBUG only
Paul Lawrenced41a9392019-01-22 14:31:43 -0800729 LOG(VERBOSE) << action << " " << le->size << " bytes from sector " << le->dest
730 << " to " << le->source << " with checksum " << std::hex
731 << le->checksum;
Paul Lawrencef5077682019-01-18 10:28:34 -0800732
Paul Lawrencea3594a62023-01-31 13:42:09 -0800733 if (ls.block_size > UINT_MAX - le->size || le->size < ls.block_size) {
734 status = error(EINVAL, "log entry is invalid");
735 break;
736 }
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800737 auto buffer = relocatedRead(device_fd, relocations, validating, le->dest, le->size,
Paul Lawrenced41a9392019-01-22 14:31:43 -0800738 ls.block_size);
Paul Lawrencea3594a62023-01-31 13:42:09 -0800739 if (buffer.size() != le->size) {
740 status = error(EINVAL, "Failed to read sector");
741 break;
742 }
Paul Lawrence4f13a902019-01-10 13:06:07 -0800743 uint32_t checksum = le->source / (ls.block_size / kSectorSize);
744 for (size_t i = 0; i < le->size; i += ls.block_size) {
745 crc32(&buffer[i], ls.block_size, &checksum);
Paul Lawrence27691c22018-11-20 14:07:59 -0800746 }
747
748 if (le->checksum && checksum != le->checksum) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700749 status = error(EINVAL, "Checksums don't match");
Paul Lawrence27691c22018-11-20 14:07:59 -0800750 break;
751 }
752
Paul Lawrenced41a9392019-01-22 14:31:43 -0800753 if (validating) {
Daniel Rosenberg52985932019-03-01 22:01:22 -0800754 relocate(relocations, le->source, le->dest, (le->size - 1) / kSectorSize + 1);
Paul Lawrenced41a9392019-01-22 14:31:43 -0800755 } else {
Daniel Rosenberg52985932019-03-01 22:01:22 -0800756 restoreSector(device_fd, used_sectors, ls_buffer, le, buffer);
Daniel Rosenbergdda59812019-03-06 17:45:17 -0800757 restore_count++;
758 if (restore_limit && restore_count >= restore_limit) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700759 status = error(EAGAIN, "Hit the test limit");
Daniel Rosenbergdda59812019-03-06 17:45:17 -0800760 break;
761 }
Paul Lawrence27691c22018-11-20 14:07:59 -0800762 }
763 }
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700764 }
Paul Lawrence27691c22018-11-20 14:07:59 -0800765
766 if (!status.isOk()) {
767 if (!validating) {
768 LOG(ERROR) << "Checkpoint restore failed even though checkpoint validation passed";
769 return status;
770 }
771
772 LOG(WARNING) << "Checkpoint validation failed - attempting to roll forward";
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800773 auto buffer = relocatedRead(device_fd, relocations, false, original_ls.sector0,
Paul Lawrenced41a9392019-01-22 14:31:43 -0800774 original_ls.block_size, original_ls.block_size);
Paul Lawrencea3594a62023-01-31 13:42:09 -0800775 if (buffer.size() != original_ls.block_size) {
776 return error(EINVAL, "Failed to read original sector");
777 }
778
779 if (lseek64(device_fd, 0, SEEK_SET) != 0) {
780 return error(EINVAL, "Failed to seek to sector 0");
781 }
782 if (write(device_fd, &buffer[0], original_ls.block_size) !=
783 static_cast<ssize_t>(original_ls.block_size)) {
784 return error(EINVAL, "Failed to write original sector");
785 }
Paul Lawrence27691c22018-11-20 14:07:59 -0800786 return Status::ok();
787 }
788
789 if (!validating) break;
790
791 validating = false;
792 action = "Restoring";
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700793 }
794
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700795 return Status::ok();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700796}
797
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700798Status cp_markBootAttempt() {
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700799 std::string oldContent, newContent;
800 int retry = 0;
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700801 struct stat st;
802 int result = stat(kMetadataCPFile.c_str(), &st);
803
804 // If the file doesn't exist, we aren't managing a checkpoint retry counter
805 if (result != 0) return Status::ok();
Paul Lawrence82b35052019-04-19 14:26:39 -0700806 if (!android::base::ReadFileToString(kMetadataCPFile, &oldContent))
807 return error("Failed to read checkpoint file");
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700808 std::string retryContent = oldContent.substr(0, oldContent.find_first_of(" "));
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700809
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700810 if (!android::base::ParseInt(retryContent, &retry))
Paul Lawrence82b35052019-04-19 14:26:39 -0700811 return error(EINVAL, "Could not parse retry count");
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700812 if (retry > 0) {
813 retry--;
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700814
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700815 newContent = std::to_string(retry);
816 if (!android::base::WriteStringToFile(newContent, kMetadataCPFile))
Paul Lawrence82b35052019-04-19 14:26:39 -0700817 return error("Could not write checkpoint file");
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700818 }
819 return Status::ok();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700820}
821
Nikita Ioffea5798fc2019-10-11 16:38:21 +0100822void cp_resetCheckpoint() {
823 std::lock_guard<std::mutex> lock(isCheckpointingLock);
824 needsCheckpointWasCalled = false;
825}
826
Weston Carvalho6ab20652024-12-03 15:21:45 -0600827bool cp_registerCheckpointListener(
828 android::sp<android::system::vold::IVoldCheckpointListener> listener) {
829 std::lock_guard<std::mutex> checkpointGuard(isCheckpointingLock);
830 if (needsCheckpointWasCalled && !isCheckpointing) {
831 // Either checkpoint already committed or we didn't need one
832 return false;
833 }
834
835 // Either we don't know whether we need a checkpoint or we're already checkpointing,
836 // so we need to save this listener to notify later.
837 std::lock_guard<std::mutex> listenersGuard(listenersLock);
838 listeners.push_back(std::move(listener));
839 return true;
840}
841
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700842} // namespace vold
843} // namespace android