bootloader_message: Add helpers for handling IBootControl MergeStatus.
Move merge_status from bootloader_control_ab, which is in vendor space, to a new generic AOSP struct in system space. This will allow more devices to share the same HAL implementation. This patch also changes libboot_control to compensate for merge_status moving out of vendor space. The reference HAL library now also provides separate helper functions for managing the merge status, so devices using a custom boot control HAL can still take advantage of the new misc implementation. Bug: 139156011 Test: manual test Change-Id: I5cd824e25f9d07aad1476301def5cdc3f506b029
This commit is contained in:
parent
8243388d57
commit
cf8427af89
4 changed files with 163 additions and 9 deletions
|
@ -62,5 +62,28 @@ class BootControl {
|
|||
unsigned int current_slot_ = 0;
|
||||
};
|
||||
|
||||
// Helper functions to write the Virtual A/B merge status message. These are
|
||||
// separate because BootControl uses bootloader_control_ab in vendor space,
|
||||
// whereas the Virtual A/B merge status is in system space. A HAL might not
|
||||
// use bootloader_control_ab, but may want to use the AOSP method of maintaining
|
||||
// the merge status.
|
||||
|
||||
// If the Virtual A/B message has not yet been initialized, then initialize it.
|
||||
// This should be called when the BootControl HAL first loads.
|
||||
//
|
||||
// If the Virtual A/B message in misc was already initialized, true is returned.
|
||||
// If initialization was attempted, but failed, false is returned, and the HAL
|
||||
// should fail to load.
|
||||
bool InitMiscVirtualAbMessageIfNeeded();
|
||||
|
||||
// Save the current merge status as well as the current slot.
|
||||
bool SetMiscVirtualAbMergeStatus(unsigned int current_slot,
|
||||
android::hardware::boot::V1_1::MergeStatus status);
|
||||
|
||||
// Return the current merge status. If the saved status is SNAPSHOTTED but the
|
||||
// slot hasn't changed, the status returned will be NONE.
|
||||
bool GetMiscVirtualAbMergeStatus(unsigned int current_slot,
|
||||
android::hardware::boot::V1_1::MergeStatus* status);
|
||||
|
||||
} // namespace bootable
|
||||
} // namespace android
|
||||
|
|
|
@ -232,6 +232,10 @@ bool BootControl::Init() {
|
|||
UpdateAndSaveBootloaderControl(device.c_str(), &boot_ctrl);
|
||||
}
|
||||
|
||||
if (!InitMiscVirtualAbMessageIfNeeded()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
num_slots_ = boot_ctrl.nb_slot;
|
||||
return true;
|
||||
}
|
||||
|
@ -335,18 +339,15 @@ bool BootControl::IsValidSlot(unsigned int slot) {
|
|||
}
|
||||
|
||||
bool BootControl::SetSnapshotMergeStatus(MergeStatus status) {
|
||||
bootloader_control bootctrl;
|
||||
if (!LoadBootloaderControl(misc_device_, &bootctrl)) return false;
|
||||
|
||||
bootctrl.merge_status = (unsigned int)status;
|
||||
return UpdateAndSaveBootloaderControl(misc_device_, &bootctrl);
|
||||
return SetMiscVirtualAbMergeStatus(current_slot_, status);
|
||||
}
|
||||
|
||||
MergeStatus BootControl::GetSnapshotMergeStatus() {
|
||||
bootloader_control bootctrl;
|
||||
if (!LoadBootloaderControl(misc_device_, &bootctrl)) return MergeStatus::UNKNOWN;
|
||||
|
||||
return (MergeStatus)bootctrl.merge_status;
|
||||
MergeStatus status;
|
||||
if (!GetMiscVirtualAbMergeStatus(current_slot_, &status)) {
|
||||
return MergeStatus::UNKNOWN;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
const char* BootControl::GetSuffix(unsigned int slot) {
|
||||
|
@ -356,5 +357,66 @@ const char* BootControl::GetSuffix(unsigned int slot) {
|
|||
return kSlotSuffixes[slot];
|
||||
}
|
||||
|
||||
bool InitMiscVirtualAbMessageIfNeeded() {
|
||||
std::string err;
|
||||
misc_virtual_ab_message message;
|
||||
if (!ReadMiscVirtualAbMessage(&message, &err)) {
|
||||
LOG(ERROR) << "Could not read merge status: " << err;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (message.version == MISC_VIRTUAL_AB_MESSAGE_VERSION) {
|
||||
// Already initialized.
|
||||
return true;
|
||||
}
|
||||
|
||||
message = {};
|
||||
message.version = MISC_VIRTUAL_AB_MESSAGE_VERSION;
|
||||
if (!WriteMiscVirtualAbMessage(message, &err)) {
|
||||
LOG(ERROR) << "Could not write merge status: " << err;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SetMiscVirtualAbMergeStatus(unsigned int current_slot,
|
||||
android::hardware::boot::V1_1::MergeStatus status) {
|
||||
std::string err;
|
||||
misc_virtual_ab_message message;
|
||||
|
||||
if (!ReadMiscVirtualAbMessage(&message, &err)) {
|
||||
LOG(ERROR) << "Could not read merge status: " << err;
|
||||
return false;
|
||||
}
|
||||
|
||||
message.merge_status = static_cast<uint8_t>(status);
|
||||
message.source_slot = current_slot;
|
||||
if (!WriteMiscVirtualAbMessage(message, &err)) {
|
||||
LOG(ERROR) << "Could not write merge status: " << err;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GetMiscVirtualAbMergeStatus(unsigned int current_slot,
|
||||
android::hardware::boot::V1_1::MergeStatus* status) {
|
||||
std::string err;
|
||||
misc_virtual_ab_message message;
|
||||
|
||||
if (!ReadMiscVirtualAbMessage(&message, &err)) {
|
||||
LOG(ERROR) << "Could not read merge status: " << err;
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the slot reverted after having created a snapshot, then the snapshot will
|
||||
// be thrown away at boot. Thus we don't count this as being in a snapshotted
|
||||
// state.
|
||||
*status = static_cast<MergeStatus>(message.merge_status);
|
||||
if (*status == MergeStatus::SNAPSHOTTED && current_slot == message.source_slot) {
|
||||
*status = MergeStatus::NONE;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace bootable
|
||||
} // namespace android
|
||||
|
|
|
@ -292,6 +292,49 @@ bool WriteMiscPartitionVendorSpace(const void* data, size_t size, size_t offset,
|
|||
err);
|
||||
}
|
||||
|
||||
static bool ValidateSystemSpaceRegion(size_t offset, size_t size, std::string* err) {
|
||||
if (size <= SYSTEM_SPACE_SIZE_IN_MISC && offset <= (SYSTEM_SPACE_SIZE_IN_MISC - size)) {
|
||||
return true;
|
||||
}
|
||||
*err = android::base::StringPrintf("Out of bound access (offset %zu size %zu)", offset, size);
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool ReadMiscPartitionSystemSpace(void* data, size_t size, size_t offset, std::string* err) {
|
||||
if (!ValidateSystemSpaceRegion(offset, size, err)) {
|
||||
return false;
|
||||
}
|
||||
auto misc_blk_device = get_misc_blk_device(err);
|
||||
if (misc_blk_device.empty()) {
|
||||
return false;
|
||||
}
|
||||
return read_misc_partition(data, size, misc_blk_device, SYSTEM_SPACE_OFFSET_IN_MISC + offset,
|
||||
err);
|
||||
}
|
||||
|
||||
static bool WriteMiscPartitionSystemSpace(const void* data, size_t size, size_t offset,
|
||||
std::string* err) {
|
||||
if (!ValidateSystemSpaceRegion(offset, size, err)) {
|
||||
return false;
|
||||
}
|
||||
auto misc_blk_device = get_misc_blk_device(err);
|
||||
if (misc_blk_device.empty()) {
|
||||
return false;
|
||||
}
|
||||
return write_misc_partition(data, size, misc_blk_device, SYSTEM_SPACE_OFFSET_IN_MISC + offset,
|
||||
err);
|
||||
}
|
||||
|
||||
bool ReadMiscVirtualAbMessage(misc_virtual_ab_message* message, std::string* err) {
|
||||
return ReadMiscPartitionSystemSpace(message, sizeof(*message),
|
||||
offsetof(misc_system_space_layout, virtual_ab_message), err);
|
||||
}
|
||||
|
||||
bool WriteMiscVirtualAbMessage(const misc_virtual_ab_message& message, std::string* err) {
|
||||
return WriteMiscPartitionSystemSpace(&message, sizeof(message),
|
||||
offsetof(misc_system_space_layout, virtual_ab_message), err);
|
||||
}
|
||||
|
||||
extern "C" bool write_reboot_bootloader(void) {
|
||||
std::string err;
|
||||
return write_reboot_bootloader(&err);
|
||||
|
|
|
@ -185,6 +185,28 @@ static_assert(sizeof(struct bootloader_control) ==
|
|||
"struct bootloader_control has wrong size");
|
||||
#endif
|
||||
|
||||
// Holds Virtual A/B merge status information. Current version is 1. New fields
|
||||
// must be added to the end.
|
||||
struct misc_virtual_ab_message {
|
||||
uint8_t version;
|
||||
uint8_t merge_status; // IBootControl 1.1, MergeStatus enum.
|
||||
uint8_t source_slot; // Slot number when merge_status was written.
|
||||
uint8_t reserved[61];
|
||||
} __attribute__((packed));
|
||||
|
||||
#define MISC_VIRTUAL_AB_MESSAGE_VERSION 1
|
||||
|
||||
#if (__STDC_VERSION__ >= 201112L) || defined(__cplusplus)
|
||||
static_assert(sizeof(struct misc_virtual_ab_message) == 64,
|
||||
"struct misc_virtual_ab_message has wrong size");
|
||||
#endif
|
||||
|
||||
// This struct is not meant to be used directly, rather, it is to make
|
||||
// computation of offsets easier. New fields must be added to the end.
|
||||
struct misc_system_space_layout {
|
||||
misc_virtual_ab_message virtual_ab_message;
|
||||
} __attribute__((packed));
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
#include <string>
|
||||
|
@ -247,6 +269,10 @@ bool ReadMiscPartitionVendorSpace(void* data, size_t size, size_t offset, std::s
|
|||
// offset is in relative to the start of the vendor space.
|
||||
bool WriteMiscPartitionVendorSpace(const void* data, size_t size, size_t offset, std::string* err);
|
||||
|
||||
// Read or write the Virtual A/B message from system space in /misc.
|
||||
bool ReadMiscVirtualAbMessage(misc_virtual_ab_message* message, std::string* err);
|
||||
bool WriteMiscVirtualAbMessage(const misc_virtual_ab_message& message, std::string* err);
|
||||
|
||||
#else
|
||||
|
||||
#include <stdbool.h>
|
||||
|
|
Loading…
Reference in a new issue