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