blob: 8f86174656f41f1ee79f0de001c22b83b9863e08 [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"
19
Paul Lawrence1abb2fe2018-09-21 10:49:57 -070020#include <fstream>
Daniel Rosenberg65f99c92018-08-28 01:58:49 -070021#include <list>
Paul Lawrence20400892018-10-03 14:14:52 -070022#include <memory>
Daniel Rosenberg65f99c92018-08-28 01:58:49 -070023#include <string>
Paul Lawrence1abb2fe2018-09-21 10:49:57 -070024#include <vector>
25
26#include <android-base/file.h>
27#include <android-base/logging.h>
28#include <android-base/parseint.h>
29#include <android-base/unique_fd.h>
Daniel Rosenbergd3992492018-10-02 17:40:44 -070030#include <android/hardware/boot/1.0/IBootControl.h>
Paul Lawrence1abb2fe2018-09-21 10:49:57 -070031#include <cutils/android_reboot.h>
32#include <fcntl.h>
33#include <fs_mgr.h>
34#include <linux/fs.h>
35#include <mntent.h>
36#include <sys/mount.h>
37#include <sys/stat.h>
Daniel Rosenberg65f99c92018-08-28 01:58:49 -070038
Daniel Rosenbergd3992492018-10-02 17:40:44 -070039using android::hardware::hidl_string;
40using android::hardware::boot::V1_0::BoolResult;
41using android::hardware::boot::V1_0::IBootControl;
42using android::hardware::boot::V1_0::Slot;
43
Daniel Rosenberg65f99c92018-08-28 01:58:49 -070044namespace android {
45namespace vold {
46
Paul Lawrence1abb2fe2018-09-21 10:49:57 -070047namespace {
48const std::string kMetadataCPFile = "/metadata/vold/checkpoint";
49
50bool setBowState(std::string const& block_device, std::string const& state) {
51 if (block_device.substr(0, 5) != "/dev/") {
52 LOG(ERROR) << "Expected block device, got " << block_device;
53 return false;
54 }
55
56 std::string state_filename = std::string("/sys/") + block_device.substr(5) + "/bow/state";
57 if (!android::base::WriteStringToFile(state, state_filename)) {
58 PLOG(ERROR) << "Failed to write to file " << state_filename;
59 return false;
60 }
61
62 return true;
63}
64
65} // namespace
Daniel Rosenberg65f99c92018-08-28 01:58:49 -070066
67bool cp_startCheckpoint(int retry) {
68 if (retry < -1) return false;
Daniel Rosenberg80d1ca52018-10-09 19:26:57 -070069 std::string content = std::to_string(retry + 1);
Daniel Rosenbergd3992492018-10-02 17:40:44 -070070 if (retry == -1) {
71 sp<IBootControl> module = IBootControl::getService();
72 if (module) {
73 std::string suffix;
74 auto cb = [&suffix](hidl_string s) { suffix = s; };
75 if (module->getSuffix(module->getCurrentSlot(), cb).isOk()) content += " " + suffix;
76 }
77 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -070078 return android::base::WriteStringToFile(content, kMetadataCPFile);
79}
80
81bool cp_commitChanges() {
Paul Lawrence1abb2fe2018-09-21 10:49:57 -070082 // Must take action for list of mounted checkpointed things here
83 // To do this, we walk the list of mounted file systems.
84 // But we also need to get the matching fstab entries to see
85 // the original flags
Paul Lawrence20400892018-10-03 14:14:52 -070086 auto fstab_default = std::unique_ptr<fstab, decltype(&fs_mgr_free_fstab)>{
87 fs_mgr_read_fstab_default(), fs_mgr_free_fstab};
88 if (!fstab_default) return false;
Daniel Rosenberg65f99c92018-08-28 01:58:49 -070089
Paul Lawrence20400892018-10-03 14:14:52 -070090 auto mounts = std::unique_ptr<fstab, decltype(&fs_mgr_free_fstab)>{
91 fs_mgr_read_fstab("/proc/mounts"), fs_mgr_free_fstab};
92 if (!mounts) return false;
Daniel Rosenberg65f99c92018-08-28 01:58:49 -070093
Paul Lawrence1abb2fe2018-09-21 10:49:57 -070094 // Walk mounted file systems
95 for (int i = 0; i < mounts->num_entries; ++i) {
96 const fstab_rec* mount_rec = &mounts->recs[i];
Paul Lawrence20400892018-10-03 14:14:52 -070097 const fstab_rec* fstab_rec =
98 fs_mgr_get_entry_for_mount_point(fstab_default.get(), mount_rec->mount_point);
Paul Lawrence1abb2fe2018-09-21 10:49:57 -070099 if (!fstab_rec) continue;
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700100
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700101 if (fs_mgr_is_checkpoint_fs(fstab_rec)) {
102 if (!strcmp(fstab_rec->fs_type, "f2fs")) {
103 mount(mount_rec->blk_device, mount_rec->mount_point, "none",
104 MS_REMOUNT | fstab_rec->flags, "checkpoint=enable");
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700105 }
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700106 } else if (fs_mgr_is_checkpoint_blk(fstab_rec)) {
107 setBowState(mount_rec->blk_device, "2");
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700108 }
109 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700110 return android::base::RemoveFileIfExists(kMetadataCPFile);
111}
112
113void cp_abortChanges() {
114 android_reboot(ANDROID_RB_RESTART2, 0, nullptr);
115}
116
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700117bool cp_needsRollback() {
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700118 std::string content;
119 bool ret;
120
121 ret = android::base::ReadFileToString(kMetadataCPFile, &content);
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700122 if (ret) {
123 if (content == "0") return true;
124 if (content.substr(0, 3) == "-1 ") {
125 std::string oldSuffix = content.substr(3);
126 sp<IBootControl> module = IBootControl::getService();
127 std::string newSuffix;
128
129 if (module) {
130 auto cb = [&newSuffix](hidl_string s) { newSuffix = s; };
131 module->getSuffix(module->getCurrentSlot(), cb);
132 if (oldSuffix == newSuffix) return true;
133 }
134 }
135 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700136 return false;
137}
138
Daniel Rosenberg80d1ca52018-10-09 19:26:57 -0700139bool cp_needsCheckpoint() {
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700140 bool ret;
141 std::string content;
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700142 sp<IBootControl> module = IBootControl::getService();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700143
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700144 if (module && module->isSlotMarkedSuccessful(module->getCurrentSlot()) == BoolResult::FALSE)
145 return true;
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700146 ret = android::base::ReadFileToString(kMetadataCPFile, &content);
147 if (ret) return content != "0";
148 return false;
149}
150
Daniel Rosenberg80d1ca52018-10-09 19:26:57 -0700151bool cp_prepareCheckpoint() {
Paul Lawrence20400892018-10-03 14:14:52 -0700152 auto fstab_default = std::unique_ptr<fstab, decltype(&fs_mgr_free_fstab)>{
153 fs_mgr_read_fstab_default(), fs_mgr_free_fstab};
154 if (!fstab_default) return false;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700155
Paul Lawrence20400892018-10-03 14:14:52 -0700156 auto mounts = std::unique_ptr<fstab, decltype(&fs_mgr_free_fstab)>{
157 fs_mgr_read_fstab("/proc/mounts"), fs_mgr_free_fstab};
158 if (!mounts) return false;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700159
160 for (int i = 0; i < mounts->num_entries; ++i) {
161 const fstab_rec* mount_rec = &mounts->recs[i];
Paul Lawrence20400892018-10-03 14:14:52 -0700162 const fstab_rec* fstab_rec =
163 fs_mgr_get_entry_for_mount_point(fstab_default.get(), mount_rec->mount_point);
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700164 if (!fstab_rec) continue;
165
166 if (fs_mgr_is_checkpoint_blk(fstab_rec)) {
167 android::base::unique_fd fd(
168 TEMP_FAILURE_RETRY(open(mount_rec->mount_point, O_RDONLY | O_CLOEXEC)));
169 if (!fd) {
170 PLOG(ERROR) << "Failed to open mount point" << mount_rec->mount_point;
171 continue;
172 }
173
174 struct fstrim_range range = {};
175 range.len = ULLONG_MAX;
176 if (ioctl(fd, FITRIM, &range)) {
177 PLOG(ERROR) << "Failed to trim " << mount_rec->mount_point;
178 continue;
179 }
180
181 setBowState(mount_rec->blk_device, "1");
182 }
183 }
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700184 return true;
185}
186
187namespace {
188const int kBlockSize = 4096;
189const int kSectorSize = 512;
190
191typedef uint64_t sector_t;
192
193struct log_entry {
194 sector_t source;
195 sector_t dest;
196 uint32_t size;
197 uint32_t checksum;
198} __attribute__((packed));
199
200struct log_sector {
201 uint32_t magic;
202 uint32_t count;
203 uint32_t sequence;
204 struct log_entry entries[];
205} __attribute__((packed));
206
207// MAGIC is BOW in ascii
208const int kMagic = 0x00574f42;
209
210void crc32(const void* data, size_t n_bytes, uint32_t* crc) {
211 static uint32_t table[0x100] = {
212 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535,
213 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD,
214 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D,
215 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
216 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4,
217 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C,
218 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC,
219 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
220 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB,
221 0xB6662D3D,
222
223 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5,
224 0xE8B8D433, 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D,
225 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED,
226 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
227 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, 0x4DB26158, 0x3AB551CE, 0xA3BC0074,
228 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC,
229 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C,
230 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
231 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B,
232 0xC0BA6CAD,
233
234 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615,
235 0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D,
236 0x0A00AE27, 0x7D079EB1, 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D,
237 0x806567CB, 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
238 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4,
239 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, 0xD80D2BDA, 0xAF0A1B4C,
240 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, 0xCB61B38C,
241 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
242 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B,
243 0x5BDEAE1D,
244
245 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785,
246 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D,
247 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD,
248 0xF6B9265B, 0x6FB077E1, 0x18B74777, 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
249 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354,
250 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC,
251 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, 0xBDBDF21C,
252 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
253 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B,
254 0x2D02EF8D};
255
256 for (size_t i = 0; i < n_bytes; ++i) {
257 *crc ^= ((uint8_t*)data)[i];
258 *crc = table[(uint8_t)*crc] ^ *crc >> 8;
259 }
260}
261
262} // namespace
263
264bool cp_restoreCheckpoint(const std::string& blockDevice) {
265 LOG(ERROR) << "Restoring checkpoint on " << blockDevice;
266 std::fstream device(blockDevice, std::ios::binary | std::ios::in | std::ios::out);
267 if (!device) {
268 PLOG(ERROR) << "Cannot open " << blockDevice;
269 return false;
270 }
271 char buffer[kBlockSize];
272 device.read(buffer, kBlockSize);
273 log_sector& ls = *(log_sector*)buffer;
274 if (ls.magic != kMagic) {
275 LOG(ERROR) << "No magic";
276 return false;
277 }
278
279 LOG(INFO) << "Restoring " << ls.sequence << " log sectors";
280
281 for (int sequence = ls.sequence; sequence >= 0; sequence--) {
282 char buffer[kBlockSize];
283 device.seekg(0);
284 device.read(buffer, kBlockSize);
285 log_sector& ls = *(log_sector*)buffer;
286 if (ls.magic != kMagic) {
287 LOG(ERROR) << "No magic!";
288 return false;
289 }
290
291 if ((int)ls.sequence != sequence) {
292 LOG(ERROR) << "Expecting log sector " << sequence << " but got " << ls.sequence;
293 return false;
294 }
295
296 LOG(INFO) << "Restoring from log sector " << ls.sequence;
297
298 for (log_entry* le = &ls.entries[ls.count - 1]; le >= ls.entries; --le) {
299 LOG(INFO) << "Restoring " << le->size << " bytes from sector " << le->dest << " to "
300 << le->source << " with checksum " << std::hex << le->checksum;
301 std::vector<char> buffer(le->size);
302 device.seekg(le->dest * kSectorSize);
303 device.read(&buffer[0], le->size);
304
305 uint32_t checksum = le->source / (kBlockSize / kSectorSize);
306 for (size_t i = 0; i < le->size; i += kBlockSize) {
307 crc32(&buffer[i], kBlockSize, &checksum);
308 }
309
310 if (le->checksum && checksum != le->checksum) {
311 LOG(ERROR) << "Checksums don't match " << std::hex << checksum;
312 return false;
313 }
314
315 device.seekg(le->source * kSectorSize);
316 device.write(&buffer[0], le->size);
317 }
318 }
319
320 return true;
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700321}
322
323bool cp_markBootAttempt() {
324 std::string oldContent, newContent;
325 int retry = 0;
326 if (!android::base::ReadFileToString(kMetadataCPFile, &oldContent)) return false;
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700327 std::string retryContent = oldContent.substr(0, oldContent.find_first_of(" "));
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700328
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700329 if (!android::base::ParseInt(retryContent, &retry)) return false;
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700330 if (retry > 0) retry--;
331
332 newContent = std::to_string(retry);
333 return android::base::WriteStringToFile(newContent, kMetadataCPFile);
334}
335
336} // namespace vold
337} // namespace android