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