mirror of
https://github.com/Evolution-X/hardware_interfaces
synced 2026-02-01 16:09:42 +00:00
On binder death, the cookie is the value that is passed to the death recipient. This value shouldn't be nullptr here since our onDeath() function expects an instance of BootControlClientAidl. If that doesn't exist, we have a null pointer dereference which will cause update_engine to crash. Bug: 369289491 Test: crash bootctl service Change-Id: I0bed4680c23b7d3516ed43aa566c4474962244fa
382 lines
14 KiB
C++
382 lines
14 KiB
C++
/*
|
|
* Copyright (C) 2022 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#include <BootControlClient.h>
|
|
|
|
#include <aidl/android/hardware/boot/IBootControl.h>
|
|
#include <android-base/logging.h>
|
|
#include <android/binder_ibinder.h>
|
|
#include <android/binder_manager.h>
|
|
#include <android/hardware/boot/1.0/IBootControl.h>
|
|
#include <android/hardware/boot/1.1/IBootControl.h>
|
|
#include <android/hardware/boot/1.2/IBootControl.h>
|
|
#include "utils/StrongPointer.h"
|
|
|
|
#define CONCAT(x, y) x##y
|
|
|
|
#define LOG_NDK_STATUS(x) \
|
|
do { \
|
|
const auto CONCAT(status, __COUNTER__) = x; \
|
|
if (!CONCAT(status, __COUNTER__).isOk()) { \
|
|
LOG(ERROR) << #x << " failed " << CONCAT(status, __COUNTER__).getDescription(); \
|
|
} \
|
|
} while (0)
|
|
|
|
using aidl::android::hardware::boot::MergeStatus;
|
|
|
|
std::ostream& operator<<(std::ostream& os, MergeStatus status) {
|
|
switch (status) {
|
|
case MergeStatus::NONE:
|
|
os << "MergeStatus::NONE";
|
|
break;
|
|
case MergeStatus::UNKNOWN:
|
|
os << "MergeStatus::UNKNOWN";
|
|
break;
|
|
case MergeStatus::SNAPSHOTTED:
|
|
os << "MergeStatus::SNAPSHOTTED";
|
|
break;
|
|
case MergeStatus::MERGING:
|
|
os << "MergeStatus::MERGING";
|
|
break;
|
|
case MergeStatus::CANCELLED:
|
|
os << "MergeStatus::CANCELLED";
|
|
break;
|
|
default:
|
|
os << static_cast<int>(status);
|
|
break;
|
|
}
|
|
return os;
|
|
}
|
|
|
|
namespace android::hal {
|
|
class BootControlClientAidl final : public BootControlClient {
|
|
using IBootControl = ::aidl::android::hardware::boot::IBootControl;
|
|
|
|
public:
|
|
explicit BootControlClientAidl(std::shared_ptr<IBootControl> module)
|
|
: module_(module),
|
|
boot_control_death_recipient(AIBinder_DeathRecipient_new(onBootControlServiceDied)) {
|
|
binder_status_t status =
|
|
AIBinder_linkToDeath(module->asBinder().get(), boot_control_death_recipient, this);
|
|
if (status != STATUS_OK) {
|
|
LOG(ERROR) << "Could not link to binder death";
|
|
return;
|
|
}
|
|
}
|
|
|
|
BootControlVersion GetVersion() const override { return BootControlVersion::BOOTCTL_AIDL; }
|
|
|
|
~BootControlClientAidl() {
|
|
if (boot_control_death_recipient) {
|
|
AIBinder_unlinkToDeath(module_->asBinder().get(), boot_control_death_recipient, this);
|
|
}
|
|
}
|
|
|
|
void onBootControlServiceDied() { LOG(ERROR) << "boot control service AIDL died"; }
|
|
|
|
int32_t GetNumSlots() const override {
|
|
int32_t ret = -1;
|
|
LOG_NDK_STATUS(module_->getNumberSlots(&ret));
|
|
return ret;
|
|
}
|
|
|
|
int32_t GetCurrentSlot() const override {
|
|
int32_t ret = -1;
|
|
LOG_NDK_STATUS(module_->getCurrentSlot(&ret));
|
|
return ret;
|
|
}
|
|
MergeStatus getSnapshotMergeStatus() const override {
|
|
MergeStatus status = MergeStatus::UNKNOWN;
|
|
LOG_NDK_STATUS(module_->getSnapshotMergeStatus(&status));
|
|
return status;
|
|
}
|
|
std::string GetSuffix(int32_t slot) const override {
|
|
std::string ret;
|
|
const auto status = module_->getSuffix(slot, &ret);
|
|
if (!status.isOk()) {
|
|
LOG(ERROR) << __FUNCTION__ << "(" << slot << ")" << " failed "
|
|
<< status.getDescription();
|
|
return {};
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
std::optional<bool> IsSlotBootable(int32_t slot) const override {
|
|
bool ret = false;
|
|
const auto status = module_->isSlotBootable(slot, &ret);
|
|
if (!status.isOk()) {
|
|
LOG(ERROR) << __FUNCTION__ << "(" << slot << ")" << " failed "
|
|
<< status.getDescription();
|
|
return {};
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
CommandResult MarkSlotUnbootable(int32_t slot) override {
|
|
const auto status = module_->setSlotAsUnbootable(slot);
|
|
if (!status.isOk()) {
|
|
LOG(ERROR) << __FUNCTION__ << "(" << slot << ")" << " failed "
|
|
<< status.getDescription();
|
|
}
|
|
return {.success = status.isOk(), .errMsg = status.getDescription()};
|
|
}
|
|
|
|
CommandResult SetActiveBootSlot(int slot) override {
|
|
const auto status = module_->setActiveBootSlot(slot);
|
|
if (!status.isOk()) {
|
|
LOG(ERROR) << __FUNCTION__ << "(" << slot << ")" << " failed "
|
|
<< status.getDescription();
|
|
}
|
|
return {.success = status.isOk(), .errMsg = status.getDescription()};
|
|
}
|
|
int GetActiveBootSlot() const {
|
|
int ret = -1;
|
|
LOG_NDK_STATUS(module_->getActiveBootSlot(&ret));
|
|
return ret;
|
|
}
|
|
|
|
// Check if |slot| is marked boot successfully.
|
|
std::optional<bool> IsSlotMarkedSuccessful(int slot) const override {
|
|
bool ret = false;
|
|
const auto status = module_->isSlotMarkedSuccessful(slot, &ret);
|
|
if (!status.isOk()) {
|
|
LOG(ERROR) << __FUNCTION__ << "(" << slot << ")" << " failed "
|
|
<< status.getDescription();
|
|
return {};
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
CommandResult MarkBootSuccessful() override {
|
|
const auto status = module_->markBootSuccessful();
|
|
if (!status.isOk()) {
|
|
LOG(ERROR) << __FUNCTION__ << " failed " << status.getDescription();
|
|
}
|
|
return {.success = status.isOk(), .errMsg = status.getDescription()};
|
|
}
|
|
|
|
CommandResult SetSnapshotMergeStatus(
|
|
aidl::android::hardware::boot::MergeStatus merge_status) override {
|
|
const auto status = module_->setSnapshotMergeStatus(merge_status);
|
|
if (!status.isOk()) {
|
|
LOG(ERROR) << __FUNCTION__ << "(" << merge_status << ")" << " failed "
|
|
<< status.getDescription();
|
|
}
|
|
return {.success = status.isOk(), .errMsg = status.getDescription()};
|
|
}
|
|
|
|
private:
|
|
const std::shared_ptr<IBootControl> module_;
|
|
AIBinder_DeathRecipient* boot_control_death_recipient;
|
|
static void onBootControlServiceDied(void* client) {
|
|
BootControlClientAidl* self = static_cast<BootControlClientAidl*>(client);
|
|
self->onBootControlServiceDied();
|
|
}
|
|
};
|
|
|
|
using namespace android::hardware::boot;
|
|
|
|
class BootControlClientHIDL final : public BootControlClient {
|
|
public:
|
|
BootControlClientHIDL(android::sp<V1_0::IBootControl> module_v1,
|
|
android::sp<V1_1::IBootControl> module_v1_1,
|
|
android::sp<V1_2::IBootControl> module_v1_2)
|
|
: module_v1_(module_v1), module_v1_1_(module_v1_1), module_v1_2_(module_v1_2) {
|
|
CHECK(module_v1_ != nullptr);
|
|
}
|
|
BootControlVersion GetVersion() const override {
|
|
if (module_v1_2_ != nullptr) {
|
|
return BootControlVersion::BOOTCTL_V1_2;
|
|
} else if (module_v1_1_ != nullptr) {
|
|
return BootControlVersion::BOOTCTL_V1_1;
|
|
} else {
|
|
return BootControlVersion::BOOTCTL_V1_0;
|
|
}
|
|
}
|
|
int32_t GetNumSlots() const override {
|
|
const auto ret = module_v1_->getNumberSlots();
|
|
if (!ret.isOk()) {
|
|
LOG(ERROR) << __FUNCTION__ << " failed " << ret.description();
|
|
}
|
|
return ret.withDefault(-1);
|
|
}
|
|
|
|
int32_t GetCurrentSlot() const override {
|
|
const auto ret = module_v1_->getCurrentSlot();
|
|
if (!ret.isOk()) {
|
|
LOG(ERROR) << __FUNCTION__ << " failed " << ret.description();
|
|
}
|
|
return ret.withDefault(-1);
|
|
}
|
|
|
|
std::string GetSuffix(int32_t slot) const override {
|
|
std::string suffix;
|
|
const auto ret = module_v1_->getSuffix(
|
|
slot,
|
|
[&](const ::android::hardware::hidl_string& slotSuffix) { suffix = slotSuffix; });
|
|
if (!ret.isOk()) {
|
|
LOG(ERROR) << __FUNCTION__ << "(" << slot << ")" << " failed " << ret.description();
|
|
}
|
|
return suffix;
|
|
}
|
|
|
|
std::optional<bool> IsSlotBootable(int32_t slot) const override {
|
|
const auto ret = module_v1_->isSlotBootable(slot);
|
|
if (!ret.isOk()) {
|
|
LOG(ERROR) << __FUNCTION__ << "(" << slot << ")" << " failed " << ret.description();
|
|
return {};
|
|
}
|
|
const auto bool_result = ret.withDefault(V1_0::BoolResult::INVALID_SLOT);
|
|
if (bool_result == V1_0::BoolResult::INVALID_SLOT) {
|
|
return {};
|
|
}
|
|
return bool_result == V1_0::BoolResult::TRUE;
|
|
}
|
|
|
|
CommandResult MarkSlotUnbootable(int32_t slot) override {
|
|
CommandResult result;
|
|
const auto ret =
|
|
module_v1_->setSlotAsUnbootable(slot, [&](const V1_0::CommandResult& error) {
|
|
result.success = error.success;
|
|
result.errMsg = error.errMsg;
|
|
});
|
|
if (!ret.isOk()) {
|
|
LOG(ERROR) << __FUNCTION__ << "(" << slot << ")" << " failed " << ret.description();
|
|
}
|
|
return result;
|
|
}
|
|
|
|
CommandResult SetActiveBootSlot(int32_t slot) override {
|
|
CommandResult result;
|
|
const auto ret = module_v1_->setActiveBootSlot(slot, [&](const V1_0::CommandResult& error) {
|
|
result.success = error.success;
|
|
result.errMsg = error.errMsg;
|
|
});
|
|
if (!ret.isOk()) {
|
|
LOG(ERROR) << __FUNCTION__ << "(" << slot << ")" << " failed " << ret.description();
|
|
}
|
|
return result;
|
|
}
|
|
|
|
CommandResult MarkBootSuccessful() override {
|
|
CommandResult result;
|
|
const auto ret = module_v1_->markBootSuccessful([&](const V1_0::CommandResult& error) {
|
|
result.success = error.success;
|
|
result.errMsg = error.errMsg;
|
|
});
|
|
if (!ret.isOk()) {
|
|
LOG(ERROR) << __FUNCTION__ << " failed " << ret.description();
|
|
}
|
|
return result;
|
|
}
|
|
|
|
std::optional<bool> IsSlotMarkedSuccessful(int32_t slot) const override {
|
|
const auto ret = module_v1_->isSlotMarkedSuccessful(slot);
|
|
if (!ret.isOk()) {
|
|
LOG(ERROR) << __FUNCTION__ << "(" << slot << ")" << " failed " << ret.description();
|
|
return {};
|
|
}
|
|
const auto bool_result = ret.withDefault(V1_0::BoolResult::INVALID_SLOT);
|
|
if (bool_result == V1_0::BoolResult::INVALID_SLOT) {
|
|
return {};
|
|
}
|
|
return bool_result == V1_0::BoolResult::TRUE;
|
|
}
|
|
|
|
MergeStatus getSnapshotMergeStatus() const override {
|
|
if (module_v1_1_ == nullptr) {
|
|
LOG(ERROR) << __FUNCTION__ << " is unsupported, requires at least boot v1.1";
|
|
return MergeStatus::UNKNOWN;
|
|
}
|
|
const auto ret = module_v1_1_->getSnapshotMergeStatus();
|
|
if (!ret.isOk()) {
|
|
LOG(ERROR) << __FUNCTION__ << " failed " << ret.description();
|
|
}
|
|
return static_cast<MergeStatus>(
|
|
ret.withDefault(static_cast<V1_1::MergeStatus>(MergeStatus::UNKNOWN)));
|
|
}
|
|
|
|
CommandResult SetSnapshotMergeStatus(MergeStatus merge_status) override {
|
|
if (module_v1_1_ == nullptr) {
|
|
return {.success = false,
|
|
.errMsg = "setSnapshotMergeStatus is unsupported, requires at least boot v1.1"};
|
|
}
|
|
const auto ret =
|
|
module_v1_1_->setSnapshotMergeStatus(static_cast<V1_1::MergeStatus>(merge_status));
|
|
if (!ret.isOk()) {
|
|
LOG(ERROR) << __FUNCTION__ << "(" << merge_status << ")" << " failed "
|
|
<< ret.description();
|
|
}
|
|
return {.success = ret.isOk(), .errMsg = ret.description()};
|
|
}
|
|
|
|
int32_t GetActiveBootSlot() const override {
|
|
if (module_v1_2_ == nullptr) {
|
|
LOG(ERROR) << __FUNCTION__ << " is unsupported, requires at least boot v1.2";
|
|
return -1;
|
|
}
|
|
const auto ret = module_v1_2_->getActiveBootSlot();
|
|
if (!ret.isOk()) {
|
|
LOG(ERROR) << __FUNCTION__ << " failed " << ret.description();
|
|
}
|
|
return ret.withDefault(-1);
|
|
}
|
|
|
|
private:
|
|
android::sp<V1_0::IBootControl> module_v1_;
|
|
android::sp<V1_1::IBootControl> module_v1_1_;
|
|
android::sp<V1_2::IBootControl> module_v1_2_;
|
|
};
|
|
|
|
std::unique_ptr<BootControlClient> BootControlClient::WaitForService() {
|
|
const auto instance_name =
|
|
std::string(::aidl::android::hardware::boot::IBootControl::descriptor) + "/default";
|
|
if (AServiceManager_isDeclared(instance_name.c_str())) {
|
|
auto module = ::aidl::android::hardware::boot::IBootControl::fromBinder(
|
|
ndk::SpAIBinder(AServiceManager_waitForService(instance_name.c_str())));
|
|
if (module == nullptr) {
|
|
LOG(ERROR) << "AIDL " << instance_name
|
|
<< " is declared but waitForService returned nullptr.";
|
|
return nullptr;
|
|
}
|
|
LOG(INFO) << "Using AIDL version of IBootControl";
|
|
return std::make_unique<BootControlClientAidl>(module);
|
|
}
|
|
LOG(INFO) << "AIDL IBootControl not available, falling back to HIDL.";
|
|
|
|
android::sp<V1_0::IBootControl> v1_0_module;
|
|
android::sp<V1_1::IBootControl> v1_1_module;
|
|
android::sp<V1_2::IBootControl> v1_2_module;
|
|
v1_0_module = V1_0::IBootControl::getService();
|
|
if (v1_0_module == nullptr) {
|
|
LOG(ERROR) << "Error getting bootctrl v1.0 module.";
|
|
return nullptr;
|
|
}
|
|
v1_1_module = V1_1::IBootControl::castFrom(v1_0_module);
|
|
v1_2_module = V1_2::IBootControl::castFrom(v1_0_module);
|
|
if (v1_2_module != nullptr) {
|
|
LOG(INFO) << "Using HIDL version 1.2 of IBootControl";
|
|
} else if (v1_1_module != nullptr) {
|
|
LOG(INFO) << "Using HIDL version 1.1 of IBootControl";
|
|
} else {
|
|
LOG(INFO) << "Using HIDL version 1.0 of IBootControl";
|
|
}
|
|
|
|
return std::make_unique<BootControlClientHIDL>(v1_0_module, v1_1_module, v1_2_module);
|
|
}
|
|
|
|
} // namespace android::hal
|