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