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