• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-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 "frameworks/bridge/js_frontend/engine/jsi/jsi_base_utils.h"
17 
18 #include <utility>
19 
20 #include "base/log/event_report.h"
21 #include "base/log/exception_handler.h"
22 #include "base/utils/utils.h"
23 #include "bridge/declarative_frontend/engine/jsi/jsi_declarative_engine.h"
24 #include "core/common/ace_application_info.h"
25 #include "core/common/ace_engine.h"
26 #include "core/common/container.h"
27 #include "frameworks/bridge/js_frontend/engine/jsi/ark_js_runtime.h"
28 #include "frameworks/bridge/js_frontend/engine/jsi/ark_js_value.h"
29 
30 namespace OHOS::Ace::Framework {
31 constexpr char JS_CRASH_CODE[] = "100001";
32 
GetLineOffset(const AceType * data)33 int32_t GetLineOffset(const AceType *data)
34 {
35 #ifndef PA_SUPPORT
36     if (data == nullptr) {
37         return 0;
38     }
39     if (AceType::InstanceOf<JsiDeclarativeEngineInstance>(data)) {
40         return 0;
41     }
42 #endif
43     const int32_t offset = 14;
44     return offset;
45 }
46 
GetMsgStr(const std::string & msg)47 std::string GetMsgStr(const std::string& msg)
48 {
49     int pos = msg.find('\n');
50     if (pos == std::string::npos) {
51         return msg;
52     }
53 
54     return msg.substr(0, pos);
55 }
56 
GetRunningPage(const AceType * data)57 RefPtr<JsAcePage> GetRunningPage(const AceType *data)
58 {
59 #ifndef PA_SUPPORT
60     if (data == nullptr) {
61         return nullptr;
62     }
63     if (AceType::InstanceOf<JsiEngineInstance>(data)) {
64         auto instance = static_cast<const JsiEngineInstance *>(data);
65         return instance->GetRunningPage();
66     } else if (AceType::InstanceOf<JsiDeclarativeEngineInstance>(data)) {
67         auto instance = static_cast<const JsiDeclarativeEngineInstance *>(data);
68         return instance->GetRunningPage();
69     }
70 #endif
71     return nullptr;
72 }
73 
GetDelegate(const AceType * data)74 RefPtr<FrontendDelegate> GetDelegate(const AceType *data)
75 {
76 #ifndef PA_SUPPORT
77     if (data == nullptr) {
78         return nullptr;
79     }
80     if (AceType::InstanceOf<JsiEngineInstance>(data)) {
81         auto instance = static_cast<const JsiEngineInstance *>(data);
82         return instance->GetDelegate();
83     } else if (AceType::InstanceOf<JsiDeclarativeEngineInstance>(data)) {
84         auto instance = static_cast<const JsiDeclarativeEngineInstance *>(data);
85         return instance->GetDelegate();
86     }
87 #endif
88     return nullptr;
89 }
90 
GenerateErrorMsg(const std::shared_ptr<JsValue> & error,const std::shared_ptr<JsRuntime> & runtime)91 std::string JsiBaseUtils::GenerateErrorMsg(
92     const std::shared_ptr<JsValue>& error, const std::shared_ptr<JsRuntime>& runtime)
93 {
94     std::string errMsg;
95     if (!error) {
96         errMsg.append("error uncaught");
97         return errMsg;
98     }
99 
100     std::string messageStr;
101     std::string rawStack;
102     shared_ptr<JsValue> message = error->GetProperty(runtime, "message");
103     if (message) {
104         messageStr = message->ToString(runtime);
105     }
106 
107     shared_ptr<JsValue> stack = error->GetProperty(runtime, "stack");
108     if (stack) {
109         rawStack = stack->ToString(runtime);
110     }
111 
112     errMsg.append("{\"ErrMsg\":\"").append(messageStr)
113         .append("\", \"Stacktrace\": \"").append(GetMsgStr(rawStack)).append("\"}");
114     return errMsg;
115 }
116 
GenerateSummaryBody(const std::shared_ptr<JsValue> & error,const std::shared_ptr<JsRuntime> & runtime)117 std::string JsiBaseUtils::GenerateSummaryBody(
118     const std::shared_ptr<JsValue>& error, const std::shared_ptr<JsRuntime>& runtime)
119 {
120     std::string summaryBody;
121     summaryBody.append("Lifetime: ")
122         .append(std::to_string(OHOS::Ace::AceApplicationInfo::GetInstance().GetLifeTime()))
123         .append("s")
124         .append("\n");
125 
126     summaryBody.append("Js-Engine: ark\n");
127 
128     if (!error) {
129         summaryBody.append("error uncaught: error is null");
130         return summaryBody;
131     }
132 
133     const AceType* data = static_cast<AceType*>(runtime->GetEmbedderData());
134     std::string pageUrl;
135     RefPtr<RevSourceMap> pageMap;
136     RefPtr<RevSourceMap> appMap;
137     std::unordered_map<std::string, RefPtr<RevSourceMap>> sourceMaps;
138     auto vm = const_cast<EcmaVM*>(std::static_pointer_cast<ArkJSRuntime>(runtime)->GetEcmaVm());
139     auto container = Container::Current();
140     if (container && container->IsUseNewPipeline()) {
141         auto frontEnd = container->GetFrontend();
142         if (frontEnd) {
143             pageUrl = frontEnd->GetCurrentPageUrl();
144             if (!JSNApi::IsBundle(vm)) {
145                 frontEnd->GetStageSourceMap(sourceMaps);
146             } else {
147                 pageMap = frontEnd->GetCurrentPageSourceMap();
148             }
149             appMap = frontEnd->GetFaAppSourceMap();
150         }
151     } else {
152         auto runningPage = GetRunningPage(data);
153         if (runningPage) {
154             pageUrl = runningPage->GetUrl();
155             appMap = runningPage->GetAppMap();
156             if (!JSNApi::IsBundle(vm)) {
157                 GetStageSourceMap(data, sourceMaps);
158             } else {
159                 pageMap = runningPage->GetPageMap();
160             }
161         }
162     }
163     if (!pageUrl.empty()) {
164         summaryBody.append("page: ").append(pageUrl).append("\n");
165     }
166     if (!error->IsObject(runtime) || error->IsNull(runtime)) {
167         std::string errorInfo = error->ToString(runtime);
168         summaryBody.append(errorInfo).append("\n");
169     }
170     shared_ptr<JsValue> message = error->GetProperty(runtime, "message");
171     std::string messageStr = message->ToString(runtime);
172     summaryBody.append("Error message: ");
173     summaryBody.append(messageStr).append("\n");
174 
175     shared_ptr<JsValue> stack = error->GetProperty(runtime, "stack");
176     std::string rawStack = stack->ToString(runtime);
177     if (rawStack.empty()) {
178         summaryBody.append("Stacktrace is empty!\n");
179         return summaryBody;
180     }
181 
182     shared_ptr<JsValue> errorFunc = error->GetProperty(runtime, "errorfunc");
183     auto errorPos = GetErrorPos(rawStack);
184     std::string sourceCodeInfo = GetSourceCodeInfo(runtime, errorFunc, errorPos);
185 
186     std::string stackHead = "Stacktrace:\n";
187     if (pageMap || appMap || !sourceMaps.empty()) {
188         std::string runningPageTag = "app_.js";
189         bool isAppPage = rawStack.find(runningPageTag, 1) != std::string::npos && appMap;
190         if (isAppPage) {
191             sourceCodeInfo = appMap->GetOriginalNames(sourceCodeInfo, errorPos.second);
192         } else if (pageMap) {
193             sourceCodeInfo = pageMap->GetOriginalNames(sourceCodeInfo, errorPos.second);
194         }
195         std::string showStack;
196         if (!JSNApi::IsBundle(vm)) {
197             showStack = TranslateBySourceMap(rawStack, pageUrl, sourceMaps, appMap, data);
198         } else {
199             showStack = TranslateStack(rawStack, pageUrl, pageMap, appMap, data);
200         }
201         summaryBody.append(sourceCodeInfo).append(stackHead).append(showStack);
202         // show raw stack for troubleshooting in the frame
203         LOGI("JS Stack:\n%{public}s", TranslateRawStack(rawStack).c_str());
204     } else {
205         summaryBody.append("Cannot get SourceMap info, dump raw stack:\n");
206         summaryBody.append(stackHead).append(rawStack);
207     }
208 
209 #if defined(WINDOWS_PLATFORM) || defined(MAC_PLATFORM)
210     std::string summaryBodyInsertedWithTagStr = "";
211     size_t lastPosOfNextLine = -1;
212     size_t currPosOfNextLine = 0;
213     while (true) {
214         lastPosOfNextLine++; // Become the next position at which we start to find the target charactor.
215         currPosOfNextLine = summaryBody.find_first_of("\n", lastPosOfNextLine);
216         if (currPosOfNextLine == -1) {
217             break;
218         }
219         summaryBodyInsertedWithTagStr
220             .append("[Engine Log]")
221             .append(summaryBody.substr(lastPosOfNextLine, (currPosOfNextLine - lastPosOfNextLine) + 1));
222         lastPosOfNextLine = currPosOfNextLine;
223     }
224     return summaryBodyInsertedWithTagStr;
225 #else
226     return summaryBody;
227 #endif
228 }
229 
GetErrorPos(const std::string & rawStack)230 ErrorPos JsiBaseUtils::GetErrorPos(const std::string& rawStack)
231 {
232     size_t findLineEnd = rawStack.find("\n");
233     if (findLineEnd == std::string::npos) {
234         return std::make_pair(0, 0);
235     }
236     uint32_t lineEnd = findLineEnd - 1;
237     if (lineEnd < 1 || rawStack[lineEnd - 1] == '?') {
238         return std::make_pair(0, 0);
239     }
240 
241     uint32_t secondPos = rawStack.rfind(':', lineEnd);
242     uint32_t fristPos = rawStack.rfind(':', secondPos - 1);
243 
244     std::string lineStr = rawStack.substr(fristPos + 1, secondPos - 1 - fristPos);
245     std::string columnStr = rawStack.substr(secondPos + 1, lineEnd - 1 - secondPos);
246 
247     return std::make_pair(StringToInt(lineStr), StringToInt(columnStr));
248 }
249 
GetSourceCodeInfo(std::shared_ptr<JsRuntime> runtime,const shared_ptr<JsValue> & errorFunc,ErrorPos pos)250 std::string JsiBaseUtils::GetSourceCodeInfo(
251     std::shared_ptr<JsRuntime> runtime, const shared_ptr<JsValue>& errorFunc, ErrorPos pos)
252 {
253     if (pos.first == 0) {
254         return "";
255     }
256     shared_ptr<ArkJSRuntime> arkJsRuntime = std::static_pointer_cast<ArkJSRuntime>(runtime);
257     LocalScope scope(arkJsRuntime->GetEcmaVm());
258     uint32_t line = pos.first;
259     uint32_t column = pos.second;
260     Local<panda::FunctionRef> function(std::static_pointer_cast<ArkJSValue>(errorFunc)->GetValue(arkJsRuntime));
261     Local<panda::StringRef> sourceCode = function->GetSourceCode(arkJsRuntime->GetEcmaVm(), line);
262     std::string sourceCodeStr = sourceCode->ToString();
263     if (sourceCodeStr.empty()) {
264         return "";
265     }
266     std::string sourceCodeInfo = "SourceCode:\n";
267     sourceCodeInfo.append(sourceCodeStr).append("\n");
268     for (uint32_t k = 0; k < column - 1; k++) {
269         sourceCodeInfo.push_back(' ');
270     }
271     sourceCodeInfo.append("^\n");
272     return sourceCodeInfo;
273 }
274 
TransSourceStack(RefPtr<JsAcePage> runningPage,const std::string & rawStack)275 std::string JsiBaseUtils::TransSourceStack(RefPtr<JsAcePage> runningPage, const std::string& rawStack)
276 {
277     RefPtr<RevSourceMap> pageMap;
278     RefPtr<RevSourceMap> appMap;
279     std::string pageUrl;
280     auto container = Container::Current();
281     if (container && container->IsUseNewPipeline()) {
282         auto frontEnd = container->GetFrontend();
283         if (frontEnd) {
284             pageUrl = frontEnd->GetCurrentPageUrl();
285             pageMap = frontEnd->GetCurrentPageSourceMap();
286             appMap = frontEnd->GetFaAppSourceMap();
287         } else {
288             LOGE("fail to find frontEnd");
289         }
290     } else {
291         if (runningPage) {
292             pageUrl = runningPage->GetUrl();
293             pageMap = runningPage->GetPageMap();
294             appMap = runningPage->GetAppMap();
295         } else {
296             LOGE("runningPage is nullptr");
297         }
298     }
299 
300     if (!pageMap) {
301         LOGE("fail to find page map");
302         return rawStack;
303     }
304 
305     std::string summaryBody;
306     summaryBody.append(" Page: ").append(pageUrl).append("\n");
307 
308     std::string stackHead = "Stacktrace:\n";
309     if (pageMap || appMap) {
310         std::string tempStack = JsiBaseUtils::TranslateStack(rawStack, pageUrl, pageMap, appMap);
311         summaryBody.append(stackHead).append(tempStack);
312     } else {
313         summaryBody.append("Cannot get SourceMap info, dump raw stack:\n");
314         summaryBody.append(stackHead).append(rawStack);
315     }
316 
317     return summaryBody;
318 }
319 
TranslateRawStack(const std::string & rawStackStr)320 std::string JsiBaseUtils::TranslateRawStack(const std::string& rawStackStr)
321 {
322     std::string ans;
323     std::string tempStack = rawStackStr;
324 
325     // find per line of stack
326     std::vector<std::string> res;
327     ExtractEachInfo(tempStack, res);
328 
329     // collect error info first
330     for (const auto& temp : res) {
331         const std::string sourceInfo = GetRelativePath(temp, "/");
332         ans = ans + sourceInfo + "\n";
333     }
334     if (ans.empty()) {
335         return tempStack;
336     }
337     return ans;
338 }
339 
TranslateStack(const std::string & stackStr,const std::string & pageUrl,const RefPtr<RevSourceMap> & pageMap,const RefPtr<RevSourceMap> & appMap,const AceType * data)340 std::string JsiBaseUtils::TranslateStack(const std::string& stackStr, const std::string& pageUrl,
341     const RefPtr<RevSourceMap>& pageMap, const RefPtr<RevSourceMap>& appMap, const AceType* data)
342 {
343     const std::string closeBrace = ")";
344     const std::string openBrace = "(";
345     std::string ans;
346     std::string tempStack = stackStr;
347     // find per line of stack
348     std::vector<std::string> res;
349     ExtractEachInfo(tempStack, res);
350 
351     std::string runningPageTag = "app_.js";
352     auto appFlag = static_cast<int32_t>(tempStack.find(runningPageTag));
353     bool isAppPage = appFlag > 0 && appMap;
354     if (!isAppPage) {
355         std::string tag = std::as_const(pageUrl);
356         std::string str = tag;
357         if (res[0].find('/') == std::string::npos) {
358             replace(str.begin(), str.end(), '/', '\\');
359         }
360         char* ch = strrchr((char*)str.c_str(), '.');
361         int index = ch - str.c_str();
362         str.insert(index, "_");
363         runningPageTag = str;
364     }
365 
366     // collect error info first
367     for (uint32_t i = 0; i < res.size(); i++) {
368         std::string temp = res[i];
369         if (temp.rfind(runningPageTag) == std::string::npos) {
370             continue;
371         }
372         auto closeBracePos = static_cast<int32_t>(temp.find(closeBrace));
373         auto openBracePos = static_cast<int32_t>(temp.find(openBrace));
374 
375         std::string line;
376         std::string column;
377         GetPosInfo(temp, closeBracePos, line, column);
378         if (line.empty() || column.empty()) {
379             LOGI("the stack without line info");
380             break;
381         }
382 
383         const std::string sourceInfo = GetSourceInfo(line, column, pageMap, appMap, isAppPage, data);
384         if (sourceInfo.empty()) {
385             break;
386         }
387         temp.replace(openBracePos, closeBracePos - openBracePos + 1, sourceInfo);
388         replace(temp.begin(), temp.end(), '\\', '/');
389         ans = ans + temp + "\n";
390     }
391     if (ans.empty()) {
392         return tempStack;
393     }
394     return ans;
395 }
396 
TranslateBySourceMap(const std::string & stackStr,const std::string & pageUrl,const std::unordered_map<std::string,RefPtr<RevSourceMap>> & sourceMaps,const RefPtr<RevSourceMap> & appMap,const AceType * data)397 std::string JsiBaseUtils::TranslateBySourceMap(const std::string& stackStr, const std::string& pageUrl,
398     const std::unordered_map<std::string, RefPtr<RevSourceMap>>& sourceMaps,
399     const RefPtr<RevSourceMap>& appMap, const AceType* data)
400 {
401     const std::string closeBrace = ")";
402     const std::string openBrace = "(";
403     std::string ans;
404     std::string tempStack = stackStr;
405     std::string runningPageTag = "app_.js";
406     auto appFlag = static_cast<int32_t>(tempStack.find(runningPageTag));
407     bool isAppPage = appFlag > 0 && appMap;
408     if (!isAppPage) {
409         std::string tag = std::as_const(pageUrl);
410         char* ch = strrchr((char*)tag.c_str(), '.');
411         int index = ch - tag.c_str();
412         tag.insert(index, "_");
413         runningPageTag = tag;
414     }
415     // find per line of stack
416     std::vector<std::string> res;
417     ExtractEachInfo(tempStack, res);
418 
419     // collect error info first
420     for (uint32_t i = 0; i < res.size(); i++) {
421         std::string temp = res[i];
422         uint32_t start = temp.find(openBrace);
423         uint32_t end  = temp.find(":");
424         std::string key = temp.substr(start + 1, end - start - 1);
425         auto closeBracePos = static_cast<int32_t>(temp.find(closeBrace));
426         auto openBracePos = static_cast<int32_t>(temp.find(openBrace));
427         std::string line;
428         std::string column;
429         GetPosInfo(temp, closeBracePos, line, column);
430         if (line.empty() || column.empty()) {
431             LOGI("the stack without line info");
432             break;
433         }
434         std::string sourceInfo;
435         auto iter = sourceMaps.find(key);
436         if (iter != sourceMaps.end()) {
437             sourceInfo = GetSourceInfo(line, column, iter->second, appMap, isAppPage, data, false);
438         }
439         if (sourceInfo.empty()) {
440             break;
441         }
442         temp.replace(openBracePos, closeBracePos - openBracePos + 1, sourceInfo);
443         replace(temp.begin(), temp.end(), '\\', '/');
444         ans = ans + temp + "\n";
445     }
446     if (ans.empty()) {
447         return tempStack;
448     }
449     return ans;
450 }
451 
ExtractEachInfo(const std::string & tempStack,std::vector<std::string> & res)452 void JsiBaseUtils::ExtractEachInfo(const std::string& tempStack, std::vector<std::string>& res)
453 {
454     std::string tempStr;
455     for (uint32_t i = 0; i < tempStack.length(); i++) {
456         if (tempStack[i] == '\n') {
457             res.push_back(tempStr);
458             tempStr = "";
459         } else {
460             tempStr += tempStack[i];
461         }
462     }
463     if (!tempStr.empty()) {
464         res.push_back(tempStr);
465     }
466 }
467 
GetPosInfo(const std::string & temp,int32_t start,std::string & line,std::string & column)468 void JsiBaseUtils::GetPosInfo(const std::string& temp, int32_t start, std::string& line, std::string& column)
469 {
470     // 0 for colum, 1 for row
471     int32_t flag = 0;
472     // find line, column
473     for (int32_t i = start - 1; i > 0; i--) {
474         if (temp[i] == ':') {
475             flag += 1;
476             continue;
477         }
478         if (flag == 0) {
479             column = temp[i] + column;
480         } else if (flag == 1) {
481             line = temp[i] + line;
482         } else {
483             break;
484         }
485     }
486 }
487 
GetSourceInfo(const std::string & line,const std::string & column,const RefPtr<RevSourceMap> & pageMap,const RefPtr<RevSourceMap> & appMap,bool isAppPage,const AceType * data,const bool isBundle)488 std::string JsiBaseUtils::GetSourceInfo(const std::string& line, const std::string& column,
489     const RefPtr<RevSourceMap>& pageMap, const RefPtr<RevSourceMap>& appMap, bool isAppPage, const AceType* data,
490     const bool isBundle)
491 {
492     int32_t offSet = GetLineOffset(data);
493     std::string sourceInfo;
494     MappingInfo mapInfo;
495     if (isAppPage) {
496         mapInfo = appMap->Find(StringToInt(line) - offSet, StringToInt(column));
497     } else {
498         mapInfo = pageMap->Find(StringToInt(line) - offSet, StringToInt(column));
499     }
500     if (mapInfo.row == 0 || mapInfo.col == 0) {
501         return "";
502     }
503 
504     std::string sources = isBundle ? GetRelativePath(mapInfo.sources) : mapInfo.sources;
505     sourceInfo = "(" + sources + ":" + std::to_string(mapInfo.row) + ":" + std::to_string(mapInfo.col) + ")";
506     return sourceInfo;
507 }
508 
GetRelativePath(const std::string & sources,std::string splitStr)509 std::string JsiBaseUtils::GetRelativePath(const std::string& sources, std::string splitStr)
510 {
511     std::string temp = sources;
512     std::size_t splitPos = std::string::npos;
513     const static int pathLevel = 3;
514     int i = 0;
515     while (i < pathLevel) {
516         splitPos = temp.find_last_of(splitStr);
517         if (splitPos != std::string::npos) {
518             temp = temp.substr(0, splitPos - 1);
519         } else {
520             break;
521         }
522         i++;
523     }
524     if (i == pathLevel) {
525         return sources.substr(splitPos);
526     }
527     LOGI("The stack path error!");
528     return sources;
529 }
530 
ReportJsErrorEvent(std::shared_ptr<JsValue> error,std::shared_ptr<JsRuntime> runtime)531 void JsiBaseUtils::ReportJsErrorEvent(std::shared_ptr<JsValue> error, std::shared_ptr<JsRuntime> runtime)
532 {
533     if (!runtime) {
534         LOGI("ReportJsErrorEvent: jsi engine has been destroyed");
535         return;
536     }
537 
538     LOGI("ReportJsErrorEvent");
539     auto arkJSRuntime = std::static_pointer_cast<ArkJSRuntime>(runtime);
540     if (arkJSRuntime && arkJSRuntime->GetErrorEventHandler()) {
541         std::string msg = GenerateErrorMsg(error, runtime);
542         LOGI("Handle error event, errMsg: \n%{public}s", msg.c_str());
543         arkJSRuntime->GetErrorEventHandler()(JS_CRASH_CODE, msg);
544         return;
545     }
546 
547     std::string summaryBody = GenerateSummaryBody(error, runtime);
548     LOGE("summaryBody: \n%{public}s", summaryBody.c_str());
549     EventReport::JsErrReport(AceApplicationInfo::GetInstance().GetPackageName(), "", summaryBody);
550 #if !defined(ANDROID_PLATFORM) && !defined(IOS_PLATFORM)
551     ExceptionHandler::HandleJsException(summaryBody);
552 #endif
553 }
554 
ParseLogContent(const std::vector<std::string> & params)555 std::string ParseLogContent(const std::vector<std::string>& params)
556 {
557     std::string ret;
558     int32_t flag = 0;
559     if (params.empty()) {
560         return ret;
561     }
562     std::string formatStr = params[0];
563     auto size = static_cast<int32_t>(params.size());
564     auto len = static_cast<int32_t>(formatStr.size());
565     int32_t pos = 0;
566     int32_t count = 1;
567     for (; pos < len; ++pos) {
568         if (count >= size) {
569             break;
570         }
571         if (formatStr[pos] == '%') {
572             flag = 1;
573             if (pos + 1 >= len) {
574                 break;
575             }
576             switch (formatStr[pos + 1]) {
577                 case 's':
578                 case 'j':
579                 case 'd':
580                 case 'O':
581                 case 'o':
582                 case 'i':
583                 case 'f':
584                 case 'c':
585                     ret += params[count++];
586                     ++pos;
587                     break;
588                 case '%':
589                     ret += formatStr[pos];
590                     ++pos;
591                     break;
592                 default:
593                     ret += formatStr[pos];
594                     break;
595             }
596         } else {
597             ret += formatStr[pos];
598         }
599     }
600     if (pos < len) {
601         ret += formatStr.substr(pos, len - pos);
602     }
603     switch (flag) {
604         case 0:
605             ret += " ";
606             for (int32_t i = 1; i < size; ++i) {
607                 ret += params[i];
608                 if (i != size - 1) {
609                     ret += " ";
610                 }
611             }
612             break;
613         case 1:
614             for (int32_t i = 2; i < size; ++i) {
615                 ret += params[i];
616             }
617             break;
618         default:
619             break;
620     }
621     return ret;
622 }
623 
GetLogContent(const shared_ptr<JsRuntime> & runtime,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)624 std::string GetLogContent(
625     const shared_ptr<JsRuntime>& runtime, const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
626 {
627     if (argc == 1) {
628         return argv[0]->ToString(runtime);
629     }
630     std::vector<std::string> params;
631     params.reserve(argc);
632     for (int32_t i = 0; i < argc; ++i) {
633         params.emplace_back(argv[i]->ToString(runtime));
634     }
635     return ParseLogContent(params);
636 }
637 
AppLogPrint(const shared_ptr<JsRuntime> & runtime,JsLogLevel level,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)638 shared_ptr<JsValue> AppLogPrint(
639     const shared_ptr<JsRuntime>& runtime, JsLogLevel level, const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
640 {
641     // Should have at least 1 parameters.
642     if (argc == 0) {
643         LOGE("the arg is error");
644         return runtime->NewUndefined();
645     }
646     std::string content = GetLogContent(runtime, argv, argc);
647     switch (level) {
648         case JsLogLevel::DEBUG:
649             APP_LOGD("app Log: %{public}s", content.c_str());
650             break;
651         case JsLogLevel::INFO:
652             APP_LOGI("app Log: %{public}s", content.c_str());
653             break;
654         case JsLogLevel::WARNING:
655             APP_LOGW("app Log: %{public}s", content.c_str());
656             break;
657         case JsLogLevel::ERROR:
658             APP_LOGE("app Log: %{public}s", content.c_str());
659             break;
660     }
661 
662     return runtime->NewUndefined();
663 }
664 
665 // native implementation for js function: console.debug()
AppDebugLogPrint(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & thisObj,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)666 shared_ptr<JsValue> JsiBaseUtils::AppDebugLogPrint(const shared_ptr<JsRuntime>& runtime,
667     const shared_ptr<JsValue>& thisObj, const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
668 {
669     return AppLogPrint(runtime, JsLogLevel::DEBUG, argv, argc);
670 }
671 
672 // native implementation for js function: console.info()
AppInfoLogPrint(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & thisObj,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)673 shared_ptr<JsValue> JsiBaseUtils::AppInfoLogPrint(const shared_ptr<JsRuntime>& runtime,
674     const shared_ptr<JsValue>& thisObj, const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
675 {
676     return AppLogPrint(runtime, JsLogLevel::INFO, argv, argc);
677 }
678 
679 // native implementation for js function: console.warn()
AppWarnLogPrint(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & thisObj,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)680 shared_ptr<JsValue> JsiBaseUtils::AppWarnLogPrint(const shared_ptr<JsRuntime>& runtime,
681     const shared_ptr<JsValue>& thisObj, const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
682 {
683     return AppLogPrint(runtime, JsLogLevel::WARNING, argv, argc);
684 }
685 
686 // native implementation for js function: console.error()
AppErrorLogPrint(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & thisObj,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)687 shared_ptr<JsValue> JsiBaseUtils::AppErrorLogPrint(const shared_ptr<JsRuntime>& runtime,
688     const shared_ptr<JsValue>& thisObj, const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
689 {
690     return AppLogPrint(runtime, JsLogLevel::ERROR, argv, argc);
691 }
692 
JsLogPrint(const shared_ptr<JsRuntime> & runtime,JsLogLevel level,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)693 shared_ptr<JsValue> JsLogPrint(
694     const shared_ptr<JsRuntime>& runtime, JsLogLevel level, const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
695 {
696     // Should have 1 parameters.
697     if (argc == 0) {
698         LOGE("the arg is error");
699         return runtime->NewUndefined();
700     }
701 
702     std::string content = GetLogContent(runtime, argv, argc);
703     switch (level) {
704         case JsLogLevel::DEBUG:
705             LOGD("ace Log: %{public}s", content.c_str());
706             break;
707         case JsLogLevel::INFO:
708             LOGI("ace Log: %{public}s", content.c_str());
709             break;
710         case JsLogLevel::WARNING:
711             LOGW("ace Log: %{public}s", content.c_str());
712             break;
713         case JsLogLevel::ERROR:
714             LOGE("ace Log: %{public}s", content.c_str());
715             break;
716     }
717 
718     shared_ptr<JsValue> ret = runtime->NewUndefined();
719     return ret;
720 }
721 
PrintLog(int id,int level,const char * tag,const char * fmt,const char * message)722 int PrintLog(int id, int level, const char* tag, const char* fmt, const char* message)
723 {
724     switch (JsLogLevel(level - 3)) {
725         case JsLogLevel::INFO:
726             LOGI("%{public}s::%{public}s", tag, message);
727             break;
728         case JsLogLevel::WARNING:
729             LOGW("%{public}s::%{public}s", tag, message);
730             break;
731         case JsLogLevel::ERROR:
732             LOGE("%{public}s::%{public}s", tag, message);
733             break;
734         case JsLogLevel::DEBUG:
735             LOGD("%{public}s::%{public}s", tag, message);
736             break;
737         default:
738             LOGF("%{public}s::%{public}s", tag, message);
739             break;
740     }
741     return 0;
742 }
743 
JsDebugLogPrint(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & thisObj,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)744 shared_ptr<JsValue> JsiBaseUtils::JsDebugLogPrint(const shared_ptr<JsRuntime>& runtime,
745     const shared_ptr<JsValue>& thisObj, const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
746 {
747     return JsLogPrint(runtime, JsLogLevel::DEBUG, argv, argc);
748 }
749 
JsInfoLogPrint(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & thisObj,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)750 shared_ptr<JsValue> JsiBaseUtils::JsInfoLogPrint(const shared_ptr<JsRuntime>& runtime,
751     const shared_ptr<JsValue>& thisObj, const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
752 {
753     return JsLogPrint(runtime, JsLogLevel::INFO, argv, argc);
754 }
755 
JsWarnLogPrint(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & thisObj,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)756 shared_ptr<JsValue> JsiBaseUtils::JsWarnLogPrint(const shared_ptr<JsRuntime>& runtime,
757     const shared_ptr<JsValue>& thisObj, const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
758 {
759     return JsLogPrint(runtime, JsLogLevel::WARNING, argv, argc);
760 }
761 
JsErrorLogPrint(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & thisObj,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)762 shared_ptr<JsValue> JsiBaseUtils::JsErrorLogPrint(const shared_ptr<JsRuntime>& runtime,
763     const shared_ptr<JsValue>& thisObj, const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
764 {
765     return JsLogPrint(runtime, JsLogLevel::ERROR, argv, argc);
766 }
767 
768 std::unique_ptr<AceScopedTrace> JsiBaseUtils::aceScopedTrace_ = nullptr;
769 
JsTraceBegin(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & thisObj,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)770 shared_ptr<JsValue> JsiBaseUtils::JsTraceBegin(const shared_ptr<JsRuntime>& runtime,
771     const shared_ptr<JsValue>& thisObj, const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
772 {
773     if (SystemProperties::GetDebugEnabled()) {
774         std::string traceName = GetLogContent(runtime, argv, argc);
775         aceScopedTrace_ = std::make_unique<AceScopedTrace>(traceName.c_str());
776     }
777     return runtime->NewUndefined();
778 }
779 
JsTraceEnd(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & thisObj,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)780 shared_ptr<JsValue> JsiBaseUtils::JsTraceEnd(const shared_ptr<JsRuntime>& runtime,
781     const shared_ptr<JsValue>& thisObj, const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
782 {
783     if (SystemProperties::GetDebugEnabled()) {
784         aceScopedTrace_.reset();
785     }
786     return runtime->NewUndefined();
787 }
788 
GetLogContent(NativeEngine * nativeEngine,NativeCallbackInfo * info)789 std::string GetLogContent(NativeEngine* nativeEngine, NativeCallbackInfo* info)
790 {
791     std::string content;
792     for (size_t i = 0; i < info->argc; ++i) {
793         if (info->argv[i]->TypeOf() != NATIVE_STRING) {
794             LOGE("argv is not NativeString");
795             continue;
796         }
797         auto nativeString = reinterpret_cast<NativeString*>(info->argv[i]->GetInterface(NativeString::INTERFACE_ID));
798         size_t bufferSize = nativeString->GetLength();
799         size_t strLength = 0;
800         char* buffer = new char[bufferSize + 1] { 0 };
801         nativeString->GetCString(buffer, bufferSize + 1, &strLength);
802         content.append(buffer);
803         delete[] buffer;
804     }
805     return content;
806 }
807 
AppLogPrint(NativeEngine * nativeEngine,NativeCallbackInfo * info,JsLogLevel level)808 NativeValue* AppLogPrint(NativeEngine* nativeEngine, NativeCallbackInfo* info, JsLogLevel level)
809 {
810     // Should have at least 1 parameters.
811     if (info->argc == 0) {
812         LOGE("the arg is error");
813         return nativeEngine->CreateUndefined();
814     }
815     std::string content = GetLogContent(nativeEngine, info);
816     switch (level) {
817         case JsLogLevel::DEBUG:
818             APP_LOGD("app Log: %{public}s", content.c_str());
819             break;
820         case JsLogLevel::INFO:
821             APP_LOGI("app Log: %{public}s", content.c_str());
822             break;
823         case JsLogLevel::WARNING:
824             APP_LOGW("app Log: %{public}s", content.c_str());
825             break;
826         case JsLogLevel::ERROR:
827             APP_LOGE("app Log: %{public}s", content.c_str());
828             break;
829     }
830 
831     return nativeEngine->CreateUndefined();
832 }
833 
AppDebugLogPrint(NativeEngine * nativeEngine,NativeCallbackInfo * info)834 NativeValue* AppDebugLogPrint(NativeEngine* nativeEngine, NativeCallbackInfo* info)
835 {
836     return AppLogPrint(nativeEngine, info, JsLogLevel::DEBUG);
837 }
838 
AppInfoLogPrint(NativeEngine * nativeEngine,NativeCallbackInfo * info)839 NativeValue* AppInfoLogPrint(NativeEngine* nativeEngine, NativeCallbackInfo* info)
840 {
841     return AppLogPrint(nativeEngine, info, JsLogLevel::INFO);
842 }
843 
AppWarnLogPrint(NativeEngine * nativeEngine,NativeCallbackInfo * info)844 NativeValue* AppWarnLogPrint(NativeEngine* nativeEngine, NativeCallbackInfo* info)
845 {
846     return AppLogPrint(nativeEngine, info, JsLogLevel::WARNING);
847 }
848 
AppErrorLogPrint(NativeEngine * nativeEngine,NativeCallbackInfo * info)849 NativeValue* AppErrorLogPrint(NativeEngine* nativeEngine, NativeCallbackInfo* info)
850 {
851     return AppLogPrint(nativeEngine, info, JsLogLevel::ERROR);
852 }
853 
GetStageSourceMap(const AceType * data,std::unordered_map<std::string,RefPtr<Framework::RevSourceMap>> & sourceMaps)854 void JsiBaseUtils::GetStageSourceMap(const AceType *data,
855     std::unordered_map<std::string, RefPtr<Framework::RevSourceMap>>& sourceMaps)
856 {
857     auto delegate = GetDelegate(data);
858     std::string maps;
859     if (delegate != nullptr &&
860         delegate->GetAssetContent(MERGE_SOURCEMAPS_PATH, maps)) {
861         auto SourceMap = AceType::MakeRefPtr<RevSourceMap>();
862         SourceMap->StageModeSourceMapSplit(maps, sourceMaps);
863     } else {
864         LOGW("GetRunningPage SourceMap load failed!");
865     }
866 }
867 } // namespace OHOS::Ace::Framework
868