1 /*
2 * Copyright (c) 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 #include "uncaught_exception_callback.h"
16
17 #include <string>
18 #include <sstream>
19
20 #include "hilog_tag_wrapper.h"
21 #include "native_engine/native_engine.h"
22 #include "ui_content.h"
23 #include "unwinder.h"
24
25 namespace OHOS {
26 namespace JsEnv {
27 constexpr char BACKTRACE[] = "=====================Backtrace========================";
28
GetNativeStrFromJsTaggedObj(napi_value obj,const char * key)29 std::string NapiUncaughtExceptionCallback::GetNativeStrFromJsTaggedObj(napi_value obj, const char* key)
30 {
31 if (obj == nullptr) {
32 TAG_LOGE(AAFwkTag::JSENV, "Failed to get value from key");
33 return "";
34 }
35
36 napi_value valueStr = nullptr;
37 napi_get_named_property(env_, obj, key, &valueStr);
38 napi_valuetype valueType = napi_undefined;
39 napi_typeof(env_, valueStr, &valueType);
40 if (valueType != napi_string) {
41 TAG_LOGD(AAFwkTag::JSENV, "Failed to convert value from key");
42 return "";
43 }
44
45 size_t valueStrBufLength = 0;
46 napi_get_value_string_utf8(env_, valueStr, nullptr, 0, &valueStrBufLength);
47 auto valueCStr = std::make_unique<char[]>(valueStrBufLength + 1);
48 size_t valueStrLength = 0;
49 napi_get_value_string_utf8(env_, valueStr, valueCStr.get(), valueStrBufLength + 1, &valueStrLength);
50 std::string ret(valueCStr.get(), valueStrLength);
51 TAG_LOGD(AAFwkTag::JSENV, "GetNativeStrFromJsTaggedObj Success");
52 return ret;
53 }
54
operator ()(napi_value obj)55 void NapiUncaughtExceptionCallback::operator()(napi_value obj)
56 {
57 std::string errorMsg = GetNativeStrFromJsTaggedObj(obj, "message");
58 std::string errorName = GetNativeStrFromJsTaggedObj(obj, "name");
59 std::string errorStack = GetNativeStrFromJsTaggedObj(obj, "stack");
60 std::string topStack = GetNativeStrFromJsTaggedObj(obj, "topstack");
61 std::string summary = "Error name:" + errorName + "\n";
62 summary += "Error message:" + errorMsg + "\n";
63 const JsEnv::ErrorObject errorObj = {
64 .name = errorName,
65 .message = errorMsg,
66 .stack = errorStack
67 };
68 bool hasProperty = false;
69 napi_has_named_property(env_, obj, "code", &hasProperty);
70 if (hasProperty) {
71 std::string errorCode = GetNativeStrFromJsTaggedObj(obj, "code");
72 summary += "Error code:" + errorCode + "\n";
73 }
74 if (errorStack.empty()) {
75 TAG_LOGE(AAFwkTag::JSENV, "errorStack is empty");
76 return;
77 }
78 auto errorPos = SourceMap::GetErrorPos(topStack);
79 std::string error;
80 if (obj != nullptr) {
81 napi_value fuc = nullptr;
82 napi_get_named_property(env_, obj, "errorfunc", &fuc);
83 napi_valuetype valueType = napi_undefined;
84 napi_typeof(env_, fuc, &valueType);
85 if (valueType == napi_function) {
86 error = reinterpret_cast<NativeEngine*>(env_)->GetSourceCodeInfo(fuc, errorPos);
87 }
88 }
89 if (errorStack.find(BACKTRACE) != std::string::npos) {
90 summary += error + "Stacktrace:\n" + GetBuildId(errorStack);
91 } else {
92 summary += error + "Stacktrace:\n" + errorStack;
93 }
94 std::string str = Ace::UIContent::GetCurrentUIStackInfo();
95 if (!str.empty()) {
96 summary.append(str);
97 }
98 if (uncaughtTask_) {
99 uncaughtTask_(summary, errorObj);
100 }
101 }
102
GetBuildId(std::string nativeStack)103 std::string NapiUncaughtExceptionCallback::GetBuildId(std::string nativeStack)
104 {
105 std::stringstream ss(nativeStack);
106 std::string tempStr;
107 std::string addBuildId;
108 int i = 0;
109 while (std::getline(ss, tempStr)) {
110 auto spitlPos = tempStr.rfind(" ");
111 if (spitlPos != std::string::npos) {
112 auto elfFile = std::make_shared<HiviewDFX::DfxElf>(tempStr.substr(spitlPos + 1));
113 std::string buildId = elfFile->GetBuildId();
114 if (i != 0 && !buildId.empty()) {
115 addBuildId += tempStr + "(" + buildId + ")" + "\n";
116 } else {
117 addBuildId += tempStr + "\n";
118 }
119 }
120 i++;
121 }
122 return addBuildId;
123 }
124 } // namespace JsEnv
125 } // namespace OHOS
126