2 * Copyright (C) 2015 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #include <sys/types.h>
28 #include <hardware/hardware.h>
29 #include <hardware/boot_control.h>
33 void module_init(boot_control_module_t *module)
37 unsigned module_getNumberSlots(boot_control_module_t *module)
42 static bool get_dev_t_for_partition(const char *name, dev_t *out_device)
47 fd = boot_info_open_partition(name, NULL, O_RDONLY);
50 if (fstat(fd, &statbuf) != 0) {
51 fprintf(stderr, "WARNING: Error getting information about part %s: %s\n",
52 name, strerror(errno));
57 *out_device = statbuf.st_rdev;
61 unsigned module_getCurrentSlot(boot_control_module_t *module)
64 dev_t system_a_dev, system_b_dev;
66 if (stat("/system", &statbuf) != 0) {
67 fprintf(stderr, "WARNING: Error getting information about /system: %s\n",
72 if (!get_dev_t_for_partition("system_a", &system_a_dev) ||
73 !get_dev_t_for_partition("system_b", &system_b_dev))
76 if (statbuf.st_dev == system_a_dev) {
78 } else if (statbuf.st_dev == system_b_dev) {
81 fprintf(stderr, "WARNING: Error determining current slot "
82 "(/system dev_t of %d:%d does not match a=%d:%d or b=%d:%d)\n",
83 major(statbuf.st_dev), minor(statbuf.st_dev),
84 major(system_a_dev), minor(system_a_dev),
85 major(system_b_dev), minor(system_b_dev));
90 int module_markBootSuccessful(boot_control_module_t *module)
95 #define COPY_BUF_SIZE 1024*1024
97 static bool copy_data(int src_fd, int dst_fd, size_t num_bytes)
99 char copy_buf[COPY_BUF_SIZE];
102 remaining = num_bytes;
103 while (remaining > 0) {
104 size_t num_to_read = remaining > COPY_BUF_SIZE ? COPY_BUF_SIZE : remaining;
107 num_read = read(src_fd, copy_buf, num_to_read);
108 } while (num_read == -1 && errno == EINTR);
110 fprintf(stderr, "Error reading %zd bytes from source: %s\n",
111 num_to_read, strerror(errno));
114 size_t num_to_write = num_read;
115 while (num_to_write > 0) {
116 size_t offset = num_read - num_to_write;
119 num_written = write(dst_fd, copy_buf + offset, num_to_write);
120 } while (num_written == -1 && errno == EINTR);
121 if (num_written <= 0) {
122 fprintf(stderr, "Error writing %zd bytes to destination: %s\n",
123 num_to_write, strerror(errno));
126 num_to_write -= num_written;
128 remaining -= num_read;
134 int module_setActiveBootSlot(boot_control_module_t *module, unsigned slot)
138 uint64_t src_size, dst_size;
144 if (!boot_info_load(&info)) {
145 fprintf(stderr, "WARNING: Error loading boot-info. Resetting.\n");
146 boot_info_reset(&info);
148 if (!boot_info_validate(&info)) {
149 fprintf(stderr, "WARNING: boot-info is invalid. Resetting.\n");
150 boot_info_reset(&info);
154 info.active_slot = slot;
155 info.slot_info[slot].bootable = true;
156 snprintf(info.bootctrl_suffix,
157 sizeof(info.bootctrl_suffix),
160 if (!boot_info_save(&info)) {
161 fprintf(stderr, "Error saving boot-info.\n");
165 // Finally copy the contents of boot_X into boot.
166 snprintf(src_name, sizeof(src_name), "boot_%c", slot + 'a');
167 src_fd = boot_info_open_partition(src_name, &src_size, O_RDONLY);
169 fprintf(stderr, "Error opening \"%s\" partition.\n", src_name);
173 dst_fd = boot_info_open_partition("boot", &dst_size, O_RDWR);
175 fprintf(stderr, "Error opening \"boot\" partition.\n");
180 if (src_size != dst_size) {
182 "src (%" PRIu64 " bytes) and dst (%" PRIu64 " bytes) "
183 "have different sizes.\n",
190 if (!copy_data(src_fd, dst_fd, src_size)) {
196 if (fsync(dst_fd) != 0) {
197 fprintf(stderr, "Error calling fsync on destination: %s\n",
207 int module_setSlotAsUnbootable(struct boot_control_module *module, unsigned slot)
214 if (!boot_info_load(&info)) {
215 fprintf(stderr, "WARNING: Error loading boot-info. Resetting.\n");
216 boot_info_reset(&info);
218 if (!boot_info_validate(&info)) {
219 fprintf(stderr, "WARNING: boot-info is invalid. Resetting.\n");
220 boot_info_reset(&info);
224 info.slot_info[slot].bootable = false;
226 if (!boot_info_save(&info)) {
227 fprintf(stderr, "Error saving boot-info.\n");
234 int module_isSlotBootable(struct boot_control_module *module, unsigned slot)
241 if (!boot_info_load(&info)) {
242 fprintf(stderr, "WARNING: Error loading boot-info. Resetting.\n");
243 boot_info_reset(&info);
245 if (!boot_info_validate(&info)) {
246 fprintf(stderr, "WARNING: boot-info is invalid. Resetting.\n");
247 boot_info_reset(&info);
251 return info.slot_info[slot].bootable;
254 const char* module_getSuffix(boot_control_module_t *module, unsigned slot)
256 static const char* suffix[2] = {"_a", "_b"};
262 static struct hw_module_methods_t module_methods = {
267 /* This boot_control HAL implementation emulates A/B by copying the
268 * contents of the boot partition of the requested slot to the boot
269 * partition. It hence works with bootloaders that are not yet aware
270 * of A/B. This code is only intended to be used for development.
273 boot_control_module_t HAL_MODULE_INFO_SYM = {
275 .tag = HARDWARE_MODULE_TAG,
276 .module_api_version = BOOT_CONTROL_MODULE_API_VERSION_0_1,
277 .hal_api_version = HARDWARE_HAL_API_VERSION,
278 .id = BOOT_CONTROL_HARDWARE_MODULE_ID,
279 .name = "Copy Implementation of boot_control HAL",
280 .author = "The Android Open Source Project",
281 .methods = &module_methods,
284 .getNumberSlots = module_getNumberSlots,
285 .getCurrentSlot = module_getCurrentSlot,
286 .markBootSuccessful = module_markBootSuccessful,
287 .setActiveBootSlot = module_setActiveBootSlot,
288 .setSlotAsUnbootable = module_setSlotAsUnbootable,
289 .isSlotBootable = module_isSlotBootable,
290 .getSuffix = module_getSuffix,