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