1 //
2 // Copyright (C) 2023 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 "super_flash_helper.h"
18
19 #include <android-base/logging.h>
20
21 #include "util.h"
22
23 using android::base::borrowed_fd;
24 using android::base::unique_fd;
25 using android::fs_mgr::SuperImageExtent;
26
SuperFlashHelper(const ImageSource & source)27 SuperFlashHelper::SuperFlashHelper(const ImageSource& source) : source_(source) {}
28
Open(borrowed_fd fd)29 bool SuperFlashHelper::Open(borrowed_fd fd) {
30 if (!builder_.Open(fd)) {
31 LOG(VERBOSE) << "device does not support optimized super flashing";
32 return false;
33 }
34
35 base_metadata_ = builder_.Export();
36 return !!base_metadata_;
37 }
38
IncludeInSuper(const std::string & partition)39 bool SuperFlashHelper::IncludeInSuper(const std::string& partition) {
40 return should_flash_in_userspace(*base_metadata_.get(), partition);
41 }
42
AddPartition(const std::string & partition,const std::string & image_name,bool optional)43 bool SuperFlashHelper::AddPartition(const std::string& partition, const std::string& image_name,
44 bool optional) {
45 if (!IncludeInSuper(partition)) {
46 return true;
47 }
48 auto iter = image_fds_.find(image_name);
49 if (iter == image_fds_.end()) {
50 unique_fd fd = source_.OpenFile(image_name);
51 if (fd < 0) {
52 if (!optional) {
53 LOG(VERBOSE) << "could not find partition image: " << image_name;
54 return false;
55 }
56 return true;
57 }
58 if (is_sparse_file(fd)) {
59 LOG(VERBOSE) << "cannot optimize dynamic partitions with sparse images";
60 return false;
61 }
62 iter = image_fds_.emplace(image_name, std::move(fd)).first;
63 }
64
65 if (!builder_.AddPartition(partition, image_name, get_file_size(iter->second))) {
66 return false;
67 }
68
69 will_flash_.emplace(partition);
70 return true;
71 }
72
GetSparseLayout()73 SparsePtr SuperFlashHelper::GetSparseLayout() {
74 // Cache extents since the sparse ptr depends on data pointers.
75 if (extents_.empty()) {
76 extents_ = builder_.GetImageLayout();
77 if (extents_.empty()) {
78 LOG(VERBOSE) << "device does not support optimized super flashing";
79 return {nullptr, nullptr};
80 }
81 }
82
83 unsigned int block_size = base_metadata_->geometry.logical_block_size;
84 int64_t flashed_size = extents_.back().offset + extents_.back().size;
85 SparsePtr s(sparse_file_new(block_size, flashed_size), sparse_file_destroy);
86
87 for (const auto& extent : extents_) {
88 if (extent.offset / block_size > UINT_MAX) {
89 // Super image is too big to send via sparse files (>8TB).
90 LOG(VERBOSE) << "super image is too big to flash";
91 return {nullptr, nullptr};
92 }
93 unsigned int block = extent.offset / block_size;
94
95 int rv = 0;
96 switch (extent.type) {
97 case SuperImageExtent::Type::DONTCARE:
98 break;
99 case SuperImageExtent::Type::ZERO:
100 rv = sparse_file_add_fill(s.get(), 0, extent.size, block);
101 break;
102 case SuperImageExtent::Type::DATA:
103 rv = sparse_file_add_data(s.get(), extent.blob->data(), extent.size, block);
104 break;
105 case SuperImageExtent::Type::PARTITION: {
106 auto iter = image_fds_.find(extent.image_name);
107 if (iter == image_fds_.end()) {
108 LOG(FATAL) << "image added but not found: " << extent.image_name;
109 return {nullptr, nullptr};
110 }
111 rv = sparse_file_add_fd(s.get(), iter->second.get(), extent.image_offset,
112 extent.size, block);
113 break;
114 }
115 default:
116 LOG(VERBOSE) << "unrecognized extent type in super image layout";
117 return {nullptr, nullptr};
118 }
119 if (rv) {
120 LOG(VERBOSE) << "sparse failure building super image layout";
121 return {nullptr, nullptr};
122 }
123 }
124 return s;
125 }
126