1 /*
2 * Copyright (c) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "extractor.h"
17
18 #include <fstream>
19 #include <sstream>
20 #include "ability_base_log_wrapper.h"
21 #include "constants.h"
22 #include "file_path_utils.h"
23 #include "hitrace_meter.h"
24 #include "securec.h"
25 #include "string_ex.h"
26
27 namespace OHOS {
28 namespace AbilityBase {
29 namespace {
30 constexpr char EXT_NAME_ABC[] = ".abc";
31 }
Extractor(const std::string &source)32 Extractor::Extractor(const std::string &source) : zipFile_(source)
33 {
34 hapPath_ = source;
35 }
36
~Extractor()37 Extractor::~Extractor()
38 {}
39
Init()40 bool Extractor::Init()
41 {
42 HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__);
43 if (!zipFile_.Open()) {
44 ABILITYBASE_LOGD("open zip file failed");
45 return false;
46 }
47 initial_ = true;
48 return true;
49 }
50
GetFileBuffer(const std::string& srcPath, std::ostringstream& dest)51 bool Extractor::GetFileBuffer(const std::string& srcPath, std::ostringstream& dest)
52 {
53 std::unique_ptr<uint8_t[]> data;
54 size_t dataLen = 0;
55
56 if (!ExtractToBufByName(srcPath, data, dataLen)) {
57 return false;
58 }
59
60 dest.write(reinterpret_cast<char*>(data.get()), dataLen);
61 return true;
62 }
63
GetFileList(const std::string& srcPath, std::vector<std::string>& assetList)64 bool Extractor::GetFileList(const std::string& srcPath, std::vector<std::string>& assetList)
65 {
66 HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__);
67 if (!initial_) {
68 ABILITYBASE_LOGE("not init");
69 return false;
70 }
71
72 if (srcPath.empty()) {
73 ABILITYBASE_LOGE("empty srcPath");
74 return false;
75 }
76 zipFile_.GetAllFileList(srcPath, assetList);
77 if (assetList.empty()) {
78 ABILITYBASE_LOGW("empty dir: %{public}s", srcPath.c_str());
79 }
80
81 return true;
82 }
83
HasEntry(const std::string &fileName) const84 bool Extractor::HasEntry(const std::string &fileName) const
85 {
86 if (!initial_) {
87 ABILITYBASE_LOGE("not init");
88 return false;
89 }
90
91 return zipFile_.HasEntry(fileName);
92 }
93
IsDirExist(const std::string &dir)94 bool Extractor::IsDirExist(const std::string &dir)
95 {
96 if (!initial_) {
97 ABILITYBASE_LOGE("not init");
98 return false;
99 }
100 if (dir.empty()) {
101 ABILITYBASE_LOGE("dir empty");
102 return false;
103 }
104 return zipFile_.IsDirExist(dir);
105 }
106
ExtractByName(const std::string &fileName, std::ostream &dest) const107 bool Extractor::ExtractByName(const std::string &fileName, std::ostream &dest) const
108 {
109 std::unique_ptr<uint8_t[]> data;
110 size_t dataLen = 0;
111 if (!ExtractToBufByName(fileName, data, dataLen)) {
112 ABILITYBASE_LOGE("ExtractFile fail: %{public}s", fileName.c_str());
113 return false;
114 }
115 dest.write(reinterpret_cast<char*>(data.get()), dataLen);
116 return true;
117 }
118
GetSpecifiedTypeFiles(std::vector<std::string> &fileNames, const std::string &suffix)119 void Extractor::GetSpecifiedTypeFiles(std::vector<std::string> &fileNames, const std::string &suffix)
120 {
121 auto &entryMap = zipFile_.GetAllEntries();
122 for (const auto &entry : entryMap) {
123 std::string fileName = entry.first;
124 auto position = fileName.rfind('.');
125 if (position != std::string::npos) {
126 std::string suffixStr = fileName.substr(position);
127 if (LowerStr(suffixStr) == suffix) {
128 fileNames.emplace_back(fileName);
129 }
130 }
131 }
132 }
133
GetData(const std::string &fileName) const134 std::unique_ptr<FileMapper> Extractor::GetData(const std::string &fileName) const
135 {
136 std::string relativePath = GetRelativePath(fileName);
137 return zipFile_.CreateFileMapper(relativePath, FileMapperType::NORMAL_MEM);
138 }
139
GetSafeData(const std::string &fileName)140 std::shared_ptr<FileMapper> Extractor::GetSafeData(const std::string &fileName)
141 {
142 std::string relativePath = GetRelativePath(fileName);
143 if (!StringEndWith(relativePath, EXT_NAME_ABC, sizeof(EXT_NAME_ABC) - 1)) {
144 return nullptr;
145 }
146
147 return zipFile_.CreateFileMapper(relativePath, FileMapperType::SAFE_ABC);
148 }
149
GetMmapData(const std::string &fileName)150 std::unique_ptr<FileMapper> Extractor::GetMmapData(const std::string &fileName)
151 {
152 std::string relativePath = GetRelativePath(fileName);
153 return zipFile_.CreateFileMapper(relativePath, FileMapperType::SHARED_MMAP);
154 }
155
UnzipData(std::unique_ptr<FileMapper> fileMapper, std::unique_ptr<uint8_t[]> &dataPtr, size_t &len) const156 bool Extractor::UnzipData(std::unique_ptr<FileMapper> fileMapper,
157 std::unique_ptr<uint8_t[]> &dataPtr, size_t &len) const
158 {
159 if (!initial_) {
160 ABILITYBASE_LOGE("not init");
161 return false;
162 }
163
164 if (!fileMapper) {
165 ABILITYBASE_LOGE("null fileMapper");
166 return false;
167 }
168
169 if (!zipFile_.ExtractFileFromMMap(fileMapper->GetFileName(), fileMapper->GetDataPtr(), dataPtr, len)) {
170 ABILITYBASE_LOGE("ExtractFileFromMMap failed");
171 return false;
172 }
173 return true;
174 }
175
IsStageModel()176 bool Extractor::IsStageModel()
177 {
178 if (isStageModel_.has_value()) {
179 return isStageModel_.value();
180 }
181 isStageModel_ = !zipFile_.HasEntry("config.json");
182 return isStageModel_.value();
183 }
184
ExtractToBufByName(const std::string &fileName, std::unique_ptr<uint8_t[]> &dataPtr, size_t &len) const185 bool Extractor::ExtractToBufByName(const std::string &fileName, std::unique_ptr<uint8_t[]> &dataPtr,
186 size_t &len) const
187 {
188 HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__);
189 std::string relativePath = GetRelativePath(fileName);
190 return zipFile_.ExtractToBufByName(relativePath, dataPtr, len);
191 }
192
GetFileInfo(const std::string &fileName, FileInfo &fileInfo) const193 bool Extractor::GetFileInfo(const std::string &fileName, FileInfo &fileInfo) const
194 {
195 std::string relativePath = GetRelativePath(fileName);
196 ZipEntry zipEntry;
197 if (!zipFile_.GetEntry(relativePath, zipEntry)) {
198 ABILITYBASE_LOGE("Get entry failed");
199 return false;
200 }
201
202 ZipPos offset = 0;
203 uint32_t length = 0;
204 if (!zipFile_.GetDataOffsetRelative(zipEntry, offset, length)) {
205 ABILITYBASE_LOGE("GetDataOffsetRelative failed");
206 return false;
207 }
208
209 fileInfo.fileName = fileName;
210 fileInfo.offset = static_cast<uint32_t>(offset);
211 fileInfo.length = static_cast<uint32_t>(length);
212 fileInfo.lastModTime = zipEntry.modifiedTime;
213 fileInfo.lastModDate = zipEntry.modifiedDate;
214 return true;
215 }
216
GetFileList(const std::string &srcPath, std::set<std::string> &fileSet)217 bool Extractor::GetFileList(const std::string &srcPath, std::set<std::string> &fileSet)
218 {
219 if (!initial_) {
220 ABILITYBASE_LOGE("not init");
221 return false;
222 }
223
224 if (srcPath.empty()) {
225 ABILITYBASE_LOGE("empty srcPath");
226 return false;
227 }
228
229 zipFile_.GetChildNames(srcPath, fileSet);
230 if (fileSet.empty()) {
231 ABILITYBASE_LOGD("empty dir: %{public}s", srcPath.c_str());
232 }
233
234 return true;
235 }
236
IsHapCompress(const std::string &fileName) const237 bool Extractor::IsHapCompress(const std::string &fileName) const
238 {
239 std::string relativePath = GetRelativePath(fileName);
240 ZipEntry zipEntry;
241 if (!zipFile_.GetEntry(relativePath, zipEntry)) {
242 ABILITYBASE_LOGE("GetEntry failed fileName: %{public}s", fileName.c_str());
243 return false;
244 }
245 return zipEntry.compressionMethod > 0;
246 }
247
248 std::mutex ExtractorUtil::mapMutex_;
249 std::unordered_map<std::string, std::shared_ptr<Extractor>> ExtractorUtil::extractorMap_;
GetLoadFilePath(const std::string &hapPath)250 std::string ExtractorUtil::GetLoadFilePath(const std::string &hapPath)
251 {
252 std::string loadPath;
253 if (StringStartWith(hapPath, Constants::ABS_CODE_PATH, std::string(Constants::ABS_CODE_PATH).length())) {
254 loadPath = GetLoadPath(hapPath);
255 } else {
256 loadPath = hapPath;
257 }
258 return loadPath;
259 }
260
GetExtractor(const std::string &hapPath, bool &newCreate, bool cache)261 std::shared_ptr<Extractor> ExtractorUtil::GetExtractor(const std::string &hapPath, bool &newCreate, bool cache)
262 {
263 newCreate = false;
264 if (hapPath.empty()) {
265 ABILITYBASE_LOGE("empty hapPath");
266 return nullptr;
267 }
268 {
269 HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, "GetExtractor_find_from_cache");
270 std::lock_guard<std::mutex> mapMutex(mapMutex_);
271 auto mapIter = extractorMap_.find(hapPath);
272 if (mapIter != extractorMap_.end()) {
273 ABILITYBASE_LOGD("hapPath: %{private}s", hapPath.c_str());
274 return mapIter->second;
275 }
276 }
277
278 std::shared_ptr<Extractor> extractor = std::make_shared<Extractor>(hapPath);
279 if (!extractor->Init()) {
280 ABILITYBASE_LOGD("create failed for %{private}s", hapPath.c_str());
281 return nullptr;
282 }
283 if (cache) {
284 HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, "GetExtractor_store");
285 std::lock_guard<std::mutex> mapMutex(mapMutex_);
286 extractorMap_.emplace(hapPath, extractor);
287 ABILITYBASE_LOGD("extractor cache size: %{public}zu", extractorMap_.size());
288 }
289 newCreate = true;
290 return extractor;
291 }
292
DeleteExtractor(const std::string &hapPath)293 void ExtractorUtil::DeleteExtractor(const std::string &hapPath)
294 {
295 HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__);
296 if (hapPath.empty()) {
297 ABILITYBASE_LOGE("empty hapPath");
298 return;
299 }
300
301 std::lock_guard<std::mutex> mapMutex(mapMutex_);
302 auto mapIter = extractorMap_.find(hapPath);
303 if (mapIter != extractorMap_.end()) {
304 ABILITYBASE_LOGI("hapPath: %{public}s", hapPath.c_str());
305 extractorMap_.erase(mapIter);
306 }
307 }
308 } // namespace AbilityBase
309 } // namespace OHOS
310