• 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             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