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 "cached_locations_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;
CachedLocationsCallbackNapi()28 CachedLocationsCallbackNapi::CachedLocationsCallbackNapi()
29 {
30 env_ = nullptr;
31 handlerCb_ = nullptr;
32 remoteDied_ = false;
33 }
34
~CachedLocationsCallbackNapi()35 CachedLocationsCallbackNapi::~CachedLocationsCallbackNapi()
36 {
37 }
38
OnRemoteRequest(uint32_t code,MessageParcel & data,MessageParcel & reply,MessageOption & option)39 int CachedLocationsCallbackNapi::OnRemoteRequest(
40 uint32_t code, MessageParcel& data, MessageParcel& reply, MessageOption& option)
41 {
42 LBSLOGD(CACHED_LOCATIONS_CALLBACK, "CachedLocationsCallbackNapi::OnRemoteRequest!");
43 if (data.ReadInterfaceToken() != GetDescriptor()) {
44 LBSLOGE(CACHED_LOCATIONS_CALLBACK, "invalid token.");
45 return -1;
46 }
47 if (remoteDied_) {
48 LBSLOGD(CACHED_LOCATIONS_CALLBACK, "Failed to `%{public}s`,Remote service is died!", __func__);
49 return -1;
50 }
51
52 switch (code) {
53 case RECEIVE_CACHED_LOCATIONS_EVENT: {
54 int size = data.ReadInt32();
55 if (size > 0 && size < MAXIMUM_CACHE_LOCATIONS) {
56 std::vector<std::unique_ptr<Location>> locations(size);
57 for (int i = 0; i < size; i++) {
58 locations.push_back(Location::Unmarshalling(data));
59 }
60 Send(locations);
61 }
62 break;
63 }
64 default: {
65 IPCObjectStub::OnRemoteRequest(code, data, reply, option);
66 break;
67 }
68 }
69 return 0;
70 }
71
GetEnv()72 napi_env CachedLocationsCallbackNapi::GetEnv()
73 {
74 std::unique_lock<std::mutex> guard(mutex_);
75 return env_;
76 }
77
SetEnv(const napi_env & env)78 void CachedLocationsCallbackNapi::SetEnv(const napi_env& env)
79 {
80 std::unique_lock<std::mutex> guard(mutex_);
81 env_ = env;
82 }
83
GetHandleCb()84 napi_ref CachedLocationsCallbackNapi::GetHandleCb()
85 {
86 std::unique_lock<std::mutex> guard(mutex_);
87 return handlerCb_;
88 }
89
SetHandleCb(const napi_ref & handlerCb)90 void CachedLocationsCallbackNapi::SetHandleCb(const napi_ref& handlerCb)
91 {
92 {
93 std::unique_lock<std::mutex> guard(mutex_);
94 handlerCb_ = handlerCb;
95 }
96 std::unique_lock<std::mutex> guard(g_regCallbackMutex);
97 g_registerCallbacks.emplace_back(handlerCb);
98 }
99
FindCachedLocationsCallback(napi_ref cb)100 bool FindCachedLocationsCallback(napi_ref cb)
101 {
102 std::unique_lock<std::mutex> guard(g_regCallbackMutex);
103 auto iter = std::find(g_registerCallbacks.begin(), g_registerCallbacks.end(), cb);
104 if (iter == g_registerCallbacks.end()) {
105 return false;
106 }
107 return true;
108 }
109
DeleteCachedLocationsCallback(napi_ref cb)110 void DeleteCachedLocationsCallback(napi_ref cb)
111 {
112 std::unique_lock<std::mutex> guard(g_regCallbackMutex);
113 for (auto iter = g_registerCallbacks.begin(); iter != g_registerCallbacks.end(); iter++) {
114 if (*iter == cb) {
115 iter = g_registerCallbacks.erase(iter);
116 break;
117 }
118 }
119 }
120
IsRemoteDied()121 bool CachedLocationsCallbackNapi::IsRemoteDied()
122 {
123 return remoteDied_;
124 }
125
Send(std::vector<std::unique_ptr<Location>> & locations)126 bool CachedLocationsCallbackNapi::Send(std::vector<std::unique_ptr<Location>>& locations)
127 {
128 std::unique_lock<std::mutex> guard(mutex_);
129 uv_loop_s *loop = nullptr;
130 NAPI_CALL_BASE(env_, napi_get_uv_event_loop(env_, &loop), false);
131 if (loop == nullptr) {
132 LBSLOGE(CACHED_LOCATIONS_CALLBACK, "loop == nullptr.");
133 return false;
134 }
135 if (handlerCb_ == nullptr) {
136 LBSLOGE(CACHED_LOCATIONS_CALLBACK, "handler is nullptr.");
137 return false;
138 }
139 uv_work_t *work = new (std::nothrow) uv_work_t;
140 if (work == nullptr) {
141 LBSLOGE(CACHED_LOCATIONS_CALLBACK, "work == nullptr.");
142 return false;
143 }
144 CachedLocationAsyncContext *context = new (std::nothrow) CachedLocationAsyncContext(env_);
145 if (context == nullptr) {
146 LBSLOGE(CACHED_LOCATIONS_CALLBACK, "context == nullptr.");
147 delete work;
148 return false;
149 }
150 if (!InitContext(context)) {
151 LBSLOGE(CACHED_LOCATIONS_CALLBACK, "InitContext fail");
152 return false;
153 }
154 for (std::unique_ptr<Location>& location : locations) {
155 context->locationList.emplace_back(std::move(location));
156 }
157 work->data = context;
158 UvQueueWork(loop, work);
159 return true;
160 }
161
UvQueueWork(uv_loop_s * loop,uv_work_t * work)162 void CachedLocationsCallbackNapi::UvQueueWork(uv_loop_s* loop, uv_work_t* work)
163 {
164 uv_queue_work(
165 loop,
166 work,
167 [](uv_work_t *work) {},
168 [](uv_work_t *work, int status) {
169 CachedLocationAsyncContext *context = nullptr;
170 napi_handle_scope scope = nullptr;
171 if (work == nullptr) {
172 LBSLOGE(CACHED_LOCATIONS_CALLBACK, "work is nullptr");
173 return;
174 }
175 context = static_cast<CachedLocationAsyncContext *>(work->data);
176 if (context == nullptr || context->env == nullptr) {
177 LBSLOGE(CACHED_LOCATIONS_CALLBACK, "context is nullptr");
178 delete work;
179 return;
180 }
181 if (!FindCachedLocationsCallback(context->callback[0])) {
182 LBSLOGE(CACHED_LOCATIONS_CALLBACK, "no valid callback");
183 delete context;
184 delete work;
185 return;
186 }
187 NAPI_CALL_RETURN_VOID(context->env, napi_open_handle_scope(context->env, &scope));
188 if (scope == nullptr) {
189 LBSLOGE(CACHED_LOCATIONS_CALLBACK, "scope is nullptr");
190 delete context;
191 delete work;
192 return;
193 }
194 napi_value jsEvent = nullptr;
195 CHK_NAPI_ERR_CLOSE_SCOPE(context->env, napi_create_object(context->env, &jsEvent),
196 scope, context, work);
197 LocationsToJs(context->env, context->locationList, jsEvent);
198 if (context->callback[0] != nullptr) {
199 napi_value undefine;
200 napi_value handler = nullptr;
201 CHK_NAPI_ERR_CLOSE_SCOPE(context->env, napi_get_undefined(context->env, &undefine),
202 scope, context, work);
203 CHK_NAPI_ERR_CLOSE_SCOPE(context->env,
204 napi_get_reference_value(context->env, context->callback[0], &handler), scope, context, work);
205 if (napi_call_function(context->env, nullptr, handler, 1,
206 &jsEvent, &undefine) != napi_ok) {
207 LBSLOGE(CACHED_LOCATIONS_CALLBACK, "Report event failed");
208 }
209 }
210 NAPI_CALL_RETURN_VOID(context->env, napi_close_handle_scope(context->env, scope));
211 delete context;
212 delete work;
213 });
214 }
215
OnCacheLocationsReport(const std::vector<std::unique_ptr<Location>> & locations)216 void CachedLocationsCallbackNapi::OnCacheLocationsReport(const std::vector<std::unique_ptr<Location>>& locations)
217 {
218 LBSLOGD(CACHED_LOCATIONS_CALLBACK, "CachedLocationsCallbackNapi::OnCacheLocationsReport");
219 }
220
DeleteHandler()221 void CachedLocationsCallbackNapi::DeleteHandler()
222 {
223 std::unique_lock<std::mutex> guard(mutex_);
224 if (handlerCb_ == nullptr || env_ == nullptr) {
225 LBSLOGE(CACHED_LOCATIONS_CALLBACK, "handler or env is nullptr.");
226 return;
227 }
228 DeleteCachedLocationsCallback(handlerCb_);
229 NAPI_CALL_RETURN_VOID(env_, napi_delete_reference(env_, handlerCb_));
230 handlerCb_ = nullptr;
231 }
232 } // namespace Location
233 } // namespace OHOS
234