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