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