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