bootcontrol: Reduce the number of writes in the set active slot function
We now write the 'gpt_disk' structure back to storage only once per each
physical disk.
Also did a minor cleanup of the code.
Bug: 28352938
Bug: 29436641
Change-Id: Id4fd887fe2978f9cd17447e9a1b715f0a8df5073
diff --git a/Android.mk b/Android.mk
index 14873fb..3e664cc 100644
--- a/Android.mk
+++ b/Android.mk
@@ -5,7 +5,7 @@
LOCAL_C_INCLUDES += $(TARGET_OUT_HEADERS)/gpt-utils/inc
LOCAL_CFLAGS += -Wall -Werror
LOCAL_SHARED_LIBRARIES += liblog librecovery_updater_msm libcutils
-LOCAL_SRC_FILES := boot_control.c
+LOCAL_SRC_FILES := boot_control.cpp
LOCAL_MODULE_RELATIVE_PATH := hw
LOCAL_MODULE := bootctrl.$(TARGET_BOARD_PLATFORM)
include $(BUILD_SHARED_LIBRARY)
diff --git a/boot_control.c b/boot_control.cpp
similarity index 72%
rename from boot_control.c
rename to boot_control.cpp
index d5e2e4b..539c52c 100644
--- a/boot_control.c
+++ b/boot_control.cpp
@@ -26,6 +26,13 @@
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+#include <map>
+#include <list>
+#include <string>
+#include <vector>
+#ifdef __cplusplus
+extern "C" {
+#endif
#include <errno.h>
#define LOG_TAG "bootcontrolhal"
#include <cutils/log.h>
@@ -46,6 +53,18 @@
#define LUN_NAME_END_LOC 14
#define BOOT_SLOT_PROP "ro.boot.slot_suffix"
+#define SLOT_ACTIVE 1
+#define SLOT_INACTIVE 2
+#define UPDATE_SLOT(pentry, guid, slot_state) ({ \
+ memcpy(pentry, guid, TYPE_GUID_SIZE); \
+ if (slot_state == SLOT_ACTIVE)\
+ *(pentry + AB_FLAG_OFFSET) = AB_SLOT_ACTIVE_VAL; \
+ else if (slot_state == SLOT_INACTIVE) \
+ *(pentry + AB_FLAG_OFFSET) = (*(pentry + AB_FLAG_OFFSET)& \
+ ~AB_PARTITION_ATTR_SLOT_ACTIVE); \
+ })
+
+using namespace std;
const char *slot_suffix_arr[] = {
AB_SLOT_A_SUFFIX,
AB_SLOT_B_SUFFIX,
@@ -169,7 +188,7 @@
"%s%s",
ptn_list[i],
slot);
- disk = gpt_disk_alloc(disk);
+ disk = gpt_disk_alloc();
if (!disk) {
ALOGE("%s: Failed to alloc disk struct",
__func__);
@@ -294,36 +313,18 @@
return 0;
}
-static unsigned get_current_active_slot(struct boot_control_module *module)
+static int boot_control_check_slot_sanity(struct boot_control_module *module,
+ unsigned slot)
{
- uint32_t num_slots = 0;
- char bootPartition[MAX_GPT_NAME_SIZE + 1];
- unsigned i = 0;
- if (!module) {
- ALOGE("%s: Invalid argument", __func__);
- goto error;
+ if (!module)
+ return -1;
+ uint32_t num_slots = get_number_slots(module);
+ if ((num_slots < 1) || (slot > num_slots - 1)) {
+ ALOGE("Invalid slot number");
+ return -1;
}
- num_slots = get_number_slots(module);
- if (num_slots <= 1) {
- //Slot 0 is the only slot around.
- return 0;
- }
- //Iterate through a list of partitons named as boot+suffix
- //and see which one is currently active.
- for (i = 0; slot_suffix_arr[i] != NULL ; i++) {
- memset(bootPartition, '\0', sizeof(bootPartition));
- snprintf(bootPartition, sizeof(bootPartition) - 1,
- "boot%s",
- slot_suffix_arr[i]);
- if (get_partition_attribute(bootPartition,
- ATTR_SLOT_ACTIVE) == 1)
- return i;
- }
-error:
- //The HAL spec requires that we return a number between
- //0 to num_slots - 1. Since something went wrong here we
- //are just going to return the default slot.
return 0;
+
}
int mark_boot_successful(struct boot_control_module *module)
@@ -346,133 +347,121 @@
const char *get_suffix(struct boot_control_module *module, unsigned slot)
{
- unsigned num_slots = 0;
- if (!module) {
- ALOGE("%s: Invalid arg", __func__);
- }
- num_slots = get_number_slots(module);
- if (num_slots < 1 || slot > num_slots - 1)
+ if (boot_control_check_slot_sanity(module, slot) != 0)
return NULL;
else
return slot_suffix_arr[slot];
}
-int set_active_boot_slot(struct boot_control_module *module, unsigned slot)
+
+//Return a gpt disk structure representing the disk that holds
+//partition.
+static struct gpt_disk* boot_ctl_get_disk_info(char *partition)
{
- const char ptn_list[][MAX_GPT_NAME_SIZE] = { AB_PTN_LIST };
+ struct gpt_disk *disk = NULL;
+ if (!partition)
+ return NULL;
+ disk = gpt_disk_alloc();
+ if (!disk) {
+ ALOGE("%s: Failed to alloc disk",
+ __func__);
+ goto error;
+ }
+ if (gpt_disk_get_disk_info(partition, disk)) {
+ ALOGE("failed to get disk info for %s",
+ partition);
+ goto error;
+ }
+ return disk;
+error:
+ if (disk)
+ gpt_disk_free(disk);
+ return NULL;
+}
+
+//The argument here is a vector of partition names(including the slot suffix)
+//that lie on a single disk
+static int boot_ctl_set_active_slot_for_partitions(vector<string> part_list,
+ unsigned slot)
+{
+ char buf[PATH_MAX] = {0};
+ struct gpt_disk *disk = NULL;
char slotA[MAX_GPT_NAME_SIZE + 1] = {0};
char slotB[MAX_GPT_NAME_SIZE + 1] = {0};
char active_guid[TYPE_GUID_SIZE + 1] = {0};
char inactive_guid[TYPE_GUID_SIZE + 1] = {0};
- struct gpt_disk *disk = NULL;
- //Pointer to partition entry of current 'A' partition
+ //Pointer to the partition entry of current 'A' partition
uint8_t *pentryA = NULL;
uint8_t *pentryA_bak = NULL;
//Pointer to partition entry of current 'B' partition
uint8_t *pentryB = NULL;
uint8_t *pentryB_bak = NULL;
- uint8_t *slot_info = NULL;
- uint32_t i;
- int rc = -1;
- char buf[PATH_MAX] = {0};
struct stat st;
- unsigned num_slots = 0;
- unsigned current_slot = 0;
- int is_ufs = gpt_utils_is_ufs_device();
+ vector<string>::iterator partition_iterator;
- if (!module) {
- ALOGE("%s: Invalid arg", __func__);
- goto error;
- }
- num_slots = get_number_slots(module);
- if ((num_slots < 1) || (slot > num_slots - 1)) {
- ALOGE("%s: Unable to get num slots/Invalid slot value",
- __func__);
- goto error;
- }
- current_slot = get_current_active_slot(module);
- if (current_slot == slot) {
- //Nothing to do here. Just return
- return 0;
- }
- for (i=0; i < ARRAY_SIZE(ptn_list); i++) {
- //XBL is handled differrently for ufs devices
- if (is_ufs && !strncmp(ptn_list[i], PTN_XBL, strlen(PTN_XBL)))
- continue;
- memset(buf, '\0', sizeof(buf));
+ for (partition_iterator = part_list.begin();
+ partition_iterator != part_list.end();
+ partition_iterator++) {
+ //Chop off the slot suffix from the partition name to
+ //make the string easier to work with.
+ string prefix = *partition_iterator;
+ if (prefix.size() < (strlen(AB_SLOT_A_SUFFIX) + 1)) {
+ ALOGE("Invalid partition name: %s", prefix.c_str());
+ goto error;
+ }
+ prefix.resize(prefix.size() - strlen(AB_SLOT_A_SUFFIX));
//Check if A/B versions of this ptn exist
- snprintf(buf, sizeof(buf) - 1,
- "%s/%s%s",
- BOOT_DEV_DIR,
- ptn_list[i],
- AB_SLOT_A_SUFFIX
- );
- if (stat(buf, &st)) {
- //partition does not have _a version
- continue;
- }
- memset(buf, '\0', sizeof(buf));
- snprintf(buf, sizeof(buf) - 1,
- "%s/%s%s",
- BOOT_DEV_DIR,
- ptn_list[i],
- AB_SLOT_B_SUFFIX
- );
- if (stat(buf, &st)) {
- //partition does not have _a version
- continue;
- }
- disk = gpt_disk_alloc();
- if (!disk)
- goto error;
- memset(slotA, 0, sizeof(slotA));
- memset(slotB, 0, sizeof(slotB));
- snprintf(slotA, sizeof(slotA) - 1, "%s%s",
- ptn_list[i],
+ snprintf(buf, sizeof(buf) - 1, "%s/%s%s", BOOT_DEV_DIR,
+ prefix.c_str(),
AB_SLOT_A_SUFFIX);
- snprintf(slotB, sizeof(slotB) - 1,"%s%s",
- ptn_list[i],
+ if (stat(buf, &st))
+ continue;
+ memset(buf, '\0', sizeof(buf));
+ snprintf(buf, sizeof(buf) - 1, "%s/%s%s", BOOT_DEV_DIR,
+ prefix.c_str(),
AB_SLOT_B_SUFFIX);
- //It is assumed that both the A and B slots reside on the
- //same physical disk
- if (gpt_disk_get_disk_info(slotA, disk))
- goto error;
- //Get partition entry for slot A from primary table
+ if (stat(buf, &st))
+ continue;
+ memset(slotA, 0, sizeof(slotA));
+ memset(slotB, 0, sizeof(slotA));
+ snprintf(slotA, sizeof(slotA) - 1, "%s%s", prefix.c_str(),
+ AB_SLOT_A_SUFFIX);
+ snprintf(slotB, sizeof(slotB) - 1,"%s%s", prefix.c_str(),
+ AB_SLOT_B_SUFFIX);
+ //Get the disk containing the partitions that were passed in.
+ //All partitions passed in must lie on the same disk.
+ if (!disk) {
+ disk = boot_ctl_get_disk_info(slotA);
+ if (!disk)
+ goto error;
+ }
+ //Get partition entry for slot A & B from the primary
+ //and backup tables.
pentryA = gpt_disk_get_pentry(disk, slotA, PRIMARY_GPT);
- //Get partition entry for slot A from backup table
pentryA_bak = gpt_disk_get_pentry(disk, slotA, SECONDARY_GPT);
- //Get partition entry for slot B from primary table
pentryB = gpt_disk_get_pentry(disk, slotB, PRIMARY_GPT);
- //Get partition entry for slot B from backup table
pentryB_bak = gpt_disk_get_pentry(disk, slotB, SECONDARY_GPT);
if ( !pentryA || !pentryA_bak || !pentryB || !pentryB_bak) {
- //Something has gone wrong here.We know that we have
- //_a and _b versions of this partition due to the
- //check at the start of the loop so none of these
- //should be NULL.
+ //None of these should be NULL since we have already
+ //checked for A & B versions earlier.
ALOGE("Slot pentries for %s not found.",
- ptn_list[i]);
+ prefix.c_str());
goto error;
}
memset(active_guid, '\0', sizeof(active_guid));
memset(inactive_guid, '\0', sizeof(inactive_guid));
if (get_partition_attribute(slotA, ATTR_SLOT_ACTIVE) == 1) {
//A is the current active slot
- memcpy((void*)active_guid,
- (const void*)pentryA,
+ memcpy((void*)active_guid, (const void*)pentryA,
TYPE_GUID_SIZE);
- memcpy((void*)inactive_guid,
- (const void*)pentryB,
+ memcpy((void*)inactive_guid,(const void*)pentryB,
TYPE_GUID_SIZE);
-
} else if (get_partition_attribute(slotB,
ATTR_SLOT_ACTIVE) == 1) {
//B is the current active slot
- memcpy((void*)active_guid,
- (const void*)pentryB,
+ memcpy((void*)active_guid, (const void*)pentryB,
TYPE_GUID_SIZE);
- memcpy((void*)inactive_guid,
- (const void*)pentryA,
+ memcpy((void*)inactive_guid, (const void*)pentryA,
TYPE_GUID_SIZE);
} else {
ALOGE("Both A & B are inactive..Aborting");
@@ -481,64 +470,97 @@
if (!strncmp(slot_suffix_arr[slot], AB_SLOT_A_SUFFIX,
strlen(AB_SLOT_A_SUFFIX))){
//Mark A as active in primary table
- memcpy(pentryA, active_guid, TYPE_GUID_SIZE);
- slot_info = pentryA + AB_FLAG_OFFSET;
- *slot_info = AB_SLOT_ACTIVE_VAL;
-
+ UPDATE_SLOT(pentryA, active_guid, SLOT_ACTIVE);
//Mark A as active in backup table
- memcpy(pentryA_bak, active_guid, TYPE_GUID_SIZE);
- slot_info = pentryA_bak + AB_FLAG_OFFSET;
- *slot_info = AB_SLOT_ACTIVE_VAL;
-
+ UPDATE_SLOT(pentryA_bak, active_guid, SLOT_ACTIVE);
//Mark B as inactive in primary table
- memcpy(pentryB, inactive_guid, TYPE_GUID_SIZE);
- slot_info = pentryB + AB_FLAG_OFFSET;
- *slot_info = *(slot_info) &
- ~AB_PARTITION_ATTR_SLOT_ACTIVE;
-
+ UPDATE_SLOT(pentryB, inactive_guid, SLOT_INACTIVE);
//Mark B as inactive in backup table
- memcpy(pentryB_bak, inactive_guid, TYPE_GUID_SIZE);
- slot_info = pentryB_bak + AB_FLAG_OFFSET;
- *slot_info = *(slot_info) &
- ~AB_PARTITION_ATTR_SLOT_ACTIVE;
+ UPDATE_SLOT(pentryB_bak, inactive_guid, SLOT_INACTIVE);
} else if (!strncmp(slot_suffix_arr[slot], AB_SLOT_B_SUFFIX,
strlen(AB_SLOT_B_SUFFIX))){
//Mark B as active in primary table
- memcpy(pentryB, active_guid, TYPE_GUID_SIZE);
- slot_info = pentryB + AB_FLAG_OFFSET;
- *slot_info = AB_SLOT_ACTIVE_VAL;
-
+ UPDATE_SLOT(pentryB, active_guid, SLOT_ACTIVE);
//Mark B as active in backup table
- memcpy(pentryB_bak, active_guid, TYPE_GUID_SIZE);
- slot_info = pentryB_bak + AB_FLAG_OFFSET;
- *slot_info = AB_SLOT_ACTIVE_VAL;
-
+ UPDATE_SLOT(pentryB_bak, active_guid, SLOT_ACTIVE);
//Mark A as inavtive in primary table
- memcpy(pentryA, inactive_guid, TYPE_GUID_SIZE);
- slot_info = pentryA + AB_FLAG_OFFSET;
- *slot_info = *(slot_info) &
- ~AB_PARTITION_ATTR_SLOT_ACTIVE;
-
+ UPDATE_SLOT(pentryA, inactive_guid, SLOT_INACTIVE);
//Mark A as inactive in backup table
- memcpy(pentryA_bak, inactive_guid, TYPE_GUID_SIZE);
- slot_info = pentryA_bak + AB_FLAG_OFFSET;
- *slot_info = *(slot_info) &
- ~AB_PARTITION_ATTR_SLOT_ACTIVE;
+ UPDATE_SLOT(pentryA_bak, inactive_guid, SLOT_INACTIVE);
} else {
//Something has gone terribly terribly wrong
ALOGE("%s: Unknown slot suffix!", __func__);
goto error;
}
- if (gpt_disk_update_crc(disk) != 0) {
- ALOGE("%s: Failed to update gpt_disk crc", __func__);
- goto error;
+ if (disk) {
+ if (gpt_disk_update_crc(disk) != 0) {
+ ALOGE("%s: Failed to update gpt_disk crc",
+ __func__);
+ goto error;
+ }
}
- if (gpt_disk_commit(disk) != 0) {
- ALOGE("%s: Failed to commit disk info", __func__);
+ }
+ //write updated content to disk
+ if (disk) {
+ if (gpt_disk_commit(disk)) {
+ ALOGE("Failed to commit disk entry");
goto error;
}
gpt_disk_free(disk);
- disk = NULL;
+ }
+ return 0;
+
+error:
+ if (disk)
+ gpt_disk_free(disk);
+ return -1;
+}
+
+int set_active_boot_slot(struct boot_control_module *module, unsigned slot)
+{
+ map<string, vector<string>> ptn_map;
+ vector<string> ptn_vec;
+ const char ptn_list[][MAX_GPT_NAME_SIZE] = { AB_PTN_LIST };
+ uint32_t i;
+ int rc = -1;
+ int is_ufs = gpt_utils_is_ufs_device();
+ map<string, vector<string>>::iterator map_iter;
+ vector<string>::iterator string_iter;
+
+ if (boot_control_check_slot_sanity(module, slot)) {
+ ALOGE("%s: Bad arguments", __func__);
+ goto error;
+ }
+ //The partition list just contains prefixes(without the _a/_b) of the
+ //partitions that support A/B. In order to get the layout we need the
+ //actual names. To do this we append the slot suffix to every member
+ //in the list.
+ for (i = 0; i < ARRAY_SIZE(ptn_list); i++) {
+ //XBL is handled differrently for ufs devices so ignore it
+ if (is_ufs && !strncmp(ptn_list[i], PTN_XBL, strlen(PTN_XBL)))
+ continue;
+ //The partition list will be the list of _a partitions
+ string cur_ptn = ptn_list[i];
+ cur_ptn.append(AB_SLOT_A_SUFFIX);
+ ptn_vec.push_back(cur_ptn);
+
+ }
+ //The partition map gives us info in the following format:
+ // [path_to_block_device_1]--><partitions on device 1>
+ // [path_to_block_device_2]--><partitions on device 2>
+ // ...
+ // ...
+ // eg:
+ // [/dev/block/sdb]---><system, boot, rpm, tz,....>
+ if (gpt_utils_get_partition_map(ptn_vec, ptn_map)) {
+ ALOGE("%s: Failed to get partition map",
+ __func__);
+ goto error;
+ }
+ for (map_iter = ptn_map.begin(); map_iter != ptn_map.end(); map_iter++){
+ if (map_iter->second.size() < 1)
+ continue;
+ boot_ctl_set_active_slot_for_partitions(map_iter->second, slot);
}
if (is_ufs) {
if (!strncmp(slot_suffix_arr[slot], AB_SLOT_A_SUFFIX,
@@ -562,22 +584,13 @@
}
return 0;
error:
- if (disk)
- gpt_disk_free(disk);
return -1;
}
int set_slot_as_unbootable(struct boot_control_module *module, unsigned slot)
{
- unsigned num_slots = 0;
- if (!module) {
- ALOGE("%s: Invalid argument", __func__);
- goto error;
- }
- num_slots = get_number_slots(module);
- if (num_slots < 1 || slot > num_slots - 1) {
- ALOGE("%s: Unable to get num_slots/Invalid slot value",
- __func__);
+ if (boot_control_check_slot_sanity(module, slot) != 0) {
+ ALOGE("%s: Argument check failed", __func__);
goto error;
}
if (update_slot_attribute(slot_suffix_arr[slot],
@@ -592,17 +605,11 @@
int is_slot_bootable(struct boot_control_module *module, unsigned slot)
{
- unsigned num_slots = 0;
int attr = 0;
char bootPartition[MAX_GPT_NAME_SIZE + 1] = {0};
- if (!module) {
- ALOGE("%s: Invalid argument", __func__);
- goto error;
- }
- num_slots = get_number_slots(module);
- if (num_slots < 1 || slot > num_slots - 1) {
- ALOGE("%s: Unable to get num_slots/Invalid slot value",
- __func__);
+
+ if (boot_control_check_slot_sanity(module, slot) != 0) {
+ ALOGE("%s: Argument check failed", __func__);
goto error;
}
snprintf(bootPartition,
@@ -617,17 +624,11 @@
int is_slot_marked_successful(struct boot_control_module *module, unsigned slot)
{
- unsigned num_slots = 0;
int attr = 0;
char bootPartition[MAX_GPT_NAME_SIZE + 1] = {0};
- if (!module) {
- ALOGE("%s: Invalid argument", __func__);
- goto error;
- }
- num_slots = get_number_slots(module);
- if (num_slots < 1 || slot > num_slots - 1) {
- ALOGE("%s: Unable to get num_slots/Invalid slot value",
- __func__);
+
+ if (boot_control_check_slot_sanity(module, slot) != 0) {
+ ALOGE("%s: Argument check failed", __func__);
goto error;
}
snprintf(bootPartition,
@@ -664,3 +665,6 @@
.getSuffix = get_suffix,
.isSlotMarkedSuccessful = is_slot_marked_successful,
};
+#ifdef __cplusplus
+}
+#endif