Integrate libsnapshot with the boot control HAL.
This patch translates UpdateState states into a MergeStatus from IBootControl 1.1, and asks the HAL to store it. Unfortunately this patch has to work around a few issues. The first issue is that Soong doesn't allow including only the headers from a HAL. The second issue is that entraining the headers requires linking to libraries that would otherwise not be needed in init. To address this, we now have three ways of linking to libsnapshot: 1. libsnapshot - Has access to gsid and HALs. 2. libsnapshot_nobinder - Has access to HALs, but not binder (for recovery). 3. libsnapshot_init - Does not use binder or HALs. The HAL code is #ifdef'd behind LIBSNAPSHOT_USE_HAL and we make use of forward declarations and dependency injection to minimize its spread. Bug: 139154945 Test: libsnapshot_test gtest Change-Id: I21ffd8a79a43d0589f2f71f346ac1b019584a183
This commit is contained in:
parent
d11c6f7fd8
commit
dfe6d07a4b
7 changed files with 146 additions and 5 deletions
|
@ -28,6 +28,7 @@ cc_defaults {
|
|||
"liblp",
|
||||
],
|
||||
static_libs: [
|
||||
"libcutils",
|
||||
"libdm",
|
||||
"libfs_mgr",
|
||||
"libfstab",
|
||||
|
@ -56,6 +57,17 @@ cc_defaults {
|
|||
},
|
||||
}
|
||||
|
||||
cc_defaults {
|
||||
name: "libsnapshot_hal_deps",
|
||||
cflags: [
|
||||
"-DLIBSNAPSHOT_USE_HAL",
|
||||
],
|
||||
shared_libs: [
|
||||
"android.hardware.boot@1.0",
|
||||
"android.hardware.boot@1.1",
|
||||
],
|
||||
}
|
||||
|
||||
filegroup {
|
||||
name: "libsnapshot_sources",
|
||||
srcs: [
|
||||
|
@ -75,7 +87,10 @@ cc_library_headers {
|
|||
|
||||
cc_library_static {
|
||||
name: "libsnapshot",
|
||||
defaults: ["libsnapshot_defaults"],
|
||||
defaults: [
|
||||
"libsnapshot_defaults",
|
||||
"libsnapshot_hal_deps",
|
||||
],
|
||||
srcs: [":libsnapshot_sources"],
|
||||
whole_static_libs: [
|
||||
"libfiemap_binder",
|
||||
|
@ -83,7 +98,7 @@ cc_library_static {
|
|||
}
|
||||
|
||||
cc_library_static {
|
||||
name: "libsnapshot_nobinder",
|
||||
name: "libsnapshot_init",
|
||||
defaults: ["libsnapshot_defaults"],
|
||||
srcs: [":libsnapshot_sources"],
|
||||
recovery_available: true,
|
||||
|
@ -92,6 +107,19 @@ cc_library_static {
|
|||
],
|
||||
}
|
||||
|
||||
cc_library_static {
|
||||
name: "libsnapshot_nobinder",
|
||||
defaults: [
|
||||
"libsnapshot_defaults",
|
||||
"libsnapshot_hal_deps",
|
||||
],
|
||||
srcs: [":libsnapshot_sources"],
|
||||
recovery_available: true,
|
||||
whole_static_libs: [
|
||||
"libfiemap_passthrough",
|
||||
],
|
||||
}
|
||||
|
||||
cc_test {
|
||||
name: "libsnapshot_test",
|
||||
defaults: ["libsnapshot_defaults"],
|
||||
|
@ -103,11 +131,13 @@ cc_test {
|
|||
],
|
||||
shared_libs: [
|
||||
"libbinder",
|
||||
"libhidlbase",
|
||||
"libprotobuf-cpp-lite",
|
||||
"libutils",
|
||||
],
|
||||
static_libs: [
|
||||
"libcutils",
|
||||
"android.hardware.boot@1.0",
|
||||
"android.hardware.boot@1.1",
|
||||
"libcrypto_static",
|
||||
"libfs_mgr",
|
||||
"libgmock",
|
||||
|
@ -134,10 +164,14 @@ cc_binary {
|
|||
"libsnapshot",
|
||||
],
|
||||
shared_libs: [
|
||||
"android.hardware.boot@1.0",
|
||||
"android.hardware.boot@1.1",
|
||||
"libbase",
|
||||
"libbinder",
|
||||
"libbinderthreadstate",
|
||||
"libext4_utils",
|
||||
"libfs_mgr",
|
||||
"libhidlbase",
|
||||
"liblog",
|
||||
"liblp",
|
||||
"libprotobuf-cpp-lite",
|
||||
|
|
|
@ -49,6 +49,16 @@ struct CreateLogicalPartitionParams;
|
|||
class IPartitionOpener;
|
||||
} // namespace fs_mgr
|
||||
|
||||
// Forward declare IBootControl types since we cannot include only the headers
|
||||
// with Soong. Note: keep the enum width in sync.
|
||||
namespace hardware {
|
||||
namespace boot {
|
||||
namespace V1_1 {
|
||||
enum class MergeStatus : int32_t;
|
||||
} // namespace V1_1
|
||||
} // namespace boot
|
||||
} // namespace hardware
|
||||
|
||||
namespace snapshot {
|
||||
|
||||
struct AutoDeleteCowImage;
|
||||
|
@ -94,6 +104,7 @@ class SnapshotManager final {
|
|||
using LpMetadata = android::fs_mgr::LpMetadata;
|
||||
using MetadataBuilder = android::fs_mgr::MetadataBuilder;
|
||||
using DeltaArchiveManifest = chromeos_update_engine::DeltaArchiveManifest;
|
||||
using MergeStatus = android::hardware::boot::V1_1::MergeStatus;
|
||||
|
||||
public:
|
||||
// Dependency injection for testing.
|
||||
|
@ -107,6 +118,7 @@ class SnapshotManager final {
|
|||
virtual std::string GetSuperDevice(uint32_t slot) const = 0;
|
||||
virtual const IPartitionOpener& GetPartitionOpener() const = 0;
|
||||
virtual bool IsOverlayfsSetup() const = 0;
|
||||
virtual bool SetBootControlMergeStatus(MergeStatus status) = 0;
|
||||
};
|
||||
|
||||
~SnapshotManager();
|
||||
|
@ -208,6 +220,7 @@ class SnapshotManager final {
|
|||
FRIEND_TEST(SnapshotTest, Merge);
|
||||
FRIEND_TEST(SnapshotTest, MergeCannotRemoveCow);
|
||||
FRIEND_TEST(SnapshotTest, NoMergeBeforeReboot);
|
||||
FRIEND_TEST(SnapshotTest, UpdateBootControlHal);
|
||||
FRIEND_TEST(SnapshotUpdateTest, SnapshotStatusFileWithoutCow);
|
||||
friend class SnapshotTest;
|
||||
friend class SnapshotUpdateTest;
|
||||
|
|
|
@ -29,6 +29,9 @@
|
|||
#include <android-base/parseint.h>
|
||||
#include <android-base/strings.h>
|
||||
#include <android-base/unique_fd.h>
|
||||
#ifdef LIBSNAPSHOT_USE_HAL
|
||||
#include <android/hardware/boot/1.1/IBootControl.h>
|
||||
#endif
|
||||
#include <ext4_utils/ext4_utils.h>
|
||||
#include <fs_mgr.h>
|
||||
#include <fs_mgr_dm_linear.h>
|
||||
|
@ -63,6 +66,7 @@ using android::fs_mgr::GetPartitionName;
|
|||
using android::fs_mgr::LpMetadata;
|
||||
using android::fs_mgr::MetadataBuilder;
|
||||
using android::fs_mgr::SlotNumberForSlotSuffix;
|
||||
using android::hardware::boot::V1_1::MergeStatus;
|
||||
using chromeos_update_engine::DeltaArchiveManifest;
|
||||
using chromeos_update_engine::InstallOperation;
|
||||
template <typename T>
|
||||
|
@ -86,11 +90,39 @@ class DeviceInfo final : public SnapshotManager::IDeviceInfo {
|
|||
return fs_mgr_get_super_partition_name(slot);
|
||||
}
|
||||
bool IsOverlayfsSetup() const override { return fs_mgr_overlayfs_is_setup(); }
|
||||
bool SetBootControlMergeStatus(MergeStatus status) override;
|
||||
|
||||
private:
|
||||
android::fs_mgr::PartitionOpener opener_;
|
||||
#ifdef LIBSNAPSHOT_USE_HAL
|
||||
android::sp<android::hardware::boot::V1_1::IBootControl> boot_control_;
|
||||
#endif
|
||||
};
|
||||
|
||||
bool DeviceInfo::SetBootControlMergeStatus([[maybe_unused]] MergeStatus status) {
|
||||
#ifdef LIBSNAPSHOT_USE_HAL
|
||||
if (!boot_control_) {
|
||||
auto hal = android::hardware::boot::V1_0::IBootControl::getService();
|
||||
if (!hal) {
|
||||
LOG(ERROR) << "Could not find IBootControl HAL";
|
||||
return false;
|
||||
}
|
||||
boot_control_ = android::hardware::boot::V1_1::IBootControl::castFrom(hal);
|
||||
if (!boot_control_) {
|
||||
LOG(ERROR) << "Could not find IBootControl 1.1 HAL";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (!boot_control_->setSnapshotMergeStatus(status)) {
|
||||
LOG(ERROR) << "Unable to set the snapshot merge status";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Note: IImageManager is an incomplete type in the header, so the default
|
||||
// destructor doesn't work.
|
||||
SnapshotManager::~SnapshotManager() {}
|
||||
|
@ -1592,6 +1624,35 @@ bool SnapshotManager::WriteUpdateState(LockedFile* file, UpdateState state) {
|
|||
PLOG(ERROR) << "Could not write to state file";
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef LIBSNAPSHOT_USE_HAL
|
||||
auto merge_status = MergeStatus::UNKNOWN;
|
||||
switch (state) {
|
||||
// The needs-reboot and completed cases imply that /data and /metadata
|
||||
// can be safely wiped, so we don't report a merge status.
|
||||
case UpdateState::None:
|
||||
case UpdateState::MergeNeedsReboot:
|
||||
case UpdateState::MergeCompleted:
|
||||
merge_status = MergeStatus::NONE;
|
||||
break;
|
||||
case UpdateState::Initiated:
|
||||
case UpdateState::Unverified:
|
||||
merge_status = MergeStatus::SNAPSHOTTED;
|
||||
break;
|
||||
case UpdateState::Merging:
|
||||
case UpdateState::MergeFailed:
|
||||
merge_status = MergeStatus::MERGING;
|
||||
break;
|
||||
default:
|
||||
// Note that Cancelled flows to here - it is never written, since
|
||||
// it only communicates a transient state to the caller.
|
||||
LOG(ERROR) << "Unexpected update status: " << state;
|
||||
break;
|
||||
}
|
||||
if (!device_->SetBootControlMergeStatus(merge_status)) {
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -617,6 +617,31 @@ TEST_F(SnapshotTest, FlashSuperDuringMerge) {
|
|||
ASSERT_EQ(sm->GetUpdateState(), UpdateState::None);
|
||||
}
|
||||
|
||||
TEST_F(SnapshotTest, UpdateBootControlHal) {
|
||||
ASSERT_TRUE(AcquireLock());
|
||||
|
||||
ASSERT_TRUE(sm->WriteUpdateState(lock_.get(), UpdateState::None));
|
||||
ASSERT_EQ(test_device->merge_status(), MergeStatus::NONE);
|
||||
|
||||
ASSERT_TRUE(sm->WriteUpdateState(lock_.get(), UpdateState::Initiated));
|
||||
ASSERT_EQ(test_device->merge_status(), MergeStatus::SNAPSHOTTED);
|
||||
|
||||
ASSERT_TRUE(sm->WriteUpdateState(lock_.get(), UpdateState::Unverified));
|
||||
ASSERT_EQ(test_device->merge_status(), MergeStatus::SNAPSHOTTED);
|
||||
|
||||
ASSERT_TRUE(sm->WriteUpdateState(lock_.get(), UpdateState::Merging));
|
||||
ASSERT_EQ(test_device->merge_status(), MergeStatus::MERGING);
|
||||
|
||||
ASSERT_TRUE(sm->WriteUpdateState(lock_.get(), UpdateState::MergeNeedsReboot));
|
||||
ASSERT_EQ(test_device->merge_status(), MergeStatus::NONE);
|
||||
|
||||
ASSERT_TRUE(sm->WriteUpdateState(lock_.get(), UpdateState::MergeCompleted));
|
||||
ASSERT_EQ(test_device->merge_status(), MergeStatus::NONE);
|
||||
|
||||
ASSERT_TRUE(sm->WriteUpdateState(lock_.get(), UpdateState::MergeFailed));
|
||||
ASSERT_EQ(test_device->merge_status(), MergeStatus::MERGING);
|
||||
}
|
||||
|
||||
class SnapshotUpdateTest : public SnapshotTest {
|
||||
public:
|
||||
void SetUp() override {
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
#include <android/hardware/boot/1.1/IBootControl.h>
|
||||
#include <gmock/gmock.h>
|
||||
#include <gtest/gtest.h>
|
||||
#include <libfiemap/image_manager.h>
|
||||
|
@ -32,6 +33,7 @@ namespace snapshot {
|
|||
using android::fs_mgr::IPropertyFetcher;
|
||||
using android::fs_mgr::MetadataBuilder;
|
||||
using android::fs_mgr::testing::MockPropertyFetcher;
|
||||
using android::hardware::boot::V1_1::MergeStatus;
|
||||
using chromeos_update_engine::DeltaArchiveManifest;
|
||||
using chromeos_update_engine::PartitionUpdate;
|
||||
using testing::_;
|
||||
|
@ -81,16 +83,22 @@ class TestDeviceInfo : public SnapshotManager::IDeviceInfo {
|
|||
const android::fs_mgr::IPartitionOpener& GetPartitionOpener() const override {
|
||||
return *opener_.get();
|
||||
}
|
||||
bool SetBootControlMergeStatus(MergeStatus status) override {
|
||||
merge_status_ = status;
|
||||
return true;
|
||||
}
|
||||
bool IsOverlayfsSetup() const override { return false; }
|
||||
|
||||
void set_slot_suffix(const std::string& suffix) { slot_suffix_ = suffix; }
|
||||
void set_fake_super(const std::string& path) {
|
||||
opener_ = std::make_unique<TestPartitionOpener>(path);
|
||||
}
|
||||
MergeStatus merge_status() const { return merge_status_; }
|
||||
|
||||
private:
|
||||
std::string slot_suffix_ = "_a";
|
||||
std::unique_ptr<TestPartitionOpener> opener_;
|
||||
MergeStatus merge_status_;
|
||||
};
|
||||
|
||||
class SnapshotTestPropertyFetcher : public android::fs_mgr::testing::MockPropertyFetcher {
|
||||
|
|
|
@ -69,7 +69,7 @@ cc_defaults {
|
|||
"libprotobuf-cpp-lite",
|
||||
"libpropertyinfoserializer",
|
||||
"libpropertyinfoparser",
|
||||
"libsnapshot_nobinder",
|
||||
"libsnapshot_init",
|
||||
],
|
||||
shared_libs: [
|
||||
"libbacktrace",
|
||||
|
|
|
@ -114,7 +114,7 @@ LOCAL_STATIC_LIBRARIES := \
|
|||
libmodprobe \
|
||||
libext2_uuid \
|
||||
libprotobuf-cpp-lite \
|
||||
libsnapshot_nobinder \
|
||||
libsnapshot_init \
|
||||
|
||||
LOCAL_SANITIZE := signed-integer-overflow
|
||||
# First stage init is weird: it may start without stdout/stderr, and no /proc.
|
||||
|
|
Loading…
Reference in a new issue