1 /*
2  * Copyright (c) 2021-2023 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 "events_emitter.h"
17 
18 #include <iterator>
19 #include <memory>
20 #include <mutex>
21 #include <new>
22 #include <uv.h>
23 #include <unordered_set>
24 #include "event_logger.h"
25 #include "js_native_api_types.h"
26 #include "napi/native_node_api.h"
27 
28 using namespace std;
29 namespace OHOS {
30 namespace AppExecFwk {
31 namespace {
32     DEFINE_EH_HILOG_LABEL("EventsEmitter");
33     constexpr static uint32_t ARGC_ONE = 1u;
34 }
35     static std::mutex g_emitterInsMutex;
36     static map<InnerEvent::EventId, std::unordered_set<std::shared_ptr<AsyncCallbackInfo>>> emitterInstances;
37     std::shared_ptr<EventHandlerInstance> eventHandler;
~AsyncCallbackInfo()38     AsyncCallbackInfo::~AsyncCallbackInfo()
39     {
40         env = nullptr;
41     }
EventHandlerInstance(const std::shared_ptr<EventRunner> & runner)42     EventHandlerInstance::EventHandlerInstance(const std::shared_ptr<EventRunner>& runner): EventHandler(runner)
43     {
44         HILOGI("EventHandlerInstance constructed");
45     }
~EventHandlerInstance()46     EventHandlerInstance::~EventHandlerInstance()
47     {
48         HILOGI("EventHandlerInstance de-constructed");
49     }
GetInstance()50     std::shared_ptr<EventHandlerInstance> EventHandlerInstance::GetInstance()
51     {
52         static auto runner = EventRunner::Create("OS_eventsEmtr", ThreadMode::FFRT);
53         if (runner.get() == nullptr) {
54             HILOGE("failed to create EventRunner events_emitter");
55             return nullptr;
56         }
57         static auto instance = std::make_shared<EventHandlerInstance>(runner);
58         return instance;
59     }
60 
ProcessCallback(const EventDataWorker * eventDataInner)61     void ProcessCallback(const EventDataWorker* eventDataInner)
62     {
63         HILOGD("enter");
64 
65         std::shared_ptr<AsyncCallbackInfo> callbackInner = eventDataInner->callbackInfo;
66         napi_value resultData = nullptr;
67         if (eventDataInner->data != nullptr && *(eventDataInner->data) != nullptr) {
68             if (napi_deserialize(callbackInner->env, *(eventDataInner->data), &resultData) != napi_ok ||
69                 resultData == nullptr) {
70                 HILOGE("Deserialize fail.");
71                 return;
72             }
73         }
74         napi_value event = nullptr;
75         napi_create_object(callbackInner->env, &event);
76         napi_set_named_property(callbackInner->env, event, "data", resultData);
77         napi_value callback = nullptr;
78         napi_value returnVal = nullptr;
79         napi_get_reference_value(callbackInner->env, callbackInner->callback, &callback);
80         napi_call_function(callbackInner->env, nullptr, callback, 1, &event, &returnVal);
81         if (callbackInner->once) {
82             HILOGD("ProcessEvent delete once");
83             std::lock_guard<std::mutex> lock(g_emitterInsMutex);
84             auto iter = emitterInstances.find(callbackInner->eventId);
85             if (iter != emitterInstances.end()) {
86                 auto callback = iter->second.find(callbackInner);
87                 if (callback != iter->second.end()) {
88                     iter->second.erase(callback);
89                 }
90             }
91         }
92     }
93 
OutPutEventIdLog(const InnerEvent::EventId & eventId)94     void OutPutEventIdLog(const InnerEvent::EventId &eventId)
95     {
96         if (eventId.index() == TYPE_U32_INDEX) {
97             HILOGD("Event id value:%{public}u", std::get<uint32_t>(eventId));
98         } else {
99             HILOGD("Event id value:%{public}s", std::get<std::string>(eventId).c_str());
100         }
101     }
102 
ThreadSafeCallback(napi_env env,napi_value jsCallback,void * context,void * data)103     void ThreadSafeCallback(napi_env env, napi_value jsCallback, void* context, void* data)
104     {
105         napi_handle_scope scope;
106         EventDataWorker* eventDataInner = static_cast<EventDataWorker*>(data);
107         if (eventDataInner != nullptr) {
108             auto callbackInfoInner = eventDataInner->callbackInfo;
109             if (callbackInfoInner && !(callbackInfoInner->isDeleted)) {
110                 HILOGD("eventDataInner address: %{public}p", &eventDataInner);
111                 napi_open_handle_scope(callbackInfoInner->env, &scope);
112                 if (scope == nullptr) {
113                     HILOGD("Scope is null");
114                     return;
115                 }
116                 ProcessCallback(eventDataInner);
117                 napi_close_handle_scope(callbackInfoInner->env, scope);
118             }
119         }
120         delete eventDataInner;
121         eventDataInner = nullptr;
122         data = nullptr;
123     }
124 
GetAsyncCallbackInfo(const InnerEvent::EventId & eventId)125     std::unordered_set<std::shared_ptr<AsyncCallbackInfo>> EventHandlerInstance::GetAsyncCallbackInfo(
126         const InnerEvent::EventId &eventId)
127     {
128         std::lock_guard<std::mutex> lock(g_emitterInsMutex);
129         auto iter = emitterInstances.find(eventId);
130         if (iter == emitterInstances.end()) {
131             std::unordered_set<std::shared_ptr<AsyncCallbackInfo>> result;
132             HILOGW("ProcessEvent has no callback");
133             return result;
134         }
135         for (auto it = iter->second.begin(); it != iter->second.end();) {
136             if ((*it)->isDeleted == true || (*it)->env == nullptr) {
137                 it = iter->second.erase(it);
138                 continue;
139             }
140             ++it;
141         }
142         return iter->second;
143     }
144 
145     void EventHandlerInstance::ProcessEvent([[maybe_unused]] const InnerEvent::Pointer& event)
146     {
147         InnerEvent::EventId eventId = event->GetInnerEventIdEx();
148         OutPutEventIdLog(eventId);
149         auto callbackInfos = GetAsyncCallbackInfo(eventId);
150         if (callbackInfos.size() <= 0) {
151             HILOGW("ProcessEvent has no valid callback");
152             return;
153         }
154 
155         size_t callbackSize = callbackInfos.size();
156         HILOGD("size = %{public}zu", callbackSize);
157         auto value = event->GetUniqueObject<napi_value>();
__anon72fa0aed0202(napi_value* pData) 158         std::shared_ptr<napi_value> eventData(value.release(), [this](napi_value* pData) {
159             if (pData != nullptr && (*pData) != nullptr && deleteEnv != nullptr) {
160                 napi_delete_serialization_data(deleteEnv, *pData);
161             } else {
162                 HILOGW("EventData delete release failed.");
163             }
164         });
165         for (auto it = callbackInfos.begin(); it != callbackInfos.end(); ++it) {
166             callbackSize--;
167             EventDataWorker* eventDataWorker = new (std::nothrow) EventDataWorker();
168             if (!eventDataWorker) {
169                 HILOGE("new object failed");
170                 if (callbackSize == 0) {
171                     HILOGW("EventData maybe release at process %{public}zu", callbackInfos.size());
172                 }
173                 continue;
174             }
175             if ((*it)->env == nullptr || (*it)->isDeleted) {
176                 HILOGE("env is release");
177                 if (callbackSize == 0) {
178                     HILOGW("EventData maybe release at nullptr %{public}zu", callbackInfos.size());
179                 }
180                 delete eventDataWorker;
181                 continue;
182             }
183             deleteEnv = (*it)->env;
184             eventDataWorker->data = eventData;
185             if (callbackSize == 0) {
186                 eventData.reset();
187             }
188             eventDataWorker->callbackInfo = (*it);
189             napi_acquire_threadsafe_function((*it)->tsfn);
190             napi_call_threadsafe_function((*it)->tsfn, eventDataWorker, napi_tsfn_nonblocking);
191             napi_release_threadsafe_function((*it)->tsfn, napi_tsfn_release);
192         }
193     }
194 
UpdateOnceFlag(std::shared_ptr<AsyncCallbackInfo> callbackInfo,bool once)195     static void UpdateOnceFlag(std::shared_ptr<AsyncCallbackInfo>callbackInfo, bool once)
196     {
197         if (!once) {
198             if (callbackInfo->once) {
199                 HILOGD("JS_On change once to on");
200                 callbackInfo->once = false;
201             } else {
202                 HILOGD("JS_On already on");
203             }
204         } else {
205             if (callbackInfo->once) {
206                 HILOGD("JS_Once already once");
207             } else {
208                 HILOGD("JS_Once change on to once");
209                 callbackInfo->once = true;
210             }
211         }
212     }
213 
DeleteCallbackInfo(napi_env env,const InnerEvent::EventId & eventIdValue,napi_value argv)214     void DeleteCallbackInfo(napi_env env, const InnerEvent::EventId &eventIdValue, napi_value argv)
215     {
216         std::lock_guard<std::mutex> lock(g_emitterInsMutex);
217         auto iter = emitterInstances.find(eventIdValue);
218         if (iter == emitterInstances.end()) {
219             return;
220         }
221         for (auto callbackInfo = iter->second.begin(); callbackInfo != iter->second.end();) {
222             napi_value callback = nullptr;
223             if ((*callbackInfo)->env != env) {
224                 ++callbackInfo;
225                 continue;
226             }
227             napi_get_reference_value((*callbackInfo)->env, (*callbackInfo)->callback, &callback);
228             bool isEq = false;
229             napi_strict_equals(env, argv, callback, &isEq);
230             if (!isEq) {
231                 ++callbackInfo;
232                 continue;
233             }
234             (*callbackInfo)->isDeleted = true;
235             callbackInfo = iter->second.erase(callbackInfo);
236             return;
237         }
238         return;
239     }
240 
SearchCallbackInfo(napi_env env,const InnerEvent::EventId & eventIdValue,napi_value argv)241     std::shared_ptr<AsyncCallbackInfo> SearchCallbackInfo(napi_env env, const InnerEvent::EventId &eventIdValue,
242         napi_value argv)
243     {
244         auto subscribe = emitterInstances.find(eventIdValue);
245         if (subscribe == emitterInstances.end()) {
246             return nullptr;
247         }
248         for (auto callbackInfo : subscribe->second) {
249             napi_value callback = nullptr;
250             if (callbackInfo->isDeleted) {
251                 continue;
252             }
253             if (callbackInfo->env != env) {
254                 continue;
255             }
256             napi_get_reference_value(callbackInfo->env, callbackInfo->callback, &callback);
257             bool isEq = false;
258             napi_strict_equals(env, argv, callback, &isEq);
259             if (!isEq) {
260                 continue;
261             }
262             return callbackInfo;
263         }
264         return nullptr;
265     }
266 
GetEventIdWithObjectOrString(napi_env env,napi_value argv,napi_valuetype eventValueType,InnerEvent::EventId & eventId)267     bool GetEventIdWithObjectOrString(
268         napi_env env, napi_value argv, napi_valuetype eventValueType, InnerEvent::EventId &eventId)
269     {
270         if (eventValueType == napi_string) {
271             auto valueCStr = std::make_unique<char[]>(NAPI_VALUE_STRING_LEN + 1);
272             size_t valueStrLength = 0;
273             napi_get_value_string_utf8(env, argv, valueCStr.get(), NAPI_VALUE_STRING_LEN, &valueStrLength);
274             std::string id(valueCStr.get(), valueStrLength);
275             if (id.empty()) {
276                 HILOGE("Event id is empty for argument 1.");
277                 return false;
278             }
279             eventId = id;
280             HILOGD("Event id value:%{public}s", id.c_str());
281         } else {
282             bool hasEventId = false;
283             napi_has_named_property(env, argv, "eventId", &hasEventId);
284             if (!hasEventId) {
285                 HILOGE("Argument 1 does not have event id.");
286                 return false;
287             }
288 
289             napi_value eventIdValue = nullptr;
290             napi_get_named_property(env, argv, "eventId", &eventIdValue);
291             uint32_t id = 0u;
292             napi_get_value_uint32(env, eventIdValue, &id);
293             eventId = id;
294             HILOGD("Event id value:%{public}u", id);
295         }
296         return true;
297     }
298 
299     void ThreadFinished(napi_env env, void* data, [[maybe_unused]] void* context)
300     {
301         HILOGD("ThreadFinished");
302     }
303 
ReleaseCallbackInfo(AsyncCallbackInfo * callbackInfo)304     void ReleaseCallbackInfo(AsyncCallbackInfo* callbackInfo)
305     {
306         if (callbackInfo != nullptr) {
307             uv_loop_s *loop = nullptr;
308             if (napi_get_uv_event_loop(callbackInfo->env, &loop) != napi_ok) {
309                 delete callbackInfo;
310                 callbackInfo = nullptr;
311                 return;
312             }
313             uv_work_t *work = new (std::nothrow) uv_work_t;
314             if (work == nullptr) {
315                 delete callbackInfo;
316                 callbackInfo = nullptr;
317                 return;
318             }
319             work->data = reinterpret_cast<void*>(callbackInfo);
320             auto ret = uv_queue_work_with_qos(loop, work, [](uv_work_t* work) {},
321             [](uv_work_t *work, int status) {
322                 AsyncCallbackInfo* callbackInfo = reinterpret_cast<AsyncCallbackInfo*>(work->data);
323                 if (napi_delete_reference(callbackInfo->env, callbackInfo->callback) != napi_ok) {
324                     HILOGE("napi_delete_reference fail.");
325                 }
326                 napi_release_threadsafe_function(callbackInfo->tsfn, napi_tsfn_release);
327                 delete callbackInfo;
328                 callbackInfo = nullptr;
329                 delete work;
330                 work = nullptr;
331             }, uv_qos_user_initiated);
332             if (ret != napi_ok)  {
333                 delete callbackInfo;
334                 callbackInfo = nullptr;
335                 delete work;
336                 work = nullptr;
337             }
338         }
339     }
340 
OnOrOnce(napi_env env,napi_callback_info cbinfo,bool once)341     napi_value OnOrOnce(napi_env env, napi_callback_info cbinfo, bool once)
342     {
343         size_t argc = ARGC_NUM;
344         napi_value argv[ARGC_NUM] = {0};
345         NAPI_CALL(env, napi_get_cb_info(env, cbinfo, &argc, argv, NULL, NULL));
346         if (argc < ARGC_NUM) {
347             HILOGE("requires 2 parameter");
348             return nullptr;
349         }
350 
351         napi_valuetype eventValueType = GetNapiType(env, argv[0]);
352         if (eventValueType != napi_object && eventValueType != napi_string) {
353             HILOGE("type mismatch for parameter 1");
354             return nullptr;
355         }
356 
357         if (GetNapiType(env, argv[1]) != napi_function) {
358             HILOGE("type mismatch for parameter 2");
359             return nullptr;
360         }
361 
362         InnerEvent::EventId eventIdValue = 0u;
363         bool ret = GetEventIdWithObjectOrString(env, argv[0], eventValueType, eventIdValue);
364         if (!ret) {
365             return nullptr;
366         }
367         std::lock_guard<std::mutex> lock(g_emitterInsMutex);
368         auto callbackInfo = SearchCallbackInfo(env, eventIdValue, argv[1]);
369         if (callbackInfo != nullptr) {
370             UpdateOnceFlag(callbackInfo, once);
371         } else {
372             callbackInfo = std::shared_ptr<AsyncCallbackInfo>(new (std::nothrow) AsyncCallbackInfo(),
373                 [](AsyncCallbackInfo* callbackInfo) {
374                 ReleaseCallbackInfo(callbackInfo);
375             });
376             if (!callbackInfo) {
377                 HILOGE("new object failed");
378                 return nullptr;
379             }
380             callbackInfo->env = env;
381             callbackInfo->once = once;
382             callbackInfo->eventId = eventIdValue;
383             napi_create_reference(env, argv[1], 1, &callbackInfo->callback);
384             napi_wrap(env, argv[1], new (std::nothrow) std::weak_ptr<AsyncCallbackInfo>(callbackInfo),
385                 [](napi_env env, void* data, void* hint) {
386                 auto callbackInfoPtr = static_cast<std::weak_ptr<AsyncCallbackInfo>*>(data);
387                 if (callbackInfoPtr != nullptr && (*callbackInfoPtr).lock() != nullptr) {
388                     (*callbackInfoPtr).lock()->isDeleted = true;
389                     (*callbackInfoPtr).lock()->env = nullptr;
390                 }
391             }, nullptr, nullptr);
392             napi_value resourceName = nullptr;
393             napi_create_string_utf8(env, "Call thread-safe function", NAPI_AUTO_LENGTH, &resourceName);
394             napi_create_threadsafe_function(env, argv[1], nullptr, resourceName, 0, 1, nullptr, ThreadFinished,
395                 nullptr, ThreadSafeCallback, &(callbackInfo->tsfn));
396             emitterInstances[eventIdValue].insert(callbackInfo);
397         }
398         return nullptr;
399     }
400 
GetEventIdWithNumberOrString(napi_env env,napi_value argv,napi_valuetype eventValueType,InnerEvent::EventId & eventId)401     bool GetEventIdWithNumberOrString(
402         napi_env env, napi_value argv, napi_valuetype eventValueType, InnerEvent::EventId &eventId)
403     {
404         if (eventValueType == napi_string) {
405             auto valueCStr = std::make_unique<char[]>(NAPI_VALUE_STRING_LEN + 1);
406             size_t valueStrLength = 0;
407             napi_get_value_string_utf8(env, argv, valueCStr.get(), NAPI_VALUE_STRING_LEN, &valueStrLength);
408             std::string id(valueCStr.get(), valueStrLength);
409             if (id.empty()) {
410                 return false;
411             }
412             eventId = id;
413             HILOGD("Event id value:%{public}s", id.c_str());
414         } else {
415             uint32_t id = 0u;
416             napi_get_value_uint32(env, argv, &id);
417             eventId = id;
418             HILOGD("Event id value:%{public}u", id);
419         }
420         return true;
421     }
422 
JS_On(napi_env env,napi_callback_info cbinfo)423     napi_value JS_On(napi_env env, napi_callback_info cbinfo)
424     {
425         HILOGD("enter");
426         return OnOrOnce(env, cbinfo, false);
427     }
428 
JS_Once(napi_env env,napi_callback_info cbinfo)429     napi_value JS_Once(napi_env env, napi_callback_info cbinfo)
430     {
431         HILOGD("enter");
432         return OnOrOnce(env, cbinfo, true);
433     }
434 
JS_Off(napi_env env,napi_callback_info cbinfo)435     napi_value JS_Off(napi_env env, napi_callback_info cbinfo)
436     {
437         HILOGD("enter");
438         size_t argc = ARGC_NUM;
439         napi_value argv[ARGC_NUM] = {0};
440         NAPI_CALL(env, napi_get_cb_info(env, cbinfo, &argc, argv, NULL, NULL));
441         if (argc < 1) {
442             HILOGE("requires at least 1 parameter");
443             return nullptr;
444         }
445 
446         napi_valuetype eventValueType;
447         napi_typeof(env, argv[0], &eventValueType);
448         if (eventValueType != napi_number && eventValueType != napi_string) {
449             HILOGE("type mismatch for parameter 1");
450             return nullptr;
451         }
452 
453         InnerEvent::EventId eventId = 0u;
454         bool ret = GetEventIdWithNumberOrString(env, argv[0], eventValueType, eventId);
455         if (!ret) {
456             HILOGE("Event id is empty for parameter 1.");
457             return nullptr;
458         }
459 
460         if (argc == ARGC_NUM) {
461             napi_valuetype eventHandleType;
462             napi_typeof(env, argv[1], &eventHandleType);
463             if (eventHandleType != napi_function) {
464                 HILOGE("type mismatch for parameter 2");
465                 return nullptr;
466             }
467             DeleteCallbackInfo(env, eventId, argv[1]);
468             return nullptr;
469         }
470         std::lock_guard<std::mutex> lock(g_emitterInsMutex);
471         auto iter = emitterInstances.find(eventId);
472         if (iter != emitterInstances.end()) {
473             for (auto callbackInfo : iter->second) {
474                 callbackInfo->isDeleted = true;
475             }
476         }
477         emitterInstances.erase(eventId);
478         return nullptr;
479     }
480 
EmitWithEventData(napi_env env,napi_value argv,const InnerEvent::EventId & eventId,Priority priority)481     bool EmitWithEventData(napi_env env, napi_value argv, const InnerEvent::EventId &eventId, Priority priority)
482     {
483         HILOGD("enter");
484         napi_valuetype dataType;
485         napi_typeof(env, argv, &dataType);
486         if (dataType != napi_object) {
487             HILOGE("type mismatch for parameter 2");
488             return false;
489         }
490         bool hasData = false;
491         void* serializeData = nullptr;
492         napi_has_named_property(env, argv, "data", &hasData);
493         if (hasData) {
494             napi_value data = nullptr;
495             napi_get_named_property(env, argv, "data", &data);
496             napi_status serializeResult = napi_ok;
497             napi_value undefined = nullptr;
498             napi_get_undefined(env, &undefined);
499             bool defaultTransfer = false;
500             bool defaultCloneSendable = false;
501             serializeResult = napi_serialize_inner(env, data, undefined, undefined,
502                                                    defaultTransfer, defaultCloneSendable, &serializeData);
503             if (serializeResult != napi_ok || serializeData == nullptr) {
504                 HILOGE("Serialize fail.");
505                 return false;
506             }
507         }
508         OutPutEventIdLog(eventId);
509         auto event = InnerEvent::Get(eventId, make_unique<napi_value>(reinterpret_cast<napi_value>(serializeData)));
510         eventHandler->SendEvent(event, 0, priority);
511         return true;
512     }
513 
IsExistValidCallback(napi_env env,const InnerEvent::EventId & eventId)514     bool IsExistValidCallback(napi_env env, const InnerEvent::EventId &eventId)
515     {
516         std::lock_guard<std::mutex> lock(g_emitterInsMutex);
517         auto subscribe = emitterInstances.find(eventId);
518         if (subscribe == emitterInstances.end()) {
519             EH_LOGW_LIMIT("JS_Emit has no callback");
520             return false;
521         }
522         if (subscribe->second.size() != 0) {
523             return true;
524         }
525         return false;
526     }
527 
EmitWithEventIdUint32(napi_env env,size_t argc,napi_value argv[])528     napi_value EmitWithEventIdUint32(napi_env env, size_t argc, napi_value argv[])
529     {
530         InnerEvent::EventId eventId = 0u;
531         bool hasEventId = false;
532         napi_value value = nullptr;
533         napi_has_named_property(env, argv[0], "eventId", &hasEventId);
534         if (hasEventId == false) {
535             HILOGE("Wrong argument 1 does not have event id.");
536             return nullptr;
537         }
538 
539         napi_get_named_property(env, argv[0], "eventId", &value);
540         uint32_t id = 0u;
541         napi_get_value_uint32(env, value, &id);
542         eventId = id;
543         HILOGD("Event id value:%{public}u", id);
544 
545         if (!IsExistValidCallback(env, eventId)) {
546             EH_LOGE_LIMIT("Invalid callback");
547             return nullptr;
548         }
549 
550         bool hasPriority = false;
551         napi_has_named_property(env, argv[0], "priority", &hasPriority);
552         Priority priority = Priority::LOW;
553         if (hasPriority) {
554             napi_get_named_property(env, argv[0], "priority", &value);
555             uint32_t priorityValue = 0u;
556             napi_get_value_uint32(env, value, &priorityValue);
557             HILOGD("Event priority:%{public}d", priorityValue);
558             priority = static_cast<Priority>(priorityValue);
559         }
560 
561         if (argc == ARGC_NUM && EmitWithEventData(env, argv[1], eventId, priority)) {
562             return nullptr;
563         } else {
564             auto event = InnerEvent::Get(eventId, make_unique<EventData>());
565             eventHandler->SendEvent(event, 0, priority);
566         }
567         return nullptr;
568     }
569 
EmitWithEventIdString(napi_env env,size_t argc,napi_value argv[])570     napi_value EmitWithEventIdString(napi_env env, size_t argc, napi_value argv[])
571     {
572         InnerEvent::EventId eventId = 0u;
573         auto valueCStr = std::make_unique<char[]>(NAPI_VALUE_STRING_LEN + 1);
574         size_t valueStrLength = 0;
575         napi_get_value_string_utf8(env, argv[0], valueCStr.get(), NAPI_VALUE_STRING_LEN, &valueStrLength);
576         std::string id(valueCStr.get(), valueStrLength);
577         if (id.empty()) {
578             HILOGE("Invalid event id:%{public}s", id.c_str());
579             return nullptr;
580         }
581         eventId = id;
582         HILOGD("Event id value:%{public}s", id.c_str());
583 
584         if (!IsExistValidCallback(env, eventId)) {
585             EH_LOGE_LIMIT("Invalid callback");
586             return nullptr;
587         }
588 
589         Priority priority = Priority::LOW;
590         if (argc < ARGC_NUM) {
591             auto event = InnerEvent::Get(eventId, make_unique<EventData>());
592             eventHandler->SendEvent(event, 0, priority);
593             return nullptr;
594         }
595 
596         bool hasPriority = false;
597         napi_value value = nullptr;
598         napi_has_named_property(env, argv[1], "priority", &hasPriority);
599         if (!hasPriority) {
600             if (!EmitWithEventData(env, argv[1], eventId, priority)) {
601                 auto event = InnerEvent::Get(eventId, make_unique<EventData>());
602                 eventHandler->SendEvent(event, 0, priority);
603             }
604             return nullptr;
605         }
606 
607         napi_get_named_property(env, argv[1], "priority", &value);
608         uint32_t priorityValue = 0u;
609         napi_get_value_uint32(env, value, &priorityValue);
610         HILOGD("Event priority:%{public}d", priorityValue);
611         priority = static_cast<Priority>(priorityValue);
612 
613         if (argc > ARGC_NUM && EmitWithEventData(env, argv[ARGC_NUM], eventId, priority)) {
614             return nullptr;
615         } else {
616             auto event = InnerEvent::Get(eventId, make_unique<EventData>());
617             eventHandler->SendEvent(event, 0, priority);
618         }
619         return nullptr;
620     }
621 
JS_Emit(napi_env env,napi_callback_info cbinfo)622     napi_value JS_Emit(napi_env env, napi_callback_info cbinfo)
623     {
624         HILOGD("enter");
625         size_t argc = ARGC_NUM + ARGC_ONE;
626         napi_value argv[ARGC_NUM + ARGC_ONE] = {0};
627         NAPI_CALL(env, napi_get_cb_info(env, cbinfo, &argc, argv, NULL, NULL));
628         if (argc < ARGC_ONE) {
629             HILOGE("Requires more than 1 parameter");
630             return nullptr;
631         }
632 
633         napi_valuetype eventValueType;
634         napi_typeof(env, argv[0], &eventValueType);
635         if (eventValueType != napi_object && eventValueType != napi_string) {
636             HILOGE("Type mismatch for parameter 1");
637             return nullptr;
638         }
639 
640         if (eventValueType == napi_string) {
641             return EmitWithEventIdString(env, argc, argv);
642         }
643         return EmitWithEventIdUint32(env, argc, argv);
644     }
645 
EnumEventClassConstructor(napi_env env,napi_callback_info info)646     napi_value EnumEventClassConstructor(napi_env env, napi_callback_info info)
647     {
648         napi_value thisArg = nullptr;
649         void *data = nullptr;
650 
651         napi_get_cb_info(env, info, nullptr, nullptr, &thisArg, &data);
652 
653         napi_value global = nullptr;
654         napi_get_global(env, &global);
655 
656         return thisArg;
657     }
658 
CreateEnumEventPriority(napi_env env,napi_value exports)659     napi_value CreateEnumEventPriority(napi_env env, napi_value exports)
660     {
661         napi_value immediate = nullptr;
662         napi_value high = nullptr;
663         napi_value low = nullptr;
664         napi_value idle = nullptr;
665 
666         napi_create_uint32(env, (uint32_t)Priority::IMMEDIATE, &immediate);
667         napi_create_uint32(env, (uint32_t)Priority::HIGH, &high);
668         napi_create_uint32(env, (uint32_t)Priority::LOW, &low);
669         napi_create_uint32(env, (uint32_t)Priority::IDLE, &idle);
670 
671         napi_property_descriptor desc[] = {
672             DECLARE_NAPI_STATIC_PROPERTY("IMMEDIATE", immediate),
673             DECLARE_NAPI_STATIC_PROPERTY("HIGH", high),
674             DECLARE_NAPI_STATIC_PROPERTY("LOW", low),
675             DECLARE_NAPI_STATIC_PROPERTY("IDLE", idle),
676         };
677         napi_value result = nullptr;
678         napi_define_class(env, "EventPriority", NAPI_AUTO_LENGTH, EnumEventClassConstructor, nullptr,
679             sizeof(desc) / sizeof(*desc), desc, &result);
680 
681         napi_set_named_property(env, exports, "EventPriority", result);
682 
683         return exports;
684     }
685 
CreateJsUndefined(napi_env env)686     napi_value CreateJsUndefined(napi_env env)
687     {
688         napi_value result = nullptr;
689         napi_get_undefined(env, &result);
690         return result;
691     }
692 
CreateJsNumber(napi_env env,uint32_t value)693     napi_value CreateJsNumber(napi_env env, uint32_t value)
694     {
695         napi_value result = nullptr;
696         napi_create_uint32(env, value, &result);
697         return result;
698     }
699 
JS_GetListenerCount(napi_env env,napi_callback_info cbinfo)700     napi_value JS_GetListenerCount(napi_env env, napi_callback_info cbinfo)
701     {
702         HILOGD("enter");
703         size_t argc = ARGC_NUM;
704         napi_value argv[ARGC_NUM] = {0};
705         NAPI_CALL(env, napi_get_cb_info(env, cbinfo, &argc, argv, NULL, NULL));
706         if (argc < ARGC_ONE) {
707             HILOGE("Requires more than 1 parameter");
708             return CreateJsUndefined(env);
709         }
710 
711         napi_valuetype eventValueType;
712         napi_typeof(env, argv[0], &eventValueType);
713         if (eventValueType != napi_number && eventValueType != napi_string) {
714             HILOGE("Type mismatch for parameter 1");
715             return CreateJsUndefined(env);
716         }
717 
718         uint32_t cnt = 0u;
719         InnerEvent::EventId eventId = 0u;
720         bool ret = GetEventIdWithNumberOrString(env, argv[0], eventValueType, eventId);
721         if (!ret) {
722             HILOGE("Event id is empty for parameter 1.");
723             return CreateJsUndefined(env);
724         }
725         std::lock_guard<std::mutex> lock(g_emitterInsMutex);
726         auto subscribe = emitterInstances.find(eventId);
727         if (subscribe != emitterInstances.end()) {
728             for (auto it = subscribe->second.begin(); it != subscribe->second.end();) {
729                 if ((*it)->isDeleted == true || (*it)->env == nullptr) {
730                     it = subscribe->second.erase(it);
731                     continue;
732                 }
733                 ++it;
734                 ++cnt;
735             }
736         }
737         return CreateJsNumber(env, cnt);
738     }
739 
EmitterInit(napi_env env,napi_value exports)740     napi_value EmitterInit(napi_env env, napi_value exports)
741     {
742         HILOGD("enter");
743         napi_property_descriptor desc[] = {
744             DECLARE_NAPI_FUNCTION("on", JS_On),
745             DECLARE_NAPI_FUNCTION("once", JS_Once),
746             DECLARE_NAPI_FUNCTION("off", JS_Off),
747             DECLARE_NAPI_FUNCTION("emit", JS_Emit),
748             DECLARE_NAPI_FUNCTION("getListenerCount", JS_GetListenerCount),
749         };
750         NAPI_CALL(env, napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc));
751 
752         CreateEnumEventPriority(env, exports);
753 
754         eventHandler = EventHandlerInstance::GetInstance();
755         return exports;
756     }
757 }  // namespace AppExecFwk
758 }  // namespace OHOS
759