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