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