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 "locating_required_data_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
24 namespace OHOS {
25 namespace Location {
26 static std::mutex g_regCallbackMutex;
27 static std::vector<napi_ref> g_registerCallbacks;
LocatingRequiredDataCallbackNapi()28 LocatingRequiredDataCallbackNapi::LocatingRequiredDataCallbackNapi()
29 {
30 env_ = nullptr;
31 handlerCb_ = nullptr;
32 remoteDied_ = false;
33 fixNumber_ = 0;
34 InitLatch();
35 }
36
~LocatingRequiredDataCallbackNapi()37 LocatingRequiredDataCallbackNapi::~LocatingRequiredDataCallbackNapi()
38 {
39 if (latch_ != nullptr) {
40 delete latch_;
41 latch_ = nullptr;
42 }
43 }
44
InitLatch()45 void LocatingRequiredDataCallbackNapi::InitLatch()
46 {
47 latch_ = new CountDownLatch();
48 latch_->SetCount(1);
49 }
50
OnRemoteRequest(uint32_t code,MessageParcel & data,MessageParcel & reply,MessageOption & option)51 int LocatingRequiredDataCallbackNapi::OnRemoteRequest(
52 uint32_t code, MessageParcel& data, MessageParcel& reply, MessageOption& option)
53 {
54 LBSLOGD(LOCATING_DATA_CALLBACK, "LocatingRequiredDataCallbackNapi::OnRemoteRequest!");
55 if (data.ReadInterfaceToken() != GetDescriptor()) {
56 LBSLOGE(LOCATING_DATA_CALLBACK, "invalid token.");
57 return -1;
58 }
59 if (remoteDied_) {
60 LBSLOGD(LOCATING_DATA_CALLBACK, "Failed to `%{public}s`,Remote service is died!", __func__);
61 return -1;
62 }
63
64 switch (code) {
65 case RECEIVE_INFO_EVENT: {
66 int cnt = data.ReadInt32();
67 if (cnt >= 0 && cnt <= MAXIMUM_LOCATING_REQUIRED_DATAS) {
68 std::vector<std::shared_ptr<LocatingRequiredData>> res;
69 for (int i = 0; cnt > 0 && i < cnt; i++) {
70 res.push_back(LocatingRequiredData::Unmarshalling(data));
71 }
72 // update wifi info
73 if (res.size() > 0 && res[0]->GetType() == LocatingRequiredDataType::WIFI) {
74 SetSingleResult(res);
75 }
76 OnLocatingDataChange(res);
77 CountDown();
78 }
79 break;
80 }
81 default: {
82 IPCObjectStub::OnRemoteRequest(code, data, reply, option);
83 break;
84 }
85 }
86 return 0;
87 }
88
GetEnv()89 napi_env LocatingRequiredDataCallbackNapi::GetEnv()
90 {
91 std::unique_lock<std::mutex> guard(mutex_);
92 return env_;
93 }
94
SetEnv(const napi_env & env)95 void LocatingRequiredDataCallbackNapi::SetEnv(const napi_env& env)
96 {
97 std::unique_lock<std::mutex> guard(mutex_);
98 env_ = env;
99 }
100
GetHandleCb()101 napi_ref LocatingRequiredDataCallbackNapi::GetHandleCb()
102 {
103 std::unique_lock<std::mutex> guard(mutex_);
104 return handlerCb_;
105 }
106
SetHandleCb(const napi_ref & handlerCb)107 void LocatingRequiredDataCallbackNapi::SetHandleCb(const napi_ref& handlerCb)
108 {
109 {
110 std::unique_lock<std::mutex> guard(mutex_);
111 handlerCb_ = handlerCb;
112 }
113 std::unique_lock<std::mutex> guard(g_regCallbackMutex);
114 g_registerCallbacks.emplace_back(handlerCb);
115 }
116
FindRequiredDataCallback(napi_ref cb)117 bool FindRequiredDataCallback(napi_ref cb)
118 {
119 std::unique_lock<std::mutex> guard(g_regCallbackMutex);
120 auto iter = std::find(g_registerCallbacks.begin(), g_registerCallbacks.end(), cb);
121 if (iter == g_registerCallbacks.end()) {
122 return false;
123 }
124 return true;
125 }
126
DeleteRequiredDataCallback(napi_ref cb)127 void DeleteRequiredDataCallback(napi_ref cb)
128 {
129 std::unique_lock<std::mutex> guard(g_regCallbackMutex);
130 for (auto iter = g_registerCallbacks.begin(); iter != g_registerCallbacks.end(); iter++) {
131 if (*iter == cb) {
132 iter = g_registerCallbacks.erase(iter);
133 break;
134 }
135 }
136 }
137
IsRemoteDied()138 bool LocatingRequiredDataCallbackNapi::IsRemoteDied()
139 {
140 return remoteDied_;
141 }
142
Send(const std::vector<std::shared_ptr<LocatingRequiredData>> & data)143 bool LocatingRequiredDataCallbackNapi::Send(const std::vector<std::shared_ptr<LocatingRequiredData>>& data)
144 {
145 if (IsSingleLocationRequest()) {
146 return false;
147 }
148 std::unique_lock<std::mutex> guard(mutex_);
149 uv_loop_s *loop = nullptr;
150 NAPI_CALL_BASE(env_, napi_get_uv_event_loop(env_, &loop), false);
151 if (loop == nullptr) {
152 LBSLOGE(LOCATING_DATA_CALLBACK, "loop == nullptr.");
153 return false;
154 }
155 if (handlerCb_ == nullptr) {
156 LBSLOGE(LOCATING_DATA_CALLBACK, "handler is nullptr.");
157 return false;
158 }
159 uv_work_t *work = new (std::nothrow) uv_work_t;
160 if (work == nullptr) {
161 LBSLOGE(LOCATING_DATA_CALLBACK, "work == nullptr.");
162 return false;
163 }
164 LocatingRequiredDataAsyncContext *context = new (std::nothrow) LocatingRequiredDataAsyncContext(env_);
165 if (context == nullptr) {
166 LBSLOGE(LOCATING_DATA_CALLBACK, "context == nullptr.");
167 delete work;
168 return false;
169 }
170 if (!InitContext(context)) {
171 LBSLOGE(LOCATING_DATA_CALLBACK, "InitContext fail");
172 return false;
173 }
174 context->locatingRequiredDataList_ = data;
175 work->data = context;
176 UvQueueWork(loop, work);
177 return true;
178 }
179
UvQueueWork(uv_loop_s * loop,uv_work_t * work)180 void LocatingRequiredDataCallbackNapi::UvQueueWork(uv_loop_s* loop, uv_work_t* work)
181 {
182 uv_queue_work(
183 loop,
184 work,
185 [](uv_work_t *work) {},
186 [](uv_work_t *work, int status) {
187 LocatingRequiredDataAsyncContext *context = nullptr;
188 napi_handle_scope scope = nullptr;
189 if (work == nullptr) {
190 LBSLOGE(LOCATING_DATA_CALLBACK, "work is nullptr");
191 return;
192 }
193 context = static_cast<LocatingRequiredDataAsyncContext *>(work->data);
194 if (context == nullptr || context->env == nullptr) {
195 LBSLOGE(LOCATING_DATA_CALLBACK, "context is nullptr");
196 delete work;
197 return;
198 }
199 if (!FindRequiredDataCallback(context->callback[0])) {
200 LBSLOGE(LOCATING_DATA_CALLBACK, "no valid callback");
201 delete context;
202 delete work;
203 return;
204 }
205 NAPI_CALL_RETURN_VOID(context->env, napi_open_handle_scope(context->env, &scope));
206 if (scope == nullptr) {
207 LBSLOGE(LOCATING_DATA_CALLBACK, "scope is nullptr");
208 delete context;
209 delete work;
210 return;
211 }
212 napi_value jsEvent = nullptr;
213 CHK_NAPI_ERR_CLOSE_SCOPE(context->env,
214 napi_create_array_with_length(context->env, context->locatingRequiredDataList_.size(), &jsEvent),
215 scope, context, work);
216 LocatingRequiredDataToJsObj(context->env, context->locatingRequiredDataList_, jsEvent);
217 if (context->callback[0] != nullptr) {
218 napi_value undefine;
219 napi_value handler = nullptr;
220 CHK_NAPI_ERR_CLOSE_SCOPE(context->env, napi_get_undefined(context->env, &undefine),
221 scope, context, work);
222 CHK_NAPI_ERR_CLOSE_SCOPE(context->env,
223 napi_get_reference_value(context->env, context->callback[0], &handler), scope, context, work);
224 if (napi_call_function(context->env, nullptr, handler, 1,
225 &jsEvent, &undefine) != napi_ok) {
226 LBSLOGE(LOCATING_DATA_CALLBACK, "Report event failed");
227 }
228 }
229 NAPI_CALL_RETURN_VOID(context->env, napi_close_handle_scope(context->env, scope));
230 delete context;
231 delete work;
232 });
233 }
234
OnLocatingDataChange(const std::vector<std::shared_ptr<LocatingRequiredData>> & data)235 void LocatingRequiredDataCallbackNapi::OnLocatingDataChange(
236 const std::vector<std::shared_ptr<LocatingRequiredData>>& data)
237 {
238 LBSLOGD(LOCATING_DATA_CALLBACK, "LocatingRequiredDataCallbackNapi::OnLocatingDataChange");
239 Send(data);
240 }
241
DeleteHandler()242 void LocatingRequiredDataCallbackNapi::DeleteHandler()
243 {
244 std::unique_lock<std::mutex> guard(mutex_);
245 if (handlerCb_ == nullptr || env_ == nullptr) {
246 LBSLOGE(LOCATING_DATA_CALLBACK, "handler or env is nullptr.");
247 return;
248 }
249 DeleteRequiredDataCallback(handlerCb_);
250 NAPI_CALL_RETURN_VOID(env_, napi_delete_reference(env_, handlerCb_));
251 handlerCb_ = nullptr;
252 }
253
IsSingleLocationRequest()254 bool LocatingRequiredDataCallbackNapi::IsSingleLocationRequest()
255 {
256 return (fixNumber_ == 1);
257 }
258
CountDown()259 void LocatingRequiredDataCallbackNapi::CountDown()
260 {
261 if (IsSingleLocationRequest() && latch_ != nullptr) {
262 latch_->CountDown();
263 }
264 }
265
Wait(int time)266 void LocatingRequiredDataCallbackNapi::Wait(int time)
267 {
268 if (IsSingleLocationRequest() && latch_ != nullptr) {
269 latch_->Wait(time);
270 }
271 }
272
GetCount()273 int LocatingRequiredDataCallbackNapi::GetCount()
274 {
275 if (IsSingleLocationRequest() && latch_ != nullptr) {
276 return latch_->GetCount();
277 }
278 return 0;
279 }
280
SetCount(int count)281 void LocatingRequiredDataCallbackNapi::SetCount(int count)
282 {
283 if (IsSingleLocationRequest() && latch_ != nullptr) {
284 return latch_->SetCount(count);
285 }
286 }
287
ClearSingleResult()288 void LocatingRequiredDataCallbackNapi::ClearSingleResult()
289 {
290 std::unique_lock<std::mutex> guard(singleResultMutex_);
291 singleResult_.clear();
292 }
293
SetSingleResult(std::vector<std::shared_ptr<LocatingRequiredData>> singleResult)294 void LocatingRequiredDataCallbackNapi::SetSingleResult(
295 std::vector<std::shared_ptr<LocatingRequiredData>> singleResult)
296 {
297 std::unique_lock<std::mutex> guard(singleResultMutex_);
298 singleResult_.assign(singleResult.begin(), singleResult.end());
299 }
300 } // namespace Location
301 } // namespace OHOS
302