platform_hardware_interfaces/boot/aidl/client/BootControlClient.cpp
Kelvin Zhang 781b4ff19e Check if AIDL service is declared before calling wait
If bootctl AIDL service is not installed and we call waitForService,
caller will block indefinitely. So check with
AServiceManager_isDeclared before calling waitForService.

Test: th
Bug: 227536004
Change-Id: I551040b222c6c9127fe79aceb36bb3d69b52c3b6
2022-06-27 16:34:28 -07:00

364 lines
13 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_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:
BootControlClientAidl(std::shared_ptr<IBootControl> module) : module_(module) {}
BootControlVersion GetVersion() const override { return BootControlVersion::BOOTCTL_AIDL; }
~BootControlClientAidl() = default;
virtual int32_t GetNumSlots() const {
int32_t ret = -1;
LOG_NDK_STATUS(module_->getNumberSlots(&ret));
return ret;
}
int32_t GetCurrentSlot() const {
int32_t ret = -1;
LOG_NDK_STATUS(module_->getCurrentSlot(&ret));
return ret;
}
MergeStatus getSnapshotMergeStatus() const {
MergeStatus status = MergeStatus::UNKNOWN;
LOG_NDK_STATUS(module_->getSnapshotMergeStatus(&status));
return status;
}
std::string GetSuffix(int32_t slot) const {
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 {
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) {
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) {
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 {
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() {
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) {
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_;
};
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 {
const auto ret = module_v1_->getNumberSlots();
if (!ret.isOk()) {
LOG(ERROR) << __FUNCTION__ << " failed " << ret.description();
}
return ret.withDefault(-1);
}
int32_t GetCurrentSlot() const {
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 {
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 {
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) {
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) {
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() {
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 {
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 {
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) {
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 {
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