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