1 /*
2 * Copyright (c) 2022 Shenzhen Kaihong Digital Industry Development 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 "nfc_napi_controller_event.h"
17 #include <uv.h>
18 #include "loghelper.h"
19 #include "nfc_controller.h"
20 #include "nfc_sdk_common.h"
21
22 namespace OHOS {
23 namespace NFC {
24 namespace KITS {
25 const std::string EVENT_NFC_STATE_CHANGE = "nfcStateChange";
26
27 static std::set<std::string> g_supportEventList = {
28 EVENT_NFC_STATE_CHANGE,
29 };
30
31 bool EventRegister::isEventRegistered = false;
32
33 constexpr uint32_t INVALID_REF_COUNT = 0xFF;
34
35 static std::shared_mutex g_regInfoMutex;
36 static std::map<std::string, std::vector<RegObj>> g_eventRegisterInfo;
37
38 class NapiEvent {
39 public:
40 napi_value CreateResult(const napi_env& env, int value);
41 bool CheckIsRegister(const std::string& type);
42 void EventNotify(AsyncEventData *asyncEvent);
43
44 template<typename T>
CheckAndNotify(const std::string & type,const T & obj)45 void CheckAndNotify(const std::string& type, const T& obj)
46 {
47 std::shared_lock<std::shared_mutex> guard(g_regInfoMutex);
48 if (!CheckIsRegister(type)) {
49 return;
50 }
51
52 std::vector<RegObj>& vecObj = g_eventRegisterInfo[type];
53 for (const auto& each : vecObj) {
54 auto result = [this, env = each.m_regEnv, obj] () -> napi_value {
55 return CreateResult(env, obj);
56 };
57 AsyncEventData *asyncEvent =
58 new (std::nothrow)AsyncEventData(each.m_regEnv, each.m_regHanderRef, result);
59 if (asyncEvent == nullptr) {
60 return;
61 }
62 EventNotify(asyncEvent);
63 }
64 }
65 };
66
after_work_cb(uv_work_t * work,int status)67 static void after_work_cb(uv_work_t *work, int status)
68 {
69 AsyncEventData *asyncData = static_cast<AsyncEventData *>(work->data);
70 InfoLog("Napi event uv_queue_work, env: %{private}p, status: %{public}d", asyncData->env, status);
71 napi_value handler = nullptr;
72 napi_handle_scope scope = nullptr;
73 napi_value jsEvent = nullptr;
74 uint32_t refCount = INVALID_REF_COUNT;
75 napi_open_handle_scope(asyncData->env, &scope);
76 if (scope == nullptr) {
77 ErrorLog("scope is nullptr");
78 goto EXIT;
79 }
80
81 napi_get_reference_value(asyncData->env, asyncData->callbackRef, &handler);
82 if (handler == nullptr) {
83 ErrorLog("handler is nullptr");
84 goto EXIT;
85 }
86 napi_value undefine;
87 napi_get_undefined(asyncData->env, &undefine);
88 jsEvent = asyncData->packResult();
89 if (napi_call_function(asyncData->env, nullptr, handler, 1, &jsEvent, &undefine) != napi_ok) {
90 DebugLog("Report event to Js failed");
91 }
92
93 EXIT:
94 napi_close_handle_scope(asyncData->env, scope);
95 napi_reference_unref(asyncData->env, asyncData->callbackRef, &refCount);
96 InfoLog("after_work_cb unref, env: %{private}p, callbackRef: %{private}p, refCount: %{public}d",
97 asyncData->env, asyncData->callbackRef, refCount);
98 if (refCount == 0) {
99 napi_delete_reference(asyncData->env, asyncData->callbackRef);
100 }
101 delete asyncData;
102 delete work;
103 asyncData = nullptr;
104 work = nullptr;
105 }
106
EventNotify(AsyncEventData * asyncEvent)107 void NapiEvent::EventNotify(AsyncEventData *asyncEvent)
108 {
109 DebugLog("Enter nfc event notify");
110 if (asyncEvent == nullptr) {
111 DebugLog("asyncEvent is null.");
112 return;
113 }
114 uv_loop_s* loop = nullptr;
115 napi_get_uv_event_loop(asyncEvent->env, &loop);
116
117 uv_work_t* work = new uv_work_t;
118 if (work == nullptr) {
119 DebugLog("uv_work_t work is null.");
120 delete asyncEvent;
121 asyncEvent = nullptr;
122 return;
123 }
124
125 uint32_t refCount = INVALID_REF_COUNT;
126 napi_reference_ref(asyncEvent->env, asyncEvent->callbackRef, &refCount);
127 work->data = asyncEvent;
128 uv_after_work_cb tmp_after_work_cb = after_work_cb;
129 uv_queue_work(
130 loop,
131 work,
132 [](uv_work_t* work) {},
133 tmp_after_work_cb);
134 }
135
CreateResult(const napi_env & env,int value)136 napi_value NapiEvent::CreateResult(const napi_env& env, int value)
137 {
138 napi_value result;
139 napi_create_int32(env, value, &result);
140 return result;
141 }
142
CheckIsRegister(const std::string & type)143 bool NapiEvent::CheckIsRegister(const std::string& type)
144 {
145 return g_eventRegisterInfo.find(type) != g_eventRegisterInfo.end();
146 }
147
148 class NfcStateListenerEvent : public INfcControllerCallback, public NapiEvent {
149 public:
NfcStateListenerEvent()150 NfcStateListenerEvent() {
151 }
152
~NfcStateListenerEvent()153 virtual ~NfcStateListenerEvent() {
154 }
155
156 public:
OnNfcStateChanged(int nfcState)157 void OnNfcStateChanged(int nfcState) override
158 {
159 InfoLog("OnNotify rcvd nfcRfState: %{public}d", nfcState);
160 CheckAndNotify(EVENT_NFC_STATE_CHANGE, nfcState);
161 }
162
AsObject()163 OHOS::sptr<OHOS::IRemoteObject> AsObject() override
164 {
165 return nullptr;
166 }
167 };
168
169 sptr<NfcStateListenerEvent> nfcStateListenerEvent =
170 sptr<NfcStateListenerEvent>(new (std::nothrow) NfcStateListenerEvent());
171
On(napi_env env,napi_callback_info cbinfo)172 napi_value On(napi_env env, napi_callback_info cbinfo)
173 {
174 size_t requireArgc = 2;
175 size_t argc = 2;
176 napi_value argv[2] = {0};
177 napi_value thisVar = 0;
178 napi_get_cb_info(env, cbinfo, &argc, argv, &thisVar, nullptr);
179 NAPI_ASSERT(env, argc >= requireArgc, "requires 2 parameter");
180
181 napi_valuetype eventName = napi_undefined;
182 napi_typeof(env, argv[0], &eventName);
183 NAPI_ASSERT(env, eventName == napi_string, "type mismatch for parameter 1");
184
185 napi_valuetype handler = napi_undefined;
186 napi_typeof(env, argv[1], &handler);
187 NAPI_ASSERT(env, handler == napi_function, "type mismatch for parameter 2");
188
189 char type[64] = {0};
190 size_t typeLen = 0;
191 napi_get_value_string_utf8(env, argv[0], type, sizeof(type), &typeLen);
192 EventRegister::GetInstance().Register(env, type, argv[1]);
193 napi_value result = nullptr;
194 napi_get_undefined(env, &result);
195 return result;
196 }
197
198
Off(napi_env env,napi_callback_info cbinfo)199 napi_value Off(napi_env env, napi_callback_info cbinfo)
200 {
201 size_t requireArgc = 1;
202 size_t requireArgcWithCb = 2;
203 size_t argc = 2;
204 napi_value argv[2] = {0};
205 napi_value thisVar = 0;
206 napi_get_cb_info(env, cbinfo, &argc, argv, &thisVar, nullptr);
207 NAPI_ASSERT(env, argc >= requireArgc, "requires at least 1 parameter");
208
209 napi_valuetype eventName = napi_undefined;
210 napi_typeof(env, argv[0], &eventName);
211 NAPI_ASSERT(env, eventName == napi_string, "type mismatch for parameter 1");
212
213 if (argc >= requireArgcWithCb) {
214 napi_valuetype handler = napi_undefined;
215 napi_typeof(env, argv[1], &handler);
216 NAPI_ASSERT(env, handler == napi_function, "type mismatch for parameter 2");
217 }
218
219 char type[64] = {0};
220 size_t typeLen = 0;
221 napi_get_value_string_utf8(env, argv[0], type, sizeof(type), &typeLen);
222 EventRegister::GetInstance().Unregister(env, type, argc >= requireArgcWithCb ? argv[1] : nullptr);
223 napi_value result = nullptr;
224 napi_get_undefined(env, &result);
225 return result;
226 }
227
RegisterNfcStateChangedEvents(const std::string & type)228 ErrorCode EventRegister::RegisterNfcStateChangedEvents(const std::string& type)
229 {
230 NfcController nfcCtrl = NfcController::GetInstance();
231 ErrorCode ret = nfcCtrl.RegListener(nfcStateListenerEvent, type);
232 if (ret != KITS::ERR_NONE) {
233 DebugLog("RegisterNfcStateChangedEvents nfcListenerEvent failed!");
234 return ret;
235 }
236 return ret;
237 }
238
UnRegisterNfcEvents(const std::string & type)239 ErrorCode EventRegister::UnRegisterNfcEvents(const std::string& type)
240 {
241 NfcController nfcCtrl = OHOS::NFC::KITS::NfcController::GetInstance();
242 ErrorCode ret = nfcCtrl.UnregListener(type);
243 if (ret != KITS::ERR_NONE) {
244 DebugLog("UnRegisterNfcEvents nfcListenerEvent failed!");
245 return ret;
246 }
247 return ret;
248 }
249
GetInstance()250 EventRegister& EventRegister::GetInstance()
251 {
252 static EventRegister inst;
253 return inst;
254 }
255
IsEventSupport(const std::string & type)256 bool EventRegister::IsEventSupport(const std::string& type)
257 {
258 return g_supportEventList.find(type) != g_supportEventList.end();
259 }
260
Register(const napi_env & env,const std::string & type,napi_value handler)261 void EventRegister::Register(const napi_env& env, const std::string& type, napi_value handler)
262 {
263 InfoLog("Register event: %{public}s", type.c_str());
264 if (!IsEventSupport(type)) {
265 DebugLog("Register type error or not support!");
266 return;
267 }
268 std::unique_lock<std::shared_mutex> guard(g_regInfoMutex);
269 if (!isEventRegistered) {
270 if (RegisterNfcStateChangedEvents(type) != KITS::ERR_NONE) {
271 return;
272 }
273 isEventRegistered = true;
274 }
275 napi_ref handlerRef = nullptr;
276 napi_create_reference(env, handler, 1, &handlerRef);
277 RegObj regObj(env, handlerRef);
278 auto iter = g_eventRegisterInfo.find(type);
279 if (iter == g_eventRegisterInfo.end()) {
280 g_eventRegisterInfo[type] = std::vector<RegObj> {regObj};
281 DebugLog("Register, add new type.");
282 return;
283 }
284 auto miter = iter->second.begin();
285 for (; miter != iter->second.end();) {
286 if (env == miter->m_regEnv) {
287 napi_value handlerTemp = nullptr;
288 napi_get_reference_value(miter->m_regEnv, miter->m_regHanderRef, &handlerTemp);
289 bool isEqual = false;
290 napi_strict_equals(miter->m_regEnv, handlerTemp, handler, &isEqual);
291 if (isEqual) {
292 DebugLog("handler function is same");
293 ++miter;
294 } else {
295 iter->second.emplace_back(regObj);
296 break;
297 }
298 } else {
299 iter->second.emplace_back(regObj);
300 break;
301 }
302 }
303 }
304
DeleteRegisterObj(const napi_env & env,std::vector<RegObj> & vecRegObjs,napi_value & handler)305 void EventRegister::DeleteRegisterObj(const napi_env& env, std::vector<RegObj>& vecRegObjs, napi_value& handler)
306 {
307 auto iter = vecRegObjs.begin();
308 for (; iter != vecRegObjs.end();) {
309 if (env == iter->m_regEnv) {
310 napi_value handlerTemp = nullptr;
311 napi_get_reference_value(iter->m_regEnv, iter->m_regHanderRef, &handlerTemp);
312 bool isEqual = false;
313 if (handlerTemp == nullptr) {
314 DebugLog("handlerTemp is null");
315 }
316 if (handler == nullptr) {
317 DebugLog("handler is null");
318 }
319 napi_strict_equals(iter->m_regEnv, handlerTemp, handler, &isEqual);
320 DebugLog("Delete register isEqual = %{public}d", isEqual);
321 if (isEqual) {
322 uint32_t refCount = INVALID_REF_COUNT;
323 napi_reference_unref(iter->m_regEnv, iter->m_regHanderRef, &refCount);
324 InfoLog("delete ref, m_regEnv: %{private}p, m_regHanderRef: %{private}p, refCount: %{public}d",
325 iter->m_regEnv, iter->m_regHanderRef, refCount);
326 if (refCount == 0) {
327 napi_delete_reference(iter->m_regEnv, iter->m_regHanderRef);
328 }
329 DebugLog("Delete register object ref.");
330 iter = vecRegObjs.erase(iter);
331 } else {
332 ++iter;
333 }
334 } else {
335 DebugLog("Unregister event, env is not equal %{private}p, : %{private}p", env, iter->m_regEnv);
336 ++iter;
337 }
338 }
339 }
340
DeleteAllRegisterObj(const napi_env & env,std::vector<RegObj> & vecRegObjs)341 void EventRegister::DeleteAllRegisterObj(const napi_env& env, std::vector<RegObj>& vecRegObjs)
342 {
343 auto iter = vecRegObjs.begin();
344 for (; iter != vecRegObjs.end();) {
345 if (env == iter->m_regEnv) {
346 uint32_t refCount = INVALID_REF_COUNT;
347 napi_reference_unref(iter->m_regEnv, iter->m_regHanderRef, &refCount);
348 InfoLog("delete all ref, m_regEnv: %{private}p, m_regHanderRef: %{private}p, refCount: %{public}d",
349 iter->m_regEnv, iter->m_regHanderRef, refCount);
350 if (refCount == 0) {
351 napi_delete_reference(iter->m_regEnv, iter->m_regHanderRef);
352 }
353 iter = vecRegObjs.erase(iter);
354 } else {
355 DebugLog("Unregister all event, env is not equal %{private}p, : %{private}p", env, iter->m_regEnv);
356 ++iter;
357 }
358 }
359 }
360
Unregister(const napi_env & env,const std::string & type,napi_value handler)361 void EventRegister::Unregister(const napi_env& env, const std::string& type, napi_value handler)
362 {
363 InfoLog("Unregister event: %{public}s", type.c_str());
364 if (!IsEventSupport(type)) {
365 DebugLog("Unregister type error or not support!");
366 return;
367 }
368 std::unique_lock<std::shared_mutex> guard(g_regInfoMutex);
369 auto iter = g_eventRegisterInfo.find(type);
370 if (iter == g_eventRegisterInfo.end()) {
371 DebugLog("Unregister type not registered!");
372 if (UnRegisterNfcEvents(type) != KITS::ERR_NONE) {
373 ErrorLog("UnRegisterNfcEvents failed.");
374 }
375 return;
376 }
377 if (handler != nullptr) {
378 DeleteRegisterObj(env, iter->second, handler);
379 } else {
380 InfoLog("All callback is unsubscribe for event: %{public}s", type.c_str());
381 DeleteAllRegisterObj(env, iter->second);
382 }
383 if (iter->second.empty()) {
384 g_eventRegisterInfo.erase(iter);
385 if (UnRegisterNfcEvents(type) != KITS::ERR_NONE) {
386 ErrorLog("UnRegisterNfcEvents failed.");
387 }
388 isEventRegistered = false;
389 }
390 }
391 } // namespace KITS
392 } // namespace NFC
393 } // namespace OHOS
394