1 /* 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 <map> 30 #include <list> 31 #include <string> 32 #include <vector> 33 #ifdef __cplusplus 34 extern "C" { 35 #endif 36 #include <errno.h> 37 #define LOG_TAG "bootcontrolhal" 38 #include <log/log.h> 39 #include <hardware/boot_control.h> 40 #include <stdio.h> 41 #include <string.h> 42 #include <unistd.h> 43 #include <dirent.h> 44 #include <sys/types.h> 45 #include <sys/stat.h> 46 #include <fcntl.h> 47 #include <limits.h> 48 #include <cutils/properties.h> 49 #include "gpt-utils.h" 50 51 #define BOOTDEV_DIR "/dev/block/bootdevice/by-name" 52 #define BOOT_IMG_PTN_NAME "boot_" 53 #define LUN_NAME_END_LOC 14 54 #define BOOT_SLOT_PROP "ro.boot.slot_suffix" 55 56 #define SLOT_ACTIVE 1 57 #define SLOT_INACTIVE 2 58 #define UPDATE_SLOT(pentry, guid, slot_state) ({ \ 59 memcpy(pentry, guid, TYPE_GUID_SIZE); \ 60 if (slot_state == SLOT_ACTIVE)\ 61 *(pentry + AB_FLAG_OFFSET) = AB_SLOT_ACTIVE_VAL; \ 62 else if (slot_state == SLOT_INACTIVE) \ 63 *(pentry + AB_FLAG_OFFSET) = (*(pentry + AB_FLAG_OFFSET)& \ 64 ~AB_PARTITION_ATTR_SLOT_ACTIVE); \ 65 }) 66 67 using namespace std; 68 const char *slot_suffix_arr[] = { 69 AB_SLOT_A_SUFFIX, 70 AB_SLOT_B_SUFFIX, 71 NULL}; 72 73 enum part_attr_type { 74 ATTR_SLOT_ACTIVE = 0, 75 ATTR_BOOT_SUCCESSFUL, 76 ATTR_UNBOOTABLE, 77 }; 78 79 void boot_control_init(struct boot_control_module *module) 80 { 81 if (!module) { 82 ALOGE("Invalid argument passed to %s", __func__); 83 return; 84 } 85 return; 86 } 87 88 //Get the value of one of the attribute fields for a partition. 89 static int get_partition_attribute(char *partname, 90 enum part_attr_type part_attr) 91 { 92 struct gpt_disk *disk = NULL; 93 uint8_t *pentry = NULL; 94 int retval = -1; 95 uint8_t *attr = NULL; 96 if (!partname) 97 goto error; 98 disk = gpt_disk_alloc(); 99 if (!disk) { 100 ALOGE("%s: Failed to alloc disk struct", __func__); 101 goto error; 102 } 103 if (gpt_disk_get_disk_info(partname, disk)) { 104 ALOGE("%s: Failed to get disk info", __func__); 105 goto error; 106 } 107 pentry = gpt_disk_get_pentry(disk, partname, PRIMARY_GPT); 108 if (!pentry) { 109 ALOGE("%s: pentry does not exist in disk struct", 110 __func__); 111 goto error; 112 } 113 attr = pentry + AB_FLAG_OFFSET; 114 if (part_attr == ATTR_SLOT_ACTIVE) 115 retval = !!(*attr & AB_PARTITION_ATTR_SLOT_ACTIVE); 116 else if (part_attr == ATTR_BOOT_SUCCESSFUL) 117 retval = !!(*attr & AB_PARTITION_ATTR_BOOT_SUCCESSFUL); 118 else if (part_attr == ATTR_UNBOOTABLE) 119 retval = !!(*attr & AB_PARTITION_ATTR_UNBOOTABLE); 120 else 121 retval = -1; 122 gpt_disk_free(disk); 123 return retval; 124 error: 125 if (disk) 126 gpt_disk_free(disk); 127 return retval; 128 } 129 130 //Set a particular attribute for all the partitions in a 131 //slot 132 static int update_slot_attribute(const char *slot, 133 enum part_attr_type ab_attr) 134 { 135 unsigned int i = 0; 136 char buf[PATH_MAX]; 137 struct stat st; 138 struct gpt_disk *disk = NULL; 139 uint8_t *pentry = NULL; 140 uint8_t *pentry_bak = NULL; 141 int rc = -1; 142 uint8_t *attr = NULL; 143 uint8_t *attr_bak = NULL; 144 char partName[MAX_GPT_NAME_SIZE + 1] = {0}; 145 const char ptn_list[][MAX_GPT_NAME_SIZE] = { AB_PTN_LIST }; 146 int slot_name_valid = 0; 147 if (!slot) { 148 ALOGE("%s: Invalid argument", __func__); 149 goto error; 150 } 151 for (i = 0; slot_suffix_arr[i] != NULL; i++) 152 { 153 if (!strncmp(slot, slot_suffix_arr[i], 154 strlen(slot_suffix_arr[i]))) 155 slot_name_valid = 1; 156 } 157 if (!slot_name_valid) { 158 ALOGE("%s: Invalid slot name", __func__); 159 goto error; 160 } 161 for (i=0; i < ARRAY_SIZE(ptn_list); i++) { 162 memset(buf, '\0', sizeof(buf)); 163 //Check if A/B versions of this ptn exist 164 snprintf(buf, sizeof(buf) - 1, 165 "%s/%s%s", 166 BOOT_DEV_DIR, 167 ptn_list[i], 168 AB_SLOT_A_SUFFIX 169 ); 170 if (stat(buf, &st)) { 171 //partition does not have _a version 172 continue; 173 } 174 memset(buf, '\0', sizeof(buf)); 175 snprintf(buf, sizeof(buf) - 1, 176 "%s/%s%s", 177 BOOT_DEV_DIR, 178 ptn_list[i], 179 AB_SLOT_B_SUFFIX 180 ); 181 if (stat(buf, &st)) { 182 //partition does not have _a version 183 continue; 184 } 185 memset(partName, '\0', sizeof(partName)); 186 snprintf(partName, 187 sizeof(partName) - 1, 188 "%s%s", 189 ptn_list[i], 190 slot); 191 disk = gpt_disk_alloc(); 192 if (!disk) { 193 ALOGE("%s: Failed to alloc disk struct", 194 __func__); 195 goto error; 196 } 197 rc = gpt_disk_get_disk_info(partName, disk); 198 if (rc != 0) { 199 ALOGE("%s: Failed to get disk info for %s", 200 __func__, 201 partName); 202 goto error; 203 } 204 pentry = gpt_disk_get_pentry(disk, partName, PRIMARY_GPT); 205 pentry_bak = gpt_disk_get_pentry(disk, partName, SECONDARY_GPT); 206 if (!pentry || !pentry_bak) { 207 ALOGE("%s: Failed to get pentry/pentry_bak for %s", 208 __func__, 209 partName); 210 goto error; 211 } 212 attr = pentry + AB_FLAG_OFFSET; 213 attr_bak = pentry_bak + AB_FLAG_OFFSET; 214 if (ab_attr == ATTR_BOOT_SUCCESSFUL) { 215 *attr = (*attr) | AB_PARTITION_ATTR_BOOT_SUCCESSFUL; 216 *attr_bak = (*attr_bak) | 217 AB_PARTITION_ATTR_BOOT_SUCCESSFUL; 218 } else if (ab_attr == ATTR_UNBOOTABLE) { 219 *attr = (*attr) | AB_PARTITION_ATTR_UNBOOTABLE; 220 *attr_bak = (*attr_bak) | AB_PARTITION_ATTR_UNBOOTABLE; 221 } else if (ab_attr == ATTR_SLOT_ACTIVE) { 222 *attr = (*attr) | AB_PARTITION_ATTR_SLOT_ACTIVE; 223 *attr_bak = (*attr) | AB_PARTITION_ATTR_SLOT_ACTIVE; 224 } else { 225 ALOGE("%s: Unrecognized attr", __func__); 226 goto error; 227 } 228 if (gpt_disk_update_crc(disk)) { 229 ALOGE("%s: Failed to update crc for %s", 230 __func__, 231 partName); 232 goto error; 233 } 234 if (gpt_disk_commit(disk)) { 235 ALOGE("%s: Failed to write back entry for %s", 236 __func__, 237 partName); 238 goto error; 239 } 240 gpt_disk_free(disk); 241 disk = NULL; 242 } 243 return 0; 244 error: 245 if (disk) 246 gpt_disk_free(disk); 247 return -1; 248 } 249 250 unsigned get_number_slots(struct boot_control_module *module) 251 { 252 struct dirent *de = NULL; 253 DIR *dir_bootdev = NULL; 254 unsigned slot_count = 0; 255 if (!module) { 256 ALOGE("%s: Invalid argument", __func__); 257 goto error; 258 } 259 dir_bootdev = opendir(BOOTDEV_DIR); 260 if (!dir_bootdev) { 261 ALOGE("%s: Failed to open bootdev dir (%s)", 262 __func__, 263 strerror(errno)); 264 goto error; 265 } 266 while ((de = readdir(dir_bootdev))) { 267 if (de->d_name[0] == '.') 268 continue; 269 static_assert(AB_SLOT_A_SUFFIX[0] == '_', "Breaking change to slot A suffix"); 270 static_assert(AB_SLOT_B_SUFFIX[0] == '_', "Breaking change to slot B suffix"); 271 if (!strncmp(de->d_name, BOOT_IMG_PTN_NAME, 272 strlen(BOOT_IMG_PTN_NAME))) 273 slot_count++; 274 } 275 closedir(dir_bootdev); 276 return slot_count; 277 error: 278 if (dir_bootdev) 279 closedir(dir_bootdev); 280 return 0; 281 } 282 283 unsigned get_current_slot(struct boot_control_module *module) 284 { 285 uint32_t num_slots = 0; 286 char bootSlotProp[PROPERTY_VALUE_MAX] = {'\0'}; 287 unsigned i = 0; 288 if (!module) { 289 ALOGE("%s: Invalid argument", __func__); 290 goto error; 291 } 292 num_slots = get_number_slots(module); 293 if (num_slots <= 1) { 294 //Slot 0 is the only slot around. 295 return 0; 296 } 297 property_get(BOOT_SLOT_PROP, bootSlotProp, "N/A"); 298 if (!strncmp(bootSlotProp, "N/A", strlen("N/A"))) { 299 ALOGE("%s: Unable to read boot slot property", 300 __func__); 301 goto error; 302 } 303 //Iterate through a list of partitons named as boot+suffix 304 //and see which one is currently active. 305 for (i = 0; slot_suffix_arr[i] != NULL ; i++) { 306 if (!strncmp(bootSlotProp, 307 slot_suffix_arr[i], 308 strlen(slot_suffix_arr[i]))) 309 return i; 310 } 311 error: 312 //The HAL spec requires that we return a number between 313 //0 to num_slots - 1. Since something went wrong here we 314 //are just going to return the default slot. 315 return 0; 316 } 317 318 static int boot_control_check_slot_sanity(struct boot_control_module *module, 319 unsigned slot) 320 { 321 if (!module) 322 return -1; 323 uint32_t num_slots = get_number_slots(module); 324 if ((num_slots < 1) || (slot > num_slots - 1)) { 325 ALOGE("Invalid slot number"); 326 return -1; 327 } 328 return 0; 329 330 } 331 332 int mark_boot_successful(struct boot_control_module *module) 333 { 334 unsigned cur_slot = 0; 335 if (!module) { 336 ALOGE("%s: Invalid argument", __func__); 337 goto error; 338 } 339 cur_slot = get_current_slot(module); 340 if (update_slot_attribute(slot_suffix_arr[cur_slot], 341 ATTR_BOOT_SUCCESSFUL)) { 342 goto error; 343 } 344 return 0; 345 error: 346 ALOGE("%s: Failed to mark boot successful", __func__); 347 return -1; 348 } 349 350 const char *get_suffix(struct boot_control_module *module, unsigned slot) 351 { 352 if (boot_control_check_slot_sanity(module, slot) != 0) 353 return NULL; 354 else 355 return slot_suffix_arr[slot]; 356 } 357 358 359 //Return a gpt disk structure representing the disk that holds 360 //partition. 361 static struct gpt_disk* boot_ctl_get_disk_info(char *partition) 362 { 363 struct gpt_disk *disk = NULL; 364 if (!partition) 365 return NULL; 366 disk = gpt_disk_alloc(); 367 if (!disk) { 368 ALOGE("%s: Failed to alloc disk", 369 __func__); 370 goto error; 371 } 372 if (gpt_disk_get_disk_info(partition, disk)) { 373 ALOGE("failed to get disk info for %s", 374 partition); 375 goto error; 376 } 377 return disk; 378 error: 379 if (disk) 380 gpt_disk_free(disk); 381 return NULL; 382 } 383 384 //The argument here is a vector of partition names(including the slot suffix) 385 //that lie on a single disk 386 static int boot_ctl_set_active_slot_for_partitions(vector<string> part_list, 387 unsigned slot) 388 { 389 char buf[PATH_MAX] = {0}; 390 struct gpt_disk *disk = NULL; 391 char slotA[MAX_GPT_NAME_SIZE + 1] = {0}; 392 char slotB[MAX_GPT_NAME_SIZE + 1] = {0}; 393 char active_guid[TYPE_GUID_SIZE + 1] = {0}; 394 char inactive_guid[TYPE_GUID_SIZE + 1] = {0}; 395 //Pointer to the partition entry of current 'A' partition 396 uint8_t *pentryA = NULL; 397 uint8_t *pentryA_bak = NULL; 398 //Pointer to partition entry of current 'B' partition 399 uint8_t *pentryB = NULL; 400 uint8_t *pentryB_bak = NULL; 401 struct stat st; 402 vector<string>::iterator partition_iterator; 403 404 for (partition_iterator = part_list.begin(); 405 partition_iterator != part_list.end(); 406 partition_iterator++) { 407 //Chop off the slot suffix from the partition name to 408 //make the string easier to work with. 409 string prefix = *partition_iterator; 410 if (prefix.size() < (strlen(AB_SLOT_A_SUFFIX) + 1)) { 411 ALOGE("Invalid partition name: %s", prefix.c_str()); 412 goto error; 413 } 414 prefix.resize(prefix.size() - strlen(AB_SLOT_A_SUFFIX)); 415 //Check if A/B versions of this ptn exist 416 snprintf(buf, sizeof(buf) - 1, "%s/%s%s", BOOT_DEV_DIR, 417 prefix.c_str(), 418 AB_SLOT_A_SUFFIX); 419 if (stat(buf, &st)) 420 continue; 421 memset(buf, '\0', sizeof(buf)); 422 snprintf(buf, sizeof(buf) - 1, "%s/%s%s", BOOT_DEV_DIR, 423 prefix.c_str(), 424 AB_SLOT_B_SUFFIX); 425 if (stat(buf, &st)) 426 continue; 427 memset(slotA, 0, sizeof(slotA)); 428 memset(slotB, 0, sizeof(slotA)); 429 snprintf(slotA, sizeof(slotA) - 1, "%s%s", prefix.c_str(), 430 AB_SLOT_A_SUFFIX); 431 snprintf(slotB, sizeof(slotB) - 1,"%s%s", prefix.c_str(), 432 AB_SLOT_B_SUFFIX); 433 //Get the disk containing the partitions that were passed in. 434 //All partitions passed in must lie on the same disk. 435 if (!disk) { 436 disk = boot_ctl_get_disk_info(slotA); 437 if (!disk) 438 goto error; 439 } 440 //Get partition entry for slot A & B from the primary 441 //and backup tables. 442 pentryA = gpt_disk_get_pentry(disk, slotA, PRIMARY_GPT); 443 pentryA_bak = gpt_disk_get_pentry(disk, slotA, SECONDARY_GPT); 444 pentryB = gpt_disk_get_pentry(disk, slotB, PRIMARY_GPT); 445 pentryB_bak = gpt_disk_get_pentry(disk, slotB, SECONDARY_GPT); 446 if ( !pentryA || !pentryA_bak || !pentryB || !pentryB_bak) { 447 //None of these should be NULL since we have already 448 //checked for A & B versions earlier. 449 ALOGE("Slot pentries for %s not found.", 450 prefix.c_str()); 451 goto error; 452 } 453 memset(active_guid, '\0', sizeof(active_guid)); 454 memset(inactive_guid, '\0', sizeof(inactive_guid)); 455 if (get_partition_attribute(slotA, ATTR_SLOT_ACTIVE) == 1) { 456 //A is the current active slot 457 memcpy((void*)active_guid, (const void*)pentryA, 458 TYPE_GUID_SIZE); 459 memcpy((void*)inactive_guid,(const void*)pentryB, 460 TYPE_GUID_SIZE); 461 } else if (get_partition_attribute(slotB, 462 ATTR_SLOT_ACTIVE) == 1) { 463 //B is the current active slot 464 memcpy((void*)active_guid, (const void*)pentryB, 465 TYPE_GUID_SIZE); 466 memcpy((void*)inactive_guid, (const void*)pentryA, 467 TYPE_GUID_SIZE); 468 } else { 469 ALOGE("Both A & B are inactive..Aborting"); 470 goto error; 471 } 472 if (!strncmp(slot_suffix_arr[slot], AB_SLOT_A_SUFFIX, 473 strlen(AB_SLOT_A_SUFFIX))){ 474 //Mark A as active in primary table 475 UPDATE_SLOT(pentryA, active_guid, SLOT_ACTIVE); 476 //Mark A as active in backup table 477 UPDATE_SLOT(pentryA_bak, active_guid, SLOT_ACTIVE); 478 //Mark B as inactive in primary table 479 UPDATE_SLOT(pentryB, inactive_guid, SLOT_INACTIVE); 480 //Mark B as inactive in backup table 481 UPDATE_SLOT(pentryB_bak, inactive_guid, SLOT_INACTIVE); 482 } else if (!strncmp(slot_suffix_arr[slot], AB_SLOT_B_SUFFIX, 483 strlen(AB_SLOT_B_SUFFIX))){ 484 //Mark B as active in primary table 485 UPDATE_SLOT(pentryB, active_guid, SLOT_ACTIVE); 486 //Mark B as active in backup table 487 UPDATE_SLOT(pentryB_bak, active_guid, SLOT_ACTIVE); 488 //Mark A as inavtive in primary table 489 UPDATE_SLOT(pentryA, inactive_guid, SLOT_INACTIVE); 490 //Mark A as inactive in backup table 491 UPDATE_SLOT(pentryA_bak, inactive_guid, SLOT_INACTIVE); 492 } else { 493 //Something has gone terribly terribly wrong 494 ALOGE("%s: Unknown slot suffix!", __func__); 495 goto error; 496 } 497 if (disk) { 498 if (gpt_disk_update_crc(disk) != 0) { 499 ALOGE("%s: Failed to update gpt_disk crc", 500 __func__); 501 goto error; 502 } 503 } 504 } 505 //write updated content to disk 506 if (disk) { 507 if (gpt_disk_commit(disk)) { 508 ALOGE("Failed to commit disk entry"); 509 goto error; 510 } 511 gpt_disk_free(disk); 512 } 513 return 0; 514 515 error: 516 if (disk) 517 gpt_disk_free(disk); 518 return -1; 519 } 520 521 int set_active_boot_slot(struct boot_control_module *module, unsigned slot) 522 { 523 map<string, vector<string>> ptn_map; 524 vector<string> ptn_vec; 525 const char ptn_list[][MAX_GPT_NAME_SIZE] = { AB_PTN_LIST }; 526 uint32_t i; 527 int rc = -1; 528 int is_ufs = gpt_utils_is_ufs_device(); 529 map<string, vector<string>>::iterator map_iter; 530 531 if (boot_control_check_slot_sanity(module, slot)) { 532 ALOGE("%s: Bad arguments", __func__); 533 goto error; 534 } 535 //The partition list just contains prefixes(without the _a/_b) of the 536 //partitions that support A/B. In order to get the layout we need the 537 //actual names. To do this we append the slot suffix to every member 538 //in the list. 539 for (i = 0; i < ARRAY_SIZE(ptn_list); i++) { 540 //XBL is handled differrently for ufs devices so ignore it 541 if (is_ufs && !strncmp(ptn_list[i], PTN_XBL, strlen(PTN_XBL))) 542 continue; 543 //The partition list will be the list of _a partitions 544 string cur_ptn = ptn_list[i]; 545 cur_ptn.append(AB_SLOT_A_SUFFIX); 546 ptn_vec.push_back(cur_ptn); 547 548 } 549 //The partition map gives us info in the following format: 550 // [path_to_block_device_1]--><partitions on device 1> 551 // [path_to_block_device_2]--><partitions on device 2> 552 // ... 553 // ... 554 // eg: 555 // [/dev/block/sdb]---><system, boot, rpm, tz,....> 556 if (gpt_utils_get_partition_map(ptn_vec, ptn_map)) { 557 ALOGE("%s: Failed to get partition map", 558 __func__); 559 goto error; 560 } 561 for (map_iter = ptn_map.begin(); map_iter != ptn_map.end(); map_iter++){ 562 if (map_iter->second.size() < 1) 563 continue; 564 if (boot_ctl_set_active_slot_for_partitions(map_iter->second, slot)) { 565 ALOGE("%s: Failed to set active slot for partitions ", __func__);; 566 goto error; 567 } 568 } 569 if (is_ufs) { 570 if (!strncmp(slot_suffix_arr[slot], AB_SLOT_A_SUFFIX, 571 strlen(AB_SLOT_A_SUFFIX))){ 572 //Set xbl_a as the boot lun 573 rc = gpt_utils_set_xbl_boot_partition(NORMAL_BOOT); 574 } else if (!strncmp(slot_suffix_arr[slot], AB_SLOT_B_SUFFIX, 575 strlen(AB_SLOT_B_SUFFIX))){ 576 //Set xbl_b as the boot lun 577 rc = gpt_utils_set_xbl_boot_partition(BACKUP_BOOT); 578 } else { 579 //Something has gone terribly terribly wrong 580 ALOGE("%s: Unknown slot suffix!", __func__); 581 goto error; 582 } 583 if (rc) { 584 ALOGE("%s: Failed to switch xbl boot partition", 585 __func__); 586 goto error; 587 } 588 } 589 return 0; 590 error: 591 return -1; 592 } 593 594 int set_slot_as_unbootable(struct boot_control_module *module, unsigned slot) 595 { 596 if (boot_control_check_slot_sanity(module, slot) != 0) { 597 ALOGE("%s: Argument check failed", __func__); 598 goto error; 599 } 600 if (update_slot_attribute(slot_suffix_arr[slot], 601 ATTR_UNBOOTABLE)) { 602 goto error; 603 } 604 return 0; 605 error: 606 ALOGE("%s: Failed to mark slot unbootable", __func__); 607 return -1; 608 } 609 610 int is_slot_bootable(struct boot_control_module *module, unsigned slot) 611 { 612 int attr = 0; 613 char bootPartition[MAX_GPT_NAME_SIZE + 1] = {0}; 614 615 if (boot_control_check_slot_sanity(module, slot) != 0) { 616 ALOGE("%s: Argument check failed", __func__); 617 goto error; 618 } 619 snprintf(bootPartition, 620 sizeof(bootPartition) - 1, "boot%s", 621 slot_suffix_arr[slot]); 622 attr = get_partition_attribute(bootPartition, ATTR_UNBOOTABLE); 623 if (attr >= 0) 624 return !attr; 625 error: 626 return -1; 627 } 628 629 int is_slot_marked_successful(struct boot_control_module *module, unsigned slot) 630 { 631 int attr = 0; 632 char bootPartition[MAX_GPT_NAME_SIZE + 1] = {0}; 633 634 if (boot_control_check_slot_sanity(module, slot) != 0) { 635 ALOGE("%s: Argument check failed", __func__); 636 goto error; 637 } 638 snprintf(bootPartition, 639 sizeof(bootPartition) - 1, 640 "boot%s", slot_suffix_arr[slot]); 641 attr = get_partition_attribute(bootPartition, ATTR_BOOT_SUCCESSFUL); 642 if (attr >= 0) 643 return attr; 644 error: 645 return -1; 646 } 647 648 static hw_module_methods_t boot_control_module_methods = { 649 .open = NULL, 650 }; 651 652 boot_control_module_t HAL_MODULE_INFO_SYM = { 653 .common = { 654 .tag = HARDWARE_MODULE_TAG, 655 .module_api_version = 1, 656 .hal_api_version = 0, 657 .id = BOOT_CONTROL_HARDWARE_MODULE_ID, 658 .name = "Boot control HAL", 659 .author = "Code Aurora Forum", 660 .methods = &boot_control_module_methods, 661 }, 662 .init = boot_control_init, 663 .getNumberSlots = get_number_slots, 664 .getCurrentSlot = get_current_slot, 665 .markBootSuccessful = mark_boot_successful, 666 .setActiveBootSlot = set_active_boot_slot, 667 .setSlotAsUnbootable = set_slot_as_unbootable, 668 .isSlotBootable = is_slot_bootable, 669 .getSuffix = get_suffix, 670 .isSlotMarkedSuccessful = is_slot_marked_successful, 671 }; 672 #ifdef __cplusplus 673 } 674 #endif 675