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