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