• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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