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