301 lines
8.4 KiB
C++
301 lines
8.4 KiB
C++
#include <errno.h>
|
|
#include <string.h>
|
|
|
|
#include <cutils/properties.h>
|
|
#include <hardware/boot_control.h>
|
|
#include <hardware/hardware.h>
|
|
|
|
#include <libavb_ab/libavb_ab.h>
|
|
#include <libavb_user/libavb_user.h>
|
|
|
|
#include <android-base/file.h>
|
|
#include <android-base/logging.h>
|
|
#include <android-base/properties.h>
|
|
#include <android-base/stringprintf.h>
|
|
#include <android-base/unique_fd.h>
|
|
|
|
#include <bootloader_message/bootloader_message.h>
|
|
#include <android/hardware/boot/1.1/IBootControl.h>
|
|
|
|
|
|
#include "rk_boot_control.h"
|
|
|
|
#define LOG_TAG "Rockchip bootctrl"
|
|
|
|
#include <log/log.h>
|
|
|
|
namespace android {
|
|
namespace bootable {
|
|
|
|
using ::android::hardware::boot::V1_1::MergeStatus;
|
|
|
|
static AvbOps* ops = NULL;
|
|
|
|
// Initialize the boot_control_private struct with the information from
|
|
// the bootloader_message buffer stored in |boot_ctrl|. Returns whether the
|
|
// initialization succeeded.
|
|
bool BootControl::Init() {
|
|
setenv("ANDROID_LOG_TAGS", "*:v", 1);
|
|
LOG(INFO) << "rk BootControl Init ";
|
|
|
|
if (!InitMiscVirtualAbMessageIfNeeded()) {
|
|
LOG(ERROR) << "rk BootControl Init InitMiscVirtualAbMessageIfNeeded failed ";
|
|
return false;
|
|
}
|
|
|
|
if (ops != NULL) {
|
|
return true;
|
|
}
|
|
|
|
ops = avb_ops_user_new();
|
|
if (ops == NULL) {
|
|
LOG(ERROR) << "rk BootControl Init Unable to allocate AvbOps instance. ";
|
|
}
|
|
return true;
|
|
}
|
|
|
|
unsigned int BootControl::GetNumberSlots() {
|
|
setenv("ANDROID_LOG_TAGS", "*:v", 1);
|
|
LOG(INFO) << "rk BootControl GetNumberSlots ";
|
|
return 2;
|
|
}
|
|
|
|
unsigned int BootControl::GetCurrentSlot() {
|
|
//char propbuf[PROPERTY_VALUE_MAX];
|
|
|
|
LOG(INFO) << "rk BootControl GetCurrentSlot ";
|
|
//property_get("ro.boot.slot_suffix", propbuf, "");
|
|
std::string suffix_prop = android::base::GetProperty("ro.boot.slot_suffix", "");
|
|
if (suffix_prop.empty()) {
|
|
LOG(ERROR) << "rk BootControl GetCurrentSlot Slot suffix property is not set";
|
|
return 0;
|
|
}
|
|
|
|
|
|
if (strcmp(suffix_prop.c_str(), "_a") == 0) {
|
|
return 0;
|
|
} else if (strcmp(suffix_prop.c_str(), "_b") == 0) {
|
|
return 1;
|
|
} else {
|
|
avb_errorv("rk BootControl GetCurrentSlot Unexpected slot suffix '", suffix_prop.c_str(), "'.\n", NULL);
|
|
LOG(ERROR) << "rk BootControl GetCurrentSlot Unexpected slot suffix: '" << suffix_prop.c_str() << "' ";
|
|
return 0;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
bool BootControl::MarkBootSuccessful() {
|
|
setenv("ANDROID_LOG_TAGS", "*:v", 1);
|
|
LOG(INFO) << "rk BootControl MarkBootSuccessful ";
|
|
if (avb_ab_mark_slot_successful(ops->ab_ops, GetCurrentSlot()) ==
|
|
AVB_IO_RESULT_OK) {
|
|
return 0;
|
|
} else {
|
|
return -EIO;
|
|
}
|
|
}
|
|
|
|
unsigned int BootControl::GetActiveBootSlot() {
|
|
AvbABData ab_data;
|
|
|
|
setenv("ANDROID_LOG_TAGS", "*:v", 1);
|
|
LOG(INFO) << "rk BootControl GetActiveBootSlot ";
|
|
|
|
if (avb_ab_data_read(ops->ab_ops, &ab_data) != AVB_IO_RESULT_OK) {
|
|
LOG(INFO) << "rk BootControl GetActiveBootSlot avb_ab_data_read failed ";
|
|
return false;
|
|
}
|
|
// Use the current slot by default.
|
|
unsigned int current_slot = GetCurrentSlot();
|
|
unsigned int num_slots_ = GetNumberSlots();
|
|
unsigned int active_boot_slot = current_slot;
|
|
unsigned int max_priority = ab_data.slots[current_slot].priority;
|
|
|
|
// Find the slot with the highest priority.
|
|
for (unsigned int i = 0; i < num_slots_; ++i) {
|
|
if (ab_data.slots[i].priority > max_priority) {
|
|
max_priority = ab_data.slots[i].priority;
|
|
active_boot_slot = i;
|
|
}
|
|
}
|
|
|
|
return active_boot_slot;
|
|
}
|
|
|
|
|
|
bool BootControl::SetActiveBootSlot(unsigned int slot) {
|
|
LOG(INFO) << "rk BootControl SetActiveBootSlot ";
|
|
if (slot >= GetNumberSlots()) {
|
|
return -EINVAL;
|
|
} else if (avb_ab_mark_slot_active(ops->ab_ops, slot) == AVB_IO_RESULT_OK) {
|
|
return 0;
|
|
} else {
|
|
return -EIO;
|
|
}
|
|
}
|
|
|
|
bool BootControl::SetSlotAsUnbootable(unsigned int slot) {
|
|
LOG(INFO) << "rk BootControl SetSlotAsUnbootable ";
|
|
if (slot >= GetNumberSlots()) {
|
|
return -EINVAL;
|
|
} else if (avb_ab_mark_slot_unbootable(ops->ab_ops, slot) ==
|
|
AVB_IO_RESULT_OK) {
|
|
return 0;
|
|
} else {
|
|
return -EIO;
|
|
}
|
|
}
|
|
|
|
bool BootControl::IsSlotBootable(unsigned int slot) {
|
|
AvbABData ab_data;
|
|
bool is_bootable;
|
|
|
|
LOG(INFO) << "rk BootControl IsSlotBootable ";
|
|
|
|
if (slot >= GetNumberSlots()) {
|
|
return -EINVAL;
|
|
} else if (avb_ab_data_read(ops->ab_ops, &ab_data) != AVB_IO_RESULT_OK) {
|
|
return -EIO;
|
|
}
|
|
|
|
is_bootable = (ab_data.slots[slot].priority > 0) &&
|
|
(ab_data.slots[slot].successful_boot ||
|
|
(ab_data.slots[slot].tries_remaining > 0));
|
|
|
|
return is_bootable ? 1 : 0;
|
|
}
|
|
|
|
bool BootControl::IsSlotMarkedSuccessful(unsigned int slot) {
|
|
AvbABData ab_data;
|
|
bool is_marked_successful;
|
|
|
|
LOG(INFO) << "rk BootControl IsSlotMarkedSuccessful ";
|
|
|
|
if (slot >= GetNumberSlots()) {
|
|
return -EINVAL;
|
|
} else if (avb_ab_data_read(ops->ab_ops, &ab_data) != AVB_IO_RESULT_OK) {
|
|
return -EIO;
|
|
}
|
|
|
|
is_marked_successful = ab_data.slots[slot].successful_boot;
|
|
|
|
return is_marked_successful ? 1 : 0;
|
|
}
|
|
|
|
bool BootControl::IsValidSlot(unsigned int slot) {
|
|
LOG(INFO) << "rk BootControl IsValidSlot ";
|
|
|
|
return slot < 2;
|
|
}
|
|
|
|
const char* BootControl::GetSuffix(unsigned int slot) {
|
|
static const char* suffix[2] = {"_a", "_b"};
|
|
|
|
LOG(INFO) << "rk BootControl GetSuffix ";
|
|
|
|
if (slot >= 2) {
|
|
return NULL;
|
|
}
|
|
return suffix[slot];
|
|
}
|
|
|
|
bool BootControl::SetSnapshotMergeStatus(MergeStatus status) {
|
|
LOG(INFO) << "rk BootControl SetSnapshotMergeStatus ";
|
|
return SetMiscVirtualAbMergeStatus(GetCurrentSlot(), status);
|
|
}
|
|
|
|
MergeStatus BootControl::GetSnapshotMergeStatus() {
|
|
MergeStatus status;
|
|
|
|
LOG(INFO) << "rk BootControl GetSnapshotMergeStatus ";
|
|
if (!GetMiscVirtualAbMergeStatus(GetCurrentSlot(), &status)) {
|
|
return MergeStatus::UNKNOWN;
|
|
}
|
|
return status;
|
|
}
|
|
|
|
|
|
|
|
// 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() {
|
|
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 &&
|
|
message.magic == MISC_VIRTUAL_AB_MAGIC_HEADER) {
|
|
// Already initialized.
|
|
return true;
|
|
}
|
|
|
|
message = {};
|
|
message.version = MISC_VIRTUAL_AB_MESSAGE_VERSION;
|
|
message.magic = MISC_VIRTUAL_AB_MAGIC_HEADER;
|
|
if (!WriteMiscVirtualAbMessage(message, &err)) {
|
|
LOG(ERROR) << "Could not write merge status: " << err;
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
// Save the current merge status as well as the current slot.
|
|
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;
|
|
}
|
|
|
|
|
|
// 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) {
|
|
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
|