Home | History | Annotate | Download | only in bootctrl
      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 <cutils/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 		if (!strncmp(de->d_name, BOOT_IMG_PTN_NAME,
    270 					strlen(BOOT_IMG_PTN_NAME)))
    271 			slot_count++;
    272 	}
    273 	closedir(dir_bootdev);
    274 	return slot_count;
    275 error:
    276 	if (dir_bootdev)
    277 		closedir(dir_bootdev);
    278 	return 0;
    279 }
    280 
    281 unsigned get_current_slot(struct boot_control_module *module)
    282 {
    283 	uint32_t num_slots = 0;
    284 	char bootSlotProp[PROPERTY_VALUE_MAX] = {'\0'};
    285 	unsigned i = 0;
    286 	if (!module) {
    287 		ALOGE("%s: Invalid argument", __func__);
    288 		goto error;
    289 	}
    290 	num_slots = get_number_slots(module);
    291 	if (num_slots <= 1) {
    292 		//Slot 0 is the only slot around.
    293 		return 0;
    294 	}
    295 	property_get(BOOT_SLOT_PROP, bootSlotProp, "N/A");
    296 	if (!strncmp(bootSlotProp, "N/A", strlen("N/A"))) {
    297 		ALOGE("%s: Unable to read boot slot property",
    298 				__func__);
    299 		goto error;
    300 	}
    301 	//Iterate through a list of partitons named as boot+suffix
    302 	//and see which one is currently active.
    303 	for (i = 0; slot_suffix_arr[i] != NULL ; i++) {
    304 		if (!strncmp(bootSlotProp,
    305 					slot_suffix_arr[i],
    306 					strlen(slot_suffix_arr[i])))
    307 				return i;
    308 	}
    309 error:
    310 	//The HAL spec requires that we return a number between
    311 	//0 to num_slots - 1. Since something went wrong here we
    312 	//are just going to return the default slot.
    313 	return 0;
    314 }
    315 
    316 static int boot_control_check_slot_sanity(struct boot_control_module *module,
    317 		unsigned slot)
    318 {
    319 	if (!module)
    320 		return -1;
    321 	uint32_t num_slots = get_number_slots(module);
    322 	if ((num_slots < 1) || (slot > num_slots - 1)) {
    323 		ALOGE("Invalid slot number");
    324 		return -1;
    325 	}
    326 	return 0;
    327 
    328 }
    329 
    330 int mark_boot_successful(struct boot_control_module *module)
    331 {
    332 	unsigned cur_slot = 0;
    333 	if (!module) {
    334 		ALOGE("%s: Invalid argument", __func__);
    335 		goto error;
    336 	}
    337 	cur_slot = get_current_slot(module);
    338 	if (update_slot_attribute(slot_suffix_arr[cur_slot],
    339 				ATTR_BOOT_SUCCESSFUL)) {
    340 		goto error;
    341 	}
    342 	return 0;
    343 error:
    344 	ALOGE("%s: Failed to mark boot successful", __func__);
    345 	return -1;
    346 }
    347 
    348 const char *get_suffix(struct boot_control_module *module, unsigned slot)
    349 {
    350 	if (boot_control_check_slot_sanity(module, slot) != 0)
    351 		return NULL;
    352 	else
    353 		return slot_suffix_arr[slot];
    354 }
    355 
    356 
    357 //Return a gpt disk structure representing the disk that holds
    358 //partition.
    359 static struct gpt_disk* boot_ctl_get_disk_info(char *partition)
    360 {
    361 	struct gpt_disk *disk = NULL;
    362 	if (!partition)
    363 		return NULL;
    364 	disk = gpt_disk_alloc();
    365 	if (!disk) {
    366 		ALOGE("%s: Failed to alloc disk",
    367 				__func__);
    368 		goto error;
    369 	}
    370 	if (gpt_disk_get_disk_info(partition, disk)) {
    371 		ALOGE("failed to get disk info for %s",
    372 				partition);
    373 		goto error;
    374 	}
    375 	return disk;
    376 error:
    377 	if (disk)
    378 		gpt_disk_free(disk);
    379 	return NULL;
    380 }
    381 
    382 //The argument here is a vector of partition names(including the slot suffix)
    383 //that lie on a single disk
    384 static int boot_ctl_set_active_slot_for_partitions(vector<string> part_list,
    385 		unsigned slot)
    386 {
    387 	char buf[PATH_MAX] = {0};
    388 	struct gpt_disk *disk = NULL;
    389 	char slotA[MAX_GPT_NAME_SIZE + 1] = {0};
    390 	char slotB[MAX_GPT_NAME_SIZE + 1] = {0};
    391 	char active_guid[TYPE_GUID_SIZE + 1] = {0};
    392 	char inactive_guid[TYPE_GUID_SIZE + 1] = {0};
    393 	//Pointer to the partition entry of current 'A' partition
    394 	uint8_t *pentryA = NULL;
    395 	uint8_t *pentryA_bak = NULL;
    396 	//Pointer to partition entry of current 'B' partition
    397 	uint8_t *pentryB = NULL;
    398 	uint8_t *pentryB_bak = NULL;
    399 	struct stat st;
    400 	vector<string>::iterator partition_iterator;
    401 
    402 	for (partition_iterator = part_list.begin();
    403 			partition_iterator != part_list.end();
    404 			partition_iterator++) {
    405 		//Chop off the slot suffix from the partition name to
    406 		//make the string easier to work with.
    407 		string prefix = *partition_iterator;
    408 		if (prefix.size() < (strlen(AB_SLOT_A_SUFFIX) + 1)) {
    409 			ALOGE("Invalid partition name: %s", prefix.c_str());
    410 			goto error;
    411 		}
    412 		prefix.resize(prefix.size() - strlen(AB_SLOT_A_SUFFIX));
    413 		//Check if A/B versions of this ptn exist
    414 		snprintf(buf, sizeof(buf) - 1, "%s/%s%s", BOOT_DEV_DIR,
    415 				prefix.c_str(),
    416 				AB_SLOT_A_SUFFIX);
    417 		if (stat(buf, &st))
    418 			continue;
    419 		memset(buf, '\0', sizeof(buf));
    420 		snprintf(buf, sizeof(buf) - 1, "%s/%s%s", BOOT_DEV_DIR,
    421 				prefix.c_str(),
    422 				AB_SLOT_B_SUFFIX);
    423 		if (stat(buf, &st))
    424 			continue;
    425 		memset(slotA, 0, sizeof(slotA));
    426 		memset(slotB, 0, sizeof(slotA));
    427 		snprintf(slotA, sizeof(slotA) - 1, "%s%s", prefix.c_str(),
    428 				AB_SLOT_A_SUFFIX);
    429 		snprintf(slotB, sizeof(slotB) - 1,"%s%s", prefix.c_str(),
    430 				AB_SLOT_B_SUFFIX);
    431 		//Get the disk containing the partitions that were passed in.
    432 		//All partitions passed in must lie on the same disk.
    433 		if (!disk) {
    434 			disk = boot_ctl_get_disk_info(slotA);
    435 			if (!disk)
    436 				goto error;
    437 		}
    438 		//Get partition entry for slot A & B from the primary
    439 		//and backup tables.
    440 		pentryA = gpt_disk_get_pentry(disk, slotA, PRIMARY_GPT);
    441 		pentryA_bak = gpt_disk_get_pentry(disk, slotA, SECONDARY_GPT);
    442 		pentryB = gpt_disk_get_pentry(disk, slotB, PRIMARY_GPT);
    443 		pentryB_bak = gpt_disk_get_pentry(disk, slotB, SECONDARY_GPT);
    444 		if ( !pentryA || !pentryA_bak || !pentryB || !pentryB_bak) {
    445 			//None of these should be NULL since we have already
    446 			//checked for A & B versions earlier.
    447 			ALOGE("Slot pentries for %s not found.",
    448 					prefix.c_str());
    449 			goto error;
    450 		}
    451 		memset(active_guid, '\0', sizeof(active_guid));
    452 		memset(inactive_guid, '\0', sizeof(inactive_guid));
    453 		if (get_partition_attribute(slotA, ATTR_SLOT_ACTIVE) == 1) {
    454 			//A is the current active slot
    455 			memcpy((void*)active_guid, (const void*)pentryA,
    456 					TYPE_GUID_SIZE);
    457 			memcpy((void*)inactive_guid,(const void*)pentryB,
    458 					TYPE_GUID_SIZE);
    459 		} else if (get_partition_attribute(slotB,
    460 					ATTR_SLOT_ACTIVE) == 1) {
    461 			//B is the current active slot
    462 			memcpy((void*)active_guid, (const void*)pentryB,
    463 					TYPE_GUID_SIZE);
    464 			memcpy((void*)inactive_guid, (const void*)pentryA,
    465 					TYPE_GUID_SIZE);
    466 		} else {
    467 			ALOGE("Both A & B are inactive..Aborting");
    468 			goto error;
    469 		}
    470 		if (!strncmp(slot_suffix_arr[slot], AB_SLOT_A_SUFFIX,
    471 					strlen(AB_SLOT_A_SUFFIX))){
    472 			//Mark A as active in primary table
    473 			UPDATE_SLOT(pentryA, active_guid, SLOT_ACTIVE);
    474 			//Mark A as active in backup table
    475 			UPDATE_SLOT(pentryA_bak, active_guid, SLOT_ACTIVE);
    476 			//Mark B as inactive in primary table
    477 			UPDATE_SLOT(pentryB, inactive_guid, SLOT_INACTIVE);
    478 			//Mark B as inactive in backup table
    479 			UPDATE_SLOT(pentryB_bak, inactive_guid, SLOT_INACTIVE);
    480 		} else if (!strncmp(slot_suffix_arr[slot], AB_SLOT_B_SUFFIX,
    481 					strlen(AB_SLOT_B_SUFFIX))){
    482 			//Mark B as active in primary table
    483 			UPDATE_SLOT(pentryB, active_guid, SLOT_ACTIVE);
    484 			//Mark B as active in backup table
    485 			UPDATE_SLOT(pentryB_bak, active_guid, SLOT_ACTIVE);
    486 			//Mark A as inavtive in primary table
    487 			UPDATE_SLOT(pentryA, inactive_guid, SLOT_INACTIVE);
    488 			//Mark A as inactive in backup table
    489 			UPDATE_SLOT(pentryA_bak, inactive_guid, SLOT_INACTIVE);
    490 		} else {
    491 			//Something has gone terribly terribly wrong
    492 			ALOGE("%s: Unknown slot suffix!", __func__);
    493 			goto error;
    494 		}
    495 		if (disk) {
    496 			if (gpt_disk_update_crc(disk) != 0) {
    497 				ALOGE("%s: Failed to update gpt_disk crc",
    498 						__func__);
    499 				goto error;
    500 			}
    501 		}
    502 	}
    503 	//write updated content to disk
    504 	if (disk) {
    505 		if (gpt_disk_commit(disk)) {
    506 			ALOGE("Failed to commit disk entry");
    507 			goto error;
    508 		}
    509 		gpt_disk_free(disk);
    510 	}
    511 	return 0;
    512 
    513 error:
    514 	if (disk)
    515 		gpt_disk_free(disk);
    516 	return -1;
    517 }
    518 
    519 int set_active_boot_slot(struct boot_control_module *module, unsigned slot)
    520 {
    521 	map<string, vector<string>> ptn_map;
    522 	vector<string> ptn_vec;
    523 	const char ptn_list[][MAX_GPT_NAME_SIZE] = { AB_PTN_LIST };
    524 	uint32_t i;
    525 	int rc = -1;
    526 	int is_ufs = gpt_utils_is_ufs_device();
    527 	map<string, vector<string>>::iterator map_iter;
    528 	vector<string>::iterator string_iter;
    529 
    530 	if (boot_control_check_slot_sanity(module, slot)) {
    531 		ALOGE("%s: Bad arguments", __func__);
    532 		goto error;
    533 	}
    534 	//The partition list just contains prefixes(without the _a/_b) of the
    535 	//partitions that support A/B. In order to get the layout we need the
    536 	//actual names. To do this we append the slot suffix to every member
    537 	//in the list.
    538 	for (i = 0; i < ARRAY_SIZE(ptn_list); i++) {
    539 		//XBL is handled differrently for ufs devices so ignore it
    540 		if (is_ufs && !strncmp(ptn_list[i], PTN_XBL, strlen(PTN_XBL)))
    541 				continue;
    542 		//The partition list will be the list of _a partitions
    543 		string cur_ptn = ptn_list[i];
    544 		cur_ptn.append(AB_SLOT_A_SUFFIX);
    545 		ptn_vec.push_back(cur_ptn);
    546 
    547 	}
    548 	//The partition map gives us info in the following format:
    549 	// [path_to_block_device_1]--><partitions on device 1>
    550 	// [path_to_block_device_2]--><partitions on device 2>
    551 	// ...
    552 	// ...
    553 	// eg:
    554 	// [/dev/block/sdb]---><system, boot, rpm, tz,....>
    555 	if (gpt_utils_get_partition_map(ptn_vec, ptn_map)) {
    556 		ALOGE("%s: Failed to get partition map",
    557 				__func__);
    558 		goto error;
    559 	}
    560 	for (map_iter = ptn_map.begin(); map_iter != ptn_map.end(); map_iter++){
    561 		if (map_iter->second.size() < 1)
    562 			continue;
    563 		boot_ctl_set_active_slot_for_partitions(map_iter->second, slot);
    564 	}
    565 	if (is_ufs) {
    566 		if (!strncmp(slot_suffix_arr[slot], AB_SLOT_A_SUFFIX,
    567 					strlen(AB_SLOT_A_SUFFIX))){
    568 			//Set xbl_a as the boot lun
    569 			rc = gpt_utils_set_xbl_boot_partition(NORMAL_BOOT);
    570 		} else if (!strncmp(slot_suffix_arr[slot], AB_SLOT_B_SUFFIX,
    571 					strlen(AB_SLOT_B_SUFFIX))){
    572 			//Set xbl_b as the boot lun
    573 			rc = gpt_utils_set_xbl_boot_partition(BACKUP_BOOT);
    574 		} else {
    575 			//Something has gone terribly terribly wrong
    576 			ALOGE("%s: Unknown slot suffix!", __func__);
    577 			goto error;
    578 		}
    579 		if (rc) {
    580 			ALOGE("%s: Failed to switch xbl boot partition",
    581 					__func__);
    582 			goto error;
    583 		}
    584 	}
    585 	return 0;
    586 error:
    587 	return -1;
    588 }
    589 
    590 int set_slot_as_unbootable(struct boot_control_module *module, unsigned slot)
    591 {
    592 	if (boot_control_check_slot_sanity(module, slot) != 0) {
    593 		ALOGE("%s: Argument check failed", __func__);
    594 		goto error;
    595 	}
    596 	if (update_slot_attribute(slot_suffix_arr[slot],
    597 				ATTR_UNBOOTABLE)) {
    598 		goto error;
    599 	}
    600 	return 0;
    601 error:
    602 	ALOGE("%s: Failed to mark slot unbootable", __func__);
    603 	return -1;
    604 }
    605 
    606 int is_slot_bootable(struct boot_control_module *module, unsigned slot)
    607 {
    608 	int attr = 0;
    609 	char bootPartition[MAX_GPT_NAME_SIZE + 1] = {0};
    610 
    611 	if (boot_control_check_slot_sanity(module, slot) != 0) {
    612 		ALOGE("%s: Argument check failed", __func__);
    613 		goto error;
    614 	}
    615 	snprintf(bootPartition,
    616 			sizeof(bootPartition) - 1, "boot%s",
    617 			slot_suffix_arr[slot]);
    618 	attr = get_partition_attribute(bootPartition, ATTR_UNBOOTABLE);
    619 	if (attr >= 0)
    620 		return !attr;
    621 error:
    622 	return -1;
    623 }
    624 
    625 int is_slot_marked_successful(struct boot_control_module *module, unsigned slot)
    626 {
    627 	int attr = 0;
    628 	char bootPartition[MAX_GPT_NAME_SIZE + 1] = {0};
    629 
    630 	if (boot_control_check_slot_sanity(module, slot) != 0) {
    631 		ALOGE("%s: Argument check failed", __func__);
    632 		goto error;
    633 	}
    634 	snprintf(bootPartition,
    635 			sizeof(bootPartition) - 1,
    636 			"boot%s", slot_suffix_arr[slot]);
    637 	attr = get_partition_attribute(bootPartition, ATTR_BOOT_SUCCESSFUL);
    638 	if (attr >= 0)
    639 		return attr;
    640 error:
    641 	return -1;
    642 }
    643 
    644 static hw_module_methods_t boot_control_module_methods = {
    645 	.open = NULL,
    646 };
    647 
    648 boot_control_module_t HAL_MODULE_INFO_SYM = {
    649 	.common = {
    650 		.tag = HARDWARE_MODULE_TAG,
    651 		.module_api_version = 1,
    652 		.hal_api_version = 0,
    653 		.id = BOOT_CONTROL_HARDWARE_MODULE_ID,
    654 		.name = "Boot control HAL",
    655 		.author = "Code Aurora Forum",
    656 		.methods = &boot_control_module_methods,
    657 	},
    658 	.init = boot_control_init,
    659 	.getNumberSlots = get_number_slots,
    660 	.getCurrentSlot = get_current_slot,
    661 	.markBootSuccessful = mark_boot_successful,
    662 	.setActiveBootSlot = set_active_boot_slot,
    663 	.setSlotAsUnbootable = set_slot_as_unbootable,
    664 	.isSlotBootable = is_slot_bootable,
    665 	.getSuffix = get_suffix,
    666 	.isSlotMarkedSuccessful = is_slot_marked_successful,
    667 };
    668 #ifdef __cplusplus
    669 }
    670 #endif
    671