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