1 /*
2 * Copyright (C) 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "liblp/builder.h"
18
19 #include <string.h>
20
21 #include <algorithm>
22 #include <limits>
23
24 #include <android-base/unique_fd.h>
25
26 #include "liblp/liblp.h"
27 #include "liblp/property_fetcher.h"
28 #include "reader.h"
29 #include "utility.h"
30
31 namespace android {
32 namespace fs_mgr {
33
operator <<(std::ostream & os,const Extent & extent)34 std::ostream& operator<<(std::ostream& os, const Extent& extent) {
35 switch (extent.GetExtentType()) {
36 case ExtentType::kZero: {
37 os << "type: Zero";
38 break;
39 }
40 case ExtentType::kLinear: {
41 auto linear_extent = static_cast<const LinearExtent*>(&extent);
42 os << "type: Linear, physical sectors: " << linear_extent->physical_sector()
43 << ", end sectors: " << linear_extent->end_sector();
44 break;
45 }
46 }
47 return os;
48 }
49
AddTo(LpMetadata * out) const50 bool LinearExtent::AddTo(LpMetadata* out) const {
51 if (device_index_ >= out->block_devices.size()) {
52 LERROR << "Extent references unknown block device.";
53 return false;
54 }
55 out->extents.emplace_back(
56 LpMetadataExtent{num_sectors_, LP_TARGET_TYPE_LINEAR, physical_sector_, device_index_});
57 return true;
58 }
59
operator ==(const android::fs_mgr::Extent & other) const60 bool LinearExtent::operator==(const android::fs_mgr::Extent& other) const {
61 if (other.GetExtentType() != ExtentType::kLinear) {
62 return false;
63 }
64
65 auto other_ptr = static_cast<const LinearExtent*>(&other);
66 return num_sectors_ == other_ptr->num_sectors_ &&
67 physical_sector_ == other_ptr->physical_sector_ &&
68 device_index_ == other_ptr->device_index_;
69 }
70
OverlapsWith(const LinearExtent & other) const71 bool LinearExtent::OverlapsWith(const LinearExtent& other) const {
72 if (device_index_ != other.device_index()) {
73 return false;
74 }
75 return physical_sector() < other.end_sector() && other.physical_sector() < end_sector();
76 }
77
OverlapsWith(const Interval & interval) const78 bool LinearExtent::OverlapsWith(const Interval& interval) const {
79 if (device_index_ != interval.device_index) {
80 return false;
81 }
82 return physical_sector() < interval.end && interval.start < end_sector();
83 }
84
AsInterval() const85 Interval LinearExtent::AsInterval() const {
86 return Interval(device_index(), physical_sector(), end_sector());
87 }
88
AddTo(LpMetadata * out) const89 bool ZeroExtent::AddTo(LpMetadata* out) const {
90 out->extents.emplace_back(LpMetadataExtent{num_sectors_, LP_TARGET_TYPE_ZERO, 0, 0});
91 return true;
92 }
93
operator ==(const android::fs_mgr::Extent & other) const94 bool ZeroExtent::operator==(const android::fs_mgr::Extent& other) const {
95 return other.GetExtentType() == ExtentType::kZero && num_sectors_ == other.num_sectors();
96 }
97
Partition(std::string_view name,std::string_view group_name,uint32_t attributes)98 Partition::Partition(std::string_view name, std::string_view group_name, uint32_t attributes)
99 : name_(name), group_name_(group_name), attributes_(attributes), size_(0) {}
100
AddExtent(std::unique_ptr<Extent> && extent)101 void Partition::AddExtent(std::unique_ptr<Extent>&& extent) {
102 size_ += extent->num_sectors() * LP_SECTOR_SIZE;
103
104 if (LinearExtent* new_extent = extent->AsLinearExtent()) {
105 if (!extents_.empty() && extents_.back()->AsLinearExtent()) {
106 LinearExtent* prev_extent = extents_.back()->AsLinearExtent();
107 if (prev_extent->end_sector() == new_extent->physical_sector() &&
108 prev_extent->device_index() == new_extent->device_index()) {
109 // If the previous extent can be merged into this new one, do so
110 // to avoid creating unnecessary extents.
111 extent = std::make_unique<LinearExtent>(
112 prev_extent->num_sectors() + new_extent->num_sectors(),
113 prev_extent->device_index(), prev_extent->physical_sector());
114 extents_.pop_back();
115 }
116 }
117 }
118 extents_.push_back(std::move(extent));
119 }
120
RemoveExtents()121 void Partition::RemoveExtents() {
122 size_ = 0;
123 extents_.clear();
124 }
125
ShrinkTo(uint64_t aligned_size)126 void Partition::ShrinkTo(uint64_t aligned_size) {
127 if (aligned_size == 0) {
128 RemoveExtents();
129 return;
130 }
131
132 // Remove or shrink extents of any kind until the total partition size is
133 // equal to the requested size.
134 uint64_t sectors_to_remove = (size_ - aligned_size) / LP_SECTOR_SIZE;
135 while (sectors_to_remove) {
136 Extent* extent = extents_.back().get();
137 if (extent->num_sectors() > sectors_to_remove) {
138 size_ -= sectors_to_remove * LP_SECTOR_SIZE;
139 extent->set_num_sectors(extent->num_sectors() - sectors_to_remove);
140 break;
141 }
142 size_ -= (extent->num_sectors() * LP_SECTOR_SIZE);
143 sectors_to_remove -= extent->num_sectors();
144 extents_.pop_back();
145 }
146 DCHECK(size_ == aligned_size);
147 }
148
GetBeginningExtents(uint64_t aligned_size) const149 Partition Partition::GetBeginningExtents(uint64_t aligned_size) const {
150 Partition p(name_, group_name_, attributes_);
151 for (const auto& extent : extents_) {
152 auto le = extent->AsLinearExtent();
153 if (le) {
154 p.AddExtent(std::make_unique<LinearExtent>(*le));
155 } else {
156 p.AddExtent(std::make_unique<ZeroExtent>(extent->num_sectors()));
157 }
158 }
159 p.ShrinkTo(aligned_size);
160 return p;
161 }
162
BytesOnDisk() const163 uint64_t Partition::BytesOnDisk() const {
164 uint64_t sectors = 0;
165 for (const auto& extent : extents_) {
166 if (!extent->AsLinearExtent()) {
167 continue;
168 }
169 sectors += extent->num_sectors();
170 }
171 return sectors * LP_SECTOR_SIZE;
172 }
173
New(const IPartitionOpener & opener,const std::string & super_partition,uint32_t slot_number)174 std::unique_ptr<MetadataBuilder> MetadataBuilder::New(const IPartitionOpener& opener,
175 const std::string& super_partition,
176 uint32_t slot_number) {
177 std::unique_ptr<LpMetadata> metadata = ReadMetadata(opener, super_partition, slot_number);
178 if (!metadata) {
179 return nullptr;
180 }
181 return New(*metadata.get(), &opener);
182 }
183
New(const std::string & super_partition,uint32_t slot_number)184 std::unique_ptr<MetadataBuilder> MetadataBuilder::New(const std::string& super_partition,
185 uint32_t slot_number) {
186 return New(PartitionOpener(), super_partition, slot_number);
187 }
188
New(const std::vector<BlockDeviceInfo> & block_devices,const std::string & super_partition,uint32_t metadata_max_size,uint32_t metadata_slot_count)189 std::unique_ptr<MetadataBuilder> MetadataBuilder::New(
190 const std::vector<BlockDeviceInfo>& block_devices, const std::string& super_partition,
191 uint32_t metadata_max_size, uint32_t metadata_slot_count) {
192 std::unique_ptr<MetadataBuilder> builder(new MetadataBuilder());
193 if (!builder->Init(block_devices, super_partition, metadata_max_size, metadata_slot_count)) {
194 return nullptr;
195 }
196 return builder;
197 }
198
New(const LpMetadata & metadata,const IPartitionOpener * opener)199 std::unique_ptr<MetadataBuilder> MetadataBuilder::New(const LpMetadata& metadata,
200 const IPartitionOpener* opener) {
201 std::unique_ptr<MetadataBuilder> builder(new MetadataBuilder());
202 if (!builder->Init(metadata)) {
203 return nullptr;
204 }
205 if (opener) {
206 for (size_t i = 0; i < builder->block_devices_.size(); i++) {
207 std::string partition_name = builder->GetBlockDevicePartitionName(i);
208 BlockDeviceInfo device_info;
209 if (opener->GetInfo(partition_name, &device_info)) {
210 builder->UpdateBlockDeviceInfo(i, device_info);
211 }
212 }
213 }
214 return builder;
215 }
216
NewForUpdate(const IPartitionOpener & opener,const std::string & source_partition,uint32_t source_slot_number,uint32_t target_slot_number,bool always_keep_source_slot)217 std::unique_ptr<MetadataBuilder> MetadataBuilder::NewForUpdate(const IPartitionOpener& opener,
218 const std::string& source_partition,
219 uint32_t source_slot_number,
220 uint32_t target_slot_number,
221 bool always_keep_source_slot) {
222 auto metadata = ReadMetadata(opener, source_partition, source_slot_number);
223 if (!metadata) {
224 return nullptr;
225 }
226
227 // On retrofit DAP devices, modify the metadata so that it is suitable for being written
228 // to the target slot later. We detect retrofit DAP devices by checking the super partition
229 // name and system properties.
230 // See comments for UpdateMetadataForOtherSuper.
231 auto super_device = GetMetadataSuperBlockDevice(*metadata.get());
232 if (android::fs_mgr::GetBlockDevicePartitionName(*super_device) != "super" &&
233 IsRetrofitDynamicPartitionsDevice()) {
234 if (!UpdateMetadataForOtherSuper(metadata.get(), source_slot_number, target_slot_number)) {
235 return nullptr;
236 }
237 }
238
239 if (IPropertyFetcher::GetInstance()->GetBoolProperty("ro.virtual_ab.enabled", false)) {
240 if (always_keep_source_slot) {
241 // always_keep_source_slot implies the target build does not support snapshots.
242 // Clear unsupported attributes.
243 SetMetadataHeaderV0(metadata.get());
244 } else {
245 // !always_keep_source_slot implies the target build supports snapshots. Do snapshot
246 // updates.
247 if (!UpdateMetadataForInPlaceSnapshot(metadata.get(), source_slot_number,
248 target_slot_number)) {
249 return nullptr;
250 }
251 }
252 }
253
254 return New(*metadata.get(), &opener);
255 }
256
257 // For retrofit DAP devices, there are (conceptually) two super partitions. We'll need to translate
258 // block device and group names to update their slot suffixes.
259 // (On the other hand, On non-retrofit DAP devices there is only one location for metadata: the
260 // super partition. update_engine will remove and resize partitions as needed.)
UpdateMetadataForOtherSuper(LpMetadata * metadata,uint32_t source_slot_number,uint32_t target_slot_number)261 bool MetadataBuilder::UpdateMetadataForOtherSuper(LpMetadata* metadata, uint32_t source_slot_number,
262 uint32_t target_slot_number) {
263 // Clear partitions and extents, since they have no meaning on the target
264 // slot. We also clear groups since they are re-added during OTA.
265 metadata->partitions.clear();
266 metadata->extents.clear();
267 metadata->groups.clear();
268
269 std::string source_slot_suffix = SlotSuffixForSlotNumber(source_slot_number);
270 std::string target_slot_suffix = SlotSuffixForSlotNumber(target_slot_number);
271
272 // Translate block devices.
273 auto source_block_devices = std::move(metadata->block_devices);
274 for (const auto& source_block_device : source_block_devices) {
275 std::string partition_name =
276 android::fs_mgr::GetBlockDevicePartitionName(source_block_device);
277 std::string slot_suffix = GetPartitionSlotSuffix(partition_name);
278 if (slot_suffix.empty() || slot_suffix != source_slot_suffix) {
279 // This should never happen. It means that the source metadata
280 // refers to a target or unknown block device.
281 LERROR << "Invalid block device for slot " << source_slot_suffix << ": "
282 << partition_name;
283 return false;
284 }
285 std::string new_name =
286 partition_name.substr(0, partition_name.size() - slot_suffix.size()) +
287 target_slot_suffix;
288
289 auto new_device = source_block_device;
290 if (!UpdateBlockDevicePartitionName(&new_device, new_name)) {
291 LERROR << "Partition name too long: " << new_name;
292 return false;
293 }
294 metadata->block_devices.emplace_back(new_device);
295 }
296
297 return true;
298 }
299
MetadataBuilder()300 MetadataBuilder::MetadataBuilder() : auto_slot_suffixing_(false) {
301 memset(&geometry_, 0, sizeof(geometry_));
302 geometry_.magic = LP_METADATA_GEOMETRY_MAGIC;
303 geometry_.struct_size = sizeof(geometry_);
304
305 memset(&header_, 0, sizeof(header_));
306 header_.magic = LP_METADATA_HEADER_MAGIC;
307 header_.major_version = LP_METADATA_MAJOR_VERSION;
308 header_.minor_version = LP_METADATA_MINOR_VERSION_MIN;
309 header_.header_size = sizeof(LpMetadataHeaderV1_0);
310 header_.partitions.entry_size = sizeof(LpMetadataPartition);
311 header_.extents.entry_size = sizeof(LpMetadataExtent);
312 header_.groups.entry_size = sizeof(LpMetadataPartitionGroup);
313 header_.block_devices.entry_size = sizeof(LpMetadataBlockDevice);
314 }
315
Init(const LpMetadata & metadata)316 bool MetadataBuilder::Init(const LpMetadata& metadata) {
317 geometry_ = metadata.geometry;
318 block_devices_ = metadata.block_devices;
319
320 // Bump the version as necessary to copy any newer fields.
321 if (metadata.header.minor_version >= LP_METADATA_VERSION_FOR_EXPANDED_HEADER) {
322 RequireExpandedMetadataHeader();
323 header_.flags = metadata.header.flags;
324 }
325
326 for (const auto& group : metadata.groups) {
327 std::string group_name = GetPartitionGroupName(group);
328 if (!AddGroup(group_name, group.maximum_size)) {
329 return false;
330 }
331 }
332
333 for (const auto& partition : metadata.partitions) {
334 std::string group_name = GetPartitionGroupName(metadata.groups[partition.group_index]);
335 Partition* builder =
336 AddPartition(GetPartitionName(partition), group_name, partition.attributes);
337 if (!builder) {
338 return false;
339 }
340 ImportExtents(builder, metadata, partition);
341 }
342 return true;
343 }
344
ImportExtents(Partition * dest,const LpMetadata & metadata,const LpMetadataPartition & source)345 void MetadataBuilder::ImportExtents(Partition* dest, const LpMetadata& metadata,
346 const LpMetadataPartition& source) {
347 for (size_t i = 0; i < source.num_extents; i++) {
348 const LpMetadataExtent& extent = metadata.extents[source.first_extent_index + i];
349 if (extent.target_type == LP_TARGET_TYPE_LINEAR) {
350 auto copy = std::make_unique<LinearExtent>(extent.num_sectors, extent.target_source,
351 extent.target_data);
352 dest->AddExtent(std::move(copy));
353 } else if (extent.target_type == LP_TARGET_TYPE_ZERO) {
354 auto copy = std::make_unique<ZeroExtent>(extent.num_sectors);
355 dest->AddExtent(std::move(copy));
356 }
357 }
358 }
359
VerifyDeviceProperties(const BlockDeviceInfo & device_info)360 static bool VerifyDeviceProperties(const BlockDeviceInfo& device_info) {
361 if (device_info.logical_block_size == 0) {
362 LERROR << "Block device " << device_info.partition_name
363 << " logical block size must not be zero.";
364 return false;
365 }
366 if (device_info.logical_block_size % LP_SECTOR_SIZE != 0) {
367 LERROR << "Block device " << device_info.partition_name
368 << " logical block size must be a multiple of 512.";
369 return false;
370 }
371 if (device_info.size % device_info.logical_block_size != 0) {
372 LERROR << "Block device " << device_info.partition_name
373 << " size must be a multiple of its block size.";
374 return false;
375 }
376 if (device_info.alignment_offset % LP_SECTOR_SIZE != 0) {
377 LERROR << "Block device " << device_info.partition_name
378 << " alignment offset is not sector-aligned.";
379 return false;
380 }
381 if (device_info.alignment % LP_SECTOR_SIZE != 0) {
382 LERROR << "Block device " << device_info.partition_name
383 << " partition alignment is not sector-aligned.";
384 return false;
385 }
386 return true;
387 }
388
Init(const std::vector<BlockDeviceInfo> & block_devices,const std::string & super_partition,uint32_t metadata_max_size,uint32_t metadata_slot_count)389 bool MetadataBuilder::Init(const std::vector<BlockDeviceInfo>& block_devices,
390 const std::string& super_partition, uint32_t metadata_max_size,
391 uint32_t metadata_slot_count) {
392 if (metadata_max_size < sizeof(LpMetadataHeader)) {
393 LERROR << "Invalid metadata maximum size.";
394 return false;
395 }
396 if (metadata_slot_count == 0) {
397 LERROR << "Invalid metadata slot count.";
398 return false;
399 }
400 if (block_devices.empty()) {
401 LERROR << "No block devices were specified.";
402 return false;
403 }
404
405 // Align the metadata size up to the nearest sector.
406 if (!AlignTo(metadata_max_size, LP_SECTOR_SIZE, &metadata_max_size)) {
407 LERROR << "Max metadata size " << metadata_max_size << " is too large.";
408 return false;
409 }
410
411 // Validate and build the block device list.
412 uint32_t logical_block_size = 0;
413 for (const auto& device_info : block_devices) {
414 if (!VerifyDeviceProperties(device_info)) {
415 return false;
416 }
417
418 if (!logical_block_size) {
419 logical_block_size = device_info.logical_block_size;
420 }
421 if (logical_block_size != device_info.logical_block_size) {
422 LERROR << "All partitions must have the same logical block size.";
423 return false;
424 }
425
426 LpMetadataBlockDevice out = {};
427 out.alignment = device_info.alignment;
428 out.alignment_offset = device_info.alignment_offset;
429 out.size = device_info.size;
430 if (device_info.partition_name.size() > sizeof(out.partition_name)) {
431 LERROR << "Partition name " << device_info.partition_name << " exceeds maximum length.";
432 return false;
433 }
434 strncpy(out.partition_name, device_info.partition_name.c_str(), sizeof(out.partition_name));
435
436 // In the case of the super partition, this field will be adjusted
437 // later. For all partitions, the first 512 bytes are considered
438 // untouched to be compatible code that looks for an MBR. Thus we
439 // start counting free sectors at sector 1, not 0.
440 uint64_t free_area_start = LP_SECTOR_SIZE;
441 bool ok;
442 if (out.alignment) {
443 ok = AlignTo(free_area_start, out.alignment, &free_area_start);
444 } else {
445 ok = AlignTo(free_area_start, logical_block_size, &free_area_start);
446 }
447 if (!ok) {
448 LERROR << "Integer overflow computing free area start";
449 return false;
450 }
451 out.first_logical_sector = free_area_start / LP_SECTOR_SIZE;
452
453 // There must be one logical block of space available.
454 uint64_t minimum_size = out.first_logical_sector * LP_SECTOR_SIZE + logical_block_size;
455 if (device_info.size < minimum_size) {
456 LERROR << "Block device " << device_info.partition_name
457 << " is too small to hold any logical partitions.";
458 return false;
459 }
460
461 // The "root" of the super partition is always listed first.
462 if (device_info.partition_name == super_partition) {
463 block_devices_.emplace(block_devices_.begin(), out);
464 } else {
465 block_devices_.emplace_back(out);
466 }
467 }
468 if (GetBlockDevicePartitionName(0) != super_partition) {
469 LERROR << "No super partition was specified.";
470 return false;
471 }
472
473 LpMetadataBlockDevice& super = block_devices_[0];
474
475 // We reserve a geometry block (4KB) plus space for each copy of the
476 // maximum size of a metadata blob. Then, we double that space since
477 // we store a backup copy of everything.
478 uint64_t total_reserved = GetTotalMetadataSize(metadata_max_size, metadata_slot_count);
479 if (super.size < total_reserved) {
480 LERROR << "Attempting to create metadata on a block device that is too small.";
481 return false;
482 }
483
484 // Compute the first free sector, factoring in alignment.
485 uint64_t free_area_start = total_reserved;
486 bool ok;
487 if (super.alignment) {
488 ok = AlignTo(free_area_start, super.alignment, &free_area_start);
489 } else {
490 ok = AlignTo(free_area_start, logical_block_size, &free_area_start);
491 }
492 if (!ok) {
493 LERROR << "Integer overflow computing free area start";
494 return false;
495 }
496 super.first_logical_sector = free_area_start / LP_SECTOR_SIZE;
497
498 // There must be one logical block of free space remaining (enough for one partition).
499 uint64_t minimum_disk_size = (super.first_logical_sector * LP_SECTOR_SIZE) + logical_block_size;
500 if (super.size < minimum_disk_size) {
501 LERROR << "Device must be at least " << minimum_disk_size << " bytes, only has "
502 << super.size;
503 return false;
504 }
505
506 geometry_.metadata_max_size = metadata_max_size;
507 geometry_.metadata_slot_count = metadata_slot_count;
508 geometry_.logical_block_size = logical_block_size;
509
510 if (!AddGroup(std::string(kDefaultGroup), 0)) {
511 return false;
512 }
513 return true;
514 }
515
AddGroup(std::string_view group_name,uint64_t maximum_size)516 bool MetadataBuilder::AddGroup(std::string_view group_name, uint64_t maximum_size) {
517 if (FindGroup(group_name)) {
518 LERROR << "Group already exists: " << group_name;
519 return false;
520 }
521 groups_.push_back(std::make_unique<PartitionGroup>(group_name, maximum_size));
522 return true;
523 }
524
AddPartition(const std::string & name,uint32_t attributes)525 Partition* MetadataBuilder::AddPartition(const std::string& name, uint32_t attributes) {
526 return AddPartition(name, kDefaultGroup, attributes);
527 }
528
AddPartition(std::string_view name,std::string_view group_name,uint32_t attributes)529 Partition* MetadataBuilder::AddPartition(std::string_view name, std::string_view group_name,
530 uint32_t attributes) {
531 if (name.empty()) {
532 LERROR << "Partition must have a non-empty name.";
533 return nullptr;
534 }
535 if (FindPartition(name)) {
536 LERROR << "Attempting to create duplication partition with name: " << name;
537 return nullptr;
538 }
539 if (!FindGroup(group_name)) {
540 LERROR << "Could not find partition group: " << group_name;
541 return nullptr;
542 }
543 partitions_.push_back(std::make_unique<Partition>(name, group_name, attributes));
544 return partitions_.back().get();
545 }
546
FindPartition(std::string_view name) const547 Partition* MetadataBuilder::FindPartition(std::string_view name) const {
548 for (const auto& partition : partitions_) {
549 if (partition->name() == name) {
550 return partition.get();
551 }
552 }
553 return nullptr;
554 }
555
FindGroup(std::string_view group_name) const556 PartitionGroup* MetadataBuilder::FindGroup(std::string_view group_name) const {
557 for (const auto& group : groups_) {
558 if (group->name() == group_name) {
559 return group.get();
560 }
561 }
562 return nullptr;
563 }
564
TotalSizeOfGroup(PartitionGroup * group) const565 uint64_t MetadataBuilder::TotalSizeOfGroup(PartitionGroup* group) const {
566 uint64_t total = 0;
567 for (const auto& partition : partitions_) {
568 if (partition->group_name() != group->name()) {
569 continue;
570 }
571 total += partition->BytesOnDisk();
572 }
573 return total;
574 }
575
RemovePartition(std::string_view name)576 void MetadataBuilder::RemovePartition(std::string_view name) {
577 for (auto iter = partitions_.begin(); iter != partitions_.end(); iter++) {
578 if ((*iter)->name() == name) {
579 partitions_.erase(iter);
580 return;
581 }
582 }
583 }
584
ExtentsToFreeList(const std::vector<Interval> & extents,std::vector<Interval> * free_regions) const585 void MetadataBuilder::ExtentsToFreeList(const std::vector<Interval>& extents,
586 std::vector<Interval>* free_regions) const {
587 // Convert the extent list into a list of gaps between the extents; i.e.,
588 // the list of ranges that are free on the disk.
589 for (size_t i = 1; i < extents.size(); i++) {
590 const Interval& previous = extents[i - 1];
591 const Interval& current = extents[i];
592 DCHECK(previous.device_index == current.device_index);
593
594 uint64_t aligned;
595 if (!AlignSector(block_devices_[current.device_index], previous.end, &aligned)) {
596 LERROR << "Sector " << previous.end << " caused integer overflow.";
597 continue;
598 }
599 if (aligned >= current.start) {
600 // There is no gap between these two extents, try the next one.
601 // Note that we check with >= instead of >, since alignment may
602 // bump the ending sector past the beginning of the next extent.
603 continue;
604 }
605
606 // The new interval represents the free space starting at the end of
607 // the previous interval, and ending at the start of the next interval.
608 free_regions->emplace_back(current.device_index, aligned, current.start);
609 }
610 }
611
GetFreeRegions() const612 auto MetadataBuilder::GetFreeRegions() const -> std::vector<Interval> {
613 std::vector<Interval> free_regions;
614
615 // Collect all extents in the partition table, per-device, then sort them
616 // by starting sector.
617 std::vector<std::vector<Interval>> device_extents(block_devices_.size());
618 for (const auto& partition : partitions_) {
619 for (const auto& extent : partition->extents()) {
620 LinearExtent* linear = extent->AsLinearExtent();
621 if (!linear) {
622 continue;
623 }
624 CHECK(linear->device_index() < device_extents.size());
625 auto& extents = device_extents[linear->device_index()];
626 extents.emplace_back(linear->device_index(), linear->physical_sector(),
627 linear->physical_sector() + extent->num_sectors());
628 }
629 }
630
631 // Add 0-length intervals for the first and last sectors. This will cause
632 // ExtentToFreeList() to treat the space in between as available.
633 for (size_t i = 0; i < device_extents.size(); i++) {
634 auto& extents = device_extents[i];
635 const auto& block_device = block_devices_[i];
636
637 uint64_t first_sector = block_device.first_logical_sector;
638 uint64_t last_sector = block_device.size / LP_SECTOR_SIZE;
639 extents.emplace_back(i, first_sector, first_sector);
640 extents.emplace_back(i, last_sector, last_sector);
641
642 std::sort(extents.begin(), extents.end());
643 ExtentsToFreeList(extents, &free_regions);
644 }
645 return free_regions;
646 }
647
ValidatePartitionSizeChange(Partition * partition,uint64_t old_size,uint64_t new_size,bool force_check)648 bool MetadataBuilder::ValidatePartitionSizeChange(Partition* partition, uint64_t old_size,
649 uint64_t new_size, bool force_check) {
650 PartitionGroup* group = FindGroup(partition->group_name());
651 CHECK(group);
652
653 if (!force_check && new_size <= old_size) {
654 return true;
655 }
656
657 // Figure out how much we need to allocate, and whether our group has
658 // enough space remaining.
659 uint64_t space_needed = new_size - old_size;
660 if (group->maximum_size() > 0) {
661 uint64_t group_size = TotalSizeOfGroup(group);
662 if (group_size >= group->maximum_size() ||
663 group->maximum_size() - group_size < space_needed) {
664 LERROR << "Partition " << partition->name() << " is part of group " << group->name()
665 << " which does not have enough space free (" << space_needed << " requested, "
666 << group_size << " used out of " << group->maximum_size() << ")";
667 return false;
668 }
669 }
670 return true;
671 }
672
Intersect(const Interval & a,const Interval & b)673 Interval Interval::Intersect(const Interval& a, const Interval& b) {
674 Interval ret = a;
675 if (a.device_index != b.device_index) {
676 ret.start = ret.end = a.start; // set length to 0 to indicate no intersection.
677 return ret;
678 }
679 ret.start = std::max(a.start, b.start);
680 ret.end = std::max(ret.start, std::min(a.end, b.end));
681 return ret;
682 }
683
Intersect(const std::vector<Interval> & a,const std::vector<Interval> & b)684 std::vector<Interval> Interval::Intersect(const std::vector<Interval>& a,
685 const std::vector<Interval>& b) {
686 std::vector<Interval> ret;
687 for (const Interval& a_interval : a) {
688 for (const Interval& b_interval : b) {
689 auto intersect = Intersect(a_interval, b_interval);
690 if (intersect.length() > 0) ret.emplace_back(std::move(intersect));
691 }
692 }
693 return ret;
694 }
695
AsExtent() const696 std::unique_ptr<Extent> Interval::AsExtent() const {
697 return std::make_unique<LinearExtent>(length(), device_index, start);
698 }
699
GrowPartition(Partition * partition,uint64_t aligned_size,const std::vector<Interval> & free_region_hint)700 bool MetadataBuilder::GrowPartition(Partition* partition, uint64_t aligned_size,
701 const std::vector<Interval>& free_region_hint) {
702 uint64_t space_needed = aligned_size - partition->size();
703 uint64_t sectors_needed = space_needed / LP_SECTOR_SIZE;
704 DCHECK(sectors_needed * LP_SECTOR_SIZE == space_needed);
705
706 std::vector<Interval> free_regions = GetFreeRegions();
707 if (!free_region_hint.empty())
708 free_regions = Interval::Intersect(free_regions, free_region_hint);
709
710 const uint64_t sectors_per_block = geometry_.logical_block_size / LP_SECTOR_SIZE;
711 CHECK_NE(sectors_per_block, 0);
712 CHECK(sectors_needed % sectors_per_block == 0);
713
714 if (IsABDevice() && ShouldHalveSuper() && GetPartitionSlotSuffix(partition->name()) == "_b") {
715 // Allocate "a" partitions top-down and "b" partitions bottom-up, to
716 // minimize fragmentation during OTA.
717 free_regions = PrioritizeSecondHalfOfSuper(free_regions);
718 }
719
720 // Note we store new extents in a temporary vector, and only commit them
721 // if we are guaranteed enough free space.
722 std::vector<std::unique_ptr<LinearExtent>> new_extents;
723
724 // If the last extent in the partition has a size < alignment, then the
725 // difference is unallocatable due to being misaligned. We peek for that
726 // case here to avoid wasting space.
727 if (auto extent = ExtendFinalExtent(partition, free_regions, sectors_needed)) {
728 sectors_needed -= extent->num_sectors();
729 new_extents.emplace_back(std::move(extent));
730 }
731
732 for (auto& region : free_regions) {
733 // Note: this comes first, since we may enter the loop not needing any
734 // more sectors.
735 if (!sectors_needed) {
736 break;
737 }
738
739 if (region.length() % sectors_per_block != 0) {
740 // This should never happen, because it would imply that we
741 // once allocated an extent that was not a multiple of the
742 // block size. That extent would be rejected by DM_TABLE_LOAD.
743 LERROR << "Region " << region.start << ".." << region.end
744 << " is not a multiple of the block size, " << sectors_per_block;
745
746 // If for some reason the final region is mis-sized we still want
747 // to be able to grow partitions. So just to be safe, round the
748 // region down to the nearest block.
749 region.end = region.start + (region.length() / sectors_per_block) * sectors_per_block;
750 if (!region.length()) {
751 continue;
752 }
753 }
754
755 uint64_t sectors = std::min(sectors_needed, region.length());
756 CHECK(sectors % sectors_per_block == 0);
757
758 auto extent = std::make_unique<LinearExtent>(sectors, region.device_index, region.start);
759 new_extents.push_back(std::move(extent));
760 sectors_needed -= sectors;
761 }
762 if (sectors_needed) {
763 LERROR << "Not enough free space to expand partition: " << partition->name();
764 return false;
765 }
766
767 // Everything succeeded, so commit the new extents.
768 for (auto& extent : new_extents) {
769 partition->AddExtent(std::move(extent));
770 }
771 return true;
772 }
773
PrioritizeSecondHalfOfSuper(const std::vector<Interval> & free_list)774 std::vector<Interval> MetadataBuilder::PrioritizeSecondHalfOfSuper(
775 const std::vector<Interval>& free_list) {
776 const auto& super = block_devices_[0];
777 uint64_t first_sector = super.first_logical_sector;
778 uint64_t last_sector = super.size / LP_SECTOR_SIZE;
779 uint64_t midpoint = first_sector + (last_sector - first_sector) / 2;
780
781 // Choose an aligned sector for the midpoint. This could lead to one half
782 // being slightly larger than the other, but this will not restrict the
783 // size of partitions (it might lead to one extra extent if "B" overflows).
784 if (!AlignSector(super, midpoint, &midpoint)) {
785 LERROR << "Unexpected integer overflow aligning midpoint " << midpoint;
786 return free_list;
787 }
788
789 std::vector<Interval> first_half;
790 std::vector<Interval> second_half;
791 for (const auto& region : free_list) {
792 // Note: deprioritze if not the main super partition. Even though we
793 // don't call this for retrofit devices, we will allow adding additional
794 // block devices on non-retrofit devices.
795 if (region.device_index != 0 || region.end <= midpoint) {
796 first_half.emplace_back(region);
797 continue;
798 }
799 if (region.start < midpoint && region.end > midpoint) {
800 // Split this into two regions.
801 first_half.emplace_back(region.device_index, region.start, midpoint);
802 second_half.emplace_back(region.device_index, midpoint, region.end);
803 } else {
804 second_half.emplace_back(region);
805 }
806 }
807 second_half.insert(second_half.end(), first_half.begin(), first_half.end());
808 return second_half;
809 }
810
ExtendFinalExtent(Partition * partition,const std::vector<Interval> & free_list,uint64_t sectors_needed) const811 std::unique_ptr<LinearExtent> MetadataBuilder::ExtendFinalExtent(
812 Partition* partition, const std::vector<Interval>& free_list,
813 uint64_t sectors_needed) const {
814 if (partition->extents().empty()) {
815 return nullptr;
816 }
817 LinearExtent* extent = partition->extents().back()->AsLinearExtent();
818 if (!extent) {
819 return nullptr;
820 }
821
822 // If the sector ends where the next aligned chunk begins, then there's
823 // no missing gap to try and allocate.
824 const auto& block_device = block_devices_[extent->device_index()];
825 uint64_t next_aligned_sector;
826 if (!AlignSector(block_device, extent->end_sector(), &next_aligned_sector)) {
827 LERROR << "Integer overflow aligning sector " << extent->end_sector();
828 return nullptr;
829 }
830 if (extent->end_sector() == next_aligned_sector) {
831 return nullptr;
832 }
833
834 uint64_t num_sectors = std::min(next_aligned_sector - extent->end_sector(), sectors_needed);
835 auto new_extent = std::make_unique<LinearExtent>(num_sectors, extent->device_index(),
836 extent->end_sector());
837 if (IsAnyRegionAllocated(*new_extent.get()) ||
838 IsAnyRegionCovered(free_list, *new_extent.get())) {
839 LERROR << "Misaligned region " << new_extent->physical_sector() << ".."
840 << new_extent->end_sector() << " was allocated or marked allocatable.";
841 return nullptr;
842 }
843 return new_extent;
844 }
845
IsAnyRegionCovered(const std::vector<Interval> & regions,const LinearExtent & candidate) const846 bool MetadataBuilder::IsAnyRegionCovered(const std::vector<Interval>& regions,
847 const LinearExtent& candidate) const {
848 for (const auto& region : regions) {
849 if (candidate.OverlapsWith(region)) {
850 return true;
851 }
852 }
853 return false;
854 }
855
IsAnyRegionAllocated(const LinearExtent & candidate) const856 bool MetadataBuilder::IsAnyRegionAllocated(const LinearExtent& candidate) const {
857 for (const auto& partition : partitions_) {
858 for (const auto& extent : partition->extents()) {
859 LinearExtent* linear = extent->AsLinearExtent();
860 if (!linear) {
861 continue;
862 }
863 if (linear->OverlapsWith(candidate)) {
864 return true;
865 }
866 }
867 }
868 return false;
869 }
870
ShrinkPartition(Partition * partition,uint64_t aligned_size)871 void MetadataBuilder::ShrinkPartition(Partition* partition, uint64_t aligned_size) {
872 partition->ShrinkTo(aligned_size);
873 }
874
Export()875 std::unique_ptr<LpMetadata> MetadataBuilder::Export() {
876 if (!ValidatePartitionGroups()) {
877 return nullptr;
878 }
879
880 std::unique_ptr<LpMetadata> metadata = std::make_unique<LpMetadata>();
881 metadata->header = header_;
882 metadata->geometry = geometry_;
883
884 // Assign this early so the extent table can read it.
885 for (const auto& block_device : block_devices_) {
886 metadata->block_devices.emplace_back(block_device);
887 if (auto_slot_suffixing_) {
888 metadata->block_devices.back().flags |= LP_BLOCK_DEVICE_SLOT_SUFFIXED;
889 }
890 }
891
892 std::map<std::string, size_t> group_indices;
893 for (const auto& group : groups_) {
894 LpMetadataPartitionGroup out = {};
895
896 if (group->name().size() > sizeof(out.name)) {
897 LERROR << "Partition group name is too long: " << group->name();
898 return nullptr;
899 }
900 if (auto_slot_suffixing_ && group->name() != kDefaultGroup) {
901 out.flags |= LP_GROUP_SLOT_SUFFIXED;
902 }
903 strncpy(out.name, group->name().c_str(), sizeof(out.name));
904 out.maximum_size = group->maximum_size();
905
906 group_indices[group->name()] = metadata->groups.size();
907 metadata->groups.push_back(out);
908 }
909
910 // Flatten the partition and extent structures into an LpMetadata, which
911 // makes it very easy to validate, serialize, or pass on to device-mapper.
912 for (const auto& partition : partitions_) {
913 LpMetadataPartition part;
914 memset(&part, 0, sizeof(part));
915
916 if (partition->name().size() > sizeof(part.name)) {
917 LERROR << "Partition name is too long: " << partition->name();
918 return nullptr;
919 }
920 if (partition->attributes() & ~(LP_PARTITION_ATTRIBUTE_MASK)) {
921 LERROR << "Partition " << partition->name() << " has unsupported attribute.";
922 return nullptr;
923 }
924
925 if (partition->attributes() & LP_PARTITION_ATTRIBUTE_MASK_V1) {
926 static const uint16_t kMinVersion = LP_METADATA_VERSION_FOR_UPDATED_ATTR;
927 metadata->header.minor_version = std::max(metadata->header.minor_version, kMinVersion);
928 }
929
930 strncpy(part.name, partition->name().c_str(), sizeof(part.name));
931 part.first_extent_index = static_cast<uint32_t>(metadata->extents.size());
932 part.num_extents = static_cast<uint32_t>(partition->extents().size());
933 part.attributes = partition->attributes();
934 if (auto_slot_suffixing_) {
935 part.attributes |= LP_PARTITION_ATTR_SLOT_SUFFIXED;
936 }
937
938 auto iter = group_indices.find(partition->group_name());
939 if (iter == group_indices.end()) {
940 LERROR << "Partition " << partition->name() << " is a member of unknown group "
941 << partition->group_name();
942 return nullptr;
943 }
944 part.group_index = iter->second;
945
946 for (const auto& extent : partition->extents()) {
947 if (!extent->AddTo(metadata.get())) {
948 return nullptr;
949 }
950 }
951 metadata->partitions.push_back(part);
952 }
953
954 metadata->header.partitions.num_entries = static_cast<uint32_t>(metadata->partitions.size());
955 metadata->header.extents.num_entries = static_cast<uint32_t>(metadata->extents.size());
956 metadata->header.groups.num_entries = static_cast<uint32_t>(metadata->groups.size());
957 metadata->header.block_devices.num_entries =
958 static_cast<uint32_t>(metadata->block_devices.size());
959 return metadata;
960 }
961
RequireExpandedMetadataHeader()962 void MetadataBuilder::RequireExpandedMetadataHeader() {
963 if (header_.minor_version >= LP_METADATA_VERSION_FOR_EXPANDED_HEADER) {
964 return;
965 }
966 header_.minor_version = LP_METADATA_VERSION_FOR_EXPANDED_HEADER;
967 header_.header_size = sizeof(LpMetadataHeaderV1_2);
968 }
969
AllocatableSpace() const970 uint64_t MetadataBuilder::AllocatableSpace() const {
971 uint64_t total_size = 0;
972 for (const auto& block_device : block_devices_) {
973 total_size += block_device.size - (block_device.first_logical_sector * LP_SECTOR_SIZE);
974 }
975 return total_size;
976 }
977
UsedSpace() const978 uint64_t MetadataBuilder::UsedSpace() const {
979 uint64_t size = 0;
980 for (const auto& partition : partitions_) {
981 size += partition->size();
982 }
983 return size;
984 }
985
AlignSector(const LpMetadataBlockDevice & block_device,uint64_t sector,uint64_t * out) const986 bool MetadataBuilder::AlignSector(const LpMetadataBlockDevice& block_device, uint64_t sector,
987 uint64_t* out) const {
988 // Note: when reading alignment info from the Kernel, we don't assume it
989 // is aligned to the sector size, so we round up to the nearest sector.
990 uint64_t lba = sector * LP_SECTOR_SIZE;
991 if (!AlignTo(lba, block_device.alignment, out)) {
992 return false;
993 }
994 if (!AlignTo(*out, LP_SECTOR_SIZE, out)) {
995 return false;
996 }
997 *out /= LP_SECTOR_SIZE;
998 return true;
999 }
1000
FindBlockDeviceByName(const std::string & partition_name,uint32_t * index) const1001 bool MetadataBuilder::FindBlockDeviceByName(const std::string& partition_name,
1002 uint32_t* index) const {
1003 for (size_t i = 0; i < block_devices_.size(); i++) {
1004 if (GetBlockDevicePartitionName(i) == partition_name) {
1005 *index = i;
1006 return true;
1007 }
1008 }
1009 return false;
1010 }
1011
HasBlockDevice(const std::string & partition_name) const1012 bool MetadataBuilder::HasBlockDevice(const std::string& partition_name) const {
1013 uint32_t index;
1014 return FindBlockDeviceByName(partition_name, &index);
1015 }
1016
GetBlockDeviceInfo(const std::string & partition_name,BlockDeviceInfo * info) const1017 bool MetadataBuilder::GetBlockDeviceInfo(const std::string& partition_name,
1018 BlockDeviceInfo* info) const {
1019 uint32_t index;
1020 if (!FindBlockDeviceByName(partition_name, &index)) {
1021 LERROR << "No device named " << partition_name;
1022 return false;
1023 }
1024 info->size = block_devices_[index].size;
1025 info->alignment = block_devices_[index].alignment;
1026 info->alignment_offset = block_devices_[index].alignment_offset;
1027 info->logical_block_size = geometry_.logical_block_size;
1028 info->partition_name = partition_name;
1029 return true;
1030 }
1031
UpdateBlockDeviceInfo(const std::string & partition_name,const BlockDeviceInfo & device_info)1032 bool MetadataBuilder::UpdateBlockDeviceInfo(const std::string& partition_name,
1033 const BlockDeviceInfo& device_info) {
1034 uint32_t index;
1035 if (!FindBlockDeviceByName(partition_name, &index)) {
1036 LERROR << "No device named " << partition_name;
1037 return false;
1038 }
1039 return UpdateBlockDeviceInfo(index, device_info);
1040 }
1041
UpdateBlockDeviceInfo(size_t index,const BlockDeviceInfo & device_info)1042 bool MetadataBuilder::UpdateBlockDeviceInfo(size_t index, const BlockDeviceInfo& device_info) {
1043 CHECK(index < block_devices_.size());
1044
1045 LpMetadataBlockDevice& block_device = block_devices_[index];
1046 if (device_info.size != block_device.size) {
1047 LERROR << "Device size does not match (got " << device_info.size << ", expected "
1048 << block_device.size << ")";
1049 return false;
1050 }
1051 if (geometry_.logical_block_size % device_info.logical_block_size) {
1052 LERROR << "Device logical block size is misaligned (block size="
1053 << device_info.logical_block_size << ", alignment=" << geometry_.logical_block_size
1054 << ")";
1055 return false;
1056 }
1057
1058 // The kernel does not guarantee these values are present, so we only
1059 // replace existing values if the new values are non-zero.
1060 if (device_info.alignment) {
1061 block_device.alignment = device_info.alignment;
1062 }
1063 if (device_info.alignment_offset) {
1064 block_device.alignment_offset = device_info.alignment_offset;
1065 }
1066 return true;
1067 }
1068
ResizePartition(Partition * partition,uint64_t requested_size,const std::vector<Interval> & free_region_hint)1069 bool MetadataBuilder::ResizePartition(Partition* partition, uint64_t requested_size,
1070 const std::vector<Interval>& free_region_hint) {
1071 // Align the space needed up to the nearest sector.
1072 uint64_t aligned_size;
1073 if (!AlignTo(requested_size, geometry_.logical_block_size, &aligned_size)) {
1074 LERROR << "Cannot resize partition " << partition->name() << " to " << requested_size
1075 << " bytes; integer overflow.";
1076 return false;
1077 }
1078 uint64_t old_size = partition->size();
1079
1080 if (!ValidatePartitionSizeChange(partition, old_size, aligned_size, false)) {
1081 return false;
1082 }
1083
1084 if (aligned_size > old_size) {
1085 if (!GrowPartition(partition, aligned_size, free_region_hint)) {
1086 return false;
1087 }
1088 } else if (aligned_size < partition->size()) {
1089 ShrinkPartition(partition, aligned_size);
1090 }
1091
1092 if (partition->size() != old_size) {
1093 LINFO << "Partition " << partition->name() << " will resize from " << old_size
1094 << " bytes to " << aligned_size << " bytes";
1095 }
1096 return true;
1097 }
1098
ListGroups() const1099 std::vector<std::string> MetadataBuilder::ListGroups() const {
1100 std::vector<std::string> names;
1101 for (const auto& group : groups_) {
1102 names.emplace_back(group->name());
1103 }
1104 return names;
1105 }
1106
RemoveGroupAndPartitions(std::string_view group_name)1107 void MetadataBuilder::RemoveGroupAndPartitions(std::string_view group_name) {
1108 if (group_name == kDefaultGroup) {
1109 // Cannot remove the default group.
1110 return;
1111 }
1112 std::vector<std::string> partition_names;
1113 for (const auto& partition : partitions_) {
1114 if (partition->group_name() == group_name) {
1115 partition_names.emplace_back(partition->name());
1116 }
1117 }
1118
1119 for (const auto& partition_name : partition_names) {
1120 RemovePartition(partition_name);
1121 }
1122 for (auto iter = groups_.begin(); iter != groups_.end(); iter++) {
1123 if ((*iter)->name() == group_name) {
1124 groups_.erase(iter);
1125 break;
1126 }
1127 }
1128 }
1129
CompareBlockDevices(const LpMetadataBlockDevice & first,const LpMetadataBlockDevice & second)1130 static bool CompareBlockDevices(const LpMetadataBlockDevice& first,
1131 const LpMetadataBlockDevice& second) {
1132 // Note: we don't compare alignment, since it's a performance thing and
1133 // won't affect whether old extents continue to work.
1134 return first.first_logical_sector == second.first_logical_sector && first.size == second.size &&
1135 android::fs_mgr::GetBlockDevicePartitionName(first) ==
1136 android::fs_mgr::GetBlockDevicePartitionName(second);
1137 }
1138
ImportPartitions(const LpMetadata & metadata,const std::set<std::string> & partition_names)1139 bool MetadataBuilder::ImportPartitions(const LpMetadata& metadata,
1140 const std::set<std::string>& partition_names) {
1141 // The block device list must be identical. We do not try to be clever and
1142 // allow ordering changes or changes that don't affect partitions. This
1143 // process is designed to allow the most common flashing scenarios and more
1144 // complex ones should require a wipe.
1145 if (metadata.block_devices.size() != block_devices_.size()) {
1146 LINFO << "Block device tables does not match.";
1147 return false;
1148 }
1149 for (size_t i = 0; i < metadata.block_devices.size(); i++) {
1150 const LpMetadataBlockDevice& old_device = metadata.block_devices[i];
1151 const LpMetadataBlockDevice& new_device = block_devices_[i];
1152 if (!CompareBlockDevices(old_device, new_device)) {
1153 LINFO << "Block device tables do not match";
1154 return false;
1155 }
1156 }
1157
1158 // Import named partitions. Note that we do not attempt to merge group
1159 // information here. If the device changed its group names, the old
1160 // partitions will fail to merge. The same could happen if the group
1161 // allocation sizes change.
1162 for (const auto& partition : metadata.partitions) {
1163 std::string partition_name = GetPartitionName(partition);
1164 if (partition_names.find(partition_name) == partition_names.end()) {
1165 continue;
1166 }
1167 if (!ImportPartition(metadata, partition)) {
1168 return false;
1169 }
1170 }
1171 return true;
1172 }
1173
ImportPartition(const LpMetadata & metadata,const LpMetadataPartition & source)1174 bool MetadataBuilder::ImportPartition(const LpMetadata& metadata,
1175 const LpMetadataPartition& source) {
1176 std::string partition_name = GetPartitionName(source);
1177 Partition* partition = FindPartition(partition_name);
1178 if (!partition) {
1179 std::string group_name = GetPartitionGroupName(metadata.groups[source.group_index]);
1180 partition = AddPartition(partition_name, group_name, source.attributes);
1181 if (!partition) {
1182 return false;
1183 }
1184 }
1185 if (partition->size() > 0) {
1186 LINFO << "Importing partition table would overwrite non-empty partition: "
1187 << partition_name;
1188 return false;
1189 }
1190
1191 ImportExtents(partition, metadata, source);
1192
1193 // Note: we've already increased the partition size by calling
1194 // ImportExtents(). In order to figure out the size before that,
1195 // we would have to iterate the extents and add up the linear
1196 // segments. Instead, we just force ValidatePartitionSizeChange
1197 // to check if the current configuration is acceptable.
1198 if (!ValidatePartitionSizeChange(partition, partition->size(), partition->size(), true)) {
1199 partition->RemoveExtents();
1200 return false;
1201 }
1202 return true;
1203 }
1204
SetAutoSlotSuffixing()1205 void MetadataBuilder::SetAutoSlotSuffixing() {
1206 auto_slot_suffixing_ = true;
1207 }
1208
SetVirtualABDeviceFlag()1209 void MetadataBuilder::SetVirtualABDeviceFlag() {
1210 RequireExpandedMetadataHeader();
1211 header_.flags |= LP_HEADER_FLAG_VIRTUAL_AB_DEVICE;
1212 }
1213
IsABDevice()1214 bool MetadataBuilder::IsABDevice() {
1215 return !IPropertyFetcher::GetInstance()->GetProperty("ro.boot.slot_suffix", "").empty();
1216 }
1217
IsRetrofitDynamicPartitionsDevice()1218 bool MetadataBuilder::IsRetrofitDynamicPartitionsDevice() {
1219 return IPropertyFetcher::GetInstance()->GetBoolProperty("ro.boot.dynamic_partitions_retrofit",
1220 false);
1221 }
1222
ShouldHalveSuper() const1223 bool MetadataBuilder::ShouldHalveSuper() const {
1224 return GetBlockDevicePartitionName(0) == LP_METADATA_DEFAULT_PARTITION_NAME &&
1225 !IPropertyFetcher::GetInstance()->GetBoolProperty("ro.virtual_ab.enabled", false);
1226 }
1227
AddLinearExtent(Partition * partition,const std::string & block_device,uint64_t num_sectors,uint64_t physical_sector)1228 bool MetadataBuilder::AddLinearExtent(Partition* partition, const std::string& block_device,
1229 uint64_t num_sectors, uint64_t physical_sector) {
1230 uint32_t device_index;
1231 if (!FindBlockDeviceByName(block_device, &device_index)) {
1232 LERROR << "Could not find backing block device for extent: " << block_device;
1233 return false;
1234 }
1235
1236 auto extent = std::make_unique<LinearExtent>(num_sectors, device_index, physical_sector);
1237 partition->AddExtent(std::move(extent));
1238 return true;
1239 }
1240
ListPartitionsInGroup(std::string_view group_name)1241 std::vector<Partition*> MetadataBuilder::ListPartitionsInGroup(std::string_view group_name) {
1242 std::vector<Partition*> partitions;
1243 for (const auto& partition : partitions_) {
1244 if (partition->group_name() == group_name) {
1245 partitions.emplace_back(partition.get());
1246 }
1247 }
1248 return partitions;
1249 }
1250
ChangePartitionGroup(Partition * partition,std::string_view group_name)1251 bool MetadataBuilder::ChangePartitionGroup(Partition* partition, std::string_view group_name) {
1252 if (!FindGroup(group_name)) {
1253 LERROR << "Partition cannot change to unknown group: " << group_name;
1254 return false;
1255 }
1256 partition->set_group_name(group_name);
1257 return true;
1258 }
1259
ValidatePartitionGroups() const1260 bool MetadataBuilder::ValidatePartitionGroups() const {
1261 for (const auto& group : groups_) {
1262 if (!group->maximum_size()) {
1263 continue;
1264 }
1265 uint64_t used = TotalSizeOfGroup(group.get());
1266 if (used > group->maximum_size()) {
1267 LERROR << "Partition group " << group->name() << " exceeds maximum size (" << used
1268 << " bytes used, maximum " << group->maximum_size() << ")";
1269 return false;
1270 }
1271 }
1272 return true;
1273 }
1274
ChangeGroupSize(const std::string & group_name,uint64_t maximum_size)1275 bool MetadataBuilder::ChangeGroupSize(const std::string& group_name, uint64_t maximum_size) {
1276 if (group_name == kDefaultGroup) {
1277 LERROR << "Cannot change the size of the default group";
1278 return false;
1279 }
1280 PartitionGroup* group = FindGroup(group_name);
1281 if (!group) {
1282 LERROR << "Cannot change size of unknown partition group: " << group_name;
1283 return false;
1284 }
1285 group->set_maximum_size(maximum_size);
1286 return true;
1287 }
1288
GetBlockDevicePartitionName(uint64_t index) const1289 std::string MetadataBuilder::GetBlockDevicePartitionName(uint64_t index) const {
1290 return index < block_devices_.size()
1291 ? android::fs_mgr::GetBlockDevicePartitionName(block_devices_[index])
1292 : "";
1293 }
1294
logical_block_size() const1295 uint64_t MetadataBuilder::logical_block_size() const {
1296 return geometry_.logical_block_size;
1297 }
1298
VerifyExtentsAgainstSourceMetadata(const MetadataBuilder & source_metadata,uint32_t source_slot_number,const MetadataBuilder & target_metadata,uint32_t target_slot_number,const std::vector<std::string> & partitions)1299 bool MetadataBuilder::VerifyExtentsAgainstSourceMetadata(
1300 const MetadataBuilder& source_metadata, uint32_t source_slot_number,
1301 const MetadataBuilder& target_metadata, uint32_t target_slot_number,
1302 const std::vector<std::string>& partitions) {
1303 for (const auto& base_name : partitions) {
1304 // Find the partition in metadata with the slot suffix.
1305 auto target_partition_name = base_name + SlotSuffixForSlotNumber(target_slot_number);
1306 const auto target_partition = target_metadata.FindPartition(target_partition_name);
1307 if (!target_partition) {
1308 LERROR << "Failed to find partition " << target_partition_name << " in metadata slot "
1309 << target_slot_number;
1310 return false;
1311 }
1312
1313 auto source_partition_name = base_name + SlotSuffixForSlotNumber(source_slot_number);
1314 const auto source_partition = source_metadata.FindPartition(source_partition_name);
1315 if (!source_partition) {
1316 LERROR << "Failed to find partition " << source_partition << " in metadata slot "
1317 << source_slot_number;
1318 return false;
1319 }
1320
1321 // We expect the partitions in the target metadata to have the identical extents as the
1322 // one in the source metadata. Because they are copied in NewForUpdate.
1323 if (target_partition->extents().size() != source_partition->extents().size()) {
1324 LERROR << "Extents count mismatch for partition " << base_name << " target slot has "
1325 << target_partition->extents().size() << ", source slot has "
1326 << source_partition->extents().size();
1327 return false;
1328 }
1329
1330 for (size_t i = 0; i < target_partition->extents().size(); i++) {
1331 const auto& src_extent = *source_partition->extents()[i];
1332 const auto& tgt_extent = *target_partition->extents()[i];
1333 if (tgt_extent != src_extent) {
1334 LERROR << "Extents " << i << " is different for partition " << base_name;
1335 LERROR << "tgt extent " << tgt_extent << "; src extent " << src_extent;
1336 return false;
1337 }
1338 }
1339 }
1340
1341 return true;
1342 }
1343
1344 } // namespace fs_mgr
1345 } // namespace android
1346