• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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