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