blob: 76e46fbda324bc7a9b3229d0a55f0d1e78738e0b [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");
Daniel Rosenberg80d1ca52018-10-09 19:26:57 -0700139 std::string content = std::to_string(retry + 1);
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700140 if (retry == -1) {
Kelvin Zhangdec03ab2022-06-21 14:31:01 -0700141 auto module = BootControlClient::WaitForService();
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700142 if (module) {
Kelvin Zhangdec03ab2022-06-21 14:31:01 -0700143 std::string suffix = module->GetSuffix(module->GetCurrentSlot());
144 if (!suffix.empty()) content += " " + suffix;
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700145 }
146 }
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700147 if (!android::base::WriteStringToFile(content, kMetadataCPFile))
Paul Lawrence82b35052019-04-19 14:26:39 -0700148 return error("Failed to write checkpoint file");
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700149 return Status::ok();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700150}
151
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800152namespace {
153
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800154volatile bool isCheckpointing = false;
faqiang.zhudd20dc32021-07-19 12:27:37 +0800155volatile bool isBow = true;
Paul Lawrence1d57f682019-08-22 09:51:18 -0700156
Nikita Ioffea5798fc2019-10-11 16:38:21 +0100157volatile bool needsCheckpointWasCalled = false;
158
159// Protects isCheckpointing, needsCheckpointWasCalled and code that makes decisions based on status
160// of isCheckpointing
Paul Lawrence1d57f682019-08-22 09:51:18 -0700161std::mutex isCheckpointingLock;
Weston Carvalho6ab20652024-12-03 15:21:45 -0600162
163std::mutex listenersLock;
164std::vector<android::sp<android::system::vold::IVoldCheckpointListener>> listeners;
165} // namespace
166
167void notifyCheckpointListeners() {
168 std::lock_guard<std::mutex> lock(listenersLock);
169
170 for (auto& listener : listeners) {
171 listener->onCheckpointingComplete();
172 listener = nullptr;
173 }
174
175 // Reclaim vector memory; we likely won't need it again.
176 listeners = std::vector<android::sp<android::system::vold::IVoldCheckpointListener>>();
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800177}
178
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700179Status cp_commitChanges() {
Paul Lawrence1d57f682019-08-22 09:51:18 -0700180 std::lock_guard<std::mutex> lock(isCheckpointingLock);
181
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800182 if (!isCheckpointing) {
183 return Status::ok();
184 }
Paul Lawrencea7972dc2019-06-12 12:03:01 -0700185 if (android::base::GetProperty("persist.vold.dont_commit_checkpoint", "0") == "1") {
186 LOG(WARNING)
187 << "NOT COMMITTING CHECKPOINT BECAUSE persist.vold.dont_commit_checkpoint IS 1";
188 return Status::ok();
189 }
Kelvin Zhangdec03ab2022-06-21 14:31:01 -0700190 auto module = BootControlClient::WaitForService();
Daniel Rosenberg886915b2019-01-23 15:16:04 -0800191 if (module) {
Kelvin Zhangdec03ab2022-06-21 14:31:01 -0700192 auto cr = module->MarkBootSuccessful();
Paul Lawrence82b35052019-04-19 14:26:39 -0700193 if (!cr.success)
194 return error(EINVAL, "Error marking booted successfully: " + std::string(cr.errMsg));
Daniel Rosenberg886915b2019-01-23 15:16:04 -0800195 LOG(INFO) << "Marked slot as booted successfully.";
Tianjie Xu09de0ff2019-11-15 14:05:29 -0800196 // Clears the warm reset flag for next reboot.
197 if (!SetProperty("ota.warm_reset", "0")) {
198 LOG(WARNING) << "Failed to reset the warm reset flag";
199 }
Kelvin Zhangdec03ab2022-06-21 14:31:01 -0700200 } else {
201 LOG(ERROR) << "Failed to get BootControl HAL, not marking slot as successful.";
Daniel Rosenberg886915b2019-01-23 15:16:04 -0800202 }
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700203 // Must take action for list of mounted checkpointed things here
204 // To do this, we walk the list of mounted file systems.
205 // But we also need to get the matching fstab entries to see
206 // the original flags
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700207 std::string err_str;
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700208
Tom Cherry4c5bde22019-01-29 14:34:01 -0800209 Fstab mounts;
210 if (!ReadFstabFromFile("/proc/mounts", &mounts)) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700211 return error(EINVAL, "Failed to get /proc/mounts");
Tom Cherry4c5bde22019-01-29 14:34:01 -0800212 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700213
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700214 // Walk mounted file systems
Tom Cherry4c5bde22019-01-29 14:34:01 -0800215 for (const auto& mount_rec : mounts) {
Kelvin Zhangfd5eb262024-04-24 14:15:06 -0700216 const auto fstab_rec =
217 GetEntryForMountPoint(&fstab_default, mount_rec.mount_point, mount_rec.fs_type);
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700218 if (!fstab_rec) continue;
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700219
Tom Cherry4c5bde22019-01-29 14:34:01 -0800220 if (fstab_rec->fs_mgr_flags.checkpoint_fs) {
221 if (fstab_rec->fs_type == "f2fs") {
222 std::string options = mount_rec.fs_options + ",checkpoint=enable";
223 if (mount(mount_rec.blk_device.c_str(), mount_rec.mount_point.c_str(), "none",
Daniel Rosenberg14ca4ac2019-01-24 18:23:18 -0800224 MS_REMOUNT | fstab_rec->flags, options.c_str())) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700225 return error(EINVAL, "Failed to remount");
Daniel Rosenberg4b86df12018-11-08 22:18:37 -0800226 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700227 }
faqiang.zhudd20dc32021-07-19 12:27:37 +0800228 } else if (fstab_rec->fs_mgr_flags.checkpoint_blk && isBow) {
Tom Cherry4c5bde22019-01-29 14:34:01 -0800229 if (!setBowState(mount_rec.blk_device, "2"))
Paul Lawrence82b35052019-04-19 14:26:39 -0700230 return error(EINVAL, "Failed to set bow state");
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700231 }
232 }
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800233 SetProperty("vold.checkpoint_committed", "1");
Daniel Rosenberg886915b2019-01-23 15:16:04 -0800234 LOG(INFO) << "Checkpoint has been committed.";
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800235 isCheckpointing = false;
Daniel Rosenberg4b86df12018-11-08 22:18:37 -0800236 if (!android::base::RemoveFileIfExists(kMetadataCPFile, &err_str))
Paul Lawrence82b35052019-04-19 14:26:39 -0700237 return error(err_str.c_str());
238
Weston Carvalho6ab20652024-12-03 15:21:45 -0600239 notifyCheckpointListeners();
240
Eric Biggersb615f3b2022-11-09 05:48:45 +0000241 std::thread(DoCheckpointCommittedWork).detach();
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700242 return Status::ok();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700243}
244
Daniel Rosenberga59e4392019-03-20 17:02:47 -0700245namespace {
246void abort_metadata_file() {
247 std::string oldContent, newContent;
248 int retry = 0;
249 struct stat st;
250 int result = stat(kMetadataCPFile.c_str(), &st);
251
252 // If the file doesn't exist, we aren't managing a checkpoint retry counter
253 if (result != 0) return;
254 if (!android::base::ReadFileToString(kMetadataCPFile, &oldContent)) {
255 PLOG(ERROR) << "Failed to read checkpoint file";
256 return;
257 }
258 std::string retryContent = oldContent.substr(0, oldContent.find_first_of(" "));
259
260 if (!android::base::ParseInt(retryContent, &retry)) {
261 PLOG(ERROR) << "Could not parse retry count";
262 return;
263 }
264 if (retry > 0) {
265 newContent = "0";
266 if (!android::base::WriteStringToFile(newContent, kMetadataCPFile))
267 PLOG(ERROR) << "Could not write checkpoint file";
268 }
269}
270} // namespace
271
272void cp_abortChanges(const std::string& message, bool retry) {
273 if (!cp_needsCheckpoint()) return;
274 if (!retry) abort_metadata_file();
275 android_reboot(ANDROID_RB_RESTART2, 0, message.c_str());
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700276}
277
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700278bool cp_needsRollback() {
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700279 std::string content;
280 bool ret;
281
282 ret = android::base::ReadFileToString(kMetadataCPFile, &content);
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700283 if (ret) {
284 if (content == "0") return true;
285 if (content.substr(0, 3) == "-1 ") {
286 std::string oldSuffix = content.substr(3);
Kelvin Zhangdec03ab2022-06-21 14:31:01 -0700287 auto module = BootControlClient::WaitForService();
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700288 std::string newSuffix;
289
290 if (module) {
Kelvin Zhangdec03ab2022-06-21 14:31:01 -0700291 newSuffix = module->GetSuffix(module->GetCurrentSlot());
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700292 if (oldSuffix == newSuffix) return true;
293 }
294 }
295 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700296 return false;
297}
298
Daniel Rosenberg80d1ca52018-10-09 19:26:57 -0700299bool cp_needsCheckpoint() {
Nikita Ioffea5798fc2019-10-11 16:38:21 +0100300 std::lock_guard<std::mutex> lock(isCheckpointingLock);
301
Paul Lawrence9a6d1f72019-08-26 15:09:41 -0700302 // Make sure we only return true during boot. See b/138952436 for discussion
Nikita Ioffea5798fc2019-10-11 16:38:21 +0100303 if (needsCheckpointWasCalled) return isCheckpointing;
304 needsCheckpointWasCalled = true;
Paul Lawrence9a6d1f72019-08-26 15:09:41 -0700305
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700306 bool ret;
307 std::string content;
Kelvin Zhangdec03ab2022-06-21 14:31:01 -0700308 auto module = BootControlClient::WaitForService();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700309
Weston Carvalhoa2db7fe2025-02-11 14:26:13 -0600310 if (isCheckpointing) return true;
311
Kelvin Zhangdec03ab2022-06-21 14:31:01 -0700312 // In case of INVALID slot or other failures, we do not perform checkpoint.
313 if (module && !module->IsSlotMarkedSuccessful(module->GetCurrentSlot()).value_or(true)) {
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800314 isCheckpointing = true;
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700315 return true;
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800316 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700317 ret = android::base::ReadFileToString(kMetadataCPFile, &content);
Weston Carvalhoa2db7fe2025-02-11 14:26:13 -0600318 if (ret && content != "0") {
319 isCheckpointing = true;
320 return true;
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800321 }
Weston Carvalhoa2db7fe2025-02-11 14:26:13 -0600322
323 // Leave isCheckpointing false and notify listeners now that we know we don't need one
324 notifyCheckpointListeners();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700325 return false;
326}
327
David Anderson23850d32020-06-10 23:51:17 -0700328bool cp_isCheckpointing() {
329 return isCheckpointing;
330}
331
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800332namespace {
Daniel Rosenbergb7dddd02019-03-26 14:42:14 -0700333const std::string kSleepTimeProp = "ro.sys.cp_msleeptime";
334const uint32_t msleeptime_default = 1000; // 1 s
335const uint32_t max_msleeptime = 3600000; // 1 h
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800336
337const std::string kMinFreeBytesProp = "ro.sys.cp_min_free_bytes";
338const uint64_t min_free_bytes_default = 100 * (1 << 20); // 100 MiB
339
340const std::string kCommitOnFullProp = "ro.sys.cp_commit_on_full";
341const bool commit_on_full_default = true;
342
343static void cp_healthDaemon(std::string mnt_pnt, std::string blk_device, bool is_fs_cp) {
344 struct statvfs data;
Daniel Rosenbergb7dddd02019-03-26 14:42:14 -0700345 uint32_t msleeptime = GetUintProperty(kSleepTimeProp, msleeptime_default, max_msleeptime);
Satoshi Futenma18d10d42019-03-25 23:13:36 +0900346 uint64_t min_free_bytes =
347 GetUintProperty(kMinFreeBytesProp, min_free_bytes_default, (uint64_t)-1);
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800348 bool commit_on_full = GetBoolProperty(kCommitOnFullProp, commit_on_full_default);
349
Daniel Rosenbergb7dddd02019-03-26 14:42:14 -0700350 struct timespec req;
351 req.tv_sec = msleeptime / 1000;
352 msleeptime %= 1000;
353 req.tv_nsec = msleeptime * 1000000;
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800354 while (isCheckpointing) {
Paul Lawrence236e5e82019-06-25 14:44:33 -0700355 uint64_t free_bytes = 0;
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800356 if (is_fs_cp) {
357 statvfs(mnt_pnt.c_str(), &data);
Qilin Tan5d0aaaf2020-01-02 19:07:47 +0800358 free_bytes = ((uint64_t) data.f_bavail) * data.f_frsize;
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800359 } else {
Paul Lawrence236e5e82019-06-25 14:44:33 -0700360 std::string bow_device = fs_mgr_find_bow_device(blk_device);
361 if (!bow_device.empty()) {
362 std::string content;
363 if (android::base::ReadFileToString(bow_device + "/bow/free", &content)) {
Qilin Tan5d0aaaf2020-01-02 19:07:47 +0800364 free_bytes = std::strtoull(content.c_str(), NULL, 10);
Paul Lawrence236e5e82019-06-25 14:44:33 -0700365 }
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800366 }
367 }
368 if (free_bytes < min_free_bytes) {
369 if (commit_on_full) {
370 LOG(INFO) << "Low space for checkpointing. Commiting changes";
371 cp_commitChanges();
372 break;
373 } else {
374 LOG(INFO) << "Low space for checkpointing. Rebooting";
375 cp_abortChanges("checkpoint,low_space", false);
376 break;
377 }
378 }
Daniel Rosenbergb7dddd02019-03-26 14:42:14 -0700379 nanosleep(&req, NULL);
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800380 }
381}
382
383} // namespace
384
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700385Status cp_prepareCheckpoint() {
Paul Lawrence4c757fb2019-10-23 09:36:18 -0700386 // Log to notify CTS - see b/137924328 for context
387 LOG(INFO) << "cp_prepareCheckpoint called";
Paul Lawrence1d57f682019-08-22 09:51:18 -0700388 std::lock_guard<std::mutex> lock(isCheckpointingLock);
Paul Lawrencedb086942019-02-19 14:18:54 -0800389 if (!isCheckpointing) {
390 return Status::ok();
391 }
392
Tom Cherry4c5bde22019-01-29 14:34:01 -0800393 Fstab mounts;
394 if (!ReadFstabFromFile("/proc/mounts", &mounts)) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700395 return error(EINVAL, "Failed to get /proc/mounts");
Tom Cherry4c5bde22019-01-29 14:34:01 -0800396 }
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700397
Tom Cherry4c5bde22019-01-29 14:34:01 -0800398 for (const auto& mount_rec : mounts) {
399 const auto fstab_rec = GetEntryForMountPoint(&fstab_default, mount_rec.mount_point);
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700400 if (!fstab_rec) continue;
401
Tom Cherry4c5bde22019-01-29 14:34:01 -0800402 if (fstab_rec->fs_mgr_flags.checkpoint_blk) {
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700403 android::base::unique_fd fd(
Tom Cherry4c5bde22019-01-29 14:34:01 -0800404 TEMP_FAILURE_RETRY(open(mount_rec.mount_point.c_str(), O_RDONLY | O_CLOEXEC)));
Bernie Innocentiebe293a2019-03-28 15:24:30 +0900405 if (fd == -1) {
Tom Cherry4c5bde22019-01-29 14:34:01 -0800406 PLOG(ERROR) << "Failed to open mount point" << mount_rec.mount_point;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700407 continue;
408 }
409
410 struct fstrim_range range = {};
411 range.len = ULLONG_MAX;
Sandeep Patilf8da61f2019-04-15 08:45:27 -0700412 nsecs_t start = systemTime(SYSTEM_TIME_BOOTTIME);
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700413 if (ioctl(fd, FITRIM, &range)) {
Tom Cherry4c5bde22019-01-29 14:34:01 -0800414 PLOG(ERROR) << "Failed to trim " << mount_rec.mount_point;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700415 continue;
416 }
Sandeep Patilf8da61f2019-04-15 08:45:27 -0700417 nsecs_t time = systemTime(SYSTEM_TIME_BOOTTIME) - start;
418 LOG(INFO) << "Trimmed " << range.len << " bytes on " << mount_rec.mount_point << " in "
419 << nanoseconds_to_milliseconds(time) << "ms for checkpoint";
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700420
faqiang.zhudd20dc32021-07-19 12:27:37 +0800421 isBow &= setBowState(mount_rec.blk_device, "1");
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700422 }
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800423 if (fstab_rec->fs_mgr_flags.checkpoint_blk || fstab_rec->fs_mgr_flags.checkpoint_fs) {
424 std::thread(cp_healthDaemon, std::string(mount_rec.mount_point),
Paul Lawrencee81f4c12019-03-29 13:06:34 -0700425 std::string(mount_rec.blk_device),
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800426 fstab_rec->fs_mgr_flags.checkpoint_fs == 1)
427 .detach();
428 }
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700429 }
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700430 return Status::ok();
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700431}
432
433namespace {
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700434const int kSectorSize = 512;
435
436typedef uint64_t sector_t;
437
438struct log_entry {
Paul Lawrenced41a9392019-01-22 14:31:43 -0800439 sector_t source; // in sectors of size kSectorSize
440 sector_t dest; // in sectors of size kSectorSize
441 uint32_t size; // in bytes
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700442 uint32_t checksum;
443} __attribute__((packed));
444
Paul Lawrencef5077682019-01-18 10:28:34 -0800445struct log_sector_v1_0 {
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700446 uint32_t magic;
Paul Lawrencef5077682019-01-18 10:28:34 -0800447 uint16_t header_version;
448 uint16_t header_size;
Paul Lawrence4f13a902019-01-10 13:06:07 -0800449 uint32_t block_size;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700450 uint32_t count;
451 uint32_t sequence;
Paul Lawrence27691c22018-11-20 14:07:59 -0800452 uint64_t sector0;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700453} __attribute__((packed));
454
455// MAGIC is BOW in ascii
456const int kMagic = 0x00574f42;
Daniel Rosenberg52985932019-03-01 22:01:22 -0800457// Partially restored MAGIC is WOB in ascii
458const int kPartialRestoreMagic = 0x00424f57;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700459
460void crc32(const void* data, size_t n_bytes, uint32_t* crc) {
461 static uint32_t table[0x100] = {
462 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535,
463 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD,
464 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D,
465 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
466 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4,
467 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C,
468 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC,
469 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
470 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB,
471 0xB6662D3D,
472
473 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5,
474 0xE8B8D433, 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D,
475 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED,
476 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
477 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, 0x4DB26158, 0x3AB551CE, 0xA3BC0074,
478 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC,
479 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C,
480 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
481 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B,
482 0xC0BA6CAD,
483
484 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615,
485 0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D,
486 0x0A00AE27, 0x7D079EB1, 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D,
487 0x806567CB, 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
488 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4,
489 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, 0xD80D2BDA, 0xAF0A1B4C,
490 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, 0xCB61B38C,
491 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
492 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B,
493 0x5BDEAE1D,
494
495 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785,
496 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D,
497 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD,
498 0xF6B9265B, 0x6FB077E1, 0x18B74777, 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
499 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354,
500 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC,
501 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, 0xBDBDF21C,
502 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
503 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B,
504 0x2D02EF8D};
505
506 for (size_t i = 0; i < n_bytes; ++i) {
507 *crc ^= ((uint8_t*)data)[i];
508 *crc = table[(uint8_t)*crc] ^ *crc >> 8;
509 }
510}
511
Paul Lawrenced41a9392019-01-22 14:31:43 -0800512// A map of relocations.
513// The map must be initialized so that relocations[0] = 0
514// During restore, we replay the log records in reverse, copying from dest to
515// source
516// To validate, we must be able to read the 'dest' sectors as though they had
517// been copied but without actually copying. This map represents how the sectors
518// would have been moved. To read a sector s, find the index <= s and read
519// relocations[index] + s - index
520typedef std::map<sector_t, sector_t> Relocations;
Paul Lawrence27691c22018-11-20 14:07:59 -0800521
Paul Lawrenced41a9392019-01-22 14:31:43 -0800522void relocate(Relocations& relocations, sector_t dest, sector_t source, int count) {
523 // Find first one we're equal to or greater than
524 auto s = --relocations.upper_bound(source);
525
526 // Take slice
527 Relocations slice;
528 slice[dest] = source - s->first + s->second;
529 ++s;
530
531 // Add rest of elements
532 for (; s != relocations.end() && s->first < source + count; ++s)
533 slice[dest - source + s->first] = s->second;
534
535 // Split range at end of dest
536 auto dest_end = --relocations.upper_bound(dest + count);
537 relocations[dest + count] = dest + count - dest_end->first + dest_end->second;
538
539 // Remove all elements in [dest, dest + count)
540 relocations.erase(relocations.lower_bound(dest), relocations.lower_bound(dest + count));
541
542 // Add new elements
543 relocations.insert(slice.begin(), slice.end());
Paul Lawrence27691c22018-11-20 14:07:59 -0800544}
545
Daniel Rosenberg52985932019-03-01 22:01:22 -0800546// A map of sectors that have been written to.
547// The final entry must always be False.
548// When we restart the restore after an interruption, we must take care that
549// when we copy from dest to source, that the block we copy to was not
550// previously copied from.
551// i e. A->B C->A; If we replay this sequence, we end up copying C->B
552// We must save our partial result whenever we finish a page, or when we copy
553// to a location that was copied from earlier (our source is an earlier dest)
554typedef std::map<sector_t, bool> Used_Sectors;
555
556bool checkCollision(Used_Sectors& used_sectors, sector_t start, sector_t end) {
557 auto second_overlap = used_sectors.upper_bound(start);
558 auto first_overlap = --second_overlap;
559
560 if (first_overlap->second) {
561 return true;
562 } else if (second_overlap != used_sectors.end() && second_overlap->first < end) {
563 return true;
564 }
565 return false;
566}
567
568void markUsed(Used_Sectors& used_sectors, sector_t start, sector_t end) {
569 auto start_pos = used_sectors.insert_or_assign(start, true).first;
570 auto end_pos = used_sectors.insert_or_assign(end, false).first;
571
572 if (start_pos == used_sectors.begin() || !std::prev(start_pos)->second) {
573 start_pos++;
574 }
575 if (std::next(end_pos) != used_sectors.end() && !std::next(end_pos)->second) {
576 end_pos++;
577 }
578 if (start_pos->first < end_pos->first) {
579 used_sectors.erase(start_pos, end_pos);
580 }
581}
582
583// Restores the given log_entry's data from dest -> source
584// If that entry is a log sector, set the magic to kPartialRestoreMagic and flush.
585void restoreSector(int device_fd, Used_Sectors& used_sectors, std::vector<char>& ls_buffer,
586 log_entry* le, std::vector<char>& buffer) {
587 log_sector_v1_0& ls = *reinterpret_cast<log_sector_v1_0*>(&ls_buffer[0]);
588 uint32_t index = le - ((log_entry*)&ls_buffer[ls.header_size]);
589 int count = (le->size - 1) / kSectorSize + 1;
590
591 if (checkCollision(used_sectors, le->source, le->source + count)) {
592 fsync(device_fd);
593 lseek64(device_fd, 0, SEEK_SET);
594 ls.count = index + 1;
595 ls.magic = kPartialRestoreMagic;
596 write(device_fd, &ls_buffer[0], ls.block_size);
597 fsync(device_fd);
598 used_sectors.clear();
599 used_sectors[0] = false;
600 }
601
602 markUsed(used_sectors, le->dest, le->dest + count);
603
604 if (index == 0 && ls.sequence != 0) {
605 log_sector_v1_0* next = reinterpret_cast<log_sector_v1_0*>(&buffer[0]);
606 if (next->magic == kMagic) {
607 next->magic = kPartialRestoreMagic;
608 }
609 }
610
611 lseek64(device_fd, le->source * kSectorSize, SEEK_SET);
612 write(device_fd, &buffer[0], le->size);
613
614 if (index == 0) {
615 fsync(device_fd);
616 }
617}
618
Paul Lawrenced41a9392019-01-22 14:31:43 -0800619// Read from the device
620// If we are validating, the read occurs as though the relocations had happened
Paul Lawrencea3594a62023-01-31 13:42:09 -0800621// returns the amount asked for or an empty buffer on error. Partial reads are considered a failure
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800622std::vector<char> relocatedRead(int device_fd, Relocations const& relocations, bool validating,
623 sector_t sector, uint32_t size, uint32_t block_size) {
Paul Lawrence27691c22018-11-20 14:07:59 -0800624 if (!validating) {
625 std::vector<char> buffer(size);
Paul Lawrencea3594a62023-01-31 13:42:09 -0800626 off64_t offset = sector * kSectorSize;
627 if (lseek64(device_fd, offset, SEEK_SET) != offset) {
628 return std::vector<char>();
629 }
630 if (read(device_fd, &buffer[0], size) != static_cast<ssize_t>(size)) {
631 return std::vector<char>();
632 }
Paul Lawrence27691c22018-11-20 14:07:59 -0800633 return buffer;
634 }
635
Paul Lawrence27691c22018-11-20 14:07:59 -0800636 std::vector<char> buffer(size);
Paul Lawrenced41a9392019-01-22 14:31:43 -0800637 for (uint32_t i = 0; i < size; i += block_size, sector += block_size / kSectorSize) {
638 auto relocation = --relocations.upper_bound(sector);
Paul Lawrencea3594a62023-01-31 13:42:09 -0800639 off64_t offset = (sector + relocation->second - relocation->first) * kSectorSize;
640 if (lseek64(device_fd, offset, SEEK_SET) != offset) {
641 return std::vector<char>();
642 }
643 if (read(device_fd, &buffer[i], block_size) != static_cast<ssize_t>(block_size)) {
644 return std::vector<char>();
645 }
Paul Lawrenced41a9392019-01-22 14:31:43 -0800646 }
Paul Lawrence27691c22018-11-20 14:07:59 -0800647
648 return buffer;
649}
650
Paul Lawrence4f13a902019-01-10 13:06:07 -0800651} // namespace
652
Daniel Rosenbergdda59812019-03-06 17:45:17 -0800653Status cp_restoreCheckpoint(const std::string& blockDevice, int restore_limit) {
Paul Lawrence27691c22018-11-20 14:07:59 -0800654 bool validating = true;
655 std::string action = "Validating";
Daniel Rosenbergdda59812019-03-06 17:45:17 -0800656 int restore_count = 0;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700657
Paul Lawrence27691c22018-11-20 14:07:59 -0800658 for (;;) {
Paul Lawrenced41a9392019-01-22 14:31:43 -0800659 Relocations relocations;
660 relocations[0] = 0;
Paul Lawrence27691c22018-11-20 14:07:59 -0800661 Status status = Status::ok();
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700662
Paul Lawrence27691c22018-11-20 14:07:59 -0800663 LOG(INFO) << action << " checkpoint on " << blockDevice;
Nick Kraleviche7e89ac2019-03-29 16:03:51 -0700664 base::unique_fd device_fd(open(blockDevice.c_str(), O_RDWR | O_CLOEXEC));
Paul Lawrence82b35052019-04-19 14:26:39 -0700665 if (device_fd < 0) return error("Cannot open " + blockDevice);
Paul Lawrence4f13a902019-01-10 13:06:07 -0800666
Paul Lawrencef5077682019-01-18 10:28:34 -0800667 log_sector_v1_0 original_ls;
Paul Lawrencea3594a62023-01-31 13:42:09 -0800668 if (read(device_fd, reinterpret_cast<char*>(&original_ls), sizeof(original_ls)) !=
669 sizeof(original_ls)) {
670 return error(EINVAL, "Cannot read sector");
671 }
Daniel Rosenberg52985932019-03-01 22:01:22 -0800672 if (original_ls.magic == kPartialRestoreMagic) {
673 validating = false;
674 action = "Restoring";
675 } else if (original_ls.magic != kMagic) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700676 return error(EINVAL, "No magic");
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700677 }
678
Paul Lawrencea3594a62023-01-31 13:42:09 -0800679 if (original_ls.block_size < sizeof(log_sector_v1_0)) {
680 return error(EINVAL, "Block size is invalid");
681 }
682
Paul Lawrence4f13a902019-01-10 13:06:07 -0800683 LOG(INFO) << action << " " << original_ls.sequence << " log sectors";
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700684
Paul Lawrence4f13a902019-01-10 13:06:07 -0800685 for (int sequence = original_ls.sequence; sequence >= 0 && status.isOk(); sequence--) {
Daniel Rosenberg52985932019-03-01 22:01:22 -0800686 auto ls_buffer = relocatedRead(device_fd, relocations, validating, 0,
687 original_ls.block_size, original_ls.block_size);
Paul Lawrencea3594a62023-01-31 13:42:09 -0800688 if (ls_buffer.size() != original_ls.block_size) {
689 status = error(EINVAL, "Failed to read log sector");
690 break;
691 }
Daniel Rosenberg52985932019-03-01 22:01:22 -0800692 log_sector_v1_0& ls = *reinterpret_cast<log_sector_v1_0*>(&ls_buffer[0]);
693
694 Used_Sectors used_sectors;
695 used_sectors[0] = false;
696
697 if (ls.magic != kMagic && (ls.magic != kPartialRestoreMagic || validating)) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700698 status = error(EINVAL, "No magic");
Paul Lawrence27691c22018-11-20 14:07:59 -0800699 break;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700700 }
701
Paul Lawrence4f13a902019-01-10 13:06:07 -0800702 if (ls.block_size != original_ls.block_size) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700703 status = error(EINVAL, "Block size mismatch");
Paul Lawrence4f13a902019-01-10 13:06:07 -0800704 break;
705 }
706
Paul Lawrence27691c22018-11-20 14:07:59 -0800707 if ((int)ls.sequence != sequence) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700708 status = error(EINVAL, "Expecting log sector " + std::to_string(sequence) +
709 " but got " + std::to_string(ls.sequence));
Paul Lawrence27691c22018-11-20 14:07:59 -0800710 break;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700711 }
712
Paul Lawrencea3594a62023-01-31 13:42:09 -0800713 if (ls.header_size < sizeof(log_sector_v1_0) || ls.header_size > ls.block_size) {
714 status = error(EINVAL, "Log sector header size is invalid");
715 break;
716 }
717 if (ls.count < 1 || ls.count > (ls.block_size - ls.header_size) / sizeof(log_entry)) {
718 status = error(EINVAL, "Log sector count is invalid");
719 break;
720 }
Paul Lawrence27691c22018-11-20 14:07:59 -0800721 LOG(INFO) << action << " from log sector " << ls.sequence;
Paul Lawrencef5077682019-01-18 10:28:34 -0800722 for (log_entry* le =
Daniel Rosenberg52985932019-03-01 22:01:22 -0800723 reinterpret_cast<log_entry*>(&ls_buffer[ls.header_size]) + ls.count - 1;
724 le >= reinterpret_cast<log_entry*>(&ls_buffer[ls.header_size]); --le) {
Paul Lawrencef5077682019-01-18 10:28:34 -0800725 // This is very noisy - limit to DEBUG only
Paul Lawrenced41a9392019-01-22 14:31:43 -0800726 LOG(VERBOSE) << action << " " << le->size << " bytes from sector " << le->dest
727 << " to " << le->source << " with checksum " << std::hex
728 << le->checksum;
Paul Lawrencef5077682019-01-18 10:28:34 -0800729
Paul Lawrencea3594a62023-01-31 13:42:09 -0800730 if (ls.block_size > UINT_MAX - le->size || le->size < ls.block_size) {
731 status = error(EINVAL, "log entry is invalid");
732 break;
733 }
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800734 auto buffer = relocatedRead(device_fd, relocations, validating, le->dest, le->size,
Paul Lawrenced41a9392019-01-22 14:31:43 -0800735 ls.block_size);
Paul Lawrencea3594a62023-01-31 13:42:09 -0800736 if (buffer.size() != le->size) {
737 status = error(EINVAL, "Failed to read sector");
738 break;
739 }
Paul Lawrence4f13a902019-01-10 13:06:07 -0800740 uint32_t checksum = le->source / (ls.block_size / kSectorSize);
741 for (size_t i = 0; i < le->size; i += ls.block_size) {
742 crc32(&buffer[i], ls.block_size, &checksum);
Paul Lawrence27691c22018-11-20 14:07:59 -0800743 }
744
745 if (le->checksum && checksum != le->checksum) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700746 status = error(EINVAL, "Checksums don't match");
Paul Lawrence27691c22018-11-20 14:07:59 -0800747 break;
748 }
749
Paul Lawrenced41a9392019-01-22 14:31:43 -0800750 if (validating) {
Daniel Rosenberg52985932019-03-01 22:01:22 -0800751 relocate(relocations, le->source, le->dest, (le->size - 1) / kSectorSize + 1);
Paul Lawrenced41a9392019-01-22 14:31:43 -0800752 } else {
Daniel Rosenberg52985932019-03-01 22:01:22 -0800753 restoreSector(device_fd, used_sectors, ls_buffer, le, buffer);
Daniel Rosenbergdda59812019-03-06 17:45:17 -0800754 restore_count++;
755 if (restore_limit && restore_count >= restore_limit) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700756 status = error(EAGAIN, "Hit the test limit");
Daniel Rosenbergdda59812019-03-06 17:45:17 -0800757 break;
758 }
Paul Lawrence27691c22018-11-20 14:07:59 -0800759 }
760 }
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700761 }
Paul Lawrence27691c22018-11-20 14:07:59 -0800762
763 if (!status.isOk()) {
764 if (!validating) {
765 LOG(ERROR) << "Checkpoint restore failed even though checkpoint validation passed";
766 return status;
767 }
768
769 LOG(WARNING) << "Checkpoint validation failed - attempting to roll forward";
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800770 auto buffer = relocatedRead(device_fd, relocations, false, original_ls.sector0,
Paul Lawrenced41a9392019-01-22 14:31:43 -0800771 original_ls.block_size, original_ls.block_size);
Paul Lawrencea3594a62023-01-31 13:42:09 -0800772 if (buffer.size() != original_ls.block_size) {
773 return error(EINVAL, "Failed to read original sector");
774 }
775
776 if (lseek64(device_fd, 0, SEEK_SET) != 0) {
777 return error(EINVAL, "Failed to seek to sector 0");
778 }
779 if (write(device_fd, &buffer[0], original_ls.block_size) !=
780 static_cast<ssize_t>(original_ls.block_size)) {
781 return error(EINVAL, "Failed to write original sector");
782 }
Paul Lawrence27691c22018-11-20 14:07:59 -0800783 return Status::ok();
784 }
785
786 if (!validating) break;
787
788 validating = false;
789 action = "Restoring";
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700790 }
791
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700792 return Status::ok();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700793}
794
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700795Status cp_markBootAttempt() {
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700796 std::string oldContent, newContent;
797 int retry = 0;
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700798 struct stat st;
799 int result = stat(kMetadataCPFile.c_str(), &st);
800
801 // If the file doesn't exist, we aren't managing a checkpoint retry counter
802 if (result != 0) return Status::ok();
Paul Lawrence82b35052019-04-19 14:26:39 -0700803 if (!android::base::ReadFileToString(kMetadataCPFile, &oldContent))
804 return error("Failed to read checkpoint file");
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700805 std::string retryContent = oldContent.substr(0, oldContent.find_first_of(" "));
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700806
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700807 if (!android::base::ParseInt(retryContent, &retry))
Paul Lawrence82b35052019-04-19 14:26:39 -0700808 return error(EINVAL, "Could not parse retry count");
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700809 if (retry > 0) {
810 retry--;
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700811
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700812 newContent = std::to_string(retry);
813 if (!android::base::WriteStringToFile(newContent, kMetadataCPFile))
Paul Lawrence82b35052019-04-19 14:26:39 -0700814 return error("Could not write checkpoint file");
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700815 }
816 return Status::ok();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700817}
818
Nikita Ioffea5798fc2019-10-11 16:38:21 +0100819void cp_resetCheckpoint() {
820 std::lock_guard<std::mutex> lock(isCheckpointingLock);
821 needsCheckpointWasCalled = false;
822}
823
Weston Carvalho6ab20652024-12-03 15:21:45 -0600824bool cp_registerCheckpointListener(
825 android::sp<android::system::vold::IVoldCheckpointListener> listener) {
826 std::lock_guard<std::mutex> checkpointGuard(isCheckpointingLock);
827 if (needsCheckpointWasCalled && !isCheckpointing) {
828 // Either checkpoint already committed or we didn't need one
829 return false;
830 }
831
832 // Either we don't know whether we need a checkpoint or we're already checkpointing,
833 // so we need to save this listener to notify later.
834 std::lock_guard<std::mutex> listenersGuard(listenersLock);
835 listeners.push_back(std::move(listener));
836 return true;
837}
838
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700839} // namespace vold
840} // namespace android