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 unsigned module_getCurrentSlot(boot_control_module_t *module)
46 if (!boot_info_load(&info)) {
47 fprintf(stderr, "WARNING: Error loading boot-info. Resetting.\n");
48 boot_info_reset(&info);
50 if (!boot_info_validate(&info)) {
51 fprintf(stderr, "WARNING: boot-info is invalid. Resetting.\n");
52 boot_info_reset(&info);
56 return info.active_slot;
59 int module_markBootSuccessful(boot_control_module_t *module)
64 #define COPY_BUF_SIZE 1024*1024
66 static bool copy_data(int src_fd, int dst_fd, size_t num_bytes)
68 char copy_buf[COPY_BUF_SIZE];
71 remaining = num_bytes;
72 while (remaining > 0) {
73 size_t num_to_read = remaining > COPY_BUF_SIZE ? COPY_BUF_SIZE : remaining;
76 num_read = read(src_fd, copy_buf, num_to_read);
77 } while (num_read == -1 && errno == EINTR);
79 fprintf(stderr, "Error reading %zd bytes from source: %s\n",
80 num_to_read, strerror(errno));
83 size_t num_to_write = num_read;
84 while (num_to_write > 0) {
85 size_t offset = num_read - num_to_write;
88 num_written = write(dst_fd, copy_buf + offset, num_to_write);
89 } while (num_written == -1 && errno == EINTR);
90 if (num_written <= 0) {
91 fprintf(stderr, "Error writing %zd bytes to destination: %s\n",
92 num_to_write, strerror(errno));
95 num_to_write -= num_written;
97 remaining -= num_read;
103 int module_setActiveBootSlot(boot_control_module_t *module, unsigned slot)
107 uint64_t src_size, dst_size;
113 if (!boot_info_load(&info)) {
114 fprintf(stderr, "WARNING: Error loading boot-info. Resetting.\n");
115 boot_info_reset(&info);
117 if (!boot_info_validate(&info)) {
118 fprintf(stderr, "WARNING: boot-info is invalid. Resetting.\n");
119 boot_info_reset(&info);
123 info.active_slot = slot;
124 info.slot_info[slot].bootable = true;
125 snprintf(info.bootctrl_suffix,
126 sizeof(info.bootctrl_suffix),
129 if (!boot_info_save(&info)) {
130 fprintf(stderr, "Error saving boot-info.\n");
134 // Finally copy the contents of boot_X into boot.
135 snprintf(src_name, sizeof(src_name), "boot_%c", slot + 'a');
136 src_fd = boot_info_open_partition(src_name, &src_size, O_RDONLY);
138 fprintf(stderr, "Error opening \"%s\" partition.\n", src_name);
142 dst_fd = boot_info_open_partition("boot", &dst_size, O_RDWR);
144 fprintf(stderr, "Error opening \"boot\" partition.\n");
149 if (src_size != dst_size) {
151 "src (%" PRIu64 " bytes) and dst (%" PRIu64 " bytes) "
152 "have different sizes.\n",
159 if (!copy_data(src_fd, dst_fd, src_size)) {
165 if (fsync(dst_fd) != 0) {
166 fprintf(stderr, "Error calling fsync on destination: %s\n",
176 int module_setSlotAsUnbootable(struct boot_control_module *module, unsigned slot)
183 if (!boot_info_load(&info)) {
184 fprintf(stderr, "WARNING: Error loading boot-info. Resetting.\n");
185 boot_info_reset(&info);
187 if (!boot_info_validate(&info)) {
188 fprintf(stderr, "WARNING: boot-info is invalid. Resetting.\n");
189 boot_info_reset(&info);
193 info.slot_info[slot].bootable = false;
195 if (!boot_info_save(&info)) {
196 fprintf(stderr, "Error saving boot-info.\n");
203 int module_isSlotBootable(struct boot_control_module *module, unsigned slot)
210 if (!boot_info_load(&info)) {
211 fprintf(stderr, "WARNING: Error loading boot-info. Resetting.\n");
212 boot_info_reset(&info);
214 if (!boot_info_validate(&info)) {
215 fprintf(stderr, "WARNING: boot-info is invalid. Resetting.\n");
216 boot_info_reset(&info);
220 return info.slot_info[slot].bootable;
223 const char* module_getSuffix(boot_control_module_t *module, unsigned slot)
225 static const char* suffix[2] = {"_a", "_b"};
231 static struct hw_module_methods_t module_methods = {
236 /* This boot_control HAL implementation emulates A/B by copying the
237 * contents of the boot partition of the requested slot to the boot
238 * partition. It hence works with bootloaders that are not yet aware
239 * of A/B. This code is only intended to be used for development.
242 boot_control_module_t HAL_MODULE_INFO_SYM = {
244 .tag = HARDWARE_MODULE_TAG,
245 .module_api_version = BOOT_CONTROL_MODULE_API_VERSION_0_1,
246 .hal_api_version = HARDWARE_HAL_API_VERSION,
247 .id = BOOT_CONTROL_HARDWARE_MODULE_ID,
248 .name = "Copy Implementation of boot_control HAL",
249 .author = "The Android Open Source Project",
250 .methods = &module_methods,
253 .getNumberSlots = module_getNumberSlots,
254 .getCurrentSlot = module_getCurrentSlot,
255 .markBootSuccessful = module_markBootSuccessful,
256 .setActiveBootSlot = module_setActiveBootSlot,
257 .setSlotAsUnbootable = module_setSlotAsUnbootable,
258 .isSlotBootable = module_isSlotBootable,
259 .getSuffix = module_getSuffix,