summaryrefslogtreecommitdiff
path: root/boot_control_android_unittest.cc
diff options
context:
space:
mode:
authorYifan Hong <elsk@google.com>2018-12-07 12:09:37 -0800
committerTao Bao <tbao@google.com>2018-12-14 10:45:33 -0800
commit1d9077f65d50cc19db82c514cd856e58a6e95fdf (patch)
tree88330634e780ac46f5422d09541c1255c5a1e8d4 /boot_control_android_unittest.cc
parent35410ede7a8ad111d7715c164ec5d859514ba2ee (diff)
Improve the logic for mapping target dynamic partitions.
While applying a retrofit update on a dynamic-partitions-enabled build, it should always use static target partitions. Otherwise reading them from the updated partition metadata would end up using mismatching info. This CL improves the logic in detecting and handling such a case. - It identifies a retrofit or regular update based on the absence of DynamicPartitionMetadata field. - Upon seeing that, it skips updating partition metadata for the target slot, and looks up target partitions as static partitions. - Source partitions will always be loaded according to the actual state. This CL also removes the re-mapping of the target partitions from InitPartitionMetadata(). It only needs to unmap those partitions, since they may become inconsistent with the updated metadata. However, it's unnecessary to re-map them, which will be done later as part of GetDynamicPartitionDevice(). Also updated tests to reflect this. Bug: 120775936 Test: update_engine_unittests Test: Apply an update with dynamic partitions; abort and resume. Test: Apply a retrofit update; abort and resume the update. Change-Id: Ic07bd98847e91a003101266e426c4d23666810f2
Diffstat (limited to 'boot_control_android_unittest.cc')
-rw-r--r--boot_control_android_unittest.cc120
1 files changed, 62 insertions, 58 deletions
diff --git a/boot_control_android_unittest.cc b/boot_control_android_unittest.cc
index d7068108..79f86625 100644
--- a/boot_control_android_unittest.cc
+++ b/boot_control_android_unittest.cc
@@ -24,10 +24,12 @@
#include <fs_mgr.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
+#include <libdm/dm.h>
#include "update_engine/mock_boot_control_hal.h"
#include "update_engine/mock_dynamic_partition_control.h"
+using android::dm::DmDeviceState;
using android::fs_mgr::MetadataBuilder;
using android::hardware::Void;
using testing::_;
@@ -49,7 +51,7 @@ namespace chromeos_update_engine {
constexpr const uint32_t kMaxNumSlots = 2;
constexpr const char* kSlotSuffixes[kMaxNumSlots] = {"_a", "_b"};
constexpr const char* kFakeDevicePath = "/fake/dev/path/";
-constexpr const char* kFakeMappedPath = "/fake/mapped/path/";
+constexpr const char* kFakeDmDevicePath = "/fake/dm/dev/path/";
constexpr const uint32_t kFakeMetadataSize = 65536;
constexpr const char* kDefaultGroup = "foo";
@@ -125,6 +127,10 @@ inline std::string GetDevice(const std::string& name) {
return kFakeDevicePath + name;
}
+inline std::string GetDmDevice(const std::string& name) {
+ return kFakeDmDevicePath + name;
+}
+
// TODO(elsk): fs_mgr_get_super_partition_name should be mocked.
inline std::string GetSuperDevice(uint32_t slot) {
return GetDevice(fs_mgr_get_super_partition_name(slot));
@@ -277,11 +283,17 @@ class BootControlAndroidTest : public ::testing::Test {
.WillByDefault(Return(true));
ON_CALL(dynamicControl(), IsDynamicPartitionsRetrofit())
.WillByDefault(Return(false));
+ ON_CALL(dynamicControl(), DeviceExists(_)).WillByDefault(Return(true));
ON_CALL(dynamicControl(), GetDeviceDir(_))
.WillByDefault(Invoke([](auto path) {
*path = kFakeDevicePath;
return true;
}));
+ ON_CALL(dynamicControl(), GetDmDevicePathByName(_, _))
+ .WillByDefault(Invoke([](auto partition_name_suffix, auto device) {
+ *device = GetDmDevice(partition_name_suffix);
+ return true;
+ }));
}
// Return the mocked HAL module.
@@ -310,31 +322,6 @@ class BootControlAndroidTest : public ::testing::Test {
}));
}
- // Expect that MapPartitionOnDeviceMapper is called on target() metadata slot
- // with each partition in |partitions|.
- void ExpectMap(const std::set<std::string>& partitions,
- bool force_writable = true) {
- // Error when MapPartitionOnDeviceMapper is called on unknown arguments.
- ON_CALL(dynamicControl(), MapPartitionOnDeviceMapper(_, _, _, _, _))
- .WillByDefault(Return(false));
-
- for (const auto& partition : partitions) {
- EXPECT_CALL(
- dynamicControl(),
- MapPartitionOnDeviceMapper(
- GetSuperDevice(target()), partition, target(), force_writable, _))
- .WillOnce(Invoke([this](auto, auto partition, auto, auto, auto path) {
- auto it = mapped_devices_.find(partition);
- if (it != mapped_devices_.end()) {
- *path = it->second;
- return true;
- }
- mapped_devices_[partition] = *path = kFakeMappedPath + partition;
- return true;
- }));
- }
- }
-
// Expect that UnmapPartitionOnDeviceMapper is called on target() metadata
// slot with each partition in |partitions|.
void ExpectUnmap(const std::set<std::string>& partitions) {
@@ -351,11 +338,6 @@ class BootControlAndroidTest : public ::testing::Test {
}
}
- void ExpectRemap(const std::set<std::string>& partitions) {
- ExpectUnmap(partitions);
- ExpectMap(partitions);
- }
-
void ExpectDevicesAreMapped(const std::set<std::string>& partitions) {
ASSERT_EQ(partitions.size(), mapped_devices_.size());
for (const auto& partition : partitions) {
@@ -440,11 +422,10 @@ TEST_P(BootControlAndroidTestP, NeedGrowIfSizeNotMatchWhenResizing) {
{S("vendor"), 1_GiB},
{T("system"), 3_GiB},
{T("vendor"), 1_GiB}});
- ExpectRemap({T("system"), T("vendor")});
+ ExpectUnmap({T("system"), T("vendor")});
EXPECT_TRUE(
InitPartitionMetadata(target(), {{"system", 3_GiB}, {"vendor", 1_GiB}}));
- ExpectDevicesAreMapped({T("system"), T("vendor")});
}
// Test resize case. Shrink if target metadata contains a partition with a size
@@ -459,22 +440,20 @@ TEST_P(BootControlAndroidTestP, NeedShrinkIfSizeNotMatchWhenResizing) {
{S("vendor"), 1_GiB},
{T("system"), 2_GiB},
{T("vendor"), 150_MiB}});
- ExpectRemap({T("system"), T("vendor")});
+ ExpectUnmap({T("system"), T("vendor")});
EXPECT_TRUE(InitPartitionMetadata(target(),
{{"system", 2_GiB}, {"vendor", 150_MiB}}));
- ExpectDevicesAreMapped({T("system"), T("vendor")});
}
// Test adding partitions on the first run.
TEST_P(BootControlAndroidTestP, AddPartitionToEmptyMetadata) {
SetMetadata(source(), PartitionSuffixSizes{});
ExpectStoreMetadata({{T("system"), 2_GiB}, {T("vendor"), 1_GiB}});
- ExpectRemap({T("system"), T("vendor")});
+ ExpectUnmap({T("system"), T("vendor")});
EXPECT_TRUE(
InitPartitionMetadata(target(), {{"system", 2_GiB}, {"vendor", 1_GiB}}));
- ExpectDevicesAreMapped({T("system"), T("vendor")});
}
// Test subsequent add case.
@@ -482,11 +461,10 @@ TEST_P(BootControlAndroidTestP, AddAdditionalPartition) {
SetMetadata(source(), {{S("system"), 2_GiB}, {T("system"), 2_GiB}});
ExpectStoreMetadata(
{{S("system"), 2_GiB}, {T("system"), 2_GiB}, {T("vendor"), 1_GiB}});
- ExpectRemap({T("system"), T("vendor")});
+ ExpectUnmap({T("system"), T("vendor")});
EXPECT_TRUE(
InitPartitionMetadata(target(), {{"system", 2_GiB}, {"vendor", 1_GiB}}));
- ExpectDevicesAreMapped({T("system"), T("vendor")});
}
// Test delete one partition.
@@ -499,10 +477,9 @@ TEST_P(BootControlAndroidTestP, DeletePartition) {
// No T("vendor")
ExpectStoreMetadata(
{{S("system"), 2_GiB}, {S("vendor"), 1_GiB}, {T("system"), 2_GiB}});
- ExpectRemap({T("system")});
+ ExpectUnmap({T("system")});
EXPECT_TRUE(InitPartitionMetadata(target(), {{"system", 2_GiB}}));
- ExpectDevicesAreMapped({T("system")});
}
// Test delete all partitions.
@@ -515,7 +492,6 @@ TEST_P(BootControlAndroidTestP, DeleteAll) {
ExpectStoreMetadata({{S("system"), 2_GiB}, {S("vendor"), 1_GiB}});
EXPECT_TRUE(InitPartitionMetadata(target(), {}));
- ExpectDevicesAreMapped({});
}
// Test corrupt source metadata case.
@@ -523,6 +499,8 @@ TEST_P(BootControlAndroidTestP, CorruptedSourceMetadata) {
EXPECT_CALL(dynamicControl(),
LoadMetadataBuilder(GetSuperDevice(source()), source(), _))
.WillOnce(Invoke([](auto, auto, auto) { return nullptr; }));
+ ExpectUnmap({T("system")});
+
EXPECT_FALSE(InitPartitionMetadata(target(), {{"system", 1_GiB}}))
<< "Should not be able to continue with corrupt source metadata";
}
@@ -551,6 +529,40 @@ TEST_P(BootControlAndroidTestP, NotEnoughSpaceForSlot) {
<< "Should not be able to grow over size of super / 2";
}
+// Test applying retrofit update on a build with dynamic partitions enabled.
+TEST_P(BootControlAndroidTestP,
+ ApplyRetrofitUpdateOnDynamicPartitionsEnabledBuild) {
+ SetMetadata(source(),
+ {{S("system"), 2_GiB},
+ {S("vendor"), 1_GiB},
+ {T("system"), 2_GiB},
+ {T("vendor"), 1_GiB}});
+ // Should not try to unmap any target partition.
+ EXPECT_CALL(dynamicControl(), UnmapPartitionOnDeviceMapper(_, _)).Times(0);
+ // Should not store metadata to target slot.
+ EXPECT_CALL(dynamicControl(),
+ StoreMetadata(GetSuperDevice(target()), _, target()))
+ .Times(0);
+
+ // Not calling through BootControlAndroidTest::InitPartitionMetadata(), since
+ // we don't want any default group in the PartitionMetadata.
+ EXPECT_TRUE(bootctl_.InitPartitionMetadata(target(), {}));
+
+ // Should use dynamic source partitions.
+ EXPECT_CALL(dynamicControl(), GetState(S("system")))
+ .Times(1)
+ .WillOnce(Return(DmDeviceState::ACTIVE));
+ std::string source_device;
+ EXPECT_TRUE(bootctl_.GetPartitionDevice("system", source(), &source_device));
+ EXPECT_EQ(GetDmDevice(S("system")), source_device);
+
+ // Should use static target partitions without querying dynamic control.
+ EXPECT_CALL(dynamicControl(), GetState(T("system"))).Times(0);
+ std::string target_device;
+ EXPECT_TRUE(bootctl_.GetPartitionDevice("system", target(), &target_device));
+ EXPECT_EQ(GetDevice(T("system")), target_device);
+}
+
INSTANTIATE_TEST_CASE_P(BootControlAndroidTest,
BootControlAndroidTestP,
testing::Values(TestParam{0, 1}, TestParam{1, 0}));
@@ -611,14 +623,13 @@ TEST_F(BootControlAndroidTest, SimulatedFirstUpdate) {
SetMetadata(source(), update_sizes_0());
SetMetadata(target(), update_sizes_0());
ExpectStoreMetadata(update_sizes_1());
- ExpectRemap({"grown_b", "shrunk_b", "same_b", "added_b"});
+ ExpectUnmap({"grown_b", "shrunk_b", "same_b", "added_b"});
EXPECT_TRUE(InitPartitionMetadata(target(),
{{"grown", 3_GiB},
{"shrunk", 150_MiB},
{"same", 100_MiB},
{"added", 150_MiB}}));
- ExpectDevicesAreMapped({"grown_b", "shrunk_b", "same_b", "added_b"});
}
// After first update, test for the second update. In the second update, the
@@ -630,14 +641,13 @@ TEST_F(BootControlAndroidTest, SimulatedSecondUpdate) {
SetMetadata(target(), update_sizes_0());
ExpectStoreMetadata(update_sizes_2());
- ExpectRemap({"grown_a", "shrunk_a", "same_a", "deleted_a"});
+ ExpectUnmap({"grown_a", "shrunk_a", "same_a", "deleted_a"});
EXPECT_TRUE(InitPartitionMetadata(target(),
{{"grown", 4_GiB},
{"shrunk", 100_MiB},
{"same", 100_MiB},
{"deleted", 64_MiB}}));
- ExpectDevicesAreMapped({"grown_a", "shrunk_a", "same_a", "deleted_a"});
}
TEST_F(BootControlAndroidTest, ApplyingToCurrentSlot) {
@@ -688,14 +698,13 @@ TEST_P(BootControlAndroidGroupTestP, ResizeWithinGroup) {
ExpectStoreMetadata(PartitionMetadata{
.groups = {SimpleGroup(T("android"), 3_GiB, T("system"), 3_GiB),
SimpleGroup(T("oem"), 2_GiB, T("vendor"), 2_GiB)}});
- ExpectRemap({T("system"), T("vendor")});
+ ExpectUnmap({T("system"), T("vendor")});
EXPECT_TRUE(bootctl_.InitPartitionMetadata(
target(),
PartitionMetadata{
.groups = {SimpleGroup("android", 3_GiB, "system", 3_GiB),
SimpleGroup("oem", 2_GiB, "vendor", 2_GiB)}}));
- ExpectDevicesAreMapped({T("system"), T("vendor")});
}
TEST_P(BootControlAndroidGroupTestP, NotEnoughSpaceForGroup) {
@@ -722,7 +731,7 @@ TEST_P(BootControlAndroidGroupTestP, AddPartitionToGroup) {
.size = 3_GiB,
.partitions = {{.name = T("system"), .size = 2_GiB},
{.name = T("product_services"), .size = 1_GiB}}}}});
- ExpectRemap({T("system"), T("vendor"), T("product_services")});
+ ExpectUnmap({T("system"), T("vendor"), T("product_services")});
EXPECT_TRUE(bootctl_.InitPartitionMetadata(
target(),
@@ -733,27 +742,25 @@ TEST_P(BootControlAndroidGroupTestP, AddPartitionToGroup) {
.partitions = {{.name = "system", .size = 2_GiB},
{.name = "product_services", .size = 1_GiB}}},
SimpleGroup("oem", 2_GiB, "vendor", 2_GiB)}}));
- ExpectDevicesAreMapped({T("system"), T("vendor"), T("product_services")});
}
TEST_P(BootControlAndroidGroupTestP, RemovePartitionFromGroup) {
ExpectStoreMetadata(PartitionMetadata{
.groups = {{.name = T("android"), .size = 3_GiB, .partitions = {}}}});
- ExpectRemap({T("vendor")});
+ ExpectUnmap({T("vendor")});
EXPECT_TRUE(bootctl_.InitPartitionMetadata(
target(),
PartitionMetadata{
.groups = {{.name = "android", .size = 3_GiB, .partitions = {}},
SimpleGroup("oem", 2_GiB, "vendor", 2_GiB)}}));
- ExpectDevicesAreMapped({T("vendor")});
}
TEST_P(BootControlAndroidGroupTestP, AddGroup) {
ExpectStoreMetadata(PartitionMetadata{
.groups = {
SimpleGroup(T("new_group"), 2_GiB, T("new_partition"), 2_GiB)}});
- ExpectRemap({T("system"), T("vendor"), T("new_partition")});
+ ExpectUnmap({T("system"), T("vendor"), T("new_partition")});
EXPECT_TRUE(bootctl_.InitPartitionMetadata(
target(),
@@ -762,31 +769,28 @@ TEST_P(BootControlAndroidGroupTestP, AddGroup) {
SimpleGroup("android", 2_GiB, "system", 2_GiB),
SimpleGroup("oem", 1_GiB, "vendor", 1_GiB),
SimpleGroup("new_group", 2_GiB, "new_partition", 2_GiB)}}));
- ExpectDevicesAreMapped({T("system"), T("vendor"), T("new_partition")});
}
TEST_P(BootControlAndroidGroupTestP, RemoveGroup) {
ExpectStoreMetadataMatch(Not(HasGroup(T("oem"))));
- ExpectRemap({T("system")});
+ ExpectUnmap({T("system")});
EXPECT_TRUE(bootctl_.InitPartitionMetadata(
target(),
PartitionMetadata{
.groups = {SimpleGroup("android", 2_GiB, "system", 2_GiB)}}));
- ExpectDevicesAreMapped({T("system")});
}
TEST_P(BootControlAndroidGroupTestP, ResizeGroup) {
ExpectStoreMetadata(PartitionMetadata{
.groups = {SimpleGroup(T("android"), 2_GiB, T("system"), 2_GiB),
SimpleGroup(T("oem"), 3_GiB, T("vendor"), 3_GiB)}});
- ExpectRemap({T("system"), T("vendor")});
+ ExpectUnmap({T("system"), T("vendor")});
EXPECT_TRUE(bootctl_.InitPartitionMetadata(
target(),
PartitionMetadata{
.groups = {SimpleGroup("android", 2_GiB, "system", 2_GiB),
SimpleGroup("oem", 3_GiB, "vendor", 3_GiB)}}));
- ExpectDevicesAreMapped({T("system"), T("vendor")});
}
INSTANTIATE_TEST_CASE_P(BootControlAndroidTest,