• 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         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