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
16 #include "napi_observer.h"
17
18 #include "dataproxy_handle_common.h"
19 #include "datashare_js_utils.h"
20 #include "datashare_log.h"
21
22 namespace OHOS {
23 namespace DataShare {
NapiObserver(napi_env env,napi_value callback)24 NapiObserver::NapiObserver(napi_env env, napi_value callback) : env_(env)
25 {
26 envMutexPtr_ = std::make_unique<std::mutex>();
27 napi_create_reference(env, callback, 1, &ref_);
28 napi_get_uv_event_loop(env, &loop_);
29 }
30
CallbackFunc(ObserverWorker * observerWorker)31 void NapiObserver::CallbackFunc(ObserverWorker *observerWorker)
32 {
33 LOG_DEBUG("ObsCallbackFunc start");
34 std::shared_ptr<NapiObserver> observer = observerWorker->observer_.lock();
35 if (observer == nullptr || observer->ref_ == nullptr || observer->envMutexPtr_ == nullptr) {
36 LOG_ERROR("rdbObserver->ref_ is nullptr");
37 delete observerWorker;
38 return;
39 }
40 std::lock_guard<std::mutex> lck(*observer->envMutexPtr_);
41 if (observer->env_ == nullptr) {
42 LOG_ERROR("rdbObserver->env_ is nullptr");
43 delete observerWorker;
44 return;
45 }
46 napi_handle_scope scope = nullptr;
47 napi_open_handle_scope(observer->env_, &scope);
48 if (scope == nullptr) {
49 LOG_ERROR("scope is nullptr");
50 delete observerWorker;
51 return;
52 }
53 napi_value callback = nullptr;
54 napi_value param[2];
55 napi_value global = nullptr;
56 napi_value result;
57 napi_get_reference_value(observer->env_, observer->ref_, &callback);
58 napi_get_global(observer->env_, &global);
59 napi_get_undefined(observer->env_, ¶m[0]);
60 param[1] = observerWorker->getParam(observer->env_);
61 napi_status callStatus = napi_call_function(observer->env_, global, callback, 2, param, &result);
62 napi_close_handle_scope(observer->env_, scope);
63 if (callStatus != napi_ok) {
64 LOG_ERROR("napi_call_function failed status : %{public}d", callStatus);
65 }
66 LOG_DEBUG("napi_call_function succeed status : %{public}d", callStatus);
67 delete observerWorker;
68 }
69
~NapiObserver()70 NapiObserver::~NapiObserver()
71 {
72 if (env_ == nullptr) {
73 LOG_ERROR("env_ is nullptr");
74 return;
75 }
76
77 if (ref_ != nullptr) {
78 auto task = [env = env_, ref = ref_, observerEnvHookWorker = observerEnvHookWorker_]() {
79 napi_delete_reference(env, ref);
80 napi_remove_env_cleanup_hook(env, &CleanEnv, observerEnvHookWorker);
81 };
82 int ret = napi_send_event(env_, task, napi_eprio_immediate);
83 if (ret != 0) {
84 LOG_ERROR("napi_send_event failed: %{public}d", ret);
85 }
86 ref_ = nullptr;
87 }
88 if (observerEnvHookWorker_ != nullptr) {
89 delete observerEnvHookWorker_;
90 observerEnvHookWorker_ = nullptr;
91 }
92 }
93
operator ==(const NapiObserver & rhs) const94 bool NapiObserver::operator==(const NapiObserver &rhs) const
95 {
96 if (ref_ == nullptr) {
97 return (rhs.ref_ == nullptr);
98 }
99
100 napi_value value1 = nullptr;
101 napi_get_reference_value(env_, ref_, &value1);
102
103 napi_value value2 = nullptr;
104 napi_get_reference_value(env_, rhs.ref_, &value2);
105
106 bool isEqual = false;
107 napi_strict_equals(env_, value1, value2, &isEqual);
108 return isEqual;
109 }
110
operator !=(const NapiObserver & rhs) const111 bool NapiObserver::operator!=(const NapiObserver &rhs) const
112 {
113 return !(rhs == *this);
114 }
115
RegisterEnvCleanHook()116 void NapiObserver::RegisterEnvCleanHook()
117 {
118 observerEnvHookWorker_ = new (std::nothrow) ObserverEnvHookWorker(shared_from_this());
119 if (observerEnvHookWorker_ == nullptr) {
120 LOG_ERROR("Failed to create observerEnvHookWorker_");
121 return;
122 }
123 napi_add_env_cleanup_hook(env_, &CleanEnv, observerEnvHookWorker_);
124 }
125
CleanEnv(void * obj)126 void NapiObserver::CleanEnv(void *obj)
127 {
128 LOG_INFO("Napi env cleanup hook is executed, env is about to exit");
129 auto observerEnvHookWorker = reinterpret_cast<ObserverEnvHookWorker *>(obj);
130 // Prevent concurrency with NAPIInnerObserver destructors
131 auto observer = observerEnvHookWorker->observer_.lock();
132 if (observer == nullptr || observer->envMutexPtr_ == nullptr) {
133 LOG_ERROR("observer or observer->envMutexPtr_ is nullptr");
134 delete observerEnvHookWorker;
135 return;
136 }
137 std::lock_guard<std::mutex> lck(*observer->envMutexPtr_);
138 if (observer->ref_ != nullptr) {
139 napi_delete_reference(observer->env_, observer->ref_);
140 observer->ref_ = nullptr;
141 }
142 observer->env_ = nullptr;
143 }
144
OnChange(const RdbChangeNode & changeNode)145 void NapiRdbObserver::OnChange(const RdbChangeNode &changeNode)
146 {
147 LOG_DEBUG("NapiRdbObserver onchange Start");
148 if (ref_ == nullptr || envMutexPtr_ == nullptr) {
149 LOG_ERROR("ref_ or envMutexPtr_ is nullptr");
150 return;
151 }
152 std::lock_guard<std::mutex> lck(*envMutexPtr_);
153 if (env_ == nullptr) {
154 LOG_ERROR("env_ is nullptr");
155 return;
156 }
157 ObserverWorker *observerWorker = new (std::nothrow) ObserverWorker(shared_from_this());
158 if (observerWorker == nullptr) {
159 LOG_ERROR("Failed to create observerWorker");
160 return;
161 }
162 observerWorker->getParam = [changeNode](napi_env env) {
163 return DataShareJSUtils::Convert2JSValue(env, changeNode);
164 };
165
166 auto task = [observerWorker]() {
167 NapiObserver::CallbackFunc(observerWorker);
168 };
169 int ret = napi_send_event(env_, task, napi_eprio_immediate);
170 if (ret != 0) {
171 LOG_ERROR("napi_send_event failed: %{public}d", ret);
172 delete observerWorker;
173 }
174 LOG_DEBUG("NapiRdbObserver onchange End: %{public}d", ret);
175 }
176
OnChange(PublishedDataChangeNode & changeNode)177 void NapiPublishedObserver::OnChange(PublishedDataChangeNode &changeNode)
178 {
179 LOG_DEBUG("NapiPublishedObserver onchange Start");
180 if (ref_ == nullptr || envMutexPtr_ == nullptr) {
181 LOG_ERROR("ref_ or envMutexPtr_ is nullptr");
182 return;
183 }
184 std::lock_guard<std::mutex> lck(*envMutexPtr_);
185 if (env_ == nullptr) {
186 LOG_ERROR("env_ is nullptr");
187 return;
188 }
189 ObserverWorker *observerWorker = new (std::nothrow) ObserverWorker(shared_from_this());
190 if (observerWorker == nullptr) {
191 LOG_ERROR("Failed to create observerWorker");
192 return;
193 }
194 std::shared_ptr<PublishedDataChangeNode> node = std::make_shared<PublishedDataChangeNode>(std::move(changeNode));
195 observerWorker->getParam = [node](napi_env env) {
196 return DataShareJSUtils::Convert2JSValue(env, *node);
197 };
198
199 auto task = [observerWorker]() {
200 NapiObserver::CallbackFunc(observerWorker);
201 };
202 int ret = napi_send_event(env_, task, napi_eprio_immediate);
203 if (ret != 0) {
204 LOG_ERROR("napi_send_event failed: %{public}d", ret);
205 delete observerWorker;
206 }
207 LOG_DEBUG("NapiRdbObserver onchange End: %{public}d", ret);
208 }
209
OnChange(const std::vector<DataProxyChangeInfo> & changeNode)210 void NapiProxyDataObserver::OnChange(const std::vector<DataProxyChangeInfo> &changeNode)
211 {
212 LOG_INFO("NapiProxyDataObserver onchange Start");
213 if (ref_ == nullptr || envMutexPtr_ == nullptr) {
214 LOG_ERROR("ref_ or envMutexPtr_ is nullptr");
215 return;
216 }
217 std::lock_guard<std::mutex> lck(*envMutexPtr_);
218 if (env_ == nullptr) {
219 LOG_ERROR("env_ is nullptr");
220 return;
221 }
222 ObserverWorker *observerWorker = new (std::nothrow) ObserverWorker(shared_from_this());
223 if (observerWorker == nullptr) {
224 LOG_ERROR("Failed to create observerWorker");
225 return;
226 }
227 std::shared_ptr<std::vector<DataProxyChangeInfo>> node =
228 std::make_shared<std::vector<DataProxyChangeInfo>>(std::move(changeNode));
229 observerWorker->getParam = [node](napi_env env) {
230 return DataShareJSUtils::Convert2JSValue(env, *node);
231 };
232
233 auto task = [observerWorker]() {
234 NapiObserver::CallbackFunc(observerWorker);
235 };
236 int ret = napi_send_event(env_, task, napi_eprio_immediate);
237 if (ret != 0) {
238 LOG_ERROR("napi_send_event failed: %{public}d", ret);
239 delete observerWorker;
240 }
241 LOG_INFO("NapiProxyDataObserver onchange End: %{public}d", ret);
242 }
243 } // namespace DataShare
244 } // namespace OHOS
245