• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_, &param[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