Re-map source partitions with RW permission during OTA
Test: th
Bug: 351928254
Change-Id: Ia58b62f038b3bd0d73b429f761f4ff05ab93e072
diff --git a/aosp/dynamic_partition_control_android.cc b/aosp/dynamic_partition_control_android.cc
index 78cda20..363a433 100644
--- a/aosp/dynamic_partition_control_android.cc
+++ b/aosp/dynamic_partition_control_android.cc
@@ -19,6 +19,7 @@
#include <algorithm>
#include <chrono> // NOLINT(build/c++11) - using libsnapshot / liblp API
#include <cstdint>
+#include <iterator>
#include <map>
#include <memory>
#include <set>
@@ -100,7 +101,11 @@
constexpr std::chrono::milliseconds kMapSnapshotTimeout{10000};
DynamicPartitionControlAndroid::~DynamicPartitionControlAndroid() {
- UnmapAllPartitions();
+ std::set<std::string> mapped = mapped_devices_;
+ LOG(INFO) << "Destroying [" << Join(mapped, ", ") << "] from device mapper";
+ for (const auto& device_name : mapped) {
+ ignore_result(UnmapPartitionOnDeviceMapper(device_name));
+ }
metadata_device_.reset();
}
@@ -184,18 +189,34 @@
return false;
}
+constexpr auto&& kRWSourcePartitionSuffix = "_ota";
+std::string DynamicPartitionControlAndroid::GetDeviceName(
+ std::string partition_name, uint32_t slot) const {
+ if (partition_name.ends_with(kRWSourcePartitionSuffix)) {
+ return partition_name;
+ }
+ if (!partition_name.ends_with("_a") && !partition_name.ends_with("_b")) {
+ partition_name += slot ? "_b" : "_a";
+ }
+ if (slot == source_slot_) {
+ return partition_name + kRWSourcePartitionSuffix;
+ }
+ return partition_name;
+}
+
bool DynamicPartitionControlAndroid::MapPartitionInternal(
const std::string& super_device,
const std::string& target_partition_name,
uint32_t slot,
bool force_writable,
std::string* path) {
+ auto device_name = GetDeviceName(target_partition_name, slot);
CreateLogicalPartitionParams params = {
.block_device = super_device,
.metadata_slot = slot,
.partition_name = target_partition_name,
.force_writable = force_writable,
- };
+ .device_name = device_name};
bool success = false;
if (GetVirtualAbFeatureFlag().IsEnabled() && target_supports_snapshot_ &&
slot != source_slot_ && force_writable && ExpectMetadataMounted()) {
@@ -219,7 +240,7 @@
LOG(INFO) << "Succesfully mapped " << target_partition_name
<< " to device mapper (force_writable = " << force_writable
<< "); device path at " << *path;
- mapped_devices_.insert(target_partition_name);
+ mapped_devices_.insert(params.device_name);
return true;
}
@@ -229,9 +250,10 @@
uint32_t slot,
bool force_writable,
std::string* path) {
- DmDeviceState state = GetState(target_partition_name);
+ auto device_name = GetDeviceName(target_partition_name, slot);
+ DmDeviceState state = GetState(device_name);
if (state == DmDeviceState::ACTIVE) {
- if (mapped_devices_.find(target_partition_name) != mapped_devices_.end()) {
+ if (mapped_devices_.find(device_name) != mapped_devices_.end()) {
if (GetDmDevicePathByName(target_partition_name, path)) {
LOG(INFO) << target_partition_name
<< " is mapped on device mapper: " << *path;
@@ -245,12 +267,13 @@
// Note that for source partitions, if GetState() == ACTIVE, callers (e.g.
// BootControlAndroid) should not call MapPartitionOnDeviceMapper, but
// should directly call GetDmDevicePathByName.
- if (!UnmapPartitionOnDeviceMapper(target_partition_name)) {
+ LOG(INFO) << "Destroying `" << device_name << "` from device mapper";
+ if (!UnmapPartitionOnDeviceMapper(device_name)) {
LOG(ERROR) << target_partition_name
<< " is mapped before the update, and it cannot be unmapped.";
return false;
}
- state = GetState(target_partition_name);
+ state = GetState(device_name);
if (state != DmDeviceState::INVALID) {
LOG(ERROR) << target_partition_name << " is unmapped but state is "
<< static_cast<std::underlying_type_t<DmDeviceState>>(state);
@@ -270,32 +293,38 @@
bool DynamicPartitionControlAndroid::UnmapPartitionOnDeviceMapper(
const std::string& target_partition_name) {
- if (DeviceMapper::Instance().GetState(target_partition_name) !=
+ auto device_name = target_partition_name;
+ if (target_partition_name.ends_with("_a") ||
+ target_partition_name.ends_with("_b")) {
+ auto slot = target_partition_name.ends_with("_a") ? 0 : 1;
+ device_name = GetDeviceName(target_partition_name, slot);
+ return false;
+ }
+ if (DeviceMapper::Instance().GetState(device_name) !=
DmDeviceState::INVALID) {
// Partitions at target slot on non-Virtual A/B devices are mapped as
// dm-linear. Also, on Virtual A/B devices, system_other may be mapped for
// preopt apps as dm-linear.
// Call DestroyLogicalPartition to handle these cases.
- bool success = DestroyLogicalPartition(target_partition_name);
+ bool success = DestroyLogicalPartition(device_name);
// On a Virtual A/B device, |target_partition_name| may be a leftover from
// a paused update. Clean up any underlying devices.
- if (ExpectMetadataMounted()) {
- success &= snapshot_->UnmapUpdateSnapshot(target_partition_name);
+ if (ExpectMetadataMounted() &&
+ !device_name.ends_with(kRWSourcePartitionSuffix)) {
+ success &= snapshot_->UnmapUpdateSnapshot(device_name);
} else {
- LOG(INFO) << "Skip UnmapUpdateSnapshot(" << target_partition_name
- << ") because metadata is not mounted";
+ LOG(INFO) << "Skip UnmapUpdateSnapshot(" << device_name << ")";
}
if (!success) {
- LOG(ERROR) << "Cannot unmap " << target_partition_name
- << " from device mapper.";
+ LOG(ERROR) << "Cannot unmap " << device_name << " from device mapper.";
return false;
}
- LOG(INFO) << "Successfully unmapped " << target_partition_name
+ LOG(INFO) << "Successfully unmapped " << device_name
<< " from device mapper.";
}
- mapped_devices_.erase(target_partition_name);
+ mapped_devices_.erase(device_name);
return true;
}
@@ -306,16 +335,27 @@
}
// UnmapPartitionOnDeviceMapper removes objects from mapped_devices_, hence
// a copy is needed for the loop.
- std::set<std::string> mapped = mapped_devices_;
+ std::set<std::string> mapped;
+ std::copy_if(mapped_devices_.begin(),
+ mapped_devices_.end(),
+ std::inserter(mapped, mapped.end()),
+ [](auto&& device_name) {
+ return !std::string_view(device_name)
+ .ends_with(kRWSourcePartitionSuffix);
+ });
LOG(INFO) << "Destroying [" << Join(mapped, ", ") << "] from device mapper";
- for (const auto& partition_name : mapped) {
- ignore_result(UnmapPartitionOnDeviceMapper(partition_name));
+ for (const auto& device_name : mapped) {
+ ignore_result(UnmapPartitionOnDeviceMapper(device_name));
}
return true;
}
void DynamicPartitionControlAndroid::Cleanup() {
- UnmapAllPartitions();
+ std::set<std::string> mapped = mapped_devices_;
+ LOG(INFO) << "Destroying [" << Join(mapped, ", ") << "] from device mapper";
+ for (const auto& device_name : mapped) {
+ ignore_result(UnmapPartitionOnDeviceMapper(device_name));
+ }
LOG(INFO) << "UnmapAllPartitions done";
metadata_device_.reset();
if (GetVirtualAbFeatureFlag().IsEnabled()) {
@@ -772,6 +812,8 @@
// In recovery, metadata might not be mounted, and
// UnmapPartitionOnDeviceMapper might fail. However,
// it is unusual that system_other has already been mapped. Hence, just skip.
+ LOG(INFO) << "Destroying `" << partition_name_suffix
+ << "` from device mapper";
TEST_AND_RETURN_FALSE(UnmapPartitionOnDeviceMapper(partition_name_suffix));
// Use CreateLogicalPartition directly to avoid mapping with existing
// snapshots.
@@ -813,6 +855,8 @@
// should be called. If DestroyLogicalPartition does fail, it is still okay
// to skip the error here and let Prepare*() fail later.
if (should_unmap) {
+ LOG(INFO) << "Destroying `" << partition_name_suffix
+ << "` from device mapper";
TEST_AND_RETURN_FALSE(UnmapPartitionOnDeviceMapper(partition_name_suffix));
}
@@ -1161,12 +1205,13 @@
std::string device;
if (GetDynamicPartitionsFeatureFlag().IsEnabled() &&
(slot == current_slot || is_target_dynamic_)) {
- switch (GetDynamicPartitionDevice(device_dir,
- partition_name_suffix,
- slot,
- current_slot,
- not_in_payload,
- &device)) {
+ auto status = GetDynamicPartitionDevice(device_dir,
+ partition_name_suffix,
+ slot,
+ current_slot,
+ not_in_payload,
+ &device);
+ switch (status) {
case DynamicPartitionDeviceStatus::SUCCESS:
return {{.rw_device_path = device,
.readonly_device_path = device,
@@ -1176,6 +1221,7 @@
break;
case DynamicPartitionDeviceStatus::ERROR: // fallthrough
default:
+ LOG(ERROR) << "Unhandled dynamic partition status " << (int)status;
return {};
}
}
@@ -1211,6 +1257,7 @@
std::string* device) {
std::string super_device =
device_dir.Append(GetSuperPartitionName(slot)).value();
+ auto device_name = GetDeviceName(partition_name_suffix, slot);
auto builder = LoadMetadataBuilder(super_device, slot);
if (builder == nullptr) {
@@ -1233,13 +1280,12 @@
}
if (slot == current_slot) {
- if (GetState(partition_name_suffix) != DmDeviceState::ACTIVE) {
- LOG(WARNING) << partition_name_suffix << " is at current slot but it is "
+ if (GetState(device_name) != DmDeviceState::ACTIVE) {
+ LOG(WARNING) << device_name << " is at current slot but it is "
<< "not mapped. Now try to map it.";
} else {
- if (GetDmDevicePathByName(partition_name_suffix, device)) {
- LOG(INFO) << partition_name_suffix
- << " is mapped on device mapper: " << *device;
+ if (GetDmDevicePathByName(device_name, device)) {
+ LOG(INFO) << device_name << " is mapped on device mapper: " << *device;
return DynamicPartitionDeviceStatus::SUCCESS;
}
LOG(ERROR) << partition_name_suffix << "is mapped but path is unknown.";
diff --git a/aosp/dynamic_partition_control_android.h b/aosp/dynamic_partition_control_android.h
index 176cf50..1f70184 100644
--- a/aosp/dynamic_partition_control_android.h
+++ b/aosp/dynamic_partition_control_android.h
@@ -338,6 +338,8 @@
// target_supports_snapshot_ and is_target_dynamic_.
bool SetTargetBuildVars(const DeltaArchiveManifest& manifest);
+ std::string GetDeviceName(std::string partition_name, uint32_t slot) const;
+
std::set<std::string> mapped_devices_;
const FeatureFlag dynamic_partitions_;
const FeatureFlag virtual_ab_;
diff --git a/aosp/dynamic_partition_control_android_unittest.cc b/aosp/dynamic_partition_control_android_unittest.cc
index c93d4c3..6822394 100644
--- a/aosp/dynamic_partition_control_android_unittest.cc
+++ b/aosp/dynamic_partition_control_android_unittest.cc
@@ -16,9 +16,7 @@
#include "update_engine/aosp/dynamic_partition_control_android.h"
-#include <algorithm>
#include <set>
-#include <vector>
#include <base/logging.h>
#include <gmock/gmock.h>
@@ -26,6 +24,7 @@
#include <libavb/libavb.h>
#include <libsnapshot/mock_snapshot.h>
+#include "update_engine/aosp/boot_control_android.h"
#include "update_engine/aosp/dynamic_partition_test_utils.h"
#include "update_engine/aosp/mock_dynamic_partition_control_android.h"
#include "update_engine/common/mock_prefs.h"
@@ -212,7 +211,7 @@
}
std::unique_ptr<DynamicPartitionControlAndroid> module_;
- TestParam slots_;
+ TestParam slots_{};
};
class DynamicPartitionControlAndroidTestP
@@ -240,7 +239,7 @@
{T("system"), 3_GiB},
{T("vendor"), 1_GiB}};
PartitionSizes update_metadata{{"system", 3_GiB}, {"vendor", 1_GiB}};
- EXPECT_TRUE(
+ ASSERT_TRUE(
UpdatePartitionMetadata(source_metadata, update_metadata, expected));
}
@@ -257,7 +256,7 @@
{T("system"), 2_GiB},
{T("vendor"), 150_MiB}};
PartitionSizes update_metadata{{"system", 2_GiB}, {"vendor", 150_MiB}};
- EXPECT_TRUE(
+ ASSERT_TRUE(
UpdatePartitionMetadata(source_metadata, update_metadata, expected));
}
@@ -266,7 +265,7 @@
PartitionSuffixSizes source_metadata{};
PartitionSuffixSizes expected{{T("system"), 2_GiB}, {T("vendor"), 1_GiB}};
PartitionSizes update_metadata{{"system", 2_GiB}, {"vendor", 1_GiB}};
- EXPECT_TRUE(
+ ASSERT_TRUE(
UpdatePartitionMetadata(source_metadata, update_metadata, expected));
}
@@ -277,7 +276,7 @@
PartitionSuffixSizes expected{
{S("system"), 2_GiB}, {T("system"), 2_GiB}, {T("vendor"), 1_GiB}};
PartitionSizes update_metadata{{"system", 2_GiB}, {"vendor", 1_GiB}};
- EXPECT_TRUE(
+ ASSERT_TRUE(
UpdatePartitionMetadata(source_metadata, update_metadata, expected));
}
@@ -291,7 +290,7 @@
PartitionSuffixSizes expected{
{S("system"), 2_GiB}, {S("vendor"), 1_GiB}, {T("system"), 2_GiB}};
PartitionSizes update_metadata{{"system", 2_GiB}};
- EXPECT_TRUE(
+ ASSERT_TRUE(
UpdatePartitionMetadata(source_metadata, update_metadata, expected));
}
@@ -303,7 +302,7 @@
{T("vendor"), 1_GiB}};
PartitionSuffixSizes expected{{S("system"), 2_GiB}, {S("vendor"), 1_GiB}};
PartitionSizes update_metadata{};
- EXPECT_TRUE(
+ ASSERT_TRUE(
UpdatePartitionMetadata(source_metadata, update_metadata, expected));
}
@@ -314,7 +313,7 @@
.WillOnce(Invoke([](auto, auto, auto) { return nullptr; }));
ExpectUnmap({T("system")});
- EXPECT_FALSE(PreparePartitionsForUpdate({{"system", 1_GiB}}))
+ ASSERT_FALSE(PreparePartitionsForUpdate({{"system", 1_GiB}}))
<< "Should not be able to continue with corrupt source metadata";
}
@@ -327,7 +326,7 @@
{T("vendor"), 0}};
PartitionSizes update_metadata{{"system", 3_GiB}, {"vendor", 3_GiB}};
- EXPECT_FALSE(UpdatePartitionMetadata(source_metadata, update_metadata, {}))
+ ASSERT_FALSE(UpdatePartitionMetadata(source_metadata, update_metadata, {}))
<< "Should not be able to fit 11GiB data into 10GiB space";
}
@@ -337,7 +336,7 @@
{T("system"), 0},
{T("vendor"), 0}};
PartitionSizes update_metadata{{"system", 3_GiB}, {"vendor", 3_GiB}};
- EXPECT_FALSE(UpdatePartitionMetadata(source_metadata, update_metadata, {}))
+ ASSERT_FALSE(UpdatePartitionMetadata(source_metadata, update_metadata, {}))
<< "Should not be able to grow over size of super / 2";
}
@@ -362,35 +361,35 @@
// Not calling through
// DynamicPartitionControlAndroidTest::PreparePartitionsForUpdate(), since we
// don't want any default group in the PartitionMetadata.
- EXPECT_TRUE(dynamicControl().PreparePartitionsForUpdate(
+ ASSERT_TRUE(dynamicControl().PreparePartitionsForUpdate(
source(), target(), {}, true, nullptr, nullptr));
// Should use dynamic source partitions.
- EXPECT_CALL(dynamicControl(), GetState(S("system")))
+ EXPECT_CALL(dynamicControl(), GetState(S("system") + "_ota"))
.Times(1)
.WillOnce(Return(DmDeviceState::ACTIVE));
string system_device;
- EXPECT_TRUE(dynamicControl().GetPartitionDevice(
+ ASSERT_TRUE(dynamicControl().GetPartitionDevice(
"system", source(), source(), &system_device));
- EXPECT_EQ(GetDmDevice(S("system")), system_device);
+ ASSERT_EQ(GetDmDevice(S("system") + "_ota"), system_device);
// Should use static target partitions without querying dynamic control.
EXPECT_CALL(dynamicControl(), GetState(T("system"))).Times(0);
- EXPECT_TRUE(dynamicControl().GetPartitionDevice(
+ ASSERT_TRUE(dynamicControl().GetPartitionDevice(
"system", target(), source(), &system_device));
- EXPECT_EQ(GetDevice(T("system")), system_device);
+ ASSERT_EQ(GetDevice(T("system")), system_device);
// Static partition "bar".
EXPECT_CALL(dynamicControl(), GetState(S("bar"))).Times(0);
std::string bar_device;
- EXPECT_TRUE(dynamicControl().GetPartitionDevice(
+ ASSERT_TRUE(dynamicControl().GetPartitionDevice(
"bar", source(), source(), &bar_device));
- EXPECT_EQ(GetDevice(S("bar")), bar_device);
+ ASSERT_EQ(GetDevice(S("bar")), bar_device);
EXPECT_CALL(dynamicControl(), GetState(T("bar"))).Times(0);
- EXPECT_TRUE(dynamicControl().GetPartitionDevice(
+ ASSERT_TRUE(dynamicControl().GetPartitionDevice(
"bar", target(), source(), &bar_device));
- EXPECT_EQ(GetDevice(T("bar")), bar_device);
+ ASSERT_EQ(GetDevice(T("bar")), bar_device);
}
TEST_P(DynamicPartitionControlAndroidTestP, GetMountableDevicePath) {
@@ -411,9 +410,9 @@
GetDevice(S("system")),
GetDevice(T("system")))))
.WillRepeatedly(Return(true));
- EXPECT_CALL(
- dynamicControl(),
- GetState(AnyOf(S("vendor"), T("vendor"), S("system"), T("system"))))
+ EXPECT_CALL(dynamicControl(),
+ GetState(AnyOf(
+ S("vendor"), T("vendor"), S("system") + "_ota", T("system"))))
.WillRepeatedly(Return(DmDeviceState::ACTIVE));
SetMetadata(source(), {{S("system"), 2_GiB}, {S("vendor"), 1_GiB}});
@@ -421,7 +420,7 @@
std::string device;
ASSERT_TRUE(dynamicControl().GetPartitionDevice(
"system", source(), source(), &device));
- ASSERT_EQ(GetDmDevice(S("system")), device);
+ ASSERT_EQ(GetDmDevice(S("system") + "_ota"), device);
ASSERT_TRUE(dynamicControl().GetPartitionDevice(
"system", target(), source(), &device));
@@ -453,9 +452,9 @@
GetDevice(S("system")),
GetDevice(T("system")))))
.WillRepeatedly(Return(true));
- EXPECT_CALL(
- dynamicControl(),
- GetState(AnyOf(S("vendor"), T("vendor"), S("system"), T("system"))))
+ EXPECT_CALL(dynamicControl(),
+ GetState(AnyOf(
+ S("vendor"), T("vendor"), S("system") + "_ota", T("system"))))
.WillRepeatedly(Return(DmDeviceState::ACTIVE));
SetMetadata(source(), {{S("system"), 2_GiB}, {S("vendor"), 1_GiB}});
@@ -464,7 +463,7 @@
std::string device;
ASSERT_TRUE(dynamicControl().GetPartitionDevice(
"system", source(), source(), &device));
- ASSERT_EQ(GetDmDevice(S("system")), device);
+ ASSERT_EQ(GetDmDevice(S("system") + "_ota"), device);
ASSERT_TRUE(dynamicControl().GetPartitionDevice(
"system", target(), source(), &device));
@@ -499,7 +498,7 @@
{T("system"), 2_GiB},
{T("vendor"), 1_GiB}});
- EXPECT_TRUE(dynamicControl().PreparePartitionsForUpdate(
+ ASSERT_TRUE(dynamicControl().PreparePartitionsForUpdate(
source(),
target(),
PartitionSizesToManifest({{"system", 2_GiB}, {"vendor", 1_GiB}}),
@@ -508,13 +507,13 @@
nullptr));
// Dynamic partition "system".
- EXPECT_CALL(dynamicControl(), GetState(S("system")))
+ EXPECT_CALL(dynamicControl(), GetState(S("system") + "_ota"))
.Times(1)
.WillOnce(Return(DmDeviceState::ACTIVE));
string system_device;
- EXPECT_TRUE(dynamicControl().GetPartitionDevice(
+ ASSERT_TRUE(dynamicControl().GetPartitionDevice(
"system", source(), source(), &system_device));
- EXPECT_EQ(GetDmDevice(S("system")), system_device);
+ ASSERT_EQ(GetDmDevice(S("system") + "_ota"), system_device);
EXPECT_CALL(dynamicControl(), GetState(T("system")))
.Times(AnyNumber())
@@ -528,21 +527,21 @@
*device = "/fake/remapped/" + name;
return true;
}));
- EXPECT_TRUE(dynamicControl().GetPartitionDevice(
+ ASSERT_TRUE(dynamicControl().GetPartitionDevice(
"system", target(), source(), &system_device));
- EXPECT_EQ("/fake/remapped/" + T("system"), system_device);
+ ASSERT_EQ("/fake/remapped/" + T("system"), system_device);
// Static partition "bar".
EXPECT_CALL(dynamicControl(), GetState(S("bar"))).Times(0);
std::string bar_device;
- EXPECT_TRUE(dynamicControl().GetPartitionDevice(
+ ASSERT_TRUE(dynamicControl().GetPartitionDevice(
"bar", source(), source(), &bar_device));
- EXPECT_EQ(GetDevice(S("bar")), bar_device);
+ ASSERT_EQ(GetDevice(S("bar")), bar_device);
EXPECT_CALL(dynamicControl(), GetState(T("bar"))).Times(0);
- EXPECT_TRUE(dynamicControl().GetPartitionDevice(
+ ASSERT_TRUE(dynamicControl().GetPartitionDevice(
"bar", target(), source(), &bar_device));
- EXPECT_EQ(GetDevice(T("bar")), bar_device);
+ ASSERT_EQ(GetDevice(T("bar")), bar_device);
}
INSTANTIATE_TEST_CASE_P(DynamicPartitionControlAndroidTest,
@@ -582,7 +581,7 @@
AddGroupAndPartition(&update_manifest, "android", 3_GiB, "system", 3_GiB);
AddGroupAndPartition(&update_manifest, "oem", 2_GiB, "vendor", 2_GiB);
- EXPECT_TRUE(
+ ASSERT_TRUE(
UpdatePartitionMetadata(source_manifest, update_manifest, expected));
}
@@ -590,7 +589,7 @@
DeltaArchiveManifest update_manifest;
AddGroupAndPartition(&update_manifest, "android", 3_GiB, "system", 1_GiB),
AddGroupAndPartition(&update_manifest, "oem", 2_GiB, "vendor", 3_GiB);
- EXPECT_FALSE(UpdatePartitionMetadata(source_manifest, update_manifest, {}))
+ ASSERT_FALSE(UpdatePartitionMetadata(source_manifest, update_manifest, {}))
<< "Should not be able to grow over maximum size of group";
}
@@ -598,7 +597,7 @@
DeltaArchiveManifest update_manifest;
AddGroup(&update_manifest, "android", 3_GiB);
AddGroup(&update_manifest, "oem", 3_GiB);
- EXPECT_FALSE(UpdatePartitionMetadata(source_manifest, update_manifest, {}))
+ ASSERT_FALSE(UpdatePartitionMetadata(source_manifest, update_manifest, {}))
<< "Should not be able to grow over size of super / 2";
}
@@ -614,7 +613,7 @@
AddPartition(&update_manifest, g, "system_ext", 1_GiB);
AddGroupAndPartition(&update_manifest, "oem", 2_GiB, "vendor", 2_GiB);
- EXPECT_TRUE(
+ ASSERT_TRUE(
UpdatePartitionMetadata(source_manifest, update_manifest, expected));
}
@@ -626,7 +625,7 @@
AddGroup(&update_manifest, "android", 3_GiB);
AddGroupAndPartition(&update_manifest, "oem", 2_GiB, "vendor", 2_GiB);
- EXPECT_TRUE(
+ ASSERT_TRUE(
UpdatePartitionMetadata(source_manifest, update_manifest, expected));
}
@@ -640,7 +639,7 @@
AddGroupAndPartition(&update_manifest, "oem", 1_GiB, "vendor", 1_GiB);
AddGroupAndPartition(
&update_manifest, "new_group", 2_GiB, "new_partition", 2_GiB);
- EXPECT_TRUE(
+ ASSERT_TRUE(
UpdatePartitionMetadata(source_manifest, update_manifest, expected));
}
@@ -648,7 +647,7 @@
DeltaArchiveManifest update_manifest;
AddGroupAndPartition(&update_manifest, "android", 2_GiB, "system", 2_GiB);
- EXPECT_TRUE(UpdatePartitionMetadata(
+ ASSERT_TRUE(UpdatePartitionMetadata(
source_manifest, update_manifest, Not(HasGroup(T("oem")))));
}
@@ -659,7 +658,7 @@
DeltaArchiveManifest update_manifest;
AddGroupAndPartition(&update_manifest, "android", 2_GiB, "system", 2_GiB),
AddGroupAndPartition(&update_manifest, "oem", 3_GiB, "vendor", 3_GiB);
- EXPECT_TRUE(
+ ASSERT_TRUE(
UpdatePartitionMetadata(source_manifest, update_manifest, expected));
}
@@ -725,7 +724,7 @@
ExpectStoreMetadata(update_sizes_1());
ExpectUnmap({"grown_b", "shrunk_b", "same_b", "added_b"});
- EXPECT_TRUE(PreparePartitionsForUpdate({{"grown", 3_GiB},
+ ASSERT_TRUE(PreparePartitionsForUpdate({{"grown", 3_GiB},
{"shrunk", 150_MiB},
{"same", 100_MiB},
{"added", 150_MiB}}));
@@ -742,7 +741,7 @@
ExpectStoreMetadata(update_sizes_2());
ExpectUnmap({"grown_a", "shrunk_a", "same_a", "deleted_a"});
- EXPECT_TRUE(PreparePartitionsForUpdate({{"grown", 4_GiB},
+ ASSERT_TRUE(PreparePartitionsForUpdate({{"grown", 4_GiB},
{"shrunk", 100_MiB},
{"same", 100_MiB},
{"deleted", 64_MiB}}));
@@ -750,7 +749,7 @@
TEST_F(DynamicPartitionControlAndroidTest, ApplyingToCurrentSlot) {
SetSlots({1, 1});
- EXPECT_FALSE(PreparePartitionsForUpdate({}))
+ ASSERT_FALSE(PreparePartitionsForUpdate({}))
<< "Should not be able to apply to current slot.";
}
@@ -766,16 +765,16 @@
InstallOperation iop;
InstallOperation optimized;
- Extent *se, *de;
+ Extent *se{}, *de{};
// Not a SOURCE_COPY operation, cannot skip.
iop.set_type(InstallOperation::REPLACE);
- EXPECT_FALSE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
+ ASSERT_FALSE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
iop.set_type(InstallOperation::SOURCE_COPY);
// By default GetVirtualAbFeatureFlag is disabled. Cannot skip operation.
- EXPECT_FALSE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
+ ASSERT_FALSE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
// Enable GetVirtualAbFeatureFlag in the mock interface.
ON_CALL(dynamicControl(), GetVirtualAbFeatureFlag())
@@ -783,21 +782,21 @@
// By default target_supports_snapshot_ is set to false. Cannot skip
// operation.
- EXPECT_FALSE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
+ ASSERT_FALSE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
SetSnapshotEnabled(true);
// Empty source and destination. Skip.
- EXPECT_TRUE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
- EXPECT_TRUE(optimized.src_extents().empty());
- EXPECT_TRUE(optimized.dst_extents().empty());
+ ASSERT_TRUE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
+ ASSERT_TRUE(optimized.src_extents().empty());
+ ASSERT_TRUE(optimized.dst_extents().empty());
se = iop.add_src_extents();
se->set_start_block(0);
se->set_num_blocks(1);
// There is something in sources, but destinations are empty. Cannot skip.
- EXPECT_FALSE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
+ ASSERT_FALSE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
InstallOperation iop2;
@@ -806,48 +805,48 @@
de->set_num_blocks(1);
// There is something in destinations, but sources are empty. Cannot skip.
- EXPECT_FALSE(dynamicControl().OptimizeOperation("foo", iop2, &optimized));
+ ASSERT_FALSE(dynamicControl().OptimizeOperation("foo", iop2, &optimized));
de = iop.add_dst_extents();
de->set_start_block(0);
de->set_num_blocks(1);
// Sources and destinations are identical. Skip.
- EXPECT_TRUE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
- EXPECT_TRUE(optimized.src_extents().empty());
- EXPECT_TRUE(optimized.dst_extents().empty());
+ ASSERT_TRUE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
+ ASSERT_TRUE(optimized.src_extents().empty());
+ ASSERT_TRUE(optimized.dst_extents().empty());
se = iop.add_src_extents();
se->set_start_block(1);
se->set_num_blocks(5);
// There is something in source, but not in destination. Cannot skip.
- EXPECT_FALSE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
+ ASSERT_FALSE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
de = iop.add_dst_extents();
de->set_start_block(1);
de->set_num_blocks(5);
// There is source and destination are equal. Skip.
- EXPECT_TRUE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
- EXPECT_TRUE(optimized.src_extents().empty());
- EXPECT_TRUE(optimized.dst_extents().empty());
+ ASSERT_TRUE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
+ ASSERT_TRUE(optimized.src_extents().empty());
+ ASSERT_TRUE(optimized.dst_extents().empty());
de = iop.add_dst_extents();
de->set_start_block(6);
de->set_num_blocks(5);
// There is something extra in dest. Cannot skip.
- EXPECT_FALSE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
+ ASSERT_FALSE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
se = iop.add_src_extents();
se->set_start_block(6);
se->set_num_blocks(5);
// Source and dest are identical again. Skip.
- EXPECT_TRUE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
- EXPECT_TRUE(optimized.src_extents().empty());
- EXPECT_TRUE(optimized.dst_extents().empty());
+ ASSERT_TRUE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
+ ASSERT_TRUE(optimized.src_extents().empty());
+ ASSERT_TRUE(optimized.dst_extents().empty());
iop.Clear();
iop.set_type(InstallOperation::SOURCE_COPY);
@@ -865,20 +864,20 @@
de->set_num_blocks(5);
// [1, 3, 4, 7, 8] -> [2, 3, 4, 5, 6] should return [1, 7, 8] -> [2, 5, 6]
- EXPECT_TRUE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
+ ASSERT_TRUE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
ASSERT_EQ(2, optimized.src_extents_size());
ASSERT_EQ(2, optimized.dst_extents_size());
- EXPECT_EQ(1u, optimized.src_extents(0).start_block());
- EXPECT_EQ(1u, optimized.src_extents(0).num_blocks());
- EXPECT_EQ(2u, optimized.dst_extents(0).start_block());
- EXPECT_EQ(1u, optimized.dst_extents(0).num_blocks());
- EXPECT_EQ(7u, optimized.src_extents(1).start_block());
- EXPECT_EQ(2u, optimized.src_extents(1).num_blocks());
- EXPECT_EQ(5u, optimized.dst_extents(1).start_block());
- EXPECT_EQ(2u, optimized.dst_extents(1).num_blocks());
+ ASSERT_EQ(1u, optimized.src_extents(0).start_block());
+ ASSERT_EQ(1u, optimized.src_extents(0).num_blocks());
+ ASSERT_EQ(2u, optimized.dst_extents(0).start_block());
+ ASSERT_EQ(1u, optimized.dst_extents(0).num_blocks());
+ ASSERT_EQ(7u, optimized.src_extents(1).start_block());
+ ASSERT_EQ(2u, optimized.src_extents(1).num_blocks());
+ ASSERT_EQ(5u, optimized.dst_extents(1).start_block());
+ ASSERT_EQ(2u, optimized.dst_extents(1).num_blocks());
// Don't skip for static partitions.
- EXPECT_FALSE(dynamicControl().OptimizeOperation("bar", iop, &optimized));
+ ASSERT_FALSE(dynamicControl().OptimizeOperation("bar", iop, &optimized));
}
TEST_F(DynamicPartitionControlAndroidTest, ResetUpdate) {
@@ -920,7 +919,7 @@
}));
ON_CALL(dynamicControl(), IsAvbEnabledOnSystemOther())
.WillByDefault(Return(false));
- EXPECT_TRUE(
+ ASSERT_TRUE(
dynamicControl().RealEraseSystemOtherAvbFooter(source(), target()));
}
@@ -929,7 +928,7 @@
ON_CALL(dynamicControl(), IsAvbEnabledOnSystemOther())
.WillByDefault(Return(true));
std::string path;
- bool should_unmap;
+ bool should_unmap{};
ASSERT_TRUE(dynamicControl().RealGetSystemOtherPath(
source(), target(), T("system"), &path, &should_unmap));
ASSERT_TRUE(path.empty()) << path;
@@ -943,7 +942,7 @@
return dynamicControl().RealGetSystemOtherPath(
source_slot, target_slot, name, path, should_unmap);
}));
- EXPECT_TRUE(
+ ASSERT_TRUE(
dynamicControl().RealEraseSystemOtherAvbFooter(source(), target()));
}
@@ -953,7 +952,7 @@
ON_CALL(dynamicControl(), IsAvbEnabledOnSystemOther())
.WillByDefault(Return(true));
std::string path;
- bool should_unmap;
+ bool should_unmap{};
ASSERT_TRUE(dynamicControl().RealGetSystemOtherPath(
source(), target(), T("system"), &path, &should_unmap));
ASSERT_TRUE(path.empty()) << path;
@@ -967,7 +966,7 @@
return dynamicControl().RealGetSystemOtherPath(
source_slot, target_slot, name, path, should_unmap);
}));
- EXPECT_TRUE(
+ ASSERT_TRUE(
dynamicControl().RealEraseSystemOtherAvbFooter(source(), target()));
}
@@ -1059,8 +1058,8 @@
ExpectCreateUpdateSnapshots(android::snapshot::Return::Ok());
SetMetadata(source(), {});
uint64_t required_size = 0;
- EXPECT_TRUE(PreparePartitionsForUpdate(&required_size));
- EXPECT_EQ(0u, required_size);
+ ASSERT_TRUE(PreparePartitionsForUpdate(&required_size));
+ ASSERT_EQ(0u, required_size);
}
// Test that if not enough space, required size returned by SnapshotManager is
@@ -1070,8 +1069,8 @@
uint64_t required_size = 0;
SetMetadata(source(), {});
- EXPECT_FALSE(PreparePartitionsForUpdate(&required_size));
- EXPECT_EQ(1_GiB, required_size);
+ ASSERT_FALSE(PreparePartitionsForUpdate(&required_size));
+ ASSERT_EQ(1_GiB, required_size);
}
// Test that in recovery, use empty space in super partition for a snapshot
@@ -1088,8 +1087,8 @@
EXPECT_CALL(dynamicControl(), PrepareDynamicPartitionsForUpdate(_, _, _, _))
.Times(0);
uint64_t required_size = 0;
- EXPECT_TRUE(PreparePartitionsForUpdate(&required_size));
- EXPECT_EQ(0u, required_size);
+ ASSERT_TRUE(PreparePartitionsForUpdate(&required_size));
+ ASSERT_EQ(0u, required_size);
}
// Test that in recovery, if CreateUpdateSnapshots throws an error, try
@@ -1124,12 +1123,32 @@
ExpectStoreMetadata({{T("system"), 3_GiB}, {T("vendor"), 1_GiB}});
uint64_t required_size = 0;
- EXPECT_TRUE(PreparePartitionsForUpdate(&required_size));
- EXPECT_EQ(0u, required_size);
+ ASSERT_TRUE(PreparePartitionsForUpdate(&required_size));
+ ASSERT_EQ(0u, required_size);
}
INSTANTIATE_TEST_CASE_P(DynamicPartitionControlAndroidTest,
SnapshotPartitionTestP,
testing::Values(TestParam{0, 1}, TestParam{1, 0}));
+TEST(SourcePartitionTest, MapSourceWritable) {
+ BootControlAndroid boot_control;
+ ASSERT_TRUE(boot_control.Init());
+ auto source_slot = boot_control.GetCurrentSlot();
+ DynamicPartitionControlAndroid dynamic_control(source_slot);
+ std::string device;
+ ASSERT_TRUE(dynamic_control.GetPartitionDevice(
+ "system", source_slot, source_slot, &device));
+ android::base::unique_fd fd(open(device.c_str(), O_RDWR | O_CLOEXEC));
+ ASSERT_TRUE(utils::SetBlockDeviceReadOnly(device, false));
+ ASSERT_GE(fd, 0) << android::base::ErrnoNumberAsString(errno);
+ std::array<char, 512> block{};
+ ASSERT_EQ(pread(fd.get(), block.data(), block.size(), 0),
+ (ssize_t)block.size())
+ << android::base::ErrnoNumberAsString(errno);
+ ASSERT_EQ(pwrite(fd.get(), block.data(), block.size(), 0),
+ (ssize_t)block.size())
+ << android::base::ErrnoNumberAsString(errno);
+}
+
} // namespace chromeos_update_engine