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 #include "location_gnss_geofence_callback_napi.h"
16
17 #include "ipc_skeleton.h"
18 #include "napi/native_common.h"
19
20 #include "common_utils.h"
21 #include "location_log.h"
22 #include "napi_util.h"
23 #include "geofence_napi.h"
24 #include "location_async_context.h"
25 #include "geofence_async_context.h"
26 #include "beacon_fence.h"
27
28 namespace OHOS {
29 namespace Location {
30 static std::mutex g_regCallbackMutex;
31 static std::vector<napi_ref> g_registerCallbacks;
LocationGnssGeofenceCallbackNapi()32 LocationGnssGeofenceCallbackNapi::LocationGnssGeofenceCallbackNapi()
33 {
34 env_ = nullptr;
35 handlerCb_ = nullptr;
36 remoteDied_ = false;
37 fenceId_ = -1;
38 type_ = GNSS_GEOFENCE_OPT_TYPE_ADD;
39 result_ = GNSS_GEOFENCE_OPERATION_SUCCESS;
40 InitLatch();
41 }
42
~LocationGnssGeofenceCallbackNapi()43 LocationGnssGeofenceCallbackNapi::~LocationGnssGeofenceCallbackNapi()
44 {
45 if (latch_ != nullptr) {
46 delete latch_;
47 latch_ = nullptr;
48 }
49 LBSLOGW(LOCATION_GNSS_GEOFENCE_CALLBACK, "~LocationGnssGeofenceCallbackNapi()");
50 }
51
InitLatch()52 void LocationGnssGeofenceCallbackNapi::InitLatch()
53 {
54 latch_ = new CountDownLatch();
55 latch_->SetCount(1);
56 }
57
OnRemoteRequest(uint32_t code,MessageParcel & data,MessageParcel & reply,MessageOption & option)58 int LocationGnssGeofenceCallbackNapi::OnRemoteRequest(
59 uint32_t code, MessageParcel& data, MessageParcel& reply, MessageOption& option)
60 {
61 LBSLOGD(LOCATION_GNSS_GEOFENCE_CALLBACK, "OnRemoteRequest enter");
62 if (data.ReadInterfaceToken() != GetDescriptor()) {
63 LBSLOGE(LOCATION_GNSS_GEOFENCE_CALLBACK, "invalid token.");
64 return -1;
65 }
66 if (remoteDied_) {
67 LBSLOGD(LOCATION_GNSS_GEOFENCE_CALLBACK, "Failed to `%{public}s`,Remote service is died!", __func__);
68 return -1;
69 }
70 switch (code) {
71 case RECEIVE_TRANSITION_STATUS_EVENT: {
72 GeofenceTransition transition;
73 transition.fenceId = data.ReadInt32();
74 transition.event =
75 static_cast<GeofenceTransitionEvent>(data.ReadInt32());
76 std::shared_ptr<BeaconFence> beaconFence(data.ReadParcelable<BeaconFence>());
77 if (beaconFence != nullptr) {
78 transition.beaconFence = beaconFence;
79 }
80 OnTransitionStatusChange(transition);
81 break;
82 }
83 case REPORT_OPERATION_RESULT_EVENT: {
84 int fenceId = data.ReadInt32();
85 int type = data.ReadInt32();
86 int result = data.ReadInt32();
87 OnReportOperationResult(fenceId, type, result);
88 CountDown();
89 break;
90 }
91 default: {
92 IPCObjectStub::OnRemoteRequest(code, data, reply, option);
93 break;
94 }
95 }
96 return 0;
97 }
98
GetEnv()99 napi_env LocationGnssGeofenceCallbackNapi::GetEnv()
100 {
101 std::unique_lock<std::mutex> guard(mutex_);
102 return env_;
103 }
104
SetEnv(const napi_env & env)105 void LocationGnssGeofenceCallbackNapi::SetEnv(const napi_env& env)
106 {
107 std::unique_lock<std::mutex> guard(mutex_);
108 env_ = env;
109 }
110
GetHandleCb()111 napi_ref LocationGnssGeofenceCallbackNapi::GetHandleCb()
112 {
113 std::unique_lock<std::mutex> guard(mutex_);
114 return handlerCb_;
115 }
116
SetHandleCb(const napi_ref & handlerCb)117 void LocationGnssGeofenceCallbackNapi::SetHandleCb(const napi_ref& handlerCb)
118 {
119 {
120 std::unique_lock<std::mutex> guard(mutex_);
121 handlerCb_ = handlerCb;
122 }
123 std::unique_lock<std::mutex> guard(g_regCallbackMutex);
124 g_registerCallbacks.emplace_back(handlerCb);
125 }
126
FindGeofenceRegCallback(napi_ref cb)127 bool FindGeofenceRegCallback(napi_ref cb)
128 {
129 std::unique_lock<std::mutex> guard(g_regCallbackMutex);
130 auto iter = std::find(g_registerCallbacks.begin(), g_registerCallbacks.end(), cb);
131 if (iter == g_registerCallbacks.end()) {
132 return false;
133 }
134 return true;
135 }
136
DeleteGeofenceRegCallback(napi_ref cb)137 void DeleteGeofenceRegCallback(napi_ref cb)
138 {
139 std::unique_lock<std::mutex> guard(g_regCallbackMutex);
140 for (auto iter = g_registerCallbacks.begin(); iter != g_registerCallbacks.end(); iter++) {
141 if (*iter == cb) {
142 iter = g_registerCallbacks.erase(iter);
143 break;
144 }
145 }
146 LBSLOGW(LOCATION_GNSS_GEOFENCE_CALLBACK, "after DeleteGeofenceRegCallback, callback size %{public}s",
147 std::to_string(g_registerCallbacks.size()).c_str());
148 }
149
OnTransitionStatusChange(GeofenceTransition transition)150 void LocationGnssGeofenceCallbackNapi::OnTransitionStatusChange(
151 GeofenceTransition transition)
152 {
153 std::unique_lock<std::mutex> guard(mutex_);
154 uv_loop_s *loop = nullptr;
155 NAPI_CALL_RETURN_VOID(env_, napi_get_uv_event_loop(env_, &loop));
156 if (loop == nullptr) {
157 LBSLOGE(LOCATION_GNSS_GEOFENCE_CALLBACK, "loop == nullptr.");
158 return;
159 }
160 if (handlerCb_ == nullptr) {
161 LBSLOGE(LOCATION_GNSS_GEOFENCE_CALLBACK, "handler is nullptr.");
162 return;
163 }
164 uv_work_t *work = new (std::nothrow) uv_work_t;
165 if (work == nullptr) {
166 LBSLOGE(LOCATION_GNSS_GEOFENCE_CALLBACK, "work == nullptr.");
167 return;
168 }
169 GnssGeofenceAsyncContext *context = new (std::nothrow) GnssGeofenceAsyncContext(env_);
170 if (context == nullptr) {
171 LBSLOGE(LOCATION_GNSS_GEOFENCE_CALLBACK, "context == nullptr.");
172 delete work;
173 return;
174 }
175 if (!InitContext(context)) {
176 LBSLOGE(LOCATION_GNSS_GEOFENCE_CALLBACK, "InitContext fail");
177 delete work;
178 delete context;
179 return;
180 }
181 context->transition_ = transition;
182 work->data = context;
183 UvQueueWork(loop, work);
184 }
185
OnReportOperationResult(int fenceId,int type,int result)186 void LocationGnssGeofenceCallbackNapi::OnReportOperationResult(int fenceId, int type, int result)
187 {
188 int addValue = static_cast<int>(GnssGeofenceOperateType::GNSS_GEOFENCE_OPT_TYPE_ADD);
189 if ((type != addValue && fenceId == GetFenceId()) ||
190 (type == addValue)) {
191 GnssGeofenceOperateResult optResult = static_cast<GnssGeofenceOperateResult>(result);
192 GnssGeofenceOperateType optType = static_cast<GnssGeofenceOperateType>(type);
193 if (result == GnssGeofenceOperateResult::GNSS_GEOFENCE_OPERATION_SUCCESS &&
194 optType == GnssGeofenceOperateType::GNSS_GEOFENCE_OPT_TYPE_ADD) {
195 SetFenceId(fenceId);
196 }
197 SetGeofenceOperationType(optType);
198 SetGeofenceOperationResult(optResult);
199 }
200 }
201
IsRemoteDied()202 bool LocationGnssGeofenceCallbackNapi::IsRemoteDied()
203 {
204 return remoteDied_;
205 }
206
UvQueueWork(uv_loop_s * loop,uv_work_t * work)207 void LocationGnssGeofenceCallbackNapi::UvQueueWork(uv_loop_s* loop, uv_work_t* work)
208 {
209 uv_queue_work(
210 loop, work, [](uv_work_t *work) {}, [](uv_work_t *work, int status) {
211 GnssGeofenceAsyncContext *context = nullptr;
212 napi_handle_scope scope = nullptr;
213 if (work == nullptr) {
214 LBSLOGE(LOCATION_GNSS_GEOFENCE_CALLBACK, "work is nullptr");
215 return;
216 }
217 context = static_cast<GnssGeofenceAsyncContext *>(work->data);
218 if (context == nullptr || context->env == nullptr) {
219 LBSLOGE(LOCATION_GNSS_GEOFENCE_CALLBACK, "context is nullptr");
220 delete work;
221 return;
222 }
223 NAPI_CALL_RETURN_VOID(context->env, napi_open_handle_scope(context->env, &scope));
224 if (scope == nullptr) {
225 LBSLOGE(LOCATION_GNSS_GEOFENCE_CALLBACK, "scope is nullptr");
226 delete context;
227 delete work;
228 return;
229 }
230 if (context->transition_.beaconFence == nullptr) {
231 napi_value jsEvent[PARAM2];
232 CHK_NAPI_ERR_CLOSE_SCOPE(context->env, napi_create_object(context->env, &jsEvent[PARAM1]),
233 scope, context, work);
234 CHK_NAPI_ERR_CLOSE_SCOPE(context->env, napi_get_undefined(context->env, &jsEvent[PARAM0]),
235 scope, context, work);
236 GeofenceTransitionToJs(context->env, context->transition_, jsEvent[PARAM1]);
237 if (context->callback[SUCCESS_CALLBACK] != nullptr) {
238 napi_value undefine;
239 napi_value handler = nullptr;
240 napi_status ret = napi_ok;
241 CHK_NAPI_ERR_CLOSE_SCOPE(context->env, napi_get_undefined(context->env, &undefine),
242 scope, context, work);
243 if (FindGeofenceRegCallback(context->callback[0])) {
244 CHK_NAPI_ERR_CLOSE_SCOPE(context->env,
245 napi_get_reference_value(context->env, context->callback[SUCCESS_CALLBACK], &handler),
246 scope, context, work);
247 ret = napi_call_function(context->env, nullptr, handler, RESULT_SIZE, jsEvent, &undefine);
248 } else {
249 LBSLOGE(LOCATION_GNSS_GEOFENCE_CALLBACK, "no valid callback");
250 }
251 if (ret != napi_ok) {
252 LBSLOGE(LOCATION_GNSS_GEOFENCE_CALLBACK, "Report event failed");
253 }
254 }
255 } else {
256 napi_value jsEvent = nullptr;
257 CHK_NAPI_ERR_CLOSE_SCOPE(context->env, napi_create_object(context->env, &jsEvent),
258 scope, context, work);
259 GeofenceTransitionToJs(context->env, context->transition_, jsEvent);
260 if (context->callback[SUCCESS_CALLBACK] != nullptr) {
261 napi_value undefine;
262 napi_value handler = nullptr;
263 napi_status ret = napi_ok;
264 CHK_NAPI_ERR_CLOSE_SCOPE(context->env, napi_get_undefined(context->env, &undefine),
265 scope, context, work);
266 if (FindGeofenceRegCallback(context->callback[0])) {
267 CHK_NAPI_ERR_CLOSE_SCOPE(context->env,
268 napi_get_reference_value(context->env, context->callback[SUCCESS_CALLBACK], &handler),
269 scope, context, work);
270 ret = napi_call_function(context->env, nullptr, handler, 1, &jsEvent, &undefine);
271 } else {
272 LBSLOGE(LOCATION_GNSS_GEOFENCE_CALLBACK, "no valid callback");
273 }
274 if (ret != napi_ok) {
275 LBSLOGE(LOCATION_GNSS_GEOFENCE_CALLBACK, "Report event failed");
276 }
277 }
278 }
279 NAPI_CALL_RETURN_VOID(context->env, napi_close_handle_scope(context->env, scope));
280 delete context;
281 delete work;
282 });
283 }
284
DeleteHandler()285 void LocationGnssGeofenceCallbackNapi::DeleteHandler()
286 {
287 std::unique_lock<std::mutex> guard(mutex_);
288 if (handlerCb_ == nullptr || env_ == nullptr) {
289 LBSLOGE(LOCATION_GNSS_GEOFENCE_CALLBACK, "handler or env is nullptr.");
290 return;
291 }
292 DeleteGeofenceRegCallback(handlerCb_);
293 NAPI_CALL_RETURN_VOID(env_, napi_delete_reference(env_, handlerCb_));
294 handlerCb_ = nullptr;
295 }
296
CountDown()297 void LocationGnssGeofenceCallbackNapi::CountDown()
298 {
299 if (latch_ != nullptr) {
300 latch_->CountDown();
301 }
302 }
303
Wait(int time)304 void LocationGnssGeofenceCallbackNapi::Wait(int time)
305 {
306 if (latch_ != nullptr) {
307 latch_->Wait(time);
308 }
309 }
310
GetCount()311 int LocationGnssGeofenceCallbackNapi::GetCount()
312 {
313 if (latch_ != nullptr) {
314 return latch_->GetCount();
315 }
316 return 0;
317 }
318
SetCount(int count)319 void LocationGnssGeofenceCallbackNapi::SetCount(int count)
320 {
321 if (latch_ != nullptr) {
322 return latch_->SetCount(count);
323 }
324 }
325
ClearFenceId()326 void LocationGnssGeofenceCallbackNapi::ClearFenceId()
327 {
328 std::unique_lock<std::mutex> guard(operationResultMutex_);
329 fenceId_ = -1;
330 }
331
GetFenceId()332 int LocationGnssGeofenceCallbackNapi::GetFenceId()
333 {
334 std::unique_lock<std::mutex> guard(operationResultMutex_);
335 return fenceId_;
336 }
337
SetFenceId(int fenceId)338 void LocationGnssGeofenceCallbackNapi::SetFenceId(int fenceId)
339 {
340 std::unique_lock<std::mutex> guard(operationResultMutex_);
341 fenceId_ = fenceId;
342 }
343
GetGeofenceOperationType()344 GnssGeofenceOperateType LocationGnssGeofenceCallbackNapi::GetGeofenceOperationType()
345 {
346 std::unique_lock<std::mutex> guard(operationResultMutex_);
347 return type_;
348 }
349
SetGeofenceOperationType(GnssGeofenceOperateType type)350 void LocationGnssGeofenceCallbackNapi::SetGeofenceOperationType(GnssGeofenceOperateType type)
351 {
352 std::unique_lock<std::mutex> guard(operationResultMutex_);
353 type_ = type;
354 }
355
GetGeofenceOperationResult()356 GnssGeofenceOperateResult LocationGnssGeofenceCallbackNapi::GetGeofenceOperationResult()
357 {
358 std::unique_lock<std::mutex> guard(operationResultMutex_);
359 return result_;
360 }
361
SetGeofenceOperationResult(GnssGeofenceOperateResult result)362 void LocationGnssGeofenceCallbackNapi::SetGeofenceOperationResult(GnssGeofenceOperateResult result)
363 {
364 std::unique_lock<std::mutex> guard(operationResultMutex_);
365 result_ = result;
366 }
367
DealGeofenceOperationResult()368 LocationErrCode LocationGnssGeofenceCallbackNapi::DealGeofenceOperationResult()
369 {
370 std::unique_lock<std::mutex> guard(operationResultMutex_);
371 LocationErrCode errCode = ERRCODE_SUCCESS;
372 GnssGeofenceOperateResult result = result_;
373 switch (result) {
374 case GnssGeofenceOperateResult::GNSS_GEOFENCE_OPERATION_SUCCESS:
375 errCode = ERRCODE_SUCCESS;
376 break;
377 case GnssGeofenceOperateResult::GNSS_GEOFENCE_OPERATION_ERROR_UNKNOWN:
378 errCode = ERRCODE_SERVICE_UNAVAILABLE;
379 break;
380 case GnssGeofenceOperateResult::GNSS_GEOFENCE_OPERATION_ERROR_TOO_MANY_GEOFENCES:
381 errCode = ERRCODE_GEOFENCE_EXCEED_MAXIMUM;
382 break;
383 case GnssGeofenceOperateResult::GNSS_GEOFENCE_OPERATION_ERROR_GEOFENCE_ID_EXISTS:
384 errCode = ERRCODE_SERVICE_UNAVAILABLE;
385 break;
386 case GnssGeofenceOperateResult::GNSS_GEOFENCE_OPERATION_ERROR_PARAMS_INVALID:
387 errCode = ERRCODE_SERVICE_UNAVAILABLE;
388 break;
389 case GnssGeofenceOperateResult::GNSS_GEOFENCE_OPERATION_ERROR_GEOFENCE_ID_UNKNOWN:
390 errCode = ERRCODE_GEOFENCE_INCORRECT_ID;
391 break;
392 case GnssGeofenceOperateResult::GNSS_GEOFENCE_OPERATION_ERROR_NOT_SUPPORTED:
393 errCode = ERRCODE_NOT_SUPPORTED;
394 break;
395 case GnssGeofenceOperateResult::GNSS_GEOFENCE_OPERATION_ERROR_OPERATE_FAILED:
396 errCode = ERRCODE_GEOFENCE_FAIL;
397 break;
398 default:
399 break;
400 }
401 return errCode;
402 }
403 } // namespace Location
404 } // namespace OHOS
405