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