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