blob: ba1d5df62633f288f2a2bb3295149971f8446e01 [file] [log] [blame]
bigbiff1f9e4842020-10-31 11:33:15 -04001/*
2 * Copyright (C) 2019 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 "twinstall/package.h"
18
19#include <string.h>
20#include <unistd.h>
21
22#include <android-base/file.h>
23#include <android-base/logging.h>
24#include <android-base/stringprintf.h>
25#include <android-base/unique_fd.h>
26
27#include "otautil/error_code.h"
28#include "otautil/sysutil.h"
29
30// This class wraps the package in memory, i.e. a memory mapped package, or a package loaded
31// to a string/vector.
32class MemoryPackage : public Package {
33 public:
34 // Constructs the class from a file. We will memory maps the file later.
35 MemoryPackage(const std::string& path, std::unique_ptr<MemMapping> map);
36
37 // Constructs the class from the package bytes in |content|.
38 MemoryPackage(std::vector<uint8_t> content);
39
40 ~MemoryPackage() override;
41
42 // Memory maps the package file if necessary. Initializes the start address and size of the
43 // package.
44 uint64_t GetPackageSize() const override {
45 return package_size_;
46 }
47
48 bool ReadFullyAtOffset(uint8_t* buffer, uint64_t byte_count, uint64_t offset) override;
49
50 ZipArchiveHandle GetZipArchiveHandle() override;
51
52 bool UpdateHashAtOffset(const std::vector<HasherUpdateCallback>& hashers, uint64_t start,
53 uint64_t length) override;
54
55 private:
56 const uint8_t* addr_; // Start address of the package in memory.
57 uint64_t package_size_; // Package size in bytes.
58
59 // The memory mapped package.
60 std::unique_ptr<MemMapping> map_;
61 // A copy of the package content, valid only if we create the class with the exact bytes of
62 // the package.
63 std::vector<uint8_t> package_content_;
64 // The physical path to the package, empty if we create the class with the package content.
65 std::string path_;
66
67 // The ZipArchiveHandle of the package.
68 ZipArchiveHandle zip_handle_;
69};
70
71void Package::SetProgress(float progress) {
72 if (set_progress_) {
73 set_progress_(progress);
74 }
75}
76
77class FilePackage : public Package {
78 public:
79 FilePackage(android::base::unique_fd&& fd, uint64_t file_size, const std::string& path,
80 const std::function<void(float)>& set_progress);
81
82 ~FilePackage() override;
83
84 uint64_t GetPackageSize() const override {
85 return package_size_;
86 }
87
88 bool ReadFullyAtOffset(uint8_t* buffer, uint64_t byte_count, uint64_t offset) override;
89
90 ZipArchiveHandle GetZipArchiveHandle() override;
91
92 bool UpdateHashAtOffset(const std::vector<HasherUpdateCallback>& hashers, uint64_t start,
93 uint64_t length) override;
94
95 private:
96 android::base::unique_fd fd_; // The underlying fd to the open package.
97 uint64_t package_size_;
98 std::string path_; // The physical path to the package.
99
100 ZipArchiveHandle zip_handle_;
101};
102
103std::unique_ptr<Package> Package::CreateMemoryPackage(
104 const std::string& path) {
105 std::unique_ptr<MemMapping> mmap = std::make_unique<MemMapping>();
106 if (!mmap->MapFile(path)) {
107 LOG(ERROR) << "failed to map file";
108 return nullptr;
109 }
110
111 return std::make_unique<MemoryPackage>(path, std::move(mmap));
112}
113
114std::unique_ptr<Package> Package::CreateFilePackage(
115 const std::string& path, const std::function<void(float)>& set_progress) {
116 android::base::unique_fd fd(open(path.c_str(), O_RDONLY));
117 if (fd == -1) {
118 PLOG(ERROR) << "Failed to open " << path;
119 return nullptr;
120 }
121
122 off64_t file_size = lseek64(fd.get(), 0, SEEK_END);
123 if (file_size == -1) {
124 PLOG(ERROR) << "Failed to get the package size";
125 return nullptr;
126 }
127
128 return std::make_unique<FilePackage>(std::move(fd), file_size, path, set_progress);
129}
130
131std::unique_ptr<Package> Package::CreateMemoryPackage(
132 std::vector<uint8_t> content) {
133 return std::make_unique<MemoryPackage>(std::move(content));
134}
135
136MemoryPackage::MemoryPackage(const std::string& path, std::unique_ptr<MemMapping> map)
137 : map_(std::move(map)), path_(path), zip_handle_(nullptr) {
138 addr_ = map_->addr;
139 package_size_ = map_->length;
140}
141
142MemoryPackage::MemoryPackage(std::vector<uint8_t> content)
143 : package_content_(std::move(content)), zip_handle_(nullptr) {
144 CHECK(!package_content_.empty());
145 addr_ = package_content_.data();
146 package_size_ = package_content_.size();
147}
148
149MemoryPackage::~MemoryPackage() {
150 if (zip_handle_) {
151 CloseArchive(zip_handle_);
152 }
153}
154
155bool MemoryPackage::ReadFullyAtOffset(uint8_t* buffer, uint64_t byte_count, uint64_t offset) {
156 if (byte_count > package_size_ || offset > package_size_ - byte_count) {
157 LOG(ERROR) << "Out of bound read, offset: " << offset << ", size: " << byte_count
158 << ", total package_size: " << package_size_;
159 return false;
160 }
161 memcpy(buffer, addr_ + offset, byte_count);
162 return true;
163}
164
165bool MemoryPackage::UpdateHashAtOffset(const std::vector<HasherUpdateCallback>& hashers,
166 uint64_t start, uint64_t length) {
167 if (length > package_size_ || start > package_size_ - length) {
168 LOG(ERROR) << "Out of bound read, offset: " << start << ", size: " << length
169 << ", total package_size: " << package_size_;
170 return false;
171 }
172
173 for (const auto& hasher : hashers) {
174 hasher(addr_ + start, length);
175 }
176 return true;
177}
178
179ZipArchiveHandle MemoryPackage::GetZipArchiveHandle() {
180 if (zip_handle_) {
181 return zip_handle_;
182 }
183
184 if (auto err = OpenArchiveFromMemory(const_cast<uint8_t*>(addr_), package_size_, path_.c_str(),
185 &zip_handle_);
186 err != 0) {
187 LOG(ERROR) << "Can't open package" << path_ << " : " << ErrorCodeString(err);
188 return nullptr;
189 }
190
191 return zip_handle_;
192}
193
194FilePackage::FilePackage(android::base::unique_fd&& fd, uint64_t file_size, const std::string& path,
195 const std::function<void(float)>& set_progress)
196 : fd_(std::move(fd)), package_size_(file_size), path_(path), zip_handle_(nullptr) {
197 set_progress_ = set_progress;
198}
199
200FilePackage::~FilePackage() {
201 if (zip_handle_) {
202 CloseArchive(zip_handle_);
203 }
204}
205
206bool FilePackage::ReadFullyAtOffset(uint8_t* buffer, uint64_t byte_count, uint64_t offset) {
207 if (byte_count > package_size_ || offset > package_size_ - byte_count) {
208 LOG(ERROR) << "Out of bound read, offset: " << offset << ", size: " << byte_count
209 << ", total package_size: " << package_size_;
210 return false;
211 }
212
213 if (!android::base::ReadFullyAtOffset(fd_.get(), buffer, byte_count, offset)) {
214 PLOG(ERROR) << "Failed to read " << byte_count << " bytes data at offset " << offset;
215 return false;
216 }
217
218 return true;
219}
220
221bool FilePackage::UpdateHashAtOffset(const std::vector<HasherUpdateCallback>& hashers,
222 uint64_t start, uint64_t length) {
223 if (length > package_size_ || start > package_size_ - length) {
224 LOG(ERROR) << "Out of bound read, offset: " << start << ", size: " << length
225 << ", total package_size: " << package_size_;
226 return false;
227 }
228
229 uint64_t so_far = 0;
230 while (so_far < length) {
231 uint64_t read_size = std::min<uint64_t>(length - so_far, 16 * MiB);
232 std::vector<uint8_t> buffer(read_size);
233 if (!ReadFullyAtOffset(buffer.data(), read_size, start + so_far)) {
234 return false;
235 }
236
237 for (const auto& hasher : hashers) {
238 hasher(buffer.data(), read_size);
239 }
240 so_far += read_size;
241 }
242
243 return true;
244}
245
246ZipArchiveHandle FilePackage::GetZipArchiveHandle() {
247 if (zip_handle_) {
248 return zip_handle_;
249 }
250
251 if (auto err = OpenArchiveFd(fd_.get(), path_.c_str(), &zip_handle_); err != 0) {
252 LOG(ERROR) << "Can't open package" << path_ << " : " << ErrorCodeString(err);
253 return nullptr;
254 }
255
256 return zip_handle_;
257}