1 /*
2  * Copyright (c) 2022-2024 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 "js_error_observer.h"
17 
18 #include <cstdint>
19 
20 #include "hilog_tag_wrapper.h"
21 #include "js_runtime.h"
22 #include "js_runtime_utils.h"
23 #include "napi/native_api.h"
24 
25 namespace OHOS {
26 namespace AbilityRuntime {
27 constexpr size_t ARGC_ONE = 1;
JsErrorObserver(napi_env env)28 JsErrorObserver::JsErrorObserver(napi_env env) : env_(env) {}
29 
30 JsErrorObserver::~JsErrorObserver() = default;
31 
OnUnhandledException(const std::string errMsg)32 void JsErrorObserver::OnUnhandledException(const std::string errMsg)
33 {
34     TAG_LOGD(AAFwkTag::JSNAPI, "called");
35     std::weak_ptr<JsErrorObserver> thisWeakPtr(shared_from_this());
36     std::shared_ptr<JsErrorObserver> jsObserver = thisWeakPtr.lock();
37     if (jsObserver) {
38         jsObserver->HandleOnUnhandledException(errMsg);
39     }
40 }
41 
HandleOnUnhandledException(const std::string & errMsg)42 void JsErrorObserver::HandleOnUnhandledException(const std::string &errMsg)
43 {
44     TAG_LOGD(AAFwkTag::JSNAPI, "called");
45     auto tmpMap = jsObserverObjectMap_;
46     for (auto &item : tmpMap) {
47         napi_value value = (item.second)->GetNapiValue();
48         napi_value argv[] = { CreateJsValue(env_, errMsg) };
49         CallJsFunction(value, "onUnhandledException", argv, ARGC_ONE);
50     }
51     tmpMap = jsObserverObjectMapSync_;
52     for (auto &item : tmpMap) {
53         napi_value value = (item.second)->GetNapiValue();
54         napi_value argv[] = { CreateJsValue(env_, errMsg) };
55         CallJsFunction(value, "onUnhandledException", argv, ARGC_ONE);
56     }
57 }
58 
CallJsFunction(napi_value obj,const char * methodName,napi_value const * argv,size_t argc)59 void JsErrorObserver::CallJsFunction(napi_value obj, const char* methodName, napi_value const* argv, size_t argc)
60 {
61     TAG_LOGD(AAFwkTag::JSNAPI, "call method:%{public}s", methodName);
62     if (obj == nullptr) {
63         TAG_LOGE(AAFwkTag::JSNAPI, "null obj");
64         return;
65     }
66 
67     napi_value method = nullptr;
68     napi_get_named_property(env_, obj, methodName, &method);
69     if (method == nullptr) {
70         TAG_LOGE(AAFwkTag::JSNAPI, "null method");
71         return;
72     }
73     napi_value callResult = nullptr;
74     napi_call_function(env_, obj, method, argc, argv, &callResult);
75 }
76 
AddJsObserverObject(const int32_t observerId,napi_value jsObserverObject,bool isSync)77 void JsErrorObserver::AddJsObserverObject(const int32_t observerId, napi_value jsObserverObject, bool isSync)
78 {
79     napi_ref ref = nullptr;
80     napi_create_reference(env_, jsObserverObject, 1, &ref);
81     if (isSync) {
82         jsObserverObjectMapSync_.emplace(
83             observerId, std::shared_ptr<NativeReference>(reinterpret_cast<NativeReference*>(ref)));
84     } else {
85         jsObserverObjectMap_.emplace(
86             observerId, std::shared_ptr<NativeReference>(reinterpret_cast<NativeReference*>(ref)));
87     }
88 }
89 
RemoveJsObserverObject(const int32_t observerId,bool isSync)90 bool JsErrorObserver::RemoveJsObserverObject(const int32_t observerId, bool isSync)
91 {
92     bool result = false;
93     if (isSync) {
94         result = (jsObserverObjectMapSync_.erase(observerId) == 1);
95     } else {
96         result = (jsObserverObjectMap_.erase(observerId) == 1);
97     }
98     return result;
99 }
100 
IsEmpty()101 bool JsErrorObserver::IsEmpty()
102 {
103     bool isEmpty = jsObserverObjectMap_.empty() && jsObserverObjectMapSync_.empty();
104     return isEmpty;
105 }
106 
OnExceptionObject(const AppExecFwk::ErrorObject & errorObj)107 void JsErrorObserver::OnExceptionObject(const AppExecFwk::ErrorObject &errorObj)
108 {
109     TAG_LOGD(AAFwkTag::JSNAPI, "called");
110     std::weak_ptr<JsErrorObserver> thisWeakPtr(shared_from_this());
111     std::shared_ptr<JsErrorObserver> jsObserver = thisWeakPtr.lock();
112     if (jsObserver) {
113         jsObserver->HandleException(errorObj);
114     }
115 }
116 
HandleException(const AppExecFwk::ErrorObject & errorObj)117 void JsErrorObserver::HandleException(const AppExecFwk::ErrorObject &errorObj)
118 {
119     TAG_LOGD(AAFwkTag::JSNAPI, "called");
120     auto tmpMap = jsObserverObjectMap_;
121     for (auto &item : tmpMap) {
122         napi_value jsObj = (item.second)->GetNapiValue();
123         napi_value jsValue[] = { CreateJsErrorObject(env_, errorObj) };
124         CallJsFunction(jsObj, "onException", jsValue, ARGC_ONE);
125     }
126     tmpMap = jsObserverObjectMapSync_;
127     for (auto &item : tmpMap) {
128         napi_value jsObj = (item.second)->GetNapiValue();
129         napi_value jsValue[] = { CreateJsErrorObject(env_, errorObj) };
130         CallJsFunction(jsObj, "onException", jsValue, ARGC_ONE);
131     }
132 }
133 
CreateJsErrorObject(napi_env env,const AppExecFwk::ErrorObject & errorObj)134 napi_value JsErrorObserver::CreateJsErrorObject(napi_env env, const AppExecFwk::ErrorObject &errorObj)
135 {
136     napi_value objValue = nullptr;
137     napi_create_object(env, &objValue);
138     if (objValue == nullptr) {
139         TAG_LOGW(AAFwkTag::JSNAPI, "null obj");
140         return objValue;
141     }
142     napi_set_named_property(env, objValue, "name", CreateJsValue(env, errorObj.name));
143     napi_set_named_property(env, objValue, "message", CreateJsValue(env, errorObj.message));
144     if (!errorObj.stack.empty()) {
145         napi_set_named_property(env, objValue, "stack", CreateJsValue(env, errorObj.stack));
146     }
147 
148     return objValue;
149 }
150 }  // namespace AbilityRuntime
151 }  // namespace OHOS
152