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