xref: /aosp_15_r20/bootable/deprecated-ota/updater/updater_runtime_dynamic_partitions.cpp (revision acea8879c968027b49a027136800575dd9783ddf)
1*acea8879SAndroid Build Coastguard Worker /*
2*acea8879SAndroid Build Coastguard Worker  * Copyright (C) 2019 The Android Open Source Project
3*acea8879SAndroid Build Coastguard Worker  *
4*acea8879SAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*acea8879SAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*acea8879SAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*acea8879SAndroid Build Coastguard Worker  *
8*acea8879SAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*acea8879SAndroid Build Coastguard Worker  *
10*acea8879SAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*acea8879SAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*acea8879SAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*acea8879SAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*acea8879SAndroid Build Coastguard Worker  * limitations under the License.
15*acea8879SAndroid Build Coastguard Worker  */
16*acea8879SAndroid Build Coastguard Worker 
17*acea8879SAndroid Build Coastguard Worker #include "updater/updater_runtime.h"
18*acea8879SAndroid Build Coastguard Worker 
19*acea8879SAndroid Build Coastguard Worker #include <algorithm>
20*acea8879SAndroid Build Coastguard Worker #include <chrono>
21*acea8879SAndroid Build Coastguard Worker #include <iterator>
22*acea8879SAndroid Build Coastguard Worker #include <optional>
23*acea8879SAndroid Build Coastguard Worker #include <string>
24*acea8879SAndroid Build Coastguard Worker #include <type_traits>
25*acea8879SAndroid Build Coastguard Worker #include <vector>
26*acea8879SAndroid Build Coastguard Worker 
27*acea8879SAndroid Build Coastguard Worker #include <android-base/logging.h>
28*acea8879SAndroid Build Coastguard Worker #include <android-base/parseint.h>
29*acea8879SAndroid Build Coastguard Worker #include <android-base/strings.h>
30*acea8879SAndroid Build Coastguard Worker #include <fs_mgr.h>
31*acea8879SAndroid Build Coastguard Worker #include <fs_mgr_dm_linear.h>
32*acea8879SAndroid Build Coastguard Worker #include <libdm/dm.h>
33*acea8879SAndroid Build Coastguard Worker #include <liblp/builder.h>
34*acea8879SAndroid Build Coastguard Worker 
35*acea8879SAndroid Build Coastguard Worker using android::dm::DeviceMapper;
36*acea8879SAndroid Build Coastguard Worker using android::dm::DmDeviceState;
37*acea8879SAndroid Build Coastguard Worker using android::fs_mgr::CreateLogicalPartition;
38*acea8879SAndroid Build Coastguard Worker using android::fs_mgr::CreateLogicalPartitionParams;
39*acea8879SAndroid Build Coastguard Worker using android::fs_mgr::DestroyLogicalPartition;
40*acea8879SAndroid Build Coastguard Worker using android::fs_mgr::LpMetadata;
41*acea8879SAndroid Build Coastguard Worker using android::fs_mgr::MetadataBuilder;
42*acea8879SAndroid Build Coastguard Worker using android::fs_mgr::Partition;
43*acea8879SAndroid Build Coastguard Worker using android::fs_mgr::PartitionOpener;
44*acea8879SAndroid Build Coastguard Worker using android::fs_mgr::SlotNumberForSlotSuffix;
45*acea8879SAndroid Build Coastguard Worker 
46*acea8879SAndroid Build Coastguard Worker static constexpr std::chrono::milliseconds kMapTimeout{ 1000 };
47*acea8879SAndroid Build Coastguard Worker 
GetSuperDevice()48*acea8879SAndroid Build Coastguard Worker static std::string GetSuperDevice() {
49*acea8879SAndroid Build Coastguard Worker   return "/dev/block/by-name/" + fs_mgr_get_super_partition_name();
50*acea8879SAndroid Build Coastguard Worker }
51*acea8879SAndroid Build Coastguard Worker 
AddSlotSuffix(const std::string & partition_name)52*acea8879SAndroid Build Coastguard Worker static std::string AddSlotSuffix(const std::string& partition_name) {
53*acea8879SAndroid Build Coastguard Worker   return partition_name + fs_mgr_get_slot_suffix();
54*acea8879SAndroid Build Coastguard Worker }
55*acea8879SAndroid Build Coastguard Worker 
UnmapPartitionWithSuffixOnDeviceMapper(const std::string & partition_name_suffix)56*acea8879SAndroid Build Coastguard Worker static bool UnmapPartitionWithSuffixOnDeviceMapper(const std::string& partition_name_suffix) {
57*acea8879SAndroid Build Coastguard Worker   auto state = DeviceMapper::Instance().GetState(partition_name_suffix);
58*acea8879SAndroid Build Coastguard Worker   if (state == DmDeviceState::INVALID) {
59*acea8879SAndroid Build Coastguard Worker     return true;
60*acea8879SAndroid Build Coastguard Worker   }
61*acea8879SAndroid Build Coastguard Worker   if (state == DmDeviceState::ACTIVE) {
62*acea8879SAndroid Build Coastguard Worker     return DestroyLogicalPartition(partition_name_suffix);
63*acea8879SAndroid Build Coastguard Worker   }
64*acea8879SAndroid Build Coastguard Worker   LOG(ERROR) << "Unknown device mapper state: "
65*acea8879SAndroid Build Coastguard Worker              << static_cast<std::underlying_type_t<DmDeviceState>>(state);
66*acea8879SAndroid Build Coastguard Worker   return false;
67*acea8879SAndroid Build Coastguard Worker }
68*acea8879SAndroid Build Coastguard Worker 
MapPartitionOnDeviceMapper(const std::string & partition_name,std::string * path)69*acea8879SAndroid Build Coastguard Worker bool UpdaterRuntime::MapPartitionOnDeviceMapper(const std::string& partition_name,
70*acea8879SAndroid Build Coastguard Worker                                                 std::string* path) {
71*acea8879SAndroid Build Coastguard Worker   auto partition_name_suffix = AddSlotSuffix(partition_name);
72*acea8879SAndroid Build Coastguard Worker   auto state = DeviceMapper::Instance().GetState(partition_name_suffix);
73*acea8879SAndroid Build Coastguard Worker   if (state == DmDeviceState::INVALID) {
74*acea8879SAndroid Build Coastguard Worker     CreateLogicalPartitionParams params = {
75*acea8879SAndroid Build Coastguard Worker       .block_device = GetSuperDevice(),
76*acea8879SAndroid Build Coastguard Worker       // If device supports A/B, apply non-A/B update to the partition at current slot. Otherwise,
77*acea8879SAndroid Build Coastguard Worker       // SlotNumberForSlotSuffix("") returns 0.
78*acea8879SAndroid Build Coastguard Worker       .metadata_slot = SlotNumberForSlotSuffix(fs_mgr_get_slot_suffix()),
79*acea8879SAndroid Build Coastguard Worker       // If device supports A/B, apply non-A/B update to the partition at current slot. Otherwise,
80*acea8879SAndroid Build Coastguard Worker       // fs_mgr_get_slot_suffix() returns empty string.
81*acea8879SAndroid Build Coastguard Worker       .partition_name = partition_name_suffix,
82*acea8879SAndroid Build Coastguard Worker       .force_writable = true,
83*acea8879SAndroid Build Coastguard Worker       .timeout_ms = kMapTimeout,
84*acea8879SAndroid Build Coastguard Worker     };
85*acea8879SAndroid Build Coastguard Worker     return CreateLogicalPartition(params, path);
86*acea8879SAndroid Build Coastguard Worker   }
87*acea8879SAndroid Build Coastguard Worker 
88*acea8879SAndroid Build Coastguard Worker   if (state == DmDeviceState::ACTIVE) {
89*acea8879SAndroid Build Coastguard Worker     return DeviceMapper::Instance().GetDmDevicePathByName(partition_name_suffix, path);
90*acea8879SAndroid Build Coastguard Worker   }
91*acea8879SAndroid Build Coastguard Worker   LOG(ERROR) << "Unknown device mapper state: "
92*acea8879SAndroid Build Coastguard Worker              << static_cast<std::underlying_type_t<DmDeviceState>>(state);
93*acea8879SAndroid Build Coastguard Worker   return false;
94*acea8879SAndroid Build Coastguard Worker }
95*acea8879SAndroid Build Coastguard Worker 
UnmapPartitionOnDeviceMapper(const std::string & partition_name)96*acea8879SAndroid Build Coastguard Worker bool UpdaterRuntime::UnmapPartitionOnDeviceMapper(const std::string& partition_name) {
97*acea8879SAndroid Build Coastguard Worker   return ::UnmapPartitionWithSuffixOnDeviceMapper(AddSlotSuffix(partition_name));
98*acea8879SAndroid Build Coastguard Worker }
99*acea8879SAndroid Build Coastguard Worker 
100*acea8879SAndroid Build Coastguard Worker namespace {  // Ops
101*acea8879SAndroid Build Coastguard Worker 
102*acea8879SAndroid Build Coastguard Worker struct OpParameters {
103*acea8879SAndroid Build Coastguard Worker   std::vector<std::string> tokens;
104*acea8879SAndroid Build Coastguard Worker   MetadataBuilder* builder;
105*acea8879SAndroid Build Coastguard Worker 
ExpectArgSize__anon3d2694da0111::OpParameters106*acea8879SAndroid Build Coastguard Worker   bool ExpectArgSize(size_t size) const {
107*acea8879SAndroid Build Coastguard Worker     CHECK(!tokens.empty());
108*acea8879SAndroid Build Coastguard Worker     auto actual = tokens.size() - 1;
109*acea8879SAndroid Build Coastguard Worker     if (actual != size) {
110*acea8879SAndroid Build Coastguard Worker       LOG(ERROR) << "Op " << op() << " expects " << size << " args, got " << actual;
111*acea8879SAndroid Build Coastguard Worker       return false;
112*acea8879SAndroid Build Coastguard Worker     }
113*acea8879SAndroid Build Coastguard Worker     return true;
114*acea8879SAndroid Build Coastguard Worker   }
op__anon3d2694da0111::OpParameters115*acea8879SAndroid Build Coastguard Worker   const std::string& op() const {
116*acea8879SAndroid Build Coastguard Worker     CHECK(!tokens.empty());
117*acea8879SAndroid Build Coastguard Worker     return tokens[0];
118*acea8879SAndroid Build Coastguard Worker   }
arg__anon3d2694da0111::OpParameters119*acea8879SAndroid Build Coastguard Worker   const std::string& arg(size_t pos) const {
120*acea8879SAndroid Build Coastguard Worker     CHECK_LE(pos + 1, tokens.size());
121*acea8879SAndroid Build Coastguard Worker     return tokens[pos + 1];
122*acea8879SAndroid Build Coastguard Worker   }
uint_arg__anon3d2694da0111::OpParameters123*acea8879SAndroid Build Coastguard Worker   std::optional<uint64_t> uint_arg(size_t pos, const std::string& name) const {
124*acea8879SAndroid Build Coastguard Worker     auto str = arg(pos);
125*acea8879SAndroid Build Coastguard Worker     uint64_t ret;
126*acea8879SAndroid Build Coastguard Worker     if (!android::base::ParseUint(str, &ret)) {
127*acea8879SAndroid Build Coastguard Worker       LOG(ERROR) << "Op " << op() << " expects uint64 for argument " << name << ", got " << str;
128*acea8879SAndroid Build Coastguard Worker       return std::nullopt;
129*acea8879SAndroid Build Coastguard Worker     }
130*acea8879SAndroid Build Coastguard Worker     return ret;
131*acea8879SAndroid Build Coastguard Worker   }
132*acea8879SAndroid Build Coastguard Worker };
133*acea8879SAndroid Build Coastguard Worker 
134*acea8879SAndroid Build Coastguard Worker using OpFunction = std::function<bool(const OpParameters&)>;
135*acea8879SAndroid Build Coastguard Worker using OpMap = std::map<std::string, OpFunction>;
136*acea8879SAndroid Build Coastguard Worker 
PerformOpResize(const OpParameters & params)137*acea8879SAndroid Build Coastguard Worker bool PerformOpResize(const OpParameters& params) {
138*acea8879SAndroid Build Coastguard Worker   if (!params.ExpectArgSize(2)) return false;
139*acea8879SAndroid Build Coastguard Worker   const auto& partition_name_suffix = AddSlotSuffix(params.arg(0));
140*acea8879SAndroid Build Coastguard Worker   auto size = params.uint_arg(1, "size");
141*acea8879SAndroid Build Coastguard Worker   if (!size.has_value()) return false;
142*acea8879SAndroid Build Coastguard Worker 
143*acea8879SAndroid Build Coastguard Worker   auto partition = params.builder->FindPartition(partition_name_suffix);
144*acea8879SAndroid Build Coastguard Worker   if (partition == nullptr) {
145*acea8879SAndroid Build Coastguard Worker     LOG(ERROR) << "Failed to find partition " << partition_name_suffix
146*acea8879SAndroid Build Coastguard Worker                << " in dynamic partition metadata.";
147*acea8879SAndroid Build Coastguard Worker     return false;
148*acea8879SAndroid Build Coastguard Worker   }
149*acea8879SAndroid Build Coastguard Worker   if (!UnmapPartitionWithSuffixOnDeviceMapper(partition_name_suffix)) {
150*acea8879SAndroid Build Coastguard Worker     LOG(ERROR) << "Cannot unmap " << partition_name_suffix << " before resizing.";
151*acea8879SAndroid Build Coastguard Worker     return false;
152*acea8879SAndroid Build Coastguard Worker   }
153*acea8879SAndroid Build Coastguard Worker   if (!params.builder->ResizePartition(partition, size.value())) {
154*acea8879SAndroid Build Coastguard Worker     LOG(ERROR) << "Failed to resize partition " << partition_name_suffix << " to size " << *size
155*acea8879SAndroid Build Coastguard Worker                << ".";
156*acea8879SAndroid Build Coastguard Worker     return false;
157*acea8879SAndroid Build Coastguard Worker   }
158*acea8879SAndroid Build Coastguard Worker   return true;
159*acea8879SAndroid Build Coastguard Worker }
160*acea8879SAndroid Build Coastguard Worker 
PerformOpRemove(const OpParameters & params)161*acea8879SAndroid Build Coastguard Worker bool PerformOpRemove(const OpParameters& params) {
162*acea8879SAndroid Build Coastguard Worker   if (!params.ExpectArgSize(1)) return false;
163*acea8879SAndroid Build Coastguard Worker   const auto& partition_name_suffix = AddSlotSuffix(params.arg(0));
164*acea8879SAndroid Build Coastguard Worker 
165*acea8879SAndroid Build Coastguard Worker   if (!UnmapPartitionWithSuffixOnDeviceMapper(partition_name_suffix)) {
166*acea8879SAndroid Build Coastguard Worker     LOG(ERROR) << "Cannot unmap " << partition_name_suffix << " before removing.";
167*acea8879SAndroid Build Coastguard Worker     return false;
168*acea8879SAndroid Build Coastguard Worker   }
169*acea8879SAndroid Build Coastguard Worker   params.builder->RemovePartition(partition_name_suffix);
170*acea8879SAndroid Build Coastguard Worker   return true;
171*acea8879SAndroid Build Coastguard Worker }
172*acea8879SAndroid Build Coastguard Worker 
PerformOpAdd(const OpParameters & params)173*acea8879SAndroid Build Coastguard Worker bool PerformOpAdd(const OpParameters& params) {
174*acea8879SAndroid Build Coastguard Worker   if (!params.ExpectArgSize(2)) return false;
175*acea8879SAndroid Build Coastguard Worker   const auto& partition_name_suffix = AddSlotSuffix(params.arg(0));
176*acea8879SAndroid Build Coastguard Worker   const auto& group_name_suffix = AddSlotSuffix(params.arg(1));
177*acea8879SAndroid Build Coastguard Worker 
178*acea8879SAndroid Build Coastguard Worker   if (params.builder->AddPartition(partition_name_suffix, group_name_suffix,
179*acea8879SAndroid Build Coastguard Worker                                    LP_PARTITION_ATTR_READONLY) == nullptr) {
180*acea8879SAndroid Build Coastguard Worker     LOG(ERROR) << "Failed to add partition " << partition_name_suffix << " to group "
181*acea8879SAndroid Build Coastguard Worker                << group_name_suffix << ".";
182*acea8879SAndroid Build Coastguard Worker     return false;
183*acea8879SAndroid Build Coastguard Worker   }
184*acea8879SAndroid Build Coastguard Worker   return true;
185*acea8879SAndroid Build Coastguard Worker }
186*acea8879SAndroid Build Coastguard Worker 
PerformOpMove(const OpParameters & params)187*acea8879SAndroid Build Coastguard Worker bool PerformOpMove(const OpParameters& params) {
188*acea8879SAndroid Build Coastguard Worker   if (!params.ExpectArgSize(2)) return false;
189*acea8879SAndroid Build Coastguard Worker   const auto& partition_name_suffix = AddSlotSuffix(params.arg(0));
190*acea8879SAndroid Build Coastguard Worker   const auto& new_group_name_suffix = AddSlotSuffix(params.arg(1));
191*acea8879SAndroid Build Coastguard Worker 
192*acea8879SAndroid Build Coastguard Worker   auto partition = params.builder->FindPartition(partition_name_suffix);
193*acea8879SAndroid Build Coastguard Worker   if (partition == nullptr) {
194*acea8879SAndroid Build Coastguard Worker     LOG(ERROR) << "Cannot move partition " << partition_name_suffix << " to group "
195*acea8879SAndroid Build Coastguard Worker                << new_group_name_suffix << " because it is not found.";
196*acea8879SAndroid Build Coastguard Worker     return false;
197*acea8879SAndroid Build Coastguard Worker   }
198*acea8879SAndroid Build Coastguard Worker 
199*acea8879SAndroid Build Coastguard Worker   auto old_group_name_suffix = partition->group_name();
200*acea8879SAndroid Build Coastguard Worker   if (old_group_name_suffix != new_group_name_suffix) {
201*acea8879SAndroid Build Coastguard Worker     if (!params.builder->ChangePartitionGroup(partition, new_group_name_suffix)) {
202*acea8879SAndroid Build Coastguard Worker       LOG(ERROR) << "Cannot move partition " << partition_name_suffix << " from group "
203*acea8879SAndroid Build Coastguard Worker                  << old_group_name_suffix << " to group " << new_group_name_suffix << ".";
204*acea8879SAndroid Build Coastguard Worker       return false;
205*acea8879SAndroid Build Coastguard Worker     }
206*acea8879SAndroid Build Coastguard Worker   }
207*acea8879SAndroid Build Coastguard Worker   return true;
208*acea8879SAndroid Build Coastguard Worker }
209*acea8879SAndroid Build Coastguard Worker 
PerformOpAddGroup(const OpParameters & params)210*acea8879SAndroid Build Coastguard Worker bool PerformOpAddGroup(const OpParameters& params) {
211*acea8879SAndroid Build Coastguard Worker   if (!params.ExpectArgSize(2)) return false;
212*acea8879SAndroid Build Coastguard Worker   const auto& group_name_suffix = AddSlotSuffix(params.arg(0));
213*acea8879SAndroid Build Coastguard Worker   auto maximum_size = params.uint_arg(1, "maximum_size");
214*acea8879SAndroid Build Coastguard Worker   if (!maximum_size.has_value()) return false;
215*acea8879SAndroid Build Coastguard Worker 
216*acea8879SAndroid Build Coastguard Worker   auto group = params.builder->FindGroup(group_name_suffix);
217*acea8879SAndroid Build Coastguard Worker   if (group != nullptr) {
218*acea8879SAndroid Build Coastguard Worker     LOG(ERROR) << "Cannot add group " << group_name_suffix << " because it already exists.";
219*acea8879SAndroid Build Coastguard Worker     return false;
220*acea8879SAndroid Build Coastguard Worker   }
221*acea8879SAndroid Build Coastguard Worker 
222*acea8879SAndroid Build Coastguard Worker   if (maximum_size.value() == 0) {
223*acea8879SAndroid Build Coastguard Worker     LOG(WARNING) << "Adding group " << group_name_suffix << " with no size limits.";
224*acea8879SAndroid Build Coastguard Worker   }
225*acea8879SAndroid Build Coastguard Worker 
226*acea8879SAndroid Build Coastguard Worker   if (!params.builder->AddGroup(group_name_suffix, maximum_size.value())) {
227*acea8879SAndroid Build Coastguard Worker     LOG(ERROR) << "Failed to add group " << group_name_suffix << " with maximum size "
228*acea8879SAndroid Build Coastguard Worker                << maximum_size.value() << ".";
229*acea8879SAndroid Build Coastguard Worker     return false;
230*acea8879SAndroid Build Coastguard Worker   }
231*acea8879SAndroid Build Coastguard Worker   return true;
232*acea8879SAndroid Build Coastguard Worker }
233*acea8879SAndroid Build Coastguard Worker 
PerformOpResizeGroup(const OpParameters & params)234*acea8879SAndroid Build Coastguard Worker bool PerformOpResizeGroup(const OpParameters& params) {
235*acea8879SAndroid Build Coastguard Worker   if (!params.ExpectArgSize(2)) return false;
236*acea8879SAndroid Build Coastguard Worker   const auto& group_name_suffix = AddSlotSuffix(params.arg(0));
237*acea8879SAndroid Build Coastguard Worker   auto new_size = params.uint_arg(1, "maximum_size");
238*acea8879SAndroid Build Coastguard Worker   if (!new_size.has_value()) return false;
239*acea8879SAndroid Build Coastguard Worker 
240*acea8879SAndroid Build Coastguard Worker   auto group = params.builder->FindGroup(group_name_suffix);
241*acea8879SAndroid Build Coastguard Worker   if (group == nullptr) {
242*acea8879SAndroid Build Coastguard Worker     LOG(ERROR) << "Cannot resize group " << group_name_suffix << " because it is not found.";
243*acea8879SAndroid Build Coastguard Worker     return false;
244*acea8879SAndroid Build Coastguard Worker   }
245*acea8879SAndroid Build Coastguard Worker 
246*acea8879SAndroid Build Coastguard Worker   auto old_size = group->maximum_size();
247*acea8879SAndroid Build Coastguard Worker   if (old_size != new_size.value()) {
248*acea8879SAndroid Build Coastguard Worker     if (!params.builder->ChangeGroupSize(group_name_suffix, new_size.value())) {
249*acea8879SAndroid Build Coastguard Worker       LOG(ERROR) << "Cannot resize group " << group_name_suffix << " from " << old_size << " to "
250*acea8879SAndroid Build Coastguard Worker                  << new_size.value() << ".";
251*acea8879SAndroid Build Coastguard Worker       return false;
252*acea8879SAndroid Build Coastguard Worker     }
253*acea8879SAndroid Build Coastguard Worker   }
254*acea8879SAndroid Build Coastguard Worker   return true;
255*acea8879SAndroid Build Coastguard Worker }
256*acea8879SAndroid Build Coastguard Worker 
ListPartitionNamesInGroup(MetadataBuilder * builder,const std::string & group_name_suffix)257*acea8879SAndroid Build Coastguard Worker std::vector<std::string> ListPartitionNamesInGroup(MetadataBuilder* builder,
258*acea8879SAndroid Build Coastguard Worker                                                    const std::string& group_name_suffix) {
259*acea8879SAndroid Build Coastguard Worker   auto partitions = builder->ListPartitionsInGroup(group_name_suffix);
260*acea8879SAndroid Build Coastguard Worker   std::vector<std::string> partition_names;
261*acea8879SAndroid Build Coastguard Worker   std::transform(partitions.begin(), partitions.end(), std::back_inserter(partition_names),
262*acea8879SAndroid Build Coastguard Worker                  [](Partition* partition) { return partition->name(); });
263*acea8879SAndroid Build Coastguard Worker   return partition_names;
264*acea8879SAndroid Build Coastguard Worker }
265*acea8879SAndroid Build Coastguard Worker 
PerformOpRemoveGroup(const OpParameters & params)266*acea8879SAndroid Build Coastguard Worker bool PerformOpRemoveGroup(const OpParameters& params) {
267*acea8879SAndroid Build Coastguard Worker   if (!params.ExpectArgSize(1)) return false;
268*acea8879SAndroid Build Coastguard Worker   const auto& group_name_suffix = AddSlotSuffix(params.arg(0));
269*acea8879SAndroid Build Coastguard Worker 
270*acea8879SAndroid Build Coastguard Worker   auto partition_names = ListPartitionNamesInGroup(params.builder, group_name_suffix);
271*acea8879SAndroid Build Coastguard Worker   if (!partition_names.empty()) {
272*acea8879SAndroid Build Coastguard Worker     LOG(ERROR) << "Cannot remove group " << group_name_suffix
273*acea8879SAndroid Build Coastguard Worker                << " because it still contains partitions ["
274*acea8879SAndroid Build Coastguard Worker                << android::base::Join(partition_names, ", ") << "]";
275*acea8879SAndroid Build Coastguard Worker     return false;
276*acea8879SAndroid Build Coastguard Worker   }
277*acea8879SAndroid Build Coastguard Worker   params.builder->RemoveGroupAndPartitions(group_name_suffix);
278*acea8879SAndroid Build Coastguard Worker   return true;
279*acea8879SAndroid Build Coastguard Worker }
280*acea8879SAndroid Build Coastguard Worker 
PerformOpRemoveAllGroups(const OpParameters & params)281*acea8879SAndroid Build Coastguard Worker bool PerformOpRemoveAllGroups(const OpParameters& params) {
282*acea8879SAndroid Build Coastguard Worker   if (!params.ExpectArgSize(0)) return false;
283*acea8879SAndroid Build Coastguard Worker 
284*acea8879SAndroid Build Coastguard Worker   auto group_names = params.builder->ListGroups();
285*acea8879SAndroid Build Coastguard Worker   for (const auto& group_name_suffix : group_names) {
286*acea8879SAndroid Build Coastguard Worker     auto partition_names = ListPartitionNamesInGroup(params.builder, group_name_suffix);
287*acea8879SAndroid Build Coastguard Worker     for (const auto& partition_name_suffix : partition_names) {
288*acea8879SAndroid Build Coastguard Worker       if (!UnmapPartitionWithSuffixOnDeviceMapper(partition_name_suffix)) {
289*acea8879SAndroid Build Coastguard Worker         LOG(ERROR) << "Cannot unmap " << partition_name_suffix << " before removing group "
290*acea8879SAndroid Build Coastguard Worker                    << group_name_suffix << ".";
291*acea8879SAndroid Build Coastguard Worker         return false;
292*acea8879SAndroid Build Coastguard Worker       }
293*acea8879SAndroid Build Coastguard Worker     }
294*acea8879SAndroid Build Coastguard Worker     params.builder->RemoveGroupAndPartitions(group_name_suffix);
295*acea8879SAndroid Build Coastguard Worker   }
296*acea8879SAndroid Build Coastguard Worker   return true;
297*acea8879SAndroid Build Coastguard Worker }
298*acea8879SAndroid Build Coastguard Worker 
299*acea8879SAndroid Build Coastguard Worker }  // namespace
300*acea8879SAndroid Build Coastguard Worker 
UpdateDynamicPartitions(const std::string_view op_list_value)301*acea8879SAndroid Build Coastguard Worker bool UpdaterRuntime::UpdateDynamicPartitions(const std::string_view op_list_value) {
302*acea8879SAndroid Build Coastguard Worker   auto super_device = GetSuperDevice();
303*acea8879SAndroid Build Coastguard Worker   auto builder = MetadataBuilder::New(PartitionOpener(), super_device, 0);
304*acea8879SAndroid Build Coastguard Worker   if (builder == nullptr) {
305*acea8879SAndroid Build Coastguard Worker     LOG(ERROR) << "Failed to load dynamic partition metadata.";
306*acea8879SAndroid Build Coastguard Worker     return false;
307*acea8879SAndroid Build Coastguard Worker   }
308*acea8879SAndroid Build Coastguard Worker 
309*acea8879SAndroid Build Coastguard Worker   static const OpMap op_map{
310*acea8879SAndroid Build Coastguard Worker     // clang-format off
311*acea8879SAndroid Build Coastguard Worker     {"resize",                PerformOpResize},
312*acea8879SAndroid Build Coastguard Worker     {"remove",                PerformOpRemove},
313*acea8879SAndroid Build Coastguard Worker     {"add",                   PerformOpAdd},
314*acea8879SAndroid Build Coastguard Worker     {"move",                  PerformOpMove},
315*acea8879SAndroid Build Coastguard Worker     {"add_group",             PerformOpAddGroup},
316*acea8879SAndroid Build Coastguard Worker     {"resize_group",          PerformOpResizeGroup},
317*acea8879SAndroid Build Coastguard Worker     {"remove_group",          PerformOpRemoveGroup},
318*acea8879SAndroid Build Coastguard Worker     {"remove_all_groups",     PerformOpRemoveAllGroups},
319*acea8879SAndroid Build Coastguard Worker     // clang-format on
320*acea8879SAndroid Build Coastguard Worker   };
321*acea8879SAndroid Build Coastguard Worker 
322*acea8879SAndroid Build Coastguard Worker   std::vector<std::string> lines = android::base::Split(std::string(op_list_value), "\n");
323*acea8879SAndroid Build Coastguard Worker   for (const auto& line : lines) {
324*acea8879SAndroid Build Coastguard Worker     auto comment_idx = line.find('#');
325*acea8879SAndroid Build Coastguard Worker     auto op_and_args = comment_idx == std::string::npos ? line : line.substr(0, comment_idx);
326*acea8879SAndroid Build Coastguard Worker     op_and_args = android::base::Trim(op_and_args);
327*acea8879SAndroid Build Coastguard Worker     if (op_and_args.empty()) continue;
328*acea8879SAndroid Build Coastguard Worker 
329*acea8879SAndroid Build Coastguard Worker     auto tokens = android::base::Split(op_and_args, " ");
330*acea8879SAndroid Build Coastguard Worker     const auto& op = tokens[0];
331*acea8879SAndroid Build Coastguard Worker     auto it = op_map.find(op);
332*acea8879SAndroid Build Coastguard Worker     if (it == op_map.end()) {
333*acea8879SAndroid Build Coastguard Worker       LOG(ERROR) << "Unknown operation in op_list: " << op;
334*acea8879SAndroid Build Coastguard Worker       return false;
335*acea8879SAndroid Build Coastguard Worker     }
336*acea8879SAndroid Build Coastguard Worker     OpParameters params;
337*acea8879SAndroid Build Coastguard Worker     params.tokens = tokens;
338*acea8879SAndroid Build Coastguard Worker     params.builder = builder.get();
339*acea8879SAndroid Build Coastguard Worker     if (!it->second(params)) {
340*acea8879SAndroid Build Coastguard Worker       return false;
341*acea8879SAndroid Build Coastguard Worker     }
342*acea8879SAndroid Build Coastguard Worker   }
343*acea8879SAndroid Build Coastguard Worker 
344*acea8879SAndroid Build Coastguard Worker   auto metadata = builder->Export();
345*acea8879SAndroid Build Coastguard Worker   if (metadata == nullptr) {
346*acea8879SAndroid Build Coastguard Worker     LOG(ERROR) << "Failed to export metadata.";
347*acea8879SAndroid Build Coastguard Worker     return false;
348*acea8879SAndroid Build Coastguard Worker   }
349*acea8879SAndroid Build Coastguard Worker 
350*acea8879SAndroid Build Coastguard Worker   if (!UpdatePartitionTable(super_device, *metadata, 0)) {
351*acea8879SAndroid Build Coastguard Worker     LOG(ERROR) << "Failed to write metadata.";
352*acea8879SAndroid Build Coastguard Worker     return false;
353*acea8879SAndroid Build Coastguard Worker   }
354*acea8879SAndroid Build Coastguard Worker 
355*acea8879SAndroid Build Coastguard Worker   return true;
356*acea8879SAndroid Build Coastguard Worker }
357