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