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 if (handler == napi_null || handler == napi_undefined) {
217 argc -= 1;
218 DebugLog("argv[1] is null or undefined, handle as no argv[1] input");
219 } else {
220 NAPI_ASSERT(env, handler == napi_function, "type mismatch for parameter 2");
221 }
222 }
223
224 char type[64] = {0};
225 size_t typeLen = 0;
226 napi_get_value_string_utf8(env, argv[0], type, sizeof(type), &typeLen);
227 EventRegister::GetInstance().Unregister(env, type, argc >= requireArgcWithCb ? argv[1] : nullptr);
228 napi_value result = nullptr;
229 napi_get_undefined(env, &result);
230 return result;
231 }
232
RegisterNfcStateChangedEvents(const std::string & type)233 ErrorCode EventRegister::RegisterNfcStateChangedEvents(const std::string& type)
234 {
235 NfcController nfcCtrl = NfcController::GetInstance();
236 ErrorCode ret = nfcCtrl.RegListener(nfcStateListenerEvent, type);
237 if (ret != KITS::ERR_NONE) {
238 DebugLog("RegisterNfcStateChangedEvents nfcListenerEvent failed!");
239 return ret;
240 }
241 return ret;
242 }
243
UnRegisterNfcEvents(const std::string & type)244 ErrorCode EventRegister::UnRegisterNfcEvents(const std::string& type)
245 {
246 NfcController nfcCtrl = OHOS::NFC::KITS::NfcController::GetInstance();
247 ErrorCode ret = nfcCtrl.UnregListener(type);
248 if (ret != KITS::ERR_NONE) {
249 DebugLog("UnRegisterNfcEvents nfcListenerEvent failed!");
250 return ret;
251 }
252 return ret;
253 }
254
GetInstance()255 EventRegister& EventRegister::GetInstance()
256 {
257 static EventRegister inst;
258 return inst;
259 }
260
IsEventSupport(const std::string & type)261 bool EventRegister::IsEventSupport(const std::string& type)
262 {
263 return g_supportEventList.find(type) != g_supportEventList.end();
264 }
265
Register(const napi_env & env,const std::string & type,napi_value handler)266 void EventRegister::Register(const napi_env& env, const std::string& type, napi_value handler)
267 {
268 InfoLog("Register event: %{public}s", type.c_str());
269 if (!IsEventSupport(type)) {
270 DebugLog("Register type error or not support!");
271 return;
272 }
273 std::unique_lock<std::shared_mutex> guard(g_regInfoMutex);
274 if (!isEventRegistered) {
275 if (RegisterNfcStateChangedEvents(type) != KITS::ERR_NONE) {
276 return;
277 }
278 isEventRegistered = true;
279 }
280 napi_ref handlerRef = nullptr;
281 napi_create_reference(env, handler, 1, &handlerRef);
282 RegObj regObj(env, handlerRef);
283 auto iter = g_eventRegisterInfo.find(type);
284 if (iter == g_eventRegisterInfo.end()) {
285 g_eventRegisterInfo[type] = std::vector<RegObj> {regObj};
286 DebugLog("Register, add new type.");
287 return;
288 }
289 auto miter = iter->second.begin();
290 for (; miter != iter->second.end();) {
291 if (env == miter->m_regEnv) {
292 napi_value handlerTemp = nullptr;
293 napi_get_reference_value(miter->m_regEnv, miter->m_regHanderRef, &handlerTemp);
294 bool isEqual = false;
295 napi_strict_equals(miter->m_regEnv, handlerTemp, handler, &isEqual);
296 if (isEqual) {
297 DebugLog("handler function is same");
298 ++miter;
299 } else {
300 iter->second.emplace_back(regObj);
301 break;
302 }
303 } else {
304 iter->second.emplace_back(regObj);
305 break;
306 }
307 }
308 }
309
DeleteRegisterObj(const napi_env & env,std::vector<RegObj> & vecRegObjs,napi_value & handler)310 void EventRegister::DeleteRegisterObj(const napi_env& env, std::vector<RegObj>& vecRegObjs, napi_value& handler)
311 {
312 auto iter = vecRegObjs.begin();
313 for (; iter != vecRegObjs.end();) {
314 if (env == iter->m_regEnv) {
315 napi_value handlerTemp = nullptr;
316 napi_get_reference_value(iter->m_regEnv, iter->m_regHanderRef, &handlerTemp);
317 bool isEqual = false;
318 if (handlerTemp == nullptr) {
319 DebugLog("handlerTemp is null");
320 }
321 if (handler == nullptr) {
322 DebugLog("handler is null");
323 }
324 napi_strict_equals(iter->m_regEnv, handlerTemp, handler, &isEqual);
325 DebugLog("Delete register isEqual = %{public}d", isEqual);
326 if (isEqual) {
327 uint32_t refCount = INVALID_REF_COUNT;
328 napi_reference_unref(iter->m_regEnv, iter->m_regHanderRef, &refCount);
329 InfoLog("delete ref, m_regEnv: %{private}p, m_regHanderRef: %{private}p, refCount: %{public}d",
330 iter->m_regEnv, iter->m_regHanderRef, refCount);
331 if (refCount == 0) {
332 napi_delete_reference(iter->m_regEnv, iter->m_regHanderRef);
333 }
334 DebugLog("Delete register object ref.");
335 iter = vecRegObjs.erase(iter);
336 } else {
337 ++iter;
338 }
339 } else {
340 DebugLog("Unregister event, env is not equal %{private}p, : %{private}p", env, iter->m_regEnv);
341 ++iter;
342 }
343 }
344 }
345
DeleteAllRegisterObj(const napi_env & env,std::vector<RegObj> & vecRegObjs)346 void EventRegister::DeleteAllRegisterObj(const napi_env& env, std::vector<RegObj>& vecRegObjs)
347 {
348 auto iter = vecRegObjs.begin();
349 for (; iter != vecRegObjs.end();) {
350 if (env == iter->m_regEnv) {
351 uint32_t refCount = INVALID_REF_COUNT;
352 napi_reference_unref(iter->m_regEnv, iter->m_regHanderRef, &refCount);
353 InfoLog("delete all ref, m_regEnv: %{private}p, m_regHanderRef: %{private}p, refCount: %{public}d",
354 iter->m_regEnv, iter->m_regHanderRef, refCount);
355 if (refCount == 0) {
356 napi_delete_reference(iter->m_regEnv, iter->m_regHanderRef);
357 }
358 iter = vecRegObjs.erase(iter);
359 } else {
360 DebugLog("Unregister all event, env is not equal %{private}p, : %{private}p", env, iter->m_regEnv);
361 ++iter;
362 }
363 }
364 }
365
Unregister(const napi_env & env,const std::string & type,napi_value handler)366 void EventRegister::Unregister(const napi_env& env, const std::string& type, napi_value handler)
367 {
368 InfoLog("Unregister event: %{public}s", type.c_str());
369 if (!IsEventSupport(type)) {
370 DebugLog("Unregister type error or not support!");
371 return;
372 }
373 std::unique_lock<std::shared_mutex> guard(g_regInfoMutex);
374 auto iter = g_eventRegisterInfo.find(type);
375 if (iter == g_eventRegisterInfo.end()) {
376 DebugLog("Unregister type not registered!");
377 if (UnRegisterNfcEvents(type) != KITS::ERR_NONE) {
378 ErrorLog("UnRegisterNfcEvents failed.");
379 }
380 return;
381 }
382 if (handler != nullptr) {
383 DeleteRegisterObj(env, iter->second, handler);
384 } else {
385 InfoLog("All callback is unsubscribe for event: %{public}s", type.c_str());
386 DeleteAllRegisterObj(env, iter->second);
387 }
388 if (iter->second.empty()) {
389 g_eventRegisterInfo.erase(iter);
390 if (UnRegisterNfcEvents(type) != KITS::ERR_NONE) {
391 ErrorLog("UnRegisterNfcEvents failed.");
392 }
393 isEventRegistered = false;
394 }
395 }
396 } // namespace KITS
397 } // namespace NFC
398 } // namespace OHOS
399