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