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