• 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 
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