blob: a6febb3facabf72d4467f78ee778536f0772dbb0 [file] [log] [blame]
xunchangf07ed2e2019-02-25 14:14:01 -08001/*
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
Jacky Liu068329e2021-12-21 00:32:50 +080017#include "otautil/package.h"
xunchangf07ed2e2019-02-25 14:14:01 -080018
19#include <string.h>
xunchang37304f32019-03-12 12:40:14 -070020#include <unistd.h>
xunchangf07ed2e2019-02-25 14:14:01 -080021
xunchang37304f32019-03-12 12:40:14 -070022#include <android-base/file.h>
xunchangf07ed2e2019-02-25 14:14:01 -080023#include <android-base/logging.h>
24#include <android-base/stringprintf.h>
xunchang37304f32019-03-12 12:40:14 -070025#include <android-base/unique_fd.h>
xunchangf07ed2e2019-02-25 14:14:01 -080026
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.
bigbiffd58ba182020-03-23 10:02:29 -040035 MemoryPackage(const std::string& path, std::unique_ptr<MemMapping> map);
xunchangf07ed2e2019-02-25 14:14:01 -080036
37 // Constructs the class from the package bytes in |content|.
bigbiffd58ba182020-03-23 10:02:29 -040038 MemoryPackage(std::vector<uint8_t> content);
xunchangf07ed2e2019-02-25 14:14:01 -080039
40 ~MemoryPackage() override;
41
Tianjie Xu980f92e2019-06-11 15:43:43 -070042 PackageType GetType() const override {
43 return PackageType::kMemory;
44 }
45
xunchangf07ed2e2019-02-25 14:14:01 -080046 // Memory maps the package file if necessary. Initializes the start address and size of the
47 // package.
48 uint64_t GetPackageSize() const override {
49 return package_size_;
50 }
51
Tianjie Xu980f92e2019-06-11 15:43:43 -070052 std::string GetPath() const override {
53 return path_;
54 }
55
xunchangf07ed2e2019-02-25 14:14:01 -080056 bool ReadFullyAtOffset(uint8_t* buffer, uint64_t byte_count, uint64_t offset) override;
57
58 ZipArchiveHandle GetZipArchiveHandle() override;
59
60 bool UpdateHashAtOffset(const std::vector<HasherUpdateCallback>& hashers, uint64_t start,
61 uint64_t length) override;
62
63 private:
64 const uint8_t* addr_; // Start address of the package in memory.
65 uint64_t package_size_; // Package size in bytes.
66
67 // The memory mapped package.
68 std::unique_ptr<MemMapping> map_;
69 // A copy of the package content, valid only if we create the class with the exact bytes of
70 // the package.
71 std::vector<uint8_t> package_content_;
72 // The physical path to the package, empty if we create the class with the package content.
73 std::string path_;
74
75 // The ZipArchiveHandle of the package.
76 ZipArchiveHandle zip_handle_;
77};
78
xunchangf07ed2e2019-02-25 14:14:01 -080079void Package::SetProgress(float progress) {
80 if (set_progress_) {
81 set_progress_(progress);
82 }
83}
84
xunchang37304f32019-03-12 12:40:14 -070085class FilePackage : public Package {
86 public:
87 FilePackage(android::base::unique_fd&& fd, uint64_t file_size, const std::string& path,
88 const std::function<void(float)>& set_progress);
89
90 ~FilePackage() override;
91
Tianjie Xu980f92e2019-06-11 15:43:43 -070092 PackageType GetType() const override {
93 return PackageType::kFile;
94 }
95
xunchang37304f32019-03-12 12:40:14 -070096 uint64_t GetPackageSize() const override {
97 return package_size_;
98 }
99
Tianjie Xu980f92e2019-06-11 15:43:43 -0700100 std::string GetPath() const override {
101 return path_;
102 }
103
xunchang37304f32019-03-12 12:40:14 -0700104 bool ReadFullyAtOffset(uint8_t* buffer, uint64_t byte_count, uint64_t offset) override;
105
106 ZipArchiveHandle GetZipArchiveHandle() override;
107
108 bool UpdateHashAtOffset(const std::vector<HasherUpdateCallback>& hashers, uint64_t start,
109 uint64_t length) override;
110
111 private:
112 android::base::unique_fd fd_; // The underlying fd to the open package.
113 uint64_t package_size_;
114 std::string path_; // The physical path to the package.
115
116 ZipArchiveHandle zip_handle_;
117};
118
xunchangf07ed2e2019-02-25 14:14:01 -0800119std::unique_ptr<Package> Package::CreateMemoryPackage(
bigbiffd58ba182020-03-23 10:02:29 -0400120 const std::string& path) {
xunchangf07ed2e2019-02-25 14:14:01 -0800121 std::unique_ptr<MemMapping> mmap = std::make_unique<MemMapping>();
122 if (!mmap->MapFile(path)) {
123 LOG(ERROR) << "failed to map file";
124 return nullptr;
125 }
126
bigbiffd58ba182020-03-23 10:02:29 -0400127 return std::make_unique<MemoryPackage>(path, std::move(mmap));
xunchangf07ed2e2019-02-25 14:14:01 -0800128}
129
xunchang37304f32019-03-12 12:40:14 -0700130std::unique_ptr<Package> Package::CreateFilePackage(
131 const std::string& path, const std::function<void(float)>& set_progress) {
132 android::base::unique_fd fd(open(path.c_str(), O_RDONLY));
133 if (fd == -1) {
134 PLOG(ERROR) << "Failed to open " << path;
135 return nullptr;
136 }
137
138 off64_t file_size = lseek64(fd.get(), 0, SEEK_END);
139 if (file_size == -1) {
140 PLOG(ERROR) << "Failed to get the package size";
141 return nullptr;
142 }
143
144 return std::make_unique<FilePackage>(std::move(fd), file_size, path, set_progress);
145}
146
xunchangf07ed2e2019-02-25 14:14:01 -0800147std::unique_ptr<Package> Package::CreateMemoryPackage(
bigbiffd58ba182020-03-23 10:02:29 -0400148 std::vector<uint8_t> content) {
149 return std::make_unique<MemoryPackage>(std::move(content));
xunchangf07ed2e2019-02-25 14:14:01 -0800150}
151
bigbiffd58ba182020-03-23 10:02:29 -0400152MemoryPackage::MemoryPackage(const std::string& path, std::unique_ptr<MemMapping> map)
xunchangf07ed2e2019-02-25 14:14:01 -0800153 : map_(std::move(map)), path_(path), zip_handle_(nullptr) {
154 addr_ = map_->addr;
155 package_size_ = map_->length;
xunchangf07ed2e2019-02-25 14:14:01 -0800156}
157
bigbiffd58ba182020-03-23 10:02:29 -0400158MemoryPackage::MemoryPackage(std::vector<uint8_t> content)
xunchangf07ed2e2019-02-25 14:14:01 -0800159 : package_content_(std::move(content)), zip_handle_(nullptr) {
160 CHECK(!package_content_.empty());
161 addr_ = package_content_.data();
162 package_size_ = package_content_.size();
xunchangf07ed2e2019-02-25 14:14:01 -0800163}
164
165MemoryPackage::~MemoryPackage() {
166 if (zip_handle_) {
167 CloseArchive(zip_handle_);
168 }
169}
170
171bool MemoryPackage::ReadFullyAtOffset(uint8_t* buffer, uint64_t byte_count, uint64_t offset) {
172 if (byte_count > package_size_ || offset > package_size_ - byte_count) {
173 LOG(ERROR) << "Out of bound read, offset: " << offset << ", size: " << byte_count
174 << ", total package_size: " << package_size_;
175 return false;
176 }
177 memcpy(buffer, addr_ + offset, byte_count);
178 return true;
179}
180
181bool MemoryPackage::UpdateHashAtOffset(const std::vector<HasherUpdateCallback>& hashers,
182 uint64_t start, uint64_t length) {
183 if (length > package_size_ || start > package_size_ - length) {
184 LOG(ERROR) << "Out of bound read, offset: " << start << ", size: " << length
185 << ", total package_size: " << package_size_;
186 return false;
187 }
188
189 for (const auto& hasher : hashers) {
190 hasher(addr_ + start, length);
191 }
192 return true;
193}
194
195ZipArchiveHandle MemoryPackage::GetZipArchiveHandle() {
196 if (zip_handle_) {
197 return zip_handle_;
198 }
199
200 if (auto err = OpenArchiveFromMemory(const_cast<uint8_t*>(addr_), package_size_, path_.c_str(),
201 &zip_handle_);
202 err != 0) {
203 LOG(ERROR) << "Can't open package" << path_ << " : " << ErrorCodeString(err);
204 return nullptr;
205 }
206
207 return zip_handle_;
208}
xunchang37304f32019-03-12 12:40:14 -0700209
210FilePackage::FilePackage(android::base::unique_fd&& fd, uint64_t file_size, const std::string& path,
211 const std::function<void(float)>& set_progress)
212 : fd_(std::move(fd)), package_size_(file_size), path_(path), zip_handle_(nullptr) {
213 set_progress_ = set_progress;
214}
215
216FilePackage::~FilePackage() {
217 if (zip_handle_) {
218 CloseArchive(zip_handle_);
219 }
220}
221
222bool FilePackage::ReadFullyAtOffset(uint8_t* buffer, uint64_t byte_count, uint64_t offset) {
223 if (byte_count > package_size_ || offset > package_size_ - byte_count) {
224 LOG(ERROR) << "Out of bound read, offset: " << offset << ", size: " << byte_count
225 << ", total package_size: " << package_size_;
226 return false;
227 }
228
229 if (!android::base::ReadFullyAtOffset(fd_.get(), buffer, byte_count, offset)) {
230 PLOG(ERROR) << "Failed to read " << byte_count << " bytes data at offset " << offset;
231 return false;
232 }
233
234 return true;
235}
236
237bool FilePackage::UpdateHashAtOffset(const std::vector<HasherUpdateCallback>& hashers,
238 uint64_t start, uint64_t length) {
239 if (length > package_size_ || start > package_size_ - length) {
240 LOG(ERROR) << "Out of bound read, offset: " << start << ", size: " << length
241 << ", total package_size: " << package_size_;
242 return false;
243 }
244
245 uint64_t so_far = 0;
246 while (so_far < length) {
247 uint64_t read_size = std::min<uint64_t>(length - so_far, 16 * MiB);
248 std::vector<uint8_t> buffer(read_size);
249 if (!ReadFullyAtOffset(buffer.data(), read_size, start + so_far)) {
250 return false;
251 }
252
253 for (const auto& hasher : hashers) {
254 hasher(buffer.data(), read_size);
255 }
256 so_far += read_size;
257 }
258
259 return true;
260}
261
262ZipArchiveHandle FilePackage::GetZipArchiveHandle() {
263 if (zip_handle_) {
264 return zip_handle_;
265 }
266
Tianjie Xu980f92e2019-06-11 15:43:43 -0700267 if (auto err = OpenArchiveFd(fd_.get(), path_.c_str(), &zip_handle_, false); err != 0) {
xunchang37304f32019-03-12 12:40:14 -0700268 LOG(ERROR) << "Can't open package" << path_ << " : " << ErrorCodeString(err);
269 return nullptr;
270 }
271
272 return zip_handle_;
273}