1 /*
2 * Copyright (C) 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 #include "locating_required_data_callback_napi.h"
16
17 #include "ipc_skeleton.h"
18 #include "napi/native_common.h"
19
20 #include "common_utils.h"
21 #include "location_log.h"
22 #include "napi_util.h"
23
24 namespace OHOS {
25 namespace Location {
26 static std::mutex g_regCallbackMutex;
27 static std::vector<napi_ref> g_registerCallbacks;
LocatingRequiredDataCallbackNapi()28 LocatingRequiredDataCallbackNapi::LocatingRequiredDataCallbackNapi()
29 {
30 env_ = nullptr;
31 handlerCb_ = nullptr;
32 remoteDied_ = false;
33 fixNumber_ = 0;
34 InitLatch();
35 }
36
~LocatingRequiredDataCallbackNapi()37 LocatingRequiredDataCallbackNapi::~LocatingRequiredDataCallbackNapi()
38 {
39 if (latch_ != nullptr) {
40 delete latch_;
41 latch_ = nullptr;
42 }
43 LBSLOGW(LOCATING_DATA_CALLBACK, "~LocatingRequiredDataCallbackNapi()");
44 }
45
InitLatch()46 void LocatingRequiredDataCallbackNapi::InitLatch()
47 {
48 latch_ = new CountDownLatch();
49 latch_->SetCount(1);
50 }
51
OnRemoteRequest(uint32_t code,MessageParcel & data,MessageParcel & reply,MessageOption & option)52 int LocatingRequiredDataCallbackNapi::OnRemoteRequest(
53 uint32_t code, MessageParcel& data, MessageParcel& reply, MessageOption& option)
54 {
55 LBSLOGD(LOCATING_DATA_CALLBACK, "LocatingRequiredDataCallbackNapi::OnRemoteRequest!");
56 if (data.ReadInterfaceToken() != GetDescriptor()) {
57 LBSLOGE(LOCATING_DATA_CALLBACK, "invalid token.");
58 return -1;
59 }
60 if (remoteDied_) {
61 LBSLOGD(LOCATING_DATA_CALLBACK, "Failed to `%{public}s`,Remote service is died!", __func__);
62 return -1;
63 }
64
65 switch (code) {
66 case RECEIVE_INFO_EVENT: {
67 int cnt = data.ReadInt32();
68 if (cnt >= 0 && cnt <= MAXIMUM_LOCATING_REQUIRED_DATAS) {
69 std::vector<std::shared_ptr<LocatingRequiredData>> res;
70 for (int i = 0; cnt > 0 && i < cnt; i++) {
71 res.push_back(LocatingRequiredData::Unmarshalling(data));
72 }
73 // update wifi info
74 if (res.size() > 0 && res[0]->GetType() == LocatingRequiredDataType::WIFI) {
75 SetSingleResult(res);
76 }
77 OnLocatingDataChange(res);
78 CountDown();
79 }
80 break;
81 }
82 default: {
83 IPCObjectStub::OnRemoteRequest(code, data, reply, option);
84 break;
85 }
86 }
87 return 0;
88 }
89
GetEnv()90 napi_env LocatingRequiredDataCallbackNapi::GetEnv()
91 {
92 std::unique_lock<std::mutex> guard(mutex_);
93 return env_;
94 }
95
SetEnv(const napi_env & env)96 void LocatingRequiredDataCallbackNapi::SetEnv(const napi_env& env)
97 {
98 std::unique_lock<std::mutex> guard(mutex_);
99 env_ = env;
100 }
101
GetHandleCb()102 napi_ref LocatingRequiredDataCallbackNapi::GetHandleCb()
103 {
104 std::unique_lock<std::mutex> guard(mutex_);
105 return handlerCb_;
106 }
107
SetHandleCb(const napi_ref & handlerCb)108 void LocatingRequiredDataCallbackNapi::SetHandleCb(const napi_ref& handlerCb)
109 {
110 {
111 std::unique_lock<std::mutex> guard(mutex_);
112 handlerCb_ = handlerCb;
113 }
114 std::unique_lock<std::mutex> guard(g_regCallbackMutex);
115 g_registerCallbacks.emplace_back(handlerCb);
116 }
117
FindRequiredDataCallback(napi_ref cb)118 bool FindRequiredDataCallback(napi_ref cb)
119 {
120 std::unique_lock<std::mutex> guard(g_regCallbackMutex);
121 auto iter = std::find(g_registerCallbacks.begin(), g_registerCallbacks.end(), cb);
122 if (iter == g_registerCallbacks.end()) {
123 return false;
124 }
125 return true;
126 }
127
DeleteRequiredDataCallback(napi_ref cb)128 void DeleteRequiredDataCallback(napi_ref cb)
129 {
130 std::unique_lock<std::mutex> guard(g_regCallbackMutex);
131 for (auto iter = g_registerCallbacks.begin(); iter != g_registerCallbacks.end(); iter++) {
132 if (*iter == cb) {
133 iter = g_registerCallbacks.erase(iter);
134 break;
135 }
136 }
137 LBSLOGW(LOCATING_DATA_CALLBACK, "after DeleteRequiredDataCallback, callback size %{public}s",
138 std::to_string(g_registerCallbacks.size()).c_str());
139 }
140
IsRemoteDied()141 bool LocatingRequiredDataCallbackNapi::IsRemoteDied()
142 {
143 return remoteDied_;
144 }
145
Send(const std::vector<std::shared_ptr<LocatingRequiredData>> & data)146 bool LocatingRequiredDataCallbackNapi::Send(const std::vector<std::shared_ptr<LocatingRequiredData>>& data)
147 {
148 if (IsSingleLocationRequest()) {
149 return false;
150 }
151 std::unique_lock<std::mutex> guard(mutex_);
152 uv_loop_s *loop = nullptr;
153 NAPI_CALL_BASE(env_, napi_get_uv_event_loop(env_, &loop), false);
154 if (loop == nullptr) {
155 LBSLOGE(LOCATING_DATA_CALLBACK, "loop == nullptr.");
156 return false;
157 }
158 if (handlerCb_ == nullptr) {
159 LBSLOGE(LOCATING_DATA_CALLBACK, "handler is nullptr.");
160 return false;
161 }
162 uv_work_t *work = new (std::nothrow) uv_work_t;
163 if (work == nullptr) {
164 LBSLOGE(LOCATING_DATA_CALLBACK, "work == nullptr.");
165 return false;
166 }
167 LocatingRequiredDataAsyncContext *context = new (std::nothrow) LocatingRequiredDataAsyncContext(env_);
168 if (context == nullptr) {
169 LBSLOGE(LOCATING_DATA_CALLBACK, "context == nullptr.");
170 delete work;
171 return false;
172 }
173 if (!InitContext(context)) {
174 LBSLOGE(LOCATING_DATA_CALLBACK, "InitContext fail");
175 delete work;
176 delete context;
177 return false;
178 }
179 context->locatingRequiredDataList_ = data;
180 work->data = context;
181 UvQueueWork(loop, work);
182 return true;
183 }
184
UvQueueWork(uv_loop_s * loop,uv_work_t * work)185 void LocatingRequiredDataCallbackNapi::UvQueueWork(uv_loop_s* loop, uv_work_t* work)
186 {
187 uv_queue_work(
188 loop,
189 work,
190 [](uv_work_t *work) {},
191 [](uv_work_t *work, int status) {
192 LocatingRequiredDataAsyncContext *context = nullptr;
193 napi_handle_scope scope = nullptr;
194 if (work == nullptr) {
195 LBSLOGE(LOCATING_DATA_CALLBACK, "work is nullptr");
196 return;
197 }
198 context = static_cast<LocatingRequiredDataAsyncContext *>(work->data);
199 if (context == nullptr || context->env == nullptr) {
200 LBSLOGE(LOCATING_DATA_CALLBACK, "context is nullptr");
201 delete work;
202 return;
203 }
204 NAPI_CALL_RETURN_VOID(context->env, napi_open_handle_scope(context->env, &scope));
205 if (scope == nullptr) {
206 LBSLOGE(LOCATING_DATA_CALLBACK, "scope is nullptr");
207 delete context;
208 delete work;
209 return;
210 }
211 napi_value jsEvent = nullptr;
212 CHK_NAPI_ERR_CLOSE_SCOPE(context->env,
213 napi_create_array_with_length(context->env, context->locatingRequiredDataList_.size(), &jsEvent),
214 scope, context, work);
215 LocatingRequiredDataToJsObj(context->env, context->locatingRequiredDataList_, jsEvent);
216 if (context->callback[0] != nullptr) {
217 napi_value undefine;
218 napi_value handler = nullptr;
219 napi_status ret = napi_ok;
220 CHK_NAPI_ERR_CLOSE_SCOPE(context->env, napi_get_undefined(context->env, &undefine),
221 scope, context, work);
222 if (FindRequiredDataCallback(context->callback[0])) {
223 CHK_NAPI_ERR_CLOSE_SCOPE(context->env,
224 napi_get_reference_value(context->env, context->callback[0], &handler), scope, context, work);
225 ret = napi_call_function(context->env, nullptr, handler, 1, &jsEvent, &undefine);
226 } else {
227 LBSLOGE(LOCATING_DATA_CALLBACK, "no valid callback");
228 }
229 if (ret != napi_ok) {
230 LBSLOGE(LOCATING_DATA_CALLBACK, "Report event failed");
231 }
232 }
233 NAPI_CALL_RETURN_VOID(context->env, napi_close_handle_scope(context->env, scope));
234 delete context;
235 delete work;
236 });
237 }
238
OnLocatingDataChange(const std::vector<std::shared_ptr<LocatingRequiredData>> & data)239 void LocatingRequiredDataCallbackNapi::OnLocatingDataChange(
240 const std::vector<std::shared_ptr<LocatingRequiredData>>& data)
241 {
242 LBSLOGD(LOCATING_DATA_CALLBACK, "LocatingRequiredDataCallbackNapi::OnLocatingDataChange");
243 Send(data);
244 }
245
DeleteHandler()246 void LocatingRequiredDataCallbackNapi::DeleteHandler()
247 {
248 std::unique_lock<std::mutex> guard(mutex_);
249 if (handlerCb_ == nullptr || env_ == nullptr) {
250 LBSLOGE(LOCATING_DATA_CALLBACK, "handler or env is nullptr.");
251 return;
252 }
253 DeleteRequiredDataCallback(handlerCb_);
254 NAPI_CALL_RETURN_VOID(env_, napi_delete_reference(env_, handlerCb_));
255 handlerCb_ = nullptr;
256 }
257
IsSingleLocationRequest()258 bool LocatingRequiredDataCallbackNapi::IsSingleLocationRequest()
259 {
260 return (fixNumber_ == 1);
261 }
262
CountDown()263 void LocatingRequiredDataCallbackNapi::CountDown()
264 {
265 if (IsSingleLocationRequest() && latch_ != nullptr) {
266 latch_->CountDown();
267 }
268 }
269
Wait(int time)270 void LocatingRequiredDataCallbackNapi::Wait(int time)
271 {
272 if (IsSingleLocationRequest() && latch_ != nullptr) {
273 latch_->Wait(time);
274 }
275 }
276
GetCount()277 int LocatingRequiredDataCallbackNapi::GetCount()
278 {
279 if (IsSingleLocationRequest() && latch_ != nullptr) {
280 return latch_->GetCount();
281 }
282 return 0;
283 }
284
SetCount(int count)285 void LocatingRequiredDataCallbackNapi::SetCount(int count)
286 {
287 if (IsSingleLocationRequest() && latch_ != nullptr) {
288 return latch_->SetCount(count);
289 }
290 }
291
ClearSingleResult()292 void LocatingRequiredDataCallbackNapi::ClearSingleResult()
293 {
294 std::unique_lock<std::mutex> guard(singleResultMutex_);
295 singleResult_.clear();
296 }
297
SetSingleResult(std::vector<std::shared_ptr<LocatingRequiredData>> singleResult)298 void LocatingRequiredDataCallbackNapi::SetSingleResult(
299 std::vector<std::shared_ptr<LocatingRequiredData>> singleResult)
300 {
301 std::unique_lock<std::mutex> guard(singleResultMutex_);
302 singleResult_.assign(singleResult.begin(), singleResult.end());
303 }
304 } // namespace Location
305 } // namespace OHOS
306