Implement updater runtime for dynamic partitions
The simulator skips executing the operations for dynamic partitions, and
will use the logical images under target_files/IMAGES directly. (Similar
to the targets without DAP enabled)
Bug: 131911365
Test: run update on cuttlefish, run simulator
Change-Id: Id318d97ece4560df9f20dc5cabeb8b2e261bdf9c
diff --git a/updater/dynamic_partitions.cpp b/updater/dynamic_partitions.cpp
index b50dd75..a340116 100644
--- a/updater/dynamic_partitions.cpp
+++ b/updater/dynamic_partitions.cpp
@@ -19,46 +19,20 @@
#include <sys/stat.h>
#include <sys/types.h>
-#include <algorithm>
-#include <chrono>
-#include <iterator>
#include <memory>
-#include <optional>
#include <string>
-#include <type_traits>
#include <vector>
#include <android-base/file.h>
#include <android-base/logging.h>
-#include <android-base/parseint.h>
#include <android-base/strings.h>
-#include <fs_mgr.h>
-#include <fs_mgr_dm_linear.h>
-#include <libdm/dm.h>
-#include <liblp/builder.h>
#include "edify/expr.h"
+#include "edify/updater_runtime_interface.h"
#include "otautil/error_code.h"
#include "otautil/paths.h"
#include "private/utils.h"
-using android::base::ParseUint;
-using android::dm::DeviceMapper;
-using android::dm::DmDeviceState;
-using android::fs_mgr::CreateLogicalPartition;
-using android::fs_mgr::DestroyLogicalPartition;
-using android::fs_mgr::LpMetadata;
-using android::fs_mgr::MetadataBuilder;
-using android::fs_mgr::Partition;
-using android::fs_mgr::PartitionOpener;
-
-static constexpr std::chrono::milliseconds kMapTimeout{ 1000 };
-static constexpr char kMetadataUpdatedMarker[] = "/dynamic_partition_metadata.UPDATED";
-
-static std::string GetSuperDevice() {
- return "/dev/block/by-name/" + fs_mgr_get_super_partition_name();
-}
-
static std::vector<std::string> ReadStringArgs(const char* name, State* state,
const std::vector<std::unique_ptr<Expr>>& argv,
const std::vector<std::string>& arg_names) {
@@ -89,40 +63,14 @@
return ret;
}
-static bool UnmapPartitionOnDeviceMapper(const std::string& partition_name) {
- auto state = DeviceMapper::Instance().GetState(partition_name);
- if (state == DmDeviceState::INVALID) {
- return true;
- }
- if (state == DmDeviceState::ACTIVE) {
- return DestroyLogicalPartition(partition_name, kMapTimeout);
- }
- LOG(ERROR) << "Unknown device mapper state: "
- << static_cast<std::underlying_type_t<DmDeviceState>>(state);
- return false;
-}
-
-static bool MapPartitionOnDeviceMapper(const std::string& partition_name, std::string* path) {
- auto state = DeviceMapper::Instance().GetState(partition_name);
- if (state == DmDeviceState::INVALID) {
- return CreateLogicalPartition(GetSuperDevice(), 0 /* metadata slot */, partition_name,
- true /* force writable */, kMapTimeout, path);
- }
-
- if (state == DmDeviceState::ACTIVE) {
- return DeviceMapper::Instance().GetDmDevicePathByName(partition_name, path);
- }
- LOG(ERROR) << "Unknown device mapper state: "
- << static_cast<std::underlying_type_t<DmDeviceState>>(state);
- return false;
-}
-
Value* UnmapPartitionFn(const char* name, State* state,
const std::vector<std::unique_ptr<Expr>>& argv) {
auto args = ReadStringArgs(name, state, argv, { "name" });
if (args.empty()) return StringValue("");
- return UnmapPartitionOnDeviceMapper(args[0]) ? StringValue("t") : StringValue("");
+ auto updater_runtime = state->updater->GetRuntime();
+ return updater_runtime->UnmapPartitionOnDeviceMapper(args[0]) ? StringValue("t")
+ : StringValue("");
}
Value* MapPartitionFn(const char* name, State* state,
@@ -131,207 +79,12 @@
if (args.empty()) return StringValue("");
std::string path;
- bool result = MapPartitionOnDeviceMapper(args[0], &path);
+ auto updater_runtime = state->updater->GetRuntime();
+ bool result = updater_runtime->MapPartitionOnDeviceMapper(args[0], &path);
return result ? StringValue(path) : StringValue("");
}
-namespace { // Ops
-
-struct OpParameters {
- std::vector<std::string> tokens;
- MetadataBuilder* builder;
-
- bool ExpectArgSize(size_t size) const {
- CHECK(!tokens.empty());
- auto actual = tokens.size() - 1;
- if (actual != size) {
- LOG(ERROR) << "Op " << op() << " expects " << size << " args, got " << actual;
- return false;
- }
- return true;
- }
- const std::string& op() const {
- CHECK(!tokens.empty());
- return tokens[0];
- }
- const std::string& arg(size_t pos) const {
- CHECK_LE(pos + 1, tokens.size());
- return tokens[pos + 1];
- }
- std::optional<uint64_t> uint_arg(size_t pos, const std::string& name) const {
- auto str = arg(pos);
- uint64_t ret;
- if (!ParseUint(str, &ret)) {
- LOG(ERROR) << "Op " << op() << " expects uint64 for argument " << name << ", got " << str;
- return std::nullopt;
- }
- return ret;
- }
-};
-
-using OpFunction = std::function<bool(const OpParameters&)>;
-using OpMap = std::map<std::string, OpFunction>;
-
-bool PerformOpResize(const OpParameters& params) {
- if (!params.ExpectArgSize(2)) return false;
- const auto& partition_name = params.arg(0);
- auto size = params.uint_arg(1, "size");
- if (!size.has_value()) return false;
-
- auto partition = params.builder->FindPartition(partition_name);
- if (partition == nullptr) {
- LOG(ERROR) << "Failed to find partition " << partition_name
- << " in dynamic partition metadata.";
- return false;
- }
- if (!UnmapPartitionOnDeviceMapper(partition_name)) {
- LOG(ERROR) << "Cannot unmap " << partition_name << " before resizing.";
- return false;
- }
- if (!params.builder->ResizePartition(partition, size.value())) {
- LOG(ERROR) << "Failed to resize partition " << partition_name << " to size " << *size << ".";
- return false;
- }
- return true;
-}
-
-bool PerformOpRemove(const OpParameters& params) {
- if (!params.ExpectArgSize(1)) return false;
- const auto& partition_name = params.arg(0);
-
- if (!UnmapPartitionOnDeviceMapper(partition_name)) {
- LOG(ERROR) << "Cannot unmap " << partition_name << " before removing.";
- return false;
- }
- params.builder->RemovePartition(partition_name);
- return true;
-}
-
-bool PerformOpAdd(const OpParameters& params) {
- if (!params.ExpectArgSize(2)) return false;
- const auto& partition_name = params.arg(0);
- const auto& group_name = params.arg(1);
-
- if (params.builder->AddPartition(partition_name, group_name, LP_PARTITION_ATTR_READONLY) ==
- nullptr) {
- LOG(ERROR) << "Failed to add partition " << partition_name << " to group " << group_name << ".";
- return false;
- }
- return true;
-}
-
-bool PerformOpMove(const OpParameters& params) {
- if (!params.ExpectArgSize(2)) return false;
- const auto& partition_name = params.arg(0);
- const auto& new_group = params.arg(1);
-
- auto partition = params.builder->FindPartition(partition_name);
- if (partition == nullptr) {
- LOG(ERROR) << "Cannot move partition " << partition_name << " to group " << new_group
- << " because it is not found.";
- return false;
- }
-
- auto old_group = partition->group_name();
- if (old_group != new_group) {
- if (!params.builder->ChangePartitionGroup(partition, new_group)) {
- LOG(ERROR) << "Cannot move partition " << partition_name << " from group " << old_group
- << " to group " << new_group << ".";
- return false;
- }
- }
- return true;
-}
-
-bool PerformOpAddGroup(const OpParameters& params) {
- if (!params.ExpectArgSize(2)) return false;
- const auto& group_name = params.arg(0);
- auto maximum_size = params.uint_arg(1, "maximum_size");
- if (!maximum_size.has_value()) return false;
-
- auto group = params.builder->FindGroup(group_name);
- if (group != nullptr) {
- LOG(ERROR) << "Cannot add group " << group_name << " because it already exists.";
- return false;
- }
-
- if (maximum_size.value() == 0) {
- LOG(WARNING) << "Adding group " << group_name << " with no size limits.";
- }
-
- if (!params.builder->AddGroup(group_name, maximum_size.value())) {
- LOG(ERROR) << "Failed to add group " << group_name << " with maximum size "
- << maximum_size.value() << ".";
- return false;
- }
- return true;
-}
-
-bool PerformOpResizeGroup(const OpParameters& params) {
- if (!params.ExpectArgSize(2)) return false;
- const auto& group_name = params.arg(0);
- auto new_size = params.uint_arg(1, "maximum_size");
- if (!new_size.has_value()) return false;
-
- auto group = params.builder->FindGroup(group_name);
- if (group == nullptr) {
- LOG(ERROR) << "Cannot resize group " << group_name << " because it is not found.";
- return false;
- }
-
- auto old_size = group->maximum_size();
- if (old_size != new_size.value()) {
- if (!params.builder->ChangeGroupSize(group_name, new_size.value())) {
- LOG(ERROR) << "Cannot resize group " << group_name << " from " << old_size << " to "
- << new_size.value() << ".";
- return false;
- }
- }
- return true;
-}
-
-std::vector<std::string> ListPartitionNamesInGroup(MetadataBuilder* builder,
- const std::string& group_name) {
- auto partitions = builder->ListPartitionsInGroup(group_name);
- std::vector<std::string> partition_names;
- std::transform(partitions.begin(), partitions.end(), std::back_inserter(partition_names),
- [](Partition* partition) { return partition->name(); });
- return partition_names;
-}
-
-bool PerformOpRemoveGroup(const OpParameters& params) {
- if (!params.ExpectArgSize(1)) return false;
- const auto& group_name = params.arg(0);
-
- auto partition_names = ListPartitionNamesInGroup(params.builder, group_name);
- if (!partition_names.empty()) {
- LOG(ERROR) << "Cannot remove group " << group_name << " because it still contains partitions ["
- << android::base::Join(partition_names, ", ") << "]";
- return false;
- }
- params.builder->RemoveGroupAndPartitions(group_name);
- return true;
-}
-
-bool PerformOpRemoveAllGroups(const OpParameters& params) {
- if (!params.ExpectArgSize(0)) return false;
-
- auto group_names = params.builder->ListGroups();
- for (const auto& group_name : group_names) {
- auto partition_names = ListPartitionNamesInGroup(params.builder, group_name);
- for (const auto& partition_name : partition_names) {
- if (!UnmapPartitionOnDeviceMapper(partition_name)) {
- LOG(ERROR) << "Cannot unmap " << partition_name << " before removing group " << group_name
- << ".";
- return false;
- }
- }
- params.builder->RemoveGroupAndPartitions(group_name);
- }
- return true;
-}
-
-} // namespace
+static constexpr char kMetadataUpdatedMarker[] = "/dynamic_partition_metadata.UPDATED";
Value* UpdateDynamicPartitionsFn(const char* name, State* state,
const std::vector<std::unique_ptr<Expr>>& argv) {
@@ -367,56 +120,8 @@
}
}
- auto super_device = GetSuperDevice();
- auto builder = MetadataBuilder::New(PartitionOpener(), super_device, 0);
- if (builder == nullptr) {
- LOG(ERROR) << "Failed to load dynamic partition metadata.";
- return StringValue("");
- }
-
- static const OpMap op_map{
- // clang-format off
- {"resize", PerformOpResize},
- {"remove", PerformOpRemove},
- {"add", PerformOpAdd},
- {"move", PerformOpMove},
- {"add_group", PerformOpAddGroup},
- {"resize_group", PerformOpResizeGroup},
- {"remove_group", PerformOpRemoveGroup},
- {"remove_all_groups", PerformOpRemoveAllGroups},
- // clang-format on
- };
-
- std::vector<std::string> lines = android::base::Split(op_list_value->data, "\n");
- for (const auto& line : lines) {
- auto comment_idx = line.find('#');
- auto op_and_args = comment_idx == std::string::npos ? line : line.substr(0, comment_idx);
- op_and_args = android::base::Trim(op_and_args);
- if (op_and_args.empty()) continue;
-
- auto tokens = android::base::Split(op_and_args, " ");
- const auto& op = tokens[0];
- auto it = op_map.find(op);
- if (it == op_map.end()) {
- LOG(ERROR) << "Unknown operation in op_list: " << op;
- return StringValue("");
- }
- OpParameters params;
- params.tokens = tokens;
- params.builder = builder.get();
- if (!it->second(params)) {
- return StringValue("");
- }
- }
-
- auto metadata = builder->Export();
- if (metadata == nullptr) {
- LOG(ERROR) << "Failed to export metadata.";
- return StringValue("");
- }
-
- if (!UpdatePartitionTable(super_device, *metadata, 0)) {
- LOG(ERROR) << "Failed to write metadata.";
+ auto updater_runtime = state->updater->GetRuntime();
+ if (!updater_runtime->UpdateDynamicPartitions(op_list_value->data)) {
return StringValue("");
}