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
16 #include "locator_callback_napi.h"
17
18 #include "ipc_object_stub.h"
19 #include "ipc_skeleton.h"
20 #include "js_native_api.h"
21 #include "message_option.h"
22 #include "message_parcel.h"
23 #include "napi/native_common.h"
24 #include "uv.h"
25
26 #include "common_utils.h"
27 #include "constant_definition.h"
28 #include "i_locator_callback.h"
29 #include "location.h"
30 #include "location_async_context.h"
31 #include "location_log.h"
32 #include "napi_util.h"
33
34 namespace OHOS {
35 namespace Location {
36 static std::mutex g_regSystemCallbackMutex;
37 static std::vector<napi_ref> g_registerSystemCallbacks;
38 static std::mutex g_regCallbackMutex;
39 static std::vector<napi_ref> g_registerCallbacks;
LocatorCallbackNapi()40 LocatorCallbackNapi::LocatorCallbackNapi()
41 {
42 env_ = nullptr;
43 handlerCb_ = nullptr;
44 successHandlerCb_ = nullptr;
45 failHandlerCb_ = nullptr;
46 completeHandlerCb_ = nullptr;
47 fixNumber_ = 0;
48 inHdArea_ = true;
49 singleLocation_ = nullptr;
50 locationPriority_ = 0;
51 errorType_ = 0;
52 InitLatch();
53 }
54
InitLatch()55 void LocatorCallbackNapi::InitLatch()
56 {
57 latch_ = new CountDownLatch();
58 latch_->SetCount(1);
59 }
60
~LocatorCallbackNapi()61 LocatorCallbackNapi::~LocatorCallbackNapi()
62 {
63 delete latch_;
64 LBSLOGW(LOCATOR_CALLBACK, "~LocatorCallbackNapi()");
65 }
66
SetSuccHandleCb(const napi_ref & successHandlerCb)67 void LocatorCallbackNapi::SetSuccHandleCb(const napi_ref& successHandlerCb)
68 {
69 successHandlerCb_ = successHandlerCb;
70 std::unique_lock<std::mutex> guard(g_regSystemCallbackMutex);
71 g_registerSystemCallbacks.emplace_back(successHandlerCb);
72 }
73
OnRemoteRequest(uint32_t code,MessageParcel & data,MessageParcel & reply,MessageOption & option)74 int LocatorCallbackNapi::OnRemoteRequest(uint32_t code,
75 MessageParcel& data, MessageParcel& reply, MessageOption& option)
76 {
77 if (data.ReadInterfaceToken() != GetDescriptor()) {
78 LBSLOGE(LOCATOR_CALLBACK, "invalid token.");
79 return -1;
80 }
81 switch (code) {
82 case RECEIVE_LOCATION_INFO_EVENT: {
83 std::unique_ptr<Location> location = Location::UnmarshallingMakeUnique(data);
84 OnLocationReport(location);
85 if (location->GetLocationSourceType() == LocationSourceType::NETWORK_TYPE) {
86 inHdArea_ = false;
87 }
88 if (NeedSetSingleLocation(location)) {
89 SetSingleLocation(location);
90 }
91 if (IfReportAccuracyLocation()) {
92 CountDown();
93 }
94 break;
95 }
96 case RECEIVE_LOCATION_STATUS_EVENT: {
97 int status = data.ReadInt32();
98 OnLocatingStatusChange(status);
99 break;
100 }
101 case RECEIVE_ERROR_INFO_EVENT: {
102 int errorCode = data.ReadInt32();
103 SetErrorType(errorCode);
104 LBSLOGI(LOCATOR_STANDARD, "CallbackSutb receive ERROR_EVENT. errorCode:%{public}d", errorCode);
105 if (errorCode == ERRCODE_LOCATING_NETWORK_FAIL) {
106 inHdArea_ = false;
107 if (GetSingleLocation() != nullptr) {
108 CountDown();
109 }
110 } else {
111 OnErrorReport(errorCode);
112 }
113 break;
114 }
115 default: {
116 IPCObjectStub::OnRemoteRequest(code, data, reply, option);
117 break;
118 }
119 }
120 return 0;
121 }
122
GetEnv()123 napi_env LocatorCallbackNapi::GetEnv()
124 {
125 std::unique_lock<std::mutex> guard(mutex_);
126 return env_;
127 }
128
SetEnv(const napi_env & env)129 void LocatorCallbackNapi::SetEnv(const napi_env& env)
130 {
131 std::unique_lock<std::mutex> guard(mutex_);
132 env_ = env;
133 }
134
GetHandleCb()135 napi_ref LocatorCallbackNapi::GetHandleCb()
136 {
137 std::unique_lock<std::mutex> guard(mutex_);
138 return handlerCb_;
139 }
140
SetHandleCb(const napi_ref & handlerCb)141 void LocatorCallbackNapi::SetHandleCb(const napi_ref& handlerCb)
142 {
143 {
144 std::unique_lock<std::mutex> guard(mutex_);
145 handlerCb_ = handlerCb;
146 }
147 std::unique_lock<std::mutex> guard(g_regCallbackMutex);
148 g_registerCallbacks.emplace_back(handlerCb);
149 }
150
FindLocationCallback(napi_ref cb)151 bool FindLocationCallback(napi_ref cb)
152 {
153 {
154 std::unique_lock<std::mutex> guard(g_regSystemCallbackMutex);
155 auto iter = std::find(g_registerSystemCallbacks.begin(), g_registerSystemCallbacks.end(), cb);
156 if (iter != g_registerSystemCallbacks.end()) {
157 return true;
158 }
159 }
160 std::unique_lock<std::mutex> guard(g_regCallbackMutex);
161 auto iter = std::find(g_registerCallbacks.begin(), g_registerCallbacks.end(), cb);
162 if (iter == g_registerCallbacks.end()) {
163 return false;
164 }
165 return true;
166 }
167
DeleteLocationCallback(napi_ref cb)168 void DeleteLocationCallback(napi_ref cb)
169 {
170 {
171 std::unique_lock<std::mutex> guard(g_regSystemCallbackMutex);
172 for (auto iter = g_registerSystemCallbacks.begin(); iter != g_registerSystemCallbacks.end(); iter++) {
173 if (*iter == cb) {
174 iter = g_registerSystemCallbacks.erase(iter);
175 break;
176 }
177 }
178 }
179 std::unique_lock<std::mutex> guard(g_regCallbackMutex);
180 for (auto iter = g_registerCallbacks.begin(); iter != g_registerCallbacks.end(); iter++) {
181 if (*iter == cb) {
182 iter = g_registerCallbacks.erase(iter);
183 break;
184 }
185 }
186 LBSLOGW(LOCATOR_CALLBACK, "after DeleteLocationCallback, callback size %{public}s",
187 std::to_string(g_registerCallbacks.size()).c_str());
188 }
189
DoSendWork(uv_loop_s * & loop,uv_work_t * & work)190 void LocatorCallbackNapi::DoSendWork(uv_loop_s*& loop, uv_work_t*& work)
191 {
192 uv_queue_work(loop, work, [](uv_work_t* work) {}, [](uv_work_t* work, int status) {
193 if (work == nullptr) {
194 return;
195 }
196 napi_handle_scope scope = nullptr;
197 auto context = static_cast<LocationAsyncContext*>(work->data);
198 if (context == nullptr) {
199 delete work;
200 return;
201 }
202 if (context->env == nullptr || context->loc == nullptr) {
203 delete context;
204 delete work;
205 return;
206 }
207 napi_open_handle_scope(context->env, &scope);
208 if (scope == nullptr) {
209 DELETE_SCOPE_CONTEXT_WORK(context->env, scope, context, work);
210 return;
211 }
212 napi_value jsEvent = nullptr;
213 CHK_NAPI_ERR_CLOSE_SCOPE(context->env, napi_create_object(context->env, &jsEvent), scope, context, work);
214 if (context->callback[1]) {
215 SystemLocationToJs(context->env, context->loc, jsEvent);
216 } else {
217 LocationToJs(context->env, context->loc, jsEvent);
218 }
219 if (context->callback[0] != nullptr) {
220 napi_value undefine = nullptr;
221 napi_value handler = nullptr;
222 napi_status ret = napi_ok;
223 CHK_NAPI_ERR_CLOSE_SCOPE(context->env, napi_get_undefined(context->env, &undefine),
224 scope, context, work);
225 if (FindLocationCallback(context->callback[0])) {
226 CHK_NAPI_ERR_CLOSE_SCOPE(context->env,
227 napi_get_reference_value(context->env, context->callback[0], &handler), scope, context, work);
228 ret = napi_call_function(context->env, nullptr, handler, 1, &jsEvent, &undefine);
229 } else {
230 LBSLOGE(LOCATOR_CALLBACK, "no valid callback");
231 }
232 if (ret != napi_ok) {
233 LBSLOGE(LOCATOR_CALLBACK, "Report location failed");
234 }
235 }
236 NAPI_CALL_RETURN_VOID(context->env, napi_close_handle_scope(context->env, scope));
237 delete context;
238 delete work;
239 });
240 }
241
DoSendErrorCode(uv_loop_s * & loop,uv_work_t * & work)242 void LocatorCallbackNapi::DoSendErrorCode(uv_loop_s *&loop, uv_work_t *&work)
243 {
244 uv_queue_work(loop, work, [](uv_work_t *work) {},
245 [](uv_work_t *work, int status) {
246 AsyncContext *context = nullptr;
247 napi_handle_scope scope = nullptr;
248 if (work == nullptr) {
249 LBSLOGE(LOCATOR_CALLBACK, "work is nullptr");
250 return;
251 }
252 context = static_cast<AsyncContext *>(work->data);
253 if (context == nullptr || context->env == nullptr) {
254 LBSLOGE(LOCATOR_CALLBACK, "context is nullptr");
255 delete work;
256 return;
257 }
258 NAPI_CALL_RETURN_VOID(context->env, napi_open_handle_scope(context->env, &scope));
259 if (scope == nullptr) {
260 LBSLOGE(LOCATOR_CALLBACK, "scope is nullptr");
261 delete context;
262 delete work;
263 return;
264 }
265 if (context->callback[FAIL_CALLBACK] != nullptr) {
266 napi_value undefine;
267 napi_value handler = nullptr;
268 CHK_NAPI_ERR_CLOSE_SCOPE(context->env, napi_get_undefined(context->env, &undefine),
269 scope, context, work);
270 CHK_NAPI_ERR_CLOSE_SCOPE(context->env,
271 napi_get_reference_value(context->env, context->callback[FAIL_CALLBACK], &handler),
272 scope, context, work);
273 std::string msg = GetErrorMsgByCode(context->errCode);
274 context->errCode = ConvertErrorCode(context->errCode);
275 CreateFailCallBackParams(*context, msg, context->errCode);
276 if (napi_call_function(context->env, nullptr, handler, RESULT_SIZE,
277 context->result, &undefine) != napi_ok) {
278 LBSLOGE(LOCATOR_CALLBACK, "Report system error failed");
279 }
280 }
281 NAPI_CALL_RETURN_VOID(context->env, napi_close_handle_scope(context->env, scope));
282 delete context;
283 delete work;
284 });
285 }
286
SendErrorCode(const int & errorCode)287 bool LocatorCallbackNapi::SendErrorCode(const int& errorCode)
288 {
289 std::unique_lock<std::mutex> guard(mutex_);
290 if (!IsSystemGeoLocationApi() && !IsSingleLocationRequest()) {
291 LBSLOGE(LOCATOR_CALLBACK, "this is Callback type,cant send error msg.");
292 return false;
293 }
294 if (env_ == nullptr) {
295 LBSLOGE(LOCATOR_CALLBACK, "env_ is nullptr.");
296 return false;
297 }
298 if (handlerCb_ == nullptr) {
299 LBSLOGE(LOCATOR_CALLBACK, "handler is nullptr.");
300 return false;
301 }
302 uv_loop_s *loop = nullptr;
303 NAPI_CALL_BASE(env_, napi_get_uv_event_loop(env_, &loop), false);
304 if (loop == nullptr) {
305 LBSLOGE(LOCATOR_CALLBACK, "loop == nullptr.");
306 return false;
307 }
308 uv_work_t *work = new (std::nothrow) uv_work_t;
309 if (work == nullptr) {
310 LBSLOGE(LOCATOR_CALLBACK, "work == nullptr.");
311 return false;
312 }
313 AsyncContext *context = new (std::nothrow) AsyncContext(env_);
314 if (context == nullptr) {
315 LBSLOGE(LOCATOR_CALLBACK, "context == nullptr.");
316 delete work;
317 return false;
318 }
319 if (!InitContext(context)) {
320 LBSLOGE(LOCATOR_CALLBACK, "InitContext fail");
321 delete work;
322 delete context;
323 return false;
324 }
325 context->errCode = errorCode;
326 work->data = context;
327 DoSendErrorCode(loop, work);
328 return true;
329 }
330
OnLocationReport(const std::unique_ptr<Location> & location)331 void LocatorCallbackNapi::OnLocationReport(const std::unique_ptr<Location>& location)
332 {
333 std::unique_lock<std::mutex> guard(mutex_);
334 uv_loop_s *loop = nullptr;
335 if (env_ == nullptr) {
336 LBSLOGD(LOCATOR_CALLBACK, "env_ is nullptr.");
337 return;
338 }
339 if (!IsSystemGeoLocationApi() && handlerCb_ == nullptr) {
340 LBSLOGE(LOCATOR_CALLBACK, "handler is nullptr.");
341 return;
342 }
343 NAPI_CALL_RETURN_VOID(env_, napi_get_uv_event_loop(env_, &loop));
344 if (loop == nullptr) {
345 LBSLOGE(LOCATOR_CALLBACK, "loop == nullptr.");
346 return;
347 }
348 uv_work_t *work = new (std::nothrow) uv_work_t;
349 if (work == nullptr) {
350 LBSLOGE(LOCATOR_CALLBACK, "work == nullptr.");
351 return;
352 }
353 auto context = new (std::nothrow) LocationAsyncContext(env_);
354 if (context == nullptr) {
355 LBSLOGE(LOCATOR_CALLBACK, "context == nullptr.");
356 delete work;
357 return;
358 }
359 if (!InitContext(context)) {
360 LBSLOGE(LOCATOR_CALLBACK, "InitContext fail");
361 delete work;
362 delete context;
363 return;
364 }
365 context->loc = std::make_unique<Location>(*location);
366 work->data = context;
367 DoSendWork(loop, work);
368 }
369
OnLocatingStatusChange(const int status)370 void LocatorCallbackNapi::OnLocatingStatusChange(const int status)
371 {
372 }
373
OnErrorReport(const int errorCode)374 void LocatorCallbackNapi::OnErrorReport(const int errorCode)
375 {
376 SendErrorCode(errorCode);
377 }
378
DeleteAllCallbacks()379 void LocatorCallbackNapi::DeleteAllCallbacks()
380 {
381 DeleteHandler();
382 }
383
DeleteHandler()384 void LocatorCallbackNapi::DeleteHandler()
385 {
386 LBSLOGD(LOCATOR_CALLBACK, "before DeleteHandler");
387 std::unique_lock<std::mutex> guard(mutex_);
388 if (env_ == nullptr) {
389 LBSLOGE(LOCATOR_CALLBACK, "env is nullptr.");
390 return;
391 }
392 if (IsSystemGeoLocationApi()) {
393 DeleteLocationCallback(successHandlerCb_);
394 if (successHandlerCb_ != nullptr) {
395 NAPI_CALL_RETURN_VOID(env_, napi_delete_reference(env_, successHandlerCb_));
396 successHandlerCb_ = nullptr;
397 }
398 if (failHandlerCb_ != nullptr) {
399 NAPI_CALL_RETURN_VOID(env_, napi_delete_reference(env_, failHandlerCb_));
400 failHandlerCb_ = nullptr;
401 }
402 if (completeHandlerCb_ != nullptr) {
403 NAPI_CALL_RETURN_VOID(env_, napi_delete_reference(env_, completeHandlerCb_));
404 completeHandlerCb_ = nullptr;
405 }
406 } else {
407 DeleteLocationCallback(handlerCb_);
408 if (handlerCb_ != nullptr) {
409 NAPI_CALL_RETURN_VOID(env_, napi_delete_reference(env_, handlerCb_));
410 handlerCb_ = nullptr;
411 }
412 }
413 }
414
IsSystemGeoLocationApi()415 bool LocatorCallbackNapi::IsSystemGeoLocationApi()
416 {
417 return (successHandlerCb_ != nullptr) ? true : false;
418 }
419
IsSingleLocationRequest()420 bool LocatorCallbackNapi::IsSingleLocationRequest()
421 {
422 return (fixNumber_ == 1);
423 }
424
CountDown()425 void LocatorCallbackNapi::CountDown()
426 {
427 if (IsSingleLocationRequest() && latch_ != nullptr) {
428 latch_->CountDown();
429 }
430 }
431
Wait(int time)432 void LocatorCallbackNapi::Wait(int time)
433 {
434 if (IsSingleLocationRequest() && latch_ != nullptr) {
435 latch_->Wait(time);
436 }
437 }
438
GetCount()439 int LocatorCallbackNapi::GetCount()
440 {
441 if (IsSingleLocationRequest() && latch_ != nullptr) {
442 return latch_->GetCount();
443 }
444 return 0;
445 }
446
SetCount(int count)447 void LocatorCallbackNapi::SetCount(int count)
448 {
449 if (IsSingleLocationRequest() && latch_ != nullptr) {
450 return latch_->SetCount(count);
451 }
452 }
453
NeedSetSingleLocation(const std::unique_ptr<Location> & location)454 bool LocatorCallbackNapi::NeedSetSingleLocation(const std::unique_ptr<Location>& location)
455 {
456 if (locationPriority_ == LOCATION_PRIORITY_ACCURACY &&
457 singleLocation_ != nullptr &&
458 location->GetLocationSourceType() == LocationSourceType::NETWORK_TYPE) {
459 return false;
460 } else {
461 return true;
462 }
463 }
464
IfReportAccuracyLocation()465 bool LocatorCallbackNapi::IfReportAccuracyLocation()
466 {
467 if (locationPriority_ == LOCATION_PRIORITY_ACCURACY &&
468 (((singleLocation_->GetLocationSourceType() == LocationSourceType::GNSS_TYPE ||
469 singleLocation_->GetLocationSourceType() == LocationSourceType::RTK_TYPE) && inHdArea_) ||
470 singleLocation_->GetLocationSourceType() == LocationSourceType::NETWORK_TYPE)) {
471 return false;
472 } else {
473 return true;
474 }
475 }
476
SetSingleLocation(const std::unique_ptr<Location> & location)477 void LocatorCallbackNapi::SetSingleLocation(const std::unique_ptr<Location>& location)
478 {
479 std::unique_lock<std::mutex> guard(mutex_);
480 singleLocation_ = std::make_shared<Location>(*location);
481 }
482 } // namespace Location
483 } // namespace OHOS
484