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
28using namespace std;
29namespace OHOS {
30namespace AppExecFwk {
31namespace {
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;
38    AsyncCallbackInfo::~AsyncCallbackInfo()
39    {
40        env = nullptr;
41    }
42    EventHandlerInstance::EventHandlerInstance(const std::shared_ptr<EventRunner>& runner): EventHandler(runner)
43    {
44        HILOGI("EventHandlerInstance constructed");
45    }
46    EventHandlerInstance::~EventHandlerInstance()
47    {
48        HILOGI("EventHandlerInstance de-constructed");
49    }
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
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
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
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
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>();
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
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
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
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
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
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
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
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
423    napi_value JS_On(napi_env env, napi_callback_info cbinfo)
424    {
425        HILOGD("enter");
426        return OnOrOnce(env, cbinfo, false);
427    }
428
429    napi_value JS_Once(napi_env env, napi_callback_info cbinfo)
430    {
431        HILOGD("enter");
432        return OnOrOnce(env, cbinfo, true);
433    }
434
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
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
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
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
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
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
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
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
686    napi_value CreateJsUndefined(napi_env env)
687    {
688        napi_value result = nullptr;
689        napi_get_undefined(env, &result);
690        return result;
691    }
692
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
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
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