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 
boot_control_init(struct boot_control_module * module)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.
get_partition_attribute(char * partname,enum part_attr_type part_attr)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
update_slot_attribute(const char * slot,enum part_attr_type ab_attr)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 
get_number_slots(struct boot_control_module * module)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 
get_current_slot(struct boot_control_module * module)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 
boot_control_check_slot_sanity(struct boot_control_module * module,unsigned slot)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 
mark_boot_successful(struct boot_control_module * module)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 
get_suffix(struct boot_control_module * module,unsigned slot)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.
boot_ctl_get_disk_info(char * 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
boot_ctl_set_active_slot_for_partitions(vector<string> part_list,unsigned slot)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 
set_active_boot_slot(struct boot_control_module * module,unsigned slot)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 
set_slot_as_unbootable(struct boot_control_module * module,unsigned slot)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 
is_slot_bootable(struct boot_control_module * module,unsigned slot)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 
is_slot_marked_successful(struct boot_control_module * module,unsigned slot)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