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