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 <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 	vector<string>::iterator string_iter;
    531 
    532 	if (boot_control_check_slot_sanity(module, slot)) {
    533 		ALOGE("%s: Bad arguments", __func__);
    534 		goto error;
    535 	}
    536 	//The partition list just contains prefixes(without the _a/_b) of the
    537 	//partitions that support A/B. In order to get the layout we need the
    538 	//actual names. To do this we append the slot suffix to every member
    539 	//in the list.
    540 	for (i = 0; i < ARRAY_SIZE(ptn_list); i++) {
    541 		//XBL is handled differrently for ufs devices so ignore it
    542 		if (is_ufs && !strncmp(ptn_list[i], PTN_XBL, strlen(PTN_XBL)))
    543 				continue;
    544 		//The partition list will be the list of _a partitions
    545 		string cur_ptn = ptn_list[i];
    546 		cur_ptn.append(AB_SLOT_A_SUFFIX);
    547 		ptn_vec.push_back(cur_ptn);
    548 
    549 	}
    550 	//The partition map gives us info in the following format:
    551 	// [path_to_block_device_1]--><partitions on device 1>
    552 	// [path_to_block_device_2]--><partitions on device 2>
    553 	// ...
    554 	// ...
    555 	// eg:
    556 	// [/dev/block/sdb]---><system, boot, rpm, tz,....>
    557 	if (gpt_utils_get_partition_map(ptn_vec, ptn_map)) {
    558 		ALOGE("%s: Failed to get partition map",
    559 				__func__);
    560 		goto error;
    561 	}
    562 	for (map_iter = ptn_map.begin(); map_iter != ptn_map.end(); map_iter++){
    563 		if (map_iter->second.size() < 1)
    564 			continue;
    565 		if (boot_ctl_set_active_slot_for_partitions(map_iter->second, slot)) {
    566 			ALOGE("%s: Failed to set active slot for partitions ", __func__);;
    567 			goto error;
    568 		}
    569 	}
    570 	if (is_ufs) {
    571 		if (!strncmp(slot_suffix_arr[slot], AB_SLOT_A_SUFFIX,
    572 					strlen(AB_SLOT_A_SUFFIX))){
    573 			//Set xbl_a as the boot lun
    574 			rc = gpt_utils_set_xbl_boot_partition(NORMAL_BOOT);
    575 		} else if (!strncmp(slot_suffix_arr[slot], AB_SLOT_B_SUFFIX,
    576 					strlen(AB_SLOT_B_SUFFIX))){
    577 			//Set xbl_b as the boot lun
    578 			rc = gpt_utils_set_xbl_boot_partition(BACKUP_BOOT);
    579 		} else {
    580 			//Something has gone terribly terribly wrong
    581 			ALOGE("%s: Unknown slot suffix!", __func__);
    582 			goto error;
    583 		}
    584 		if (rc) {
    585 			ALOGE("%s: Failed to switch xbl boot partition",
    586 					__func__);
    587 			goto error;
    588 		}
    589 	}
    590 	return 0;
    591 error:
    592 	return -1;
    593 }
    594 
    595 int set_slot_as_unbootable(struct boot_control_module *module, unsigned slot)
    596 {
    597 	if (boot_control_check_slot_sanity(module, slot) != 0) {
    598 		ALOGE("%s: Argument check failed", __func__);
    599 		goto error;
    600 	}
    601 	if (update_slot_attribute(slot_suffix_arr[slot],
    602 				ATTR_UNBOOTABLE)) {
    603 		goto error;
    604 	}
    605 	return 0;
    606 error:
    607 	ALOGE("%s: Failed to mark slot unbootable", __func__);
    608 	return -1;
    609 }
    610 
    611 int is_slot_bootable(struct boot_control_module *module, unsigned slot)
    612 {
    613 	int attr = 0;
    614 	char bootPartition[MAX_GPT_NAME_SIZE + 1] = {0};
    615 
    616 	if (boot_control_check_slot_sanity(module, slot) != 0) {
    617 		ALOGE("%s: Argument check failed", __func__);
    618 		goto error;
    619 	}
    620 	snprintf(bootPartition,
    621 			sizeof(bootPartition) - 1, "boot%s",
    622 			slot_suffix_arr[slot]);
    623 	attr = get_partition_attribute(bootPartition, ATTR_UNBOOTABLE);
    624 	if (attr >= 0)
    625 		return !attr;
    626 error:
    627 	return -1;
    628 }
    629 
    630 int is_slot_marked_successful(struct boot_control_module *module, unsigned slot)
    631 {
    632 	int attr = 0;
    633 	char bootPartition[MAX_GPT_NAME_SIZE + 1] = {0};
    634 
    635 	if (boot_control_check_slot_sanity(module, slot) != 0) {
    636 		ALOGE("%s: Argument check failed", __func__);
    637 		goto error;
    638 	}
    639 	snprintf(bootPartition,
    640 			sizeof(bootPartition) - 1,
    641 			"boot%s", slot_suffix_arr[slot]);
    642 	attr = get_partition_attribute(bootPartition, ATTR_BOOT_SUCCESSFUL);
    643 	if (attr >= 0)
    644 		return attr;
    645 error:
    646 	return -1;
    647 }
    648 
    649 static hw_module_methods_t boot_control_module_methods = {
    650 	.open = NULL,
    651 };
    652 
    653 boot_control_module_t HAL_MODULE_INFO_SYM = {
    654 	.common = {
    655 		.tag = HARDWARE_MODULE_TAG,
    656 		.module_api_version = 1,
    657 		.hal_api_version = 0,
    658 		.id = BOOT_CONTROL_HARDWARE_MODULE_ID,
    659 		.name = "Boot control HAL",
    660 		.author = "Code Aurora Forum",
    661 		.methods = &boot_control_module_methods,
    662 	},
    663 	.init = boot_control_init,
    664 	.getNumberSlots = get_number_slots,
    665 	.getCurrentSlot = get_current_slot,
    666 	.markBootSuccessful = mark_boot_successful,
    667 	.setActiveBootSlot = set_active_boot_slot,
    668 	.setSlotAsUnbootable = set_slot_as_unbootable,
    669 	.isSlotBootable = is_slot_bootable,
    670 	.getSuffix = get_suffix,
    671 	.isSlotMarkedSuccessful = is_slot_marked_successful,
    672 };
    673 #ifdef __cplusplus
    674 }
    675 #endif
    676