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