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