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