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 if (initial_) {
43 ABILITYBASE_LOGD("already init");
44 return true;
45 }
46 HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__);
47 if (!zipFile_.Open()) {
48 ABILITYBASE_LOGD("open zip file failed");
49 return false;
50 }
51 initial_ = true;
52 return true;
53 }
54
GetFileBuffer(const std::string & srcPath,std::ostringstream & dest)55 bool Extractor::GetFileBuffer(const std::string& srcPath, std::ostringstream& dest)
56 {
57 std::unique_ptr<uint8_t[]> data;
58 size_t dataLen = 0;
59
60 if (!ExtractToBufByName(srcPath, data, dataLen)) {
61 return false;
62 }
63
64 dest.write(reinterpret_cast<char*>(data.get()), dataLen);
65 return true;
66 }
67
GetFileList(const std::string & srcPath,std::vector<std::string> & assetList)68 bool Extractor::GetFileList(const std::string& srcPath, std::vector<std::string>& assetList)
69 {
70 HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__);
71 if (!initial_) {
72 ABILITYBASE_LOGE("not init");
73 return false;
74 }
75
76 if (srcPath.empty()) {
77 ABILITYBASE_LOGE("empty srcPath");
78 return false;
79 }
80 zipFile_.GetAllFileList(srcPath, assetList);
81 if (assetList.empty()) {
82 ABILITYBASE_LOGW("empty dir: %{public}s", srcPath.c_str());
83 }
84
85 return true;
86 }
87
HasEntry(const std::string & fileName) const88 bool Extractor::HasEntry(const std::string &fileName) const
89 {
90 if (!initial_) {
91 ABILITYBASE_LOGE("not init");
92 return false;
93 }
94
95 return zipFile_.HasEntry(fileName);
96 }
97
IsDirExist(const std::string & dir)98 bool Extractor::IsDirExist(const std::string &dir)
99 {
100 if (!initial_) {
101 ABILITYBASE_LOGE("not init");
102 return false;
103 }
104 if (dir.empty()) {
105 ABILITYBASE_LOGE("dir empty");
106 return false;
107 }
108 return zipFile_.IsDirExist(dir);
109 }
110
ExtractByName(const std::string & fileName,std::ostream & dest) const111 bool Extractor::ExtractByName(const std::string &fileName, std::ostream &dest) const
112 {
113 std::unique_ptr<uint8_t[]> data;
114 size_t dataLen = 0;
115 if (!ExtractToBufByName(fileName, data, dataLen)) {
116 ABILITYBASE_LOGE("ExtractFile fail: %{public}s", fileName.c_str());
117 return false;
118 }
119 dest.write(reinterpret_cast<char*>(data.get()), dataLen);
120 return true;
121 }
122
GetSpecifiedTypeFiles(std::vector<std::string> & fileNames,const std::string & suffix)123 void Extractor::GetSpecifiedTypeFiles(std::vector<std::string> &fileNames, const std::string &suffix)
124 {
125 auto &entryMap = zipFile_.GetAllEntries();
126 for (const auto &entry : entryMap) {
127 std::string fileName = entry.first;
128 auto position = fileName.rfind('.');
129 if (position != std::string::npos) {
130 std::string suffixStr = fileName.substr(position);
131 if (LowerStr(suffixStr) == suffix) {
132 fileNames.emplace_back(fileName);
133 }
134 }
135 }
136 }
137
GetData(const std::string & fileName) const138 std::unique_ptr<FileMapper> Extractor::GetData(const std::string &fileName) const
139 {
140 std::string relativePath = GetRelativePath(fileName);
141 return zipFile_.CreateFileMapper(relativePath, FileMapperType::NORMAL_MEM);
142 }
143
GetSafeData(const std::string & fileName)144 std::shared_ptr<FileMapper> Extractor::GetSafeData(const std::string &fileName)
145 {
146 std::string relativePath = GetRelativePath(fileName);
147 if (!StringEndWith(relativePath, EXT_NAME_ABC, sizeof(EXT_NAME_ABC) - 1)) {
148 return nullptr;
149 }
150
151 return zipFile_.CreateFileMapper(relativePath, FileMapperType::SAFE_ABC);
152 }
153
GetMmapData(const std::string & fileName)154 std::unique_ptr<FileMapper> Extractor::GetMmapData(const std::string &fileName)
155 {
156 std::string relativePath = GetRelativePath(fileName);
157 return zipFile_.CreateFileMapper(relativePath, FileMapperType::SHARED_MMAP);
158 }
159
UnzipData(std::unique_ptr<FileMapper> fileMapper,std::unique_ptr<uint8_t[]> & dataPtr,size_t & len) const160 bool Extractor::UnzipData(std::unique_ptr<FileMapper> fileMapper,
161 std::unique_ptr<uint8_t[]> &dataPtr, size_t &len) const
162 {
163 if (!initial_) {
164 ABILITYBASE_LOGE("not init");
165 return false;
166 }
167
168 if (!fileMapper) {
169 ABILITYBASE_LOGE("null fileMapper");
170 return false;
171 }
172
173 if (!zipFile_.ExtractFileFromMMap(fileMapper->GetFileName(), fileMapper->GetDataPtr(), dataPtr, len)) {
174 ABILITYBASE_LOGE("ExtractFileFromMMap failed");
175 return false;
176 }
177 return true;
178 }
179
IsStageModel()180 bool Extractor::IsStageModel()
181 {
182 if (isStageModel_.has_value()) {
183 return isStageModel_.value();
184 }
185 isStageModel_ = !zipFile_.HasEntry("config.json");
186 return isStageModel_.value();
187 }
188
ExtractToBufByName(const std::string & fileName,std::unique_ptr<uint8_t[]> & dataPtr,size_t & len) const189 bool Extractor::ExtractToBufByName(const std::string &fileName, std::unique_ptr<uint8_t[]> &dataPtr,
190 size_t &len) const
191 {
192 if (!initial_) {
193 ABILITYBASE_LOGW("not init");
194 return false;
195 }
196 HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__);
197 std::string relativePath = GetRelativePath(fileName);
198 return zipFile_.ExtractToBufByName(relativePath, dataPtr, len);
199 }
200
GetFileInfo(const std::string & fileName,FileInfo & fileInfo) const201 bool Extractor::GetFileInfo(const std::string &fileName, FileInfo &fileInfo) const
202 {
203 std::string relativePath = GetRelativePath(fileName);
204 ZipEntry zipEntry;
205 if (!zipFile_.GetEntry(relativePath, zipEntry)) {
206 ABILITYBASE_LOGE("Get entry failed");
207 return false;
208 }
209
210 ZipPos offset = 0;
211 uint32_t length = 0;
212 if (!zipFile_.GetDataOffsetRelative(zipEntry, offset, length)) {
213 ABILITYBASE_LOGE("GetDataOffsetRelative failed");
214 return false;
215 }
216
217 fileInfo.fileName = fileName;
218 fileInfo.offset = static_cast<uint32_t>(offset);
219 fileInfo.length = static_cast<uint32_t>(length);
220 fileInfo.lastModTime = zipEntry.modifiedTime;
221 fileInfo.lastModDate = zipEntry.modifiedDate;
222 return true;
223 }
224
GetFileList(const std::string & srcPath,std::set<std::string> & fileSet)225 bool Extractor::GetFileList(const std::string &srcPath, std::set<std::string> &fileSet)
226 {
227 if (!initial_) {
228 ABILITYBASE_LOGE("not init");
229 return false;
230 }
231
232 if (srcPath.empty()) {
233 ABILITYBASE_LOGE("empty srcPath");
234 return false;
235 }
236
237 zipFile_.GetChildNames(srcPath, fileSet);
238 if (fileSet.empty()) {
239 ABILITYBASE_LOGD("empty dir: %{public}s", srcPath.c_str());
240 }
241
242 return true;
243 }
244
IsHapCompress(const std::string & fileName) const245 bool Extractor::IsHapCompress(const std::string &fileName) const
246 {
247 std::string relativePath = GetRelativePath(fileName);
248 ZipEntry zipEntry;
249 if (!zipFile_.GetEntry(relativePath, zipEntry)) {
250 ABILITYBASE_LOGE("GetEntry failed fileName: %{public}s", fileName.c_str());
251 return false;
252 }
253 return zipEntry.compressionMethod > 0;
254 }
255
256 std::mutex ExtractorUtil::mapMutex_;
257 std::unordered_map<std::string, std::shared_ptr<Extractor>> ExtractorUtil::extractorMap_;
GetLoadFilePath(const std::string & hapPath)258 std::string ExtractorUtil::GetLoadFilePath(const std::string &hapPath)
259 {
260 std::string loadPath;
261 if (StringStartWith(hapPath, Constants::ABS_CODE_PATH, std::string(Constants::ABS_CODE_PATH).length())) {
262 loadPath = GetLoadPath(hapPath);
263 } else {
264 loadPath = hapPath;
265 }
266 return loadPath;
267 }
268
GetExtractor(const std::string & hapPath,bool & newCreate,bool cache)269 std::shared_ptr<Extractor> ExtractorUtil::GetExtractor(const std::string &hapPath, bool &newCreate, bool cache)
270 {
271 newCreate = false;
272 if (hapPath.empty()) {
273 ABILITYBASE_LOGE("empty hapPath");
274 return nullptr;
275 }
276 {
277 HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, "GetExtractor_find_from_cache");
278 std::lock_guard<std::mutex> mapMutex(mapMutex_);
279 auto mapIter = extractorMap_.find(hapPath);
280 if (mapIter != extractorMap_.end()) {
281 ABILITYBASE_LOGD("hapPath: %{private}s", hapPath.c_str());
282 return mapIter->second;
283 }
284 }
285
286 std::shared_ptr<Extractor> extractor = std::make_shared<Extractor>(hapPath);
287 if (!extractor->Init()) {
288 ABILITYBASE_LOGD("create failed for %{private}s", hapPath.c_str());
289 return nullptr;
290 }
291 if (cache) {
292 HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, "GetExtractor_store");
293 std::lock_guard<std::mutex> mapMutex(mapMutex_);
294 extractorMap_.emplace(hapPath, extractor);
295 ABILITYBASE_LOGD("extractor cache size: %{public}zu", extractorMap_.size());
296 }
297 newCreate = true;
298 return extractor;
299 }
300
DeleteExtractor(const std::string & hapPath)301 void ExtractorUtil::DeleteExtractor(const std::string &hapPath)
302 {
303 HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__);
304 if (hapPath.empty()) {
305 ABILITYBASE_LOGE("empty hapPath");
306 return;
307 }
308
309 std::lock_guard<std::mutex> mapMutex(mapMutex_);
310 auto mapIter = extractorMap_.find(hapPath);
311 if (mapIter != extractorMap_.end()) {
312 ABILITYBASE_LOGI("hapPath: %{public}s", hapPath.c_str());
313 extractorMap_.erase(mapIter);
314 }
315 }
316 } // namespace AbilityBase
317 } // namespace OHOS
318