• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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