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 }