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