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