blob: d5e2e4ba20763b8e86f5fe11354fee92c83cff93 [file] [log] [blame]
Steve Pfetschd7b03992016-04-20 17:53:38 -07001/*
2 * Copyright (c) 2016, The Linux Foundation. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above
10 * copyright notice, this list of conditions and the following
11 * disclaimer in the documentation and/or other materials provided
12 * with the distribution.
13 * * Neither the name of The Linux Foundation nor the names of its
14 * contributors may be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
18 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
24 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
26 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29#include <errno.h>
30#define LOG_TAG "bootcontrolhal"
31#include <cutils/log.h>
32#include <hardware/boot_control.h>
33#include <stdio.h>
34#include <string.h>
35#include <unistd.h>
36#include <dirent.h>
37#include <sys/types.h>
38#include <sys/stat.h>
39#include <fcntl.h>
40#include <limits.h>
Naveen Ramaraj2af29222016-05-05 10:23:02 -070041#include <cutils/properties.h>
Steve Pfetschd7b03992016-04-20 17:53:38 -070042#include "gpt-utils.h"
43
44#define BOOTDEV_DIR "/dev/block/bootdevice/by-name"
45#define BOOT_IMG_PTN_NAME "boot"
46#define LUN_NAME_END_LOC 14
Naveen Ramaraj2af29222016-05-05 10:23:02 -070047#define BOOT_SLOT_PROP "ro.boot.slot_suffix"
Steve Pfetschd7b03992016-04-20 17:53:38 -070048
49const char *slot_suffix_arr[] = {
50 AB_SLOT_A_SUFFIX,
51 AB_SLOT_B_SUFFIX,
52 NULL};
53
54enum part_attr_type {
55 ATTR_SLOT_ACTIVE = 0,
56 ATTR_BOOT_SUCCESSFUL,
57 ATTR_UNBOOTABLE,
58};
59
60void boot_control_init(struct boot_control_module *module)
61{
62 if (!module) {
63 ALOGE("Invalid argument passed to %s", __func__);
64 return;
65 }
66 return;
67}
68
69//Get the value of one of the attribute fields for a partition.
70static int get_partition_attribute(char *partname,
71 enum part_attr_type part_attr)
72{
73 struct gpt_disk *disk = NULL;
74 uint8_t *pentry = NULL;
75 int retval = -1;
76 uint8_t *attr = NULL;
77 if (!partname)
78 goto error;
79 disk = gpt_disk_alloc();
80 if (!disk) {
81 ALOGE("%s: Failed to alloc disk struct", __func__);
82 goto error;
83 }
84 if (gpt_disk_get_disk_info(partname, disk)) {
85 ALOGE("%s: Failed to get disk info", __func__);
86 goto error;
87 }
88 pentry = gpt_disk_get_pentry(disk, partname, PRIMARY_GPT);
89 if (!pentry) {
90 ALOGE("%s: pentry does not exist in disk struct",
91 __func__);
92 goto error;
93 }
94 attr = pentry + AB_FLAG_OFFSET;
95 if (part_attr == ATTR_SLOT_ACTIVE)
96 retval = !!(*attr & AB_PARTITION_ATTR_SLOT_ACTIVE);
97 else if (part_attr == ATTR_BOOT_SUCCESSFUL)
98 retval = !!(*attr & AB_PARTITION_ATTR_BOOT_SUCCESSFUL);
99 else if (part_attr == ATTR_UNBOOTABLE)
100 retval = !!(*attr & AB_PARTITION_ATTR_UNBOOTABLE);
101 else
102 retval = -1;
103 gpt_disk_free(disk);
104 return retval;
105error:
106 if (disk)
107 gpt_disk_free(disk);
108 return retval;
109}
110
111//Set a particular attribute for all the partitions in a
112//slot
113static int update_slot_attribute(const char *slot,
114 enum part_attr_type ab_attr)
115{
116 unsigned int i = 0;
117 char buf[PATH_MAX];
118 struct stat st;
119 struct gpt_disk *disk = NULL;
120 uint8_t *pentry = NULL;
121 uint8_t *pentry_bak = NULL;
122 int rc = -1;
123 uint8_t *attr = NULL;
124 uint8_t *attr_bak = NULL;
125 char partName[MAX_GPT_NAME_SIZE + 1] = {0};
126 const char ptn_list[][MAX_GPT_NAME_SIZE] = { AB_PTN_LIST };
127 int slot_name_valid = 0;
128 if (!slot) {
129 ALOGE("%s: Invalid argument", __func__);
130 goto error;
131 }
132 for (i = 0; slot_suffix_arr[i] != NULL; i++)
133 {
134 if (!strncmp(slot, slot_suffix_arr[i],
135 strlen(slot_suffix_arr[i])))
136 slot_name_valid = 1;
137 }
138 if (!slot_name_valid) {
139 ALOGE("%s: Invalid slot name", __func__);
140 goto error;
141 }
142 for (i=0; i < ARRAY_SIZE(ptn_list); i++) {
143 memset(buf, '\0', sizeof(buf));
144 //Check if A/B versions of this ptn exist
145 snprintf(buf, sizeof(buf) - 1,
146 "%s/%s%s",
147 BOOT_DEV_DIR,
148 ptn_list[i],
149 AB_SLOT_A_SUFFIX
150 );
151 if (stat(buf, &st)) {
152 //partition does not have _a version
153 continue;
154 }
155 memset(buf, '\0', sizeof(buf));
156 snprintf(buf, sizeof(buf) - 1,
157 "%s/%s%s",
158 BOOT_DEV_DIR,
159 ptn_list[i],
160 AB_SLOT_B_SUFFIX
161 );
162 if (stat(buf, &st)) {
163 //partition does not have _a version
164 continue;
165 }
166 memset(partName, '\0', sizeof(partName));
167 snprintf(partName,
168 sizeof(partName) - 1,
169 "%s%s",
170 ptn_list[i],
171 slot);
172 disk = gpt_disk_alloc(disk);
173 if (!disk) {
174 ALOGE("%s: Failed to alloc disk struct",
175 __func__);
176 goto error;
177 }
178 rc = gpt_disk_get_disk_info(partName, disk);
179 if (rc != 0) {
180 ALOGE("%s: Failed to get disk info for %s",
181 __func__,
182 partName);
183 goto error;
184 }
185 pentry = gpt_disk_get_pentry(disk, partName, PRIMARY_GPT);
186 pentry_bak = gpt_disk_get_pentry(disk, partName, SECONDARY_GPT);
187 if (!pentry || !pentry_bak) {
188 ALOGE("%s: Failed to get pentry/pentry_bak for %s",
189 __func__,
190 partName);
191 goto error;
192 }
193 attr = pentry + AB_FLAG_OFFSET;
194 attr_bak = pentry_bak + AB_FLAG_OFFSET;
195 if (ab_attr == ATTR_BOOT_SUCCESSFUL) {
196 *attr = (*attr) | AB_PARTITION_ATTR_BOOT_SUCCESSFUL;
197 *attr_bak = (*attr_bak) |
198 AB_PARTITION_ATTR_BOOT_SUCCESSFUL;
199 } else if (ab_attr == ATTR_UNBOOTABLE) {
200 *attr = (*attr) | AB_PARTITION_ATTR_UNBOOTABLE;
201 *attr_bak = (*attr_bak) | AB_PARTITION_ATTR_UNBOOTABLE;
202 } else if (ab_attr == ATTR_SLOT_ACTIVE) {
203 *attr = (*attr) | AB_PARTITION_ATTR_SLOT_ACTIVE;
204 *attr_bak = (*attr) | AB_PARTITION_ATTR_SLOT_ACTIVE;
205 } else {
206 ALOGE("%s: Unrecognized attr", __func__);
207 goto error;
208 }
209 if (gpt_disk_update_crc(disk)) {
210 ALOGE("%s: Failed to update crc for %s",
211 __func__,
212 partName);
213 goto error;
214 }
215 if (gpt_disk_commit(disk)) {
216 ALOGE("%s: Failed to write back entry for %s",
217 __func__,
218 partName);
219 goto error;
220 }
221 gpt_disk_free(disk);
222 disk = NULL;
223 }
224 return 0;
225error:
226 if (disk)
227 gpt_disk_free(disk);
228 return -1;
229}
230
231unsigned get_number_slots(struct boot_control_module *module)
232{
233 struct dirent *de = NULL;
234 DIR *dir_bootdev = NULL;
235 unsigned slot_count = 0;
236 if (!module) {
237 ALOGE("%s: Invalid argument", __func__);
238 goto error;
239 }
240 dir_bootdev = opendir(BOOTDEV_DIR);
241 if (!dir_bootdev) {
242 ALOGE("%s: Failed to open bootdev dir (%s)",
243 __func__,
244 strerror(errno));
245 goto error;
246 }
247 while ((de = readdir(dir_bootdev))) {
248 if (de->d_name[0] == '.')
249 continue;
250 if (!strncmp(de->d_name, BOOT_IMG_PTN_NAME,
251 strlen(BOOT_IMG_PTN_NAME)))
252 slot_count++;
253 }
254 closedir(dir_bootdev);
255 return slot_count;
256error:
257 if (dir_bootdev)
258 closedir(dir_bootdev);
259 return 0;
260}
261
262unsigned get_current_slot(struct boot_control_module *module)
263{
264 uint32_t num_slots = 0;
Naveen Ramaraj2af29222016-05-05 10:23:02 -0700265 char bootSlotProp[PROPERTY_VALUE_MAX] = {'\0'};
Steve Pfetschd7b03992016-04-20 17:53:38 -0700266 unsigned i = 0;
267 if (!module) {
268 ALOGE("%s: Invalid argument", __func__);
269 goto error;
270 }
271 num_slots = get_number_slots(module);
272 if (num_slots <= 1) {
273 //Slot 0 is the only slot around.
274 return 0;
275 }
Naveen Ramaraj2af29222016-05-05 10:23:02 -0700276 property_get(BOOT_SLOT_PROP, bootSlotProp, "N/A");
277 if (!strncmp(bootSlotProp, "N/A", strlen("N/A"))) {
278 ALOGE("%s: Unable to read boot slot property",
279 __func__);
280 goto error;
281 }
Steve Pfetschd7b03992016-04-20 17:53:38 -0700282 //Iterate through a list of partitons named as boot+suffix
283 //and see which one is currently active.
284 for (i = 0; slot_suffix_arr[i] != NULL ; i++) {
Naveen Ramaraj2af29222016-05-05 10:23:02 -0700285 if (!strncmp(bootSlotProp,
286 slot_suffix_arr[i],
287 strlen(slot_suffix_arr[i])))
288 return i;
Steve Pfetschd7b03992016-04-20 17:53:38 -0700289 }
290error:
291 //The HAL spec requires that we return a number between
292 //0 to num_slots - 1. Since something went wrong here we
293 //are just going to return the default slot.
294 return 0;
295}
296
Naveen Ramaraj710b9bf2016-05-05 10:28:04 -0700297static unsigned get_current_active_slot(struct boot_control_module *module)
298{
299 uint32_t num_slots = 0;
300 char bootPartition[MAX_GPT_NAME_SIZE + 1];
301 unsigned i = 0;
302 if (!module) {
303 ALOGE("%s: Invalid argument", __func__);
304 goto error;
305 }
306 num_slots = get_number_slots(module);
307 if (num_slots <= 1) {
308 //Slot 0 is the only slot around.
309 return 0;
310 }
311 //Iterate through a list of partitons named as boot+suffix
312 //and see which one is currently active.
313 for (i = 0; slot_suffix_arr[i] != NULL ; i++) {
314 memset(bootPartition, '\0', sizeof(bootPartition));
315 snprintf(bootPartition, sizeof(bootPartition) - 1,
316 "boot%s",
317 slot_suffix_arr[i]);
318 if (get_partition_attribute(bootPartition,
319 ATTR_SLOT_ACTIVE) == 1)
320 return i;
321 }
322error:
323 //The HAL spec requires that we return a number between
324 //0 to num_slots - 1. Since something went wrong here we
325 //are just going to return the default slot.
326 return 0;
327}
328
Steve Pfetschd7b03992016-04-20 17:53:38 -0700329int mark_boot_successful(struct boot_control_module *module)
330{
331 unsigned cur_slot = 0;
332 if (!module) {
333 ALOGE("%s: Invalid argument", __func__);
334 goto error;
335 }
336 cur_slot = get_current_slot(module);
337 if (update_slot_attribute(slot_suffix_arr[cur_slot],
338 ATTR_BOOT_SUCCESSFUL)) {
339 goto error;
340 }
341 return 0;
342error:
343 ALOGE("%s: Failed to mark boot successful", __func__);
344 return -1;
345}
346
347const char *get_suffix(struct boot_control_module *module, unsigned slot)
348{
349 unsigned num_slots = 0;
350 if (!module) {
351 ALOGE("%s: Invalid arg", __func__);
352 }
353 num_slots = get_number_slots(module);
354 if (num_slots < 1 || slot > num_slots - 1)
355 return NULL;
356 else
357 return slot_suffix_arr[slot];
358}
359
360int set_active_boot_slot(struct boot_control_module *module, unsigned slot)
361{
362 const char ptn_list[][MAX_GPT_NAME_SIZE] = { AB_PTN_LIST };
363 char slotA[MAX_GPT_NAME_SIZE + 1] = {0};
364 char slotB[MAX_GPT_NAME_SIZE + 1] = {0};
365 char active_guid[TYPE_GUID_SIZE + 1] = {0};
366 char inactive_guid[TYPE_GUID_SIZE + 1] = {0};
367 struct gpt_disk *disk = NULL;
368 //Pointer to partition entry of current 'A' partition
369 uint8_t *pentryA = NULL;
370 uint8_t *pentryA_bak = NULL;
371 //Pointer to partition entry of current 'B' partition
372 uint8_t *pentryB = NULL;
373 uint8_t *pentryB_bak = NULL;
374 uint8_t *slot_info = NULL;
375 uint32_t i;
376 int rc = -1;
377 char buf[PATH_MAX] = {0};
378 struct stat st;
379 unsigned num_slots = 0;
380 unsigned current_slot = 0;
381 int is_ufs = gpt_utils_is_ufs_device();
382
383 if (!module) {
384 ALOGE("%s: Invalid arg", __func__);
385 goto error;
386 }
387 num_slots = get_number_slots(module);
388 if ((num_slots < 1) || (slot > num_slots - 1)) {
389 ALOGE("%s: Unable to get num slots/Invalid slot value",
390 __func__);
391 goto error;
392 }
Naveen Ramaraj710b9bf2016-05-05 10:28:04 -0700393 current_slot = get_current_active_slot(module);
Steve Pfetschd7b03992016-04-20 17:53:38 -0700394 if (current_slot == slot) {
395 //Nothing to do here. Just return
396 return 0;
397 }
398 for (i=0; i < ARRAY_SIZE(ptn_list); i++) {
399 //XBL is handled differrently for ufs devices
400 if (is_ufs && !strncmp(ptn_list[i], PTN_XBL, strlen(PTN_XBL)))
401 continue;
402 memset(buf, '\0', sizeof(buf));
403 //Check if A/B versions of this ptn exist
404 snprintf(buf, sizeof(buf) - 1,
405 "%s/%s%s",
406 BOOT_DEV_DIR,
407 ptn_list[i],
408 AB_SLOT_A_SUFFIX
409 );
410 if (stat(buf, &st)) {
411 //partition does not have _a version
412 continue;
413 }
414 memset(buf, '\0', sizeof(buf));
415 snprintf(buf, sizeof(buf) - 1,
416 "%s/%s%s",
417 BOOT_DEV_DIR,
418 ptn_list[i],
419 AB_SLOT_B_SUFFIX
420 );
421 if (stat(buf, &st)) {
422 //partition does not have _a version
423 continue;
424 }
425 disk = gpt_disk_alloc();
426 if (!disk)
427 goto error;
428 memset(slotA, 0, sizeof(slotA));
429 memset(slotB, 0, sizeof(slotB));
430 snprintf(slotA, sizeof(slotA) - 1, "%s%s",
431 ptn_list[i],
432 AB_SLOT_A_SUFFIX);
433 snprintf(slotB, sizeof(slotB) - 1,"%s%s",
434 ptn_list[i],
435 AB_SLOT_B_SUFFIX);
436 //It is assumed that both the A and B slots reside on the
437 //same physical disk
438 if (gpt_disk_get_disk_info(slotA, disk))
439 goto error;
440 //Get partition entry for slot A from primary table
441 pentryA = gpt_disk_get_pentry(disk, slotA, PRIMARY_GPT);
442 //Get partition entry for slot A from backup table
443 pentryA_bak = gpt_disk_get_pentry(disk, slotA, SECONDARY_GPT);
444 //Get partition entry for slot B from primary table
445 pentryB = gpt_disk_get_pentry(disk, slotB, PRIMARY_GPT);
446 //Get partition entry for slot B from backup table
447 pentryB_bak = gpt_disk_get_pentry(disk, slotB, SECONDARY_GPT);
448 if ( !pentryA || !pentryA_bak || !pentryB || !pentryB_bak) {
449 //Something has gone wrong here.We know that we have
450 //_a and _b versions of this partition due to the
451 //check at the start of the loop so none of these
452 //should be NULL.
453 ALOGE("Slot pentries for %s not found.",
454 ptn_list[i]);
455 goto error;
456 }
457 memset(active_guid, '\0', sizeof(active_guid));
458 memset(inactive_guid, '\0', sizeof(inactive_guid));
459 if (get_partition_attribute(slotA, ATTR_SLOT_ACTIVE) == 1) {
460 //A is the current active slot
461 memcpy((void*)active_guid,
462 (const void*)pentryA,
463 TYPE_GUID_SIZE);
464 memcpy((void*)inactive_guid,
465 (const void*)pentryB,
466 TYPE_GUID_SIZE);
467
468 } else if (get_partition_attribute(slotB,
469 ATTR_SLOT_ACTIVE) == 1) {
470 //B is the current active slot
471 memcpy((void*)active_guid,
472 (const void*)pentryB,
473 TYPE_GUID_SIZE);
474 memcpy((void*)inactive_guid,
475 (const void*)pentryA,
476 TYPE_GUID_SIZE);
477 } else {
478 ALOGE("Both A & B are inactive..Aborting");
479 goto error;
480 }
481 if (!strncmp(slot_suffix_arr[slot], AB_SLOT_A_SUFFIX,
482 strlen(AB_SLOT_A_SUFFIX))){
483 //Mark A as active in primary table
484 memcpy(pentryA, active_guid, TYPE_GUID_SIZE);
485 slot_info = pentryA + AB_FLAG_OFFSET;
486 *slot_info = AB_SLOT_ACTIVE_VAL;
487
488 //Mark A as active in backup table
489 memcpy(pentryA_bak, active_guid, TYPE_GUID_SIZE);
490 slot_info = pentryA_bak + AB_FLAG_OFFSET;
491 *slot_info = AB_SLOT_ACTIVE_VAL;
492
493 //Mark B as inactive in primary table
494 memcpy(pentryB, inactive_guid, TYPE_GUID_SIZE);
495 slot_info = pentryB + AB_FLAG_OFFSET;
496 *slot_info = *(slot_info) &
497 ~AB_PARTITION_ATTR_SLOT_ACTIVE;
498
499 //Mark B as inactive in backup table
500 memcpy(pentryB_bak, inactive_guid, TYPE_GUID_SIZE);
501 slot_info = pentryB_bak + AB_FLAG_OFFSET;
502 *slot_info = *(slot_info) &
503 ~AB_PARTITION_ATTR_SLOT_ACTIVE;
504 } else if (!strncmp(slot_suffix_arr[slot], AB_SLOT_B_SUFFIX,
505 strlen(AB_SLOT_B_SUFFIX))){
506 //Mark B as active in primary table
507 memcpy(pentryB, active_guid, TYPE_GUID_SIZE);
508 slot_info = pentryB + AB_FLAG_OFFSET;
509 *slot_info = AB_SLOT_ACTIVE_VAL;
510
511 //Mark B as active in backup table
512 memcpy(pentryB_bak, active_guid, TYPE_GUID_SIZE);
513 slot_info = pentryB_bak + AB_FLAG_OFFSET;
514 *slot_info = AB_SLOT_ACTIVE_VAL;
515
516 //Mark A as inavtive in primary table
517 memcpy(pentryA, inactive_guid, TYPE_GUID_SIZE);
518 slot_info = pentryA + AB_FLAG_OFFSET;
519 *slot_info = *(slot_info) &
520 ~AB_PARTITION_ATTR_SLOT_ACTIVE;
521
522 //Mark A as inactive in backup table
523 memcpy(pentryA_bak, inactive_guid, TYPE_GUID_SIZE);
524 slot_info = pentryA_bak + AB_FLAG_OFFSET;
525 *slot_info = *(slot_info) &
526 ~AB_PARTITION_ATTR_SLOT_ACTIVE;
527 } else {
528 //Something has gone terribly terribly wrong
529 ALOGE("%s: Unknown slot suffix!", __func__);
530 goto error;
531 }
532 if (gpt_disk_update_crc(disk) != 0) {
533 ALOGE("%s: Failed to update gpt_disk crc", __func__);
534 goto error;
535 }
536 if (gpt_disk_commit(disk) != 0) {
537 ALOGE("%s: Failed to commit disk info", __func__);
538 goto error;
539 }
540 gpt_disk_free(disk);
541 disk = NULL;
542 }
543 if (is_ufs) {
544 if (!strncmp(slot_suffix_arr[slot], AB_SLOT_A_SUFFIX,
545 strlen(AB_SLOT_A_SUFFIX))){
546 //Set xbl_a as the boot lun
547 rc = gpt_utils_set_xbl_boot_partition(NORMAL_BOOT);
548 } else if (!strncmp(slot_suffix_arr[slot], AB_SLOT_B_SUFFIX,
549 strlen(AB_SLOT_B_SUFFIX))){
550 //Set xbl_b as the boot lun
551 rc = gpt_utils_set_xbl_boot_partition(BACKUP_BOOT);
552 } else {
553 //Something has gone terribly terribly wrong
554 ALOGE("%s: Unknown slot suffix!", __func__);
555 goto error;
556 }
557 if (rc) {
558 ALOGE("%s: Failed to switch xbl boot partition",
559 __func__);
560 goto error;
561 }
562 }
563 return 0;
564error:
565 if (disk)
566 gpt_disk_free(disk);
567 return -1;
568}
569
570int set_slot_as_unbootable(struct boot_control_module *module, unsigned slot)
571{
572 unsigned num_slots = 0;
573 if (!module) {
574 ALOGE("%s: Invalid argument", __func__);
575 goto error;
576 }
577 num_slots = get_number_slots(module);
578 if (num_slots < 1 || slot > num_slots - 1) {
579 ALOGE("%s: Unable to get num_slots/Invalid slot value",
580 __func__);
581 goto error;
582 }
583 if (update_slot_attribute(slot_suffix_arr[slot],
584 ATTR_UNBOOTABLE)) {
585 goto error;
586 }
587 return 0;
588error:
589 ALOGE("%s: Failed to mark slot unbootable", __func__);
590 return -1;
591}
592
593int is_slot_bootable(struct boot_control_module *module, unsigned slot)
594{
595 unsigned num_slots = 0;
596 int attr = 0;
597 char bootPartition[MAX_GPT_NAME_SIZE + 1] = {0};
598 if (!module) {
599 ALOGE("%s: Invalid argument", __func__);
600 goto error;
601 }
602 num_slots = get_number_slots(module);
603 if (num_slots < 1 || slot > num_slots - 1) {
604 ALOGE("%s: Unable to get num_slots/Invalid slot value",
605 __func__);
606 goto error;
607 }
608 snprintf(bootPartition,
609 sizeof(bootPartition) - 1, "boot%s",
610 slot_suffix_arr[slot]);
611 attr = get_partition_attribute(bootPartition, ATTR_UNBOOTABLE);
612 if (attr >= 0)
613 return !attr;
614error:
615 return -1;
616}
617
618int is_slot_marked_successful(struct boot_control_module *module, unsigned slot)
619{
620 unsigned num_slots = 0;
621 int attr = 0;
622 char bootPartition[MAX_GPT_NAME_SIZE + 1] = {0};
623 if (!module) {
624 ALOGE("%s: Invalid argument", __func__);
625 goto error;
626 }
627 num_slots = get_number_slots(module);
628 if (num_slots < 1 || slot > num_slots - 1) {
629 ALOGE("%s: Unable to get num_slots/Invalid slot value",
630 __func__);
631 goto error;
632 }
633 snprintf(bootPartition,
634 sizeof(bootPartition) - 1,
635 "boot%s", slot_suffix_arr[slot]);
636 attr = get_partition_attribute(bootPartition, ATTR_BOOT_SUCCESSFUL);
637 if (attr >= 0)
638 return attr;
639error:
640 return -1;
641}
642
643static hw_module_methods_t boot_control_module_methods = {
644 .open = NULL,
645};
646
647boot_control_module_t HAL_MODULE_INFO_SYM = {
648 .common = {
649 .tag = HARDWARE_MODULE_TAG,
650 .module_api_version = 1,
651 .hal_api_version = 0,
652 .id = BOOT_CONTROL_HARDWARE_MODULE_ID,
653 .name = "Boot control HAL",
654 .author = "Code Aurora Forum",
655 .methods = &boot_control_module_methods,
656 },
657 .init = boot_control_init,
658 .getNumberSlots = get_number_slots,
659 .getCurrentSlot = get_current_slot,
660 .markBootSuccessful = mark_boot_successful,
661 .setActiveBootSlot = set_active_boot_slot,
662 .setSlotAsUnbootable = set_slot_as_unbootable,
663 .isSlotBootable = is_slot_bootable,
664 .getSuffix = get_suffix,
665 .isSlotMarkedSuccessful = is_slot_marked_successful,
666};