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