• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 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 #include "StageContext.h"
16 #include <sstream>
17 #include <fstream>
18 #include <cctype>
19 #include "json/json.h"
20 #include "JsonReader.h"
21 #include "FileSystem.h"
22 #include "TraceTool.h"
23 #include "PreviewerEngineLog.h"
24 #include "zlib.h"
25 #include "contrib/minizip/unzip.h"
26 using namespace std;
27 
28 namespace OHOS::Ide {
GetInstance()29 StageContext& StageContext::GetInstance()
30 {
31     static StageContext instance;
32     return instance;
33 }
34 
ReadFileContents(const std::string & filePath) const35 const std::optional<std::vector<uint8_t>> StageContext::ReadFileContents(const std::string& filePath) const
36 {
37     if (!FileSystem::IsFileExists(filePath)) {
38         ELOG("file %s is not exist.", filePath.c_str());
39         return std::nullopt;
40     }
41     std::ifstream file(filePath, std::ios::binary | std::ios::ate);
42     if (!file) {
43         ELOG("open file %s failed.", filePath.c_str());
44         return std::nullopt;
45     }
46     std::streamsize fileSize = file.tellg();
47     file.seekg(0, std::ios::beg);
48     std::vector<uint8_t> data(fileSize);
49     if (file.read(reinterpret_cast<char*>(data.data()), fileSize)) {
50         return data;
51     } else {
52         ELOG("read file %s failed.", filePath.c_str());
53         return std::nullopt;
54     }
55 }
56 
SetLoaderJsonPath(const std::string & assetPath)57 void StageContext::SetLoaderJsonPath(const std::string& assetPath)
58 {
59     loaderJsonPath = assetPath;
60     if (loaderJsonPath.empty() || !FileSystem::IsFileExists(loaderJsonPath)) {
61         ELOG("the loaderJsonPath %s is not exist.", loaderJsonPath.c_str());
62         return;
63     }
64     ILOG("set loaderJsonPath: %s successed.", loaderJsonPath.c_str());
65 }
66 
GetModulePathMapFromLoaderJson()67 void StageContext::GetModulePathMapFromLoaderJson()
68 {
69     if (!FileSystem::IsFileExists(loaderJsonPath)) {
70         ELOG("the loaderJsonPath is not exist.");
71         return;
72     }
73     string jsonStr = JsonReader::ReadFile(loaderJsonPath);
74     Json::Value rootJson = JsonReader::ParseJsonData(jsonStr);
75     if (!rootJson) {
76         ELOG("Get loader.json content failed.");
77         return;
78     }
79     if (!rootJson.isMember("modulePathMap")) {
80         ELOG("Don't find modulePathMap node in loader.json.");
81         return;
82     }
83     std::unique_ptr<Json::Value> jsonObj = JsonReader::GetObject(rootJson, "modulePathMap");
84     for (const auto& key : jsonObj->getMemberNames()) {
85         string val = JsonReader::GetString(*jsonObj, key);
86         modulePathMap[key] = val;
87     }
88     std::unique_ptr<Json::Value> jsonObjOhm = JsonReader::GetObject(rootJson, "harNameOhmMap");
89     for (const auto& key : jsonObjOhm->getMemberNames()) {
90         string val = JsonReader::GetString(*jsonObjOhm, key);
91         harNameOhmMap[key] = val;
92     }
93     projectRootPath = JsonReader::GetString(rootJson, "projectRootPath");
94 }
95 
GetHspAceModuleBuild(const std::string & hspConfigPath)96 std::string StageContext::GetHspAceModuleBuild(const std::string& hspConfigPath)
97 {
98     if (!FileSystem::IsFileExists(hspConfigPath)) {
99         ELOG("hspConfigPath: %s is not exist.", hspConfigPath.c_str());
100         return "";
101     }
102     string jsonStr = JsonReader::ReadFile(hspConfigPath);
103     Json::Value rootJson = JsonReader::ParseJsonData(jsonStr);
104     if (!rootJson) {
105         ELOG("Get hsp buildConfig.json content failed.");
106         return "";
107     }
108     if (!rootJson.isMember("aceModuleBuild")) {
109         ELOG("Don't find aceModuleBuild node in hsp buildConfig.json.");
110         return "";
111     }
112     return JsonReader::GetString(rootJson, "aceModuleBuild");
113 }
114 
ReleaseHspBuffers()115 void StageContext::ReleaseHspBuffers()
116 {
117     for (std::vector<uint8_t>* ptr : hspBufferPtrsVec) {
118         delete ptr;
119     }
120     hspBufferPtrsVec.clear();
121     ILOG("ReleaseHspBuffers finished.");
122 }
123 
GetModulePathMap() const124 std::map<std::string, std::string> StageContext::GetModulePathMap() const
125 {
126     return modulePathMap;
127 }
128 
GetModuleBuffer(const std::string & inputPath)129 std::vector<uint8_t>* StageContext::GetModuleBuffer(const std::string& inputPath)
130 {
131     ILOG("inputPath is:%s.", inputPath.c_str());
132     TraceTool::GetInstance().HandleTrace("HSP is loaded");
133     std::string spliter = "/";
134     size_t pos = inputPath.rfind(spliter);
135     if (pos == std::string::npos) {
136         ELOG("inputPath: %s format error.", inputPath.c_str());
137         return nullptr;
138     }
139     std::string bundleName = inputPath.substr(0, pos);
140     ILOG("bundleName is:%s.", bundleName.c_str());
141     if (bundleName.empty()) {
142         ELOG("bundleName is empty.");
143         return nullptr;
144     }
145     std::string moduleName = inputPath.substr(pos + spliter.size());
146     ILOG("moduleName is:%s.", moduleName.c_str());
147     if (modulePathMap.empty()) {
148         ELOG("modulePathMap is empty.");
149         return nullptr;
150     }
151     if (bundleName == localBundleName) { // local hsp
152         if (modulePathMap.count(moduleName) > 0) { // exist local hsp
153             return GetLocalModuleBuffer(moduleName);
154         } else { // local hsp not exist, load cloud hsp
155             ILOG("cloud hsp bundleName is same as the local project.");
156             return GetCloudModuleBuffer(moduleName);
157         }
158     } else { // cloud hsp
159         return GetCloudModuleBuffer(moduleName);
160     }
161 }
162 
GetLocalModuleBuffer(const std::string & moduleName)163 std::vector<uint8_t>* StageContext::GetLocalModuleBuffer(const std::string& moduleName)
164 {
165     std::string modulePath = StageContext::GetInstance().modulePathMap[moduleName];
166     if (modulePath.empty()) {
167         ELOG("modulePath is empty.");
168         return nullptr;
169     }
170     ILOG("get modulePath: %s successed.", modulePath.c_str());
171     if (!FileSystem::IsDirectoryExists(modulePath)) {
172         ELOG("don't find moduleName: %s in modulePathMap from loader.json.", moduleName.c_str());
173         return nullptr;
174     }
175     if (ContainsRelativePath(modulePath)) {
176         ELOG("modulePath format error: %s.", modulePath.c_str());
177         return nullptr;
178     }
179     std::string separator = FileSystem::GetSeparator();
180     // 读取hsp的.preview/config/buildConfig.json获取aceModuleBuild值就是hsp的modules.abc所在文件夹
181     std::string hspConfigPath = modulePath + separator + ".preview" + separator + "config" +
182         separator + "buildConfig.json";
183     std::string abcDir = GetHspAceModuleBuild(hspConfigPath);
184     if (!FileSystem::IsDirectoryExists(abcDir)) {
185         ELOG("the abcDir:%s is not exist.", abcDir.c_str());
186         return nullptr;
187     }
188     std::string abcPath = abcDir + separator + "modules.abc";
189     if (!FileSystem::IsFileExists(abcPath)) {
190         ELOG("the abcPath:%s is not exist.", abcPath.c_str());
191         return nullptr;
192     }
193     ILOG("get modules.abc path: %s successed.", abcPath.c_str());
194     std::optional<std::vector<uint8_t>> opt = ReadFileContents(abcPath);
195     if (!opt.has_value()) {
196         ELOG("read modules.abc buffer failed.");
197         return nullptr;
198     }
199     std::vector<uint8_t> *buf = new std::vector<uint8_t>(opt.value());
200     hspBufferPtrsVec.push_back(buf);
201     return buf;
202 }
203 
GetCloudHspVersion(const std::string & hspPath,const std::string & actualName)204 std::string StageContext::GetCloudHspVersion(const std::string& hspPath, const std::string& actualName)
205 {
206     string flag = "@";
207     std::string spliter = actualName + flag;
208     // 以partName字符串拆分出版本号
209     size_t pos = hspPath.rfind(spliter);
210     if (pos == std::string::npos) {
211         ELOG("hspPath: %s format error. no spliter:%s exist", hspPath.c_str(), spliter.c_str());
212         return "";
213     }
214     int idx = pos + spliter.size();
215     return hspPath.substr(idx);
216 }
217 
SplitHspVersion(const std::string & version)218 std::vector<int> StageContext::SplitHspVersion(const std::string& version)
219 {
220     std::vector<int> segments;
221     std::istringstream iss(version);
222     std::string segment;
223     while (getline(iss, segment, '.')) {
224         segments.push_back(std::stoi(segment));
225     }
226     return segments;
227 }
228 
CompareHspVersion(const std::string & version1,const std::string & version2)229 int StageContext::CompareHspVersion(const std::string& version1, const std::string& version2)
230 {
231     ILOG("module hsp version:%s, project hsp version:%s", version1.c_str(), version2.c_str());
232     std::vector<int> ver1 = SplitHspVersion(version1);
233     std::vector<int> ver2 = SplitHspVersion(version2);
234     // 将两个版本号的分段个数补齐
235     while (ver1.size() < ver2.size()) {
236         ver1.push_back(0);
237     }
238     while (ver2.size() < ver1.size()) {
239         ver2.push_back(0);
240     }
241     // 逐段比较版本号
242     for (size_t i = 0; i < ver1.size(); ++i) {
243         if (ver1[i] < ver2[i]) {
244             return -1;
245         } else if (ver1[i] > ver2[i]) {
246             return 1;
247         }
248     }
249     return 0;
250 }
251 
GetActualCloudHspDir(const std::string & actualName)252 std::string StageContext::GetActualCloudHspDir(const std::string& actualName)
253 {
254     string moduleHspPath = GetCloudModuleHspPath(actualName);
255     string projectHspPath = GetCloudProjectHspPath(actualName);
256     ILOG("moduleHspPath:%s, projectHspPath:%s", moduleHspPath.c_str(), projectHspPath.c_str());
257     if (moduleHspPath.empty() || !FileSystem::IsDirectoryExists(moduleHspPath)) {
258         return projectHspPath; // 模块级不存在,加载项目级
259     }
260     if (projectHspPath.empty() || !FileSystem::IsDirectoryExists(projectHspPath)) {
261         return moduleHspPath; // 模块级存在,项目级不存在,加载模块级
262     }
263     // 模块级和项目级都存在,加载版本号高的
264     string moduleHspVersion = GetCloudHspVersion(moduleHspPath, actualName);
265     string projectHspVersion = GetCloudHspVersion(projectHspPath, actualName);
266     if (moduleHspVersion.empty()) {
267         return projectHspPath; // 模块级版本号不存在,加载项目级
268     }
269     if (projectHspVersion.empty()) {
270         return moduleHspPath; // 模块级版本号存在,项目级版本号不存在,加载模块级
271     }
272     int ret = CompareHspVersion(moduleHspVersion, projectHspVersion);
273     ILOG("CompareHspVersion result is:%d", ret);
274     return ret >= 0 ? moduleHspPath : projectHspPath; // 优先加载版本号高的,版本号相同则优先加载模块级的
275 }
276 
GetCloudProjectHspPath(const std::string & actualName)277 std::string StageContext::GetCloudProjectHspPath(const std::string& actualName)
278 {
279     ILOG("get projectRootPath:%s", projectRootPath.c_str());
280     std::string hspDir = projectRootPath + "/oh_modules/.hsp";
281     if (!FileSystem::IsDirectoryExists(hspDir)) {
282         ELOG("hspDir: %s in project is not exist.", hspDir.c_str());
283         return "";
284     }
285     return GetCloudHspPath(hspDir, actualName);
286 }
287 
GetCloudModuleHspPath(const std::string & actualName)288 std::string StageContext::GetCloudModuleHspPath(const std::string& actualName)
289 {
290     int upwardLevel = 5;
291     int pos = GetUpwardDirIndex(loaderJsonPath, upwardLevel);
292     if (pos < 0) {
293         ILOG("GetUpwardDirIndex:%d failed.", pos);
294         return "";
295     }
296     std::string moduleRootPath = loaderJsonPath.substr(0, pos);
297     ILOG("get moduleRootPath:%s", moduleRootPath.c_str());
298     std::string hspDir = moduleRootPath + "/oh_modules/.hsp";
299     if (!FileSystem::IsDirectoryExists(hspDir)) {
300         ELOG("hspDir: %s in module is not exist.", hspDir.c_str());
301         return "";
302     }
303     return GetCloudHspPath(hspDir, actualName);
304 }
305 
GetCloudModuleBuffer(const std::string & moduleName)306 std::vector<uint8_t>* StageContext::GetCloudModuleBuffer(const std::string& moduleName)
307 {
308     std::string actualName;
309     int ret = GetHspActualName(moduleName, actualName);
310     if (ret > 1) {
311         WLOG("have more same module name hsp in the project, load the first as default.");
312     }
313     if (actualName.empty()) {
314         ELOG("get hsp actual name failed.");
315         return nullptr;
316     }
317     // 1.以entry(指代模块根目录或项目根目录)拆分,拼接oh_modules/.hsp,在这个拼接目录下查找以actualName@开头的文件夹
318     // 2.获取拼接目录下的actualName.hsp文件
319     // 3.使用zlib获取hsp压缩包下的ets/modules.abc内容
320     std::string hspPath = GetActualCloudHspDir(actualName);
321     ILOG("get hspPath:%s actualName:%s", hspPath.c_str(), actualName.c_str());
322     if (!FileSystem::IsDirectoryExists(hspPath)) {
323         ELOG("hspPath: %s is not exist.", hspPath.c_str());
324         return nullptr;
325     }
326     std::string moduleHspFile = hspPath + "/" + actualName + ".hsp";
327     ILOG("get moduleHspFile:%s.", moduleHspFile.c_str());
328     if (!FileSystem::IsFileExists(moduleHspFile)) {
329         ELOG("the moduleHspFile:%s is not exist.", moduleHspFile.c_str());
330         return nullptr;
331     }
332     // unzip and get ets/moudles.abc buffer
333     std::vector<uint8_t>* buf = GetModuleBufferFromHsp(moduleHspFile, "ets/modules.abc");
334     if (!buf) {
335         ELOG("read modules.abc buffer failed.");
336     }
337     return buf;
338 }
339 
GetCloudHspPath(const std::string & hspDir,const std::string & moduleName)340 std::string StageContext::GetCloudHspPath(const std::string& hspDir, const std::string& moduleName)
341 {
342     string flag = "@";
343     std::string partName = moduleName + flag;
344     return FileSystem::FindSubfolderByName(hspDir, partName);
345 }
346 
GetModuleBufferFromHsp(const std::string & hspFilePath,const std::string & fileName)347 std::vector<uint8_t>* StageContext::GetModuleBufferFromHsp(const std::string& hspFilePath,
348     const std::string& fileName)
349 {
350     unzFile zipfile = unzOpen2(hspFilePath.c_str(), nullptr);
351     if (zipfile == NULL) {
352         printf("Failed to open the zip file: %s\n", hspFilePath.c_str());
353         return nullptr;
354     }
355 
356     if (unzLocateFile(zipfile, fileName.c_str(), 1) != UNZ_OK) {
357         printf("Failed to locate the file: %s\n", fileName.c_str());
358         unzClose(zipfile);
359         return nullptr;
360     }
361 
362     unz_file_info file_info;
363     if (unzGetCurrentFileInfo(zipfile, &file_info, NULL, 0, NULL, 0, NULL, 0) != UNZ_OK) {
364         printf("Failed to get the file info: %s\n", fileName.c_str());
365         unzClose(zipfile);
366         return nullptr;
367     }
368 
369     if (unzOpenCurrentFile(zipfile) != UNZ_OK) {
370         printf("Failed to open the file: %s\n", fileName.c_str());
371         unzClose(zipfile);
372         return nullptr;
373     }
374 
375     char buffer[1024];
376     int bytesRead;
377     std::vector<uint8_t>* fileContent = new std::vector<uint8_t>();
378     while ((bytesRead = unzReadCurrentFile(zipfile, buffer, sizeof(buffer))) > 0) {
379         fileContent->insert(fileContent->end(), buffer, buffer + bytesRead);
380     }
381     hspBufferPtrsVec.push_back(fileContent);
382     unzCloseCurrentFile(zipfile);
383     unzClose(zipfile);
384 
385     printf("File extracted and content saved: %s\n", fileName.c_str());
386     return fileContent;
387 }
388 
ContainsRelativePath(const std::string & path) const389 bool StageContext::ContainsRelativePath(const std::string& path) const
390 {
391     std::string flg1 = ".." + FileSystem::GetSeparator();
392     std::string flg2 = "." + FileSystem::GetSeparator();
393     return (path.find(flg1) != std::string::npos || path.find(flg2) != std::string::npos);
394 }
395 
ParseMockJsonFile(const std::string & mockJsonFilePath)396 std::map<string, string> StageContext::ParseMockJsonFile(const std::string& mockJsonFilePath)
397 {
398     std::map<string, string> mapInfo;
399     if (!FileSystem::IsFileExists(mockJsonFilePath)) {
400         ELOG("the mockJsonFilePath:%s is not exist.", mockJsonFilePath.c_str());
401         return mapInfo;
402     }
403     std::string jsonStr = JsonReader::ReadFile(mockJsonFilePath);
404     Json::Value rootJson = JsonReader::ParseJsonData(jsonStr);
405     if (!rootJson) {
406         ELOG("get mock-config.json content failed.");
407         return mapInfo;
408     }
409     for (const auto& key : rootJson.getMemberNames()) {
410         if (!rootJson[key].isNull() && rootJson[key].isMember("source") && rootJson[key]["source"].isString()) {
411             mapInfo[key] = rootJson[key]["source"].asString();
412         }
413     }
414     return mapInfo;
415 }
416 
GetUpwardDirIndex(const std::string & path,const int upwardLevel) const417 int StageContext::GetUpwardDirIndex(const std::string& path, const int upwardLevel) const
418 {
419     std::string::size_type pos = path.find_last_of(FileSystem::GetSeparator().c_str());
420     std::string::size_type count = 0;
421     while (count < upwardLevel) {
422         if (pos == std::string::npos) {
423             ELOG("GetUpwardDir:%s failed.");
424             int errCode = -1;
425             return errCode;
426         }
427         pos = path.find_last_of(FileSystem::GetSeparator().c_str(), pos - 1);
428         ++count;
429     }
430     ILOG("GetUpwardDir path:%s pos:%d", path.c_str(), pos);
431     return pos;
432 }
433 
ReplaceLastStr(const std::string & str,const std::string & find,const std::string & replace)434 std::string StageContext::ReplaceLastStr(const std::string& str, const std::string& find, const std::string& replace)
435 {
436     std::string ret = str;
437     size_t pos = ret.rfind(find);
438     if (pos != std::string::npos) {
439         ret.replace(pos, find.size(), replace);
440     }
441     return ret;
442 }
443 
GetHspActualName(const std::string & input,std::string & ret)444 int StageContext::GetHspActualName(const std::string& input, std::string& ret)
445 {
446     int num = 0;
447     string flag = "/" + input + "/";
448     for (const auto& pair : harNameOhmMap) {
449         if (pair.second.find(flag) != std::string::npos) {
450             if (num == 0) {
451                 ret = pair.first;
452             }
453             num++;
454             WLOG("find hsp actual name:%s", pair.first.c_str());
455         }
456     }
457     return num;
458 }
459 }