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